aboutsummaryrefslogtreecommitdiffstats
path: root/pySim
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2024-02-15 20:32:41 +0100
committerHarald Welte <laforge@osmocom.org>2024-02-15 20:35:29 +0100
commit979c837286d3e5fa41322d2f97c4a31494cb5da5 (patch)
treee384246f43e5ce5a8ef2de72a2e4d3d1bb471cc0 /pySim
parent1432af51500de2b06cfc6861416e8e29128c05fd (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.py16
-rw-r--r--pySim/global_platform/__init__.py5
-rw-r--r--pySim/global_platform/scp.py5
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: