diff options
author | Harald Welte <laforge@osmocom.org> | 2024-02-15 20:32:41 +0100 |
---|---|---|
committer | Harald Welte <laforge@osmocom.org> | 2024-02-15 20:35:29 +0100 |
commit | 979c837286d3e5fa41322d2f97c4a31494cb5da5 (patch) | |
tree | e384246f43e5ce5a8ef2de72a2e4d3d1bb471cc0 /pySim | |
parent | 1432af51500de2b06cfc6861416e8e29128c05fd (diff) |
Dynamically determine maximum CMD data length depending on SCP
If we're using a Secure Channel Protocol, this will add overhead
in terms of the C-MAC appended to the C-APDU. This means in turn that
the useable length of the data field shrinks by a certain number of
bytes.
Let's make sure the SCP instances expose an 'overhead' property
of how much overhead they add - and that other commands use this to
determine the maximum command data field length.
Change-Id: I0a081a23efe20c77557600e62b52ba90a401058d
Diffstat (limited to 'pySim')
-rw-r--r-- | pySim/commands.py | 16 | ||||
-rw-r--r-- | pySim/global_platform/__init__.py | 5 | ||||
-rw-r--r-- | pySim/global_platform/scp.py | 5 |
3 files changed, 20 insertions, 6 deletions
diff --git a/pySim/commands.py b/pySim/commands.py index 4e439e6..9a49124 100644 --- a/pySim/commands.py +++ b/pySim/commands.py @@ -84,6 +84,14 @@ class SimCardCommands: """Return the (cached) patched default CLA byte for this card.""" return self._cla4lchan + @property + def max_cmd_len(self) -> int: + """Maximum length of the command apdu data section. Depends on secure channel protocol used.""" + if self.scp: + return 255 - self.scp.overhead + else: + return 255 + @cla_byte.setter def cla_byte(self, new_val: Hexstr): """Set the (raw, without lchan) default CLA value for this card.""" @@ -318,7 +326,7 @@ class SimCardCommands: total_data = '' chunk_offset = 0 while chunk_offset < length: - chunk_len = min(255, length-chunk_offset) + chunk_len = min(self.max_cmd_len, length-chunk_offset) pdu = self.cla_byte + \ 'b0%04x%02x' % (offset + chunk_offset, chunk_len) try: @@ -376,7 +384,7 @@ class SimCardCommands: total_data = '' chunk_offset = 0 while chunk_offset < data_length: - chunk_len = min(255, data_length - chunk_offset) + chunk_len = min(self.max_cmd_len, data_length - chunk_offset) # chunk_offset is bytes, but data slicing is hex chars, so we need to multiply by 2 pdu = self.cla_byte + \ 'd6%04x%02x' % (offset + chunk_offset, chunk_len) + \ @@ -560,10 +568,10 @@ class SimCardCommands: total_len = len(tlv_bin) remaining = tlv_bin while len(remaining) > 0: - fragment = remaining[:255] + fragment = remaining[:self.max_cmd_len] rdata, sw = self._set_data(fragment, first=first) first = False - remaining = remaining[255:] + remaining = remaining[self.max_cmd_len:] return rdata, sw def run_gsm(self, rand: Hexstr) -> ResTuple: diff --git a/pySim/global_platform/__init__.py b/pySim/global_platform/__init__.py index 4d553a7..9960560 100644 --- a/pySim/global_platform/__init__.py +++ b/pySim/global_platform/__init__.py @@ -492,13 +492,14 @@ class ADF_SD(CardADF): def store_data(self, data: bytes, structure:str = 'none', encryption:str = 'none', response_permitted: bool = False) -> bytes: """Perform the GlobalPlatform GET DATA command in order to store some card-specific data. See GlobalPlatform CardSpecification v2.3Section 11.11 for details.""" + max_cmd_len = self._cmd.lchan.scc.max_cmd_len # Table 11-89 of GP Card Specification v2.3 remainder = data block_nr = 0 response = '' while len(remainder): - chunk = remainder[:255] - remainder = remainder[255:] + chunk = remainder[:max_cmd_len] + remainder = remainder[max_cmd_len:] p1b = build_construct(ADF_SD.StoreData, {'last_block': len(remainder) == 0, 'encryption': encryption, 'structure': structure, 'response': response_permitted}) diff --git a/pySim/global_platform/scp.py b/pySim/global_platform/scp.py index 0804492..967a582 100644 --- a/pySim/global_platform/scp.py +++ b/pySim/global_platform/scp.py @@ -218,6 +218,10 @@ class SCP02(SCP): 'seq_counter'/Int16ub, 'card_challenge'/Bytes(6), 'card_cryptogram'/Bytes(8)) kvn_range = [0x20, 0x2f] + def __init__(self, *args, **kwargs): + self.overhead = 8 + super().__init__(*args, **kwargs) + def dek_encrypt(self, plaintext:bytes) -> bytes: cipher = DES.new(self.card_keys.dek, DES.MODE_ECB) return cipher.encrypt(plaintext) @@ -410,6 +414,7 @@ class SCP03(SCP): def __init__(self, *args, **kwargs): self.s_mode = kwargs.pop('s_mode', 8) + self.overhead = self.s_mode super().__init__(*args, **kwargs) def dek_encrypt(self, plaintext:bytes) -> bytes: |