pySim/transport add support for T=1 protocol and fix APDU/TPDU layer conflicts

ETSI TS 102 221, section 7.3 specifies that UICCs (and eUICCs) may support two
different transport protocols: T=0 or T=1 or both. The spec also says that the
terminal must support both protocols.

This patch adds the necessary functionality to support the T=1 protocol
alongside the T=0 protocol. However, this also means that we have to sharpen
the lines between APDUs and TPDUs.

As this patch also touches the low level interface to readers it was also
manually tested with a classic serial reader. Calypso and AT command readers
were not tested.

Change-Id: I8b56d7804a2b4c392f43f8540e0b6e70001a8970
Related: OS#6367
This commit is contained in:
Philipp Maier
2024-10-28 17:28:43 +01:00
parent f951c56449
commit 852eff54df
25 changed files with 606 additions and 144 deletions

View File

@@ -25,14 +25,14 @@ import serial
from osmocom.utils import Hexstr
from pySim.utils import ResTuple
from pySim.transport import LinkBase
from pySim.transport import LinkBaseTpdu
from pySim.exceptions import ReaderError, ProtocolError
# HACK: if somebody needs to debug this thing
# log.root.setLevel(log.DEBUG)
class ModemATCommandLink(LinkBase):
class ModemATCommandLink(LinkBaseTpdu):
"""Transport Link for 3GPP TS 27.007 compliant modems."""
name = "modem for Generic SIM Access (3GPP TS 27.007)"
@@ -145,12 +145,12 @@ class ModemATCommandLink(LinkBase):
def wait_for_card(self, timeout: Optional[int] = None, newcardonly: bool = False):
pass # Nothing to do really ...
def _send_apdu_raw(self, pdu: Hexstr) -> ResTuple:
def send_tpdu(self, tpdu: Hexstr) -> ResTuple:
# Make sure pdu has upper case hex digits [A-F]
pdu = pdu.upper()
tpdu = tpdu.upper()
# Prepare the command as described in 8.17
cmd = 'AT+CSIM=%d,\"%s\"' % (len(pdu), pdu)
cmd = 'AT+CSIM=%d,\"%s\"' % (len(tpdu), tpdu)
log.debug('Sending command: %s', cmd)
# Send AT+CSIM command to the modem
@@ -164,14 +164,14 @@ class ModemATCommandLink(LinkBase):
# Make sure that the response has format: b'+CSIM: %d,\"%s\"'
try:
result = re.match(b'\+CSIM: (\d+),\"([0-9A-F]+)\"', rsp)
(_rsp_pdu_len, rsp_pdu) = result.groups()
(_rsp_tpdu_len, rsp_tpdu) = result.groups()
except Exception as exc:
raise ReaderError('Failed to parse response from modem: %s' % rsp) from exc
# TODO: make sure we have at least SW
data = rsp_pdu[:-4].decode().lower()
sw = rsp_pdu[-4:].decode().lower()
log.debug('Command response: %s, %s', data, sw)
data = rsp_tpdu[:-4].decode().lower()
sw = rsp_tpdu[-4:].decode().lower()
log.debug('Command response: %s, %s', data, sw)
return data, sw
def __str__(self) -> str: