laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/29067 )
Change subject: proactive: Send a Terminal Response automatically after a Fetch ......................................................................
proactive: Send a Terminal Response automatically after a Fetch
Change-Id: I43bc994e7517b5907fb40a98d84797c54056c47d --- M pySim/transport/__init__.py 1 file changed, 43 insertions(+), 7 deletions(-)
Approvals: Jenkins Builder: Verified laforge: Looks good to me, approved
diff --git a/pySim/transport/__init__.py b/pySim/transport/__init__.py index fb04209..09752ac 100644 --- a/pySim/transport/__init__.py +++ b/pySim/transport/__init__.py @@ -10,7 +10,7 @@ from pySim.exceptions import * from pySim.construct import filter_dict from pySim.utils import sw_match, b2h, h2b, i2h, Hexstr -from pySim.cat import ProactiveCommand +from pySim.cat import ProactiveCommand, CommandDetails, DeviceIdentities, Result
# # Copyright (C) 2009-2010 Sylvain Munaut tnt@246tNt.com @@ -42,10 +42,7 @@ """Abstract base class representing the interface of some code that handles the proactive commands, as returned by the card in responses to the FETCH command.""" - def receive_fetch_raw(self, payload: Hexstr): - # parse the proactive command - pcmd = ProactiveCommand() - parsed = pcmd.from_tlv(h2b(payload)) + def receive_fetch_raw(self, pcmd: ProactiveCommand, parsed: Hexstr): # try to find a generic handler like handle_SendShortMessage handle_name = 'handle_%s' % type(parsed).__name__ if hasattr(self, handle_name): @@ -167,11 +164,50 @@ # need not concern the caller. rv = (rv[0], '9000') # proactive sim as per TS 102 221 Setion 7.4.2 + # TODO: Check SW manually to avoid recursing on the stack (provided this piece of code stays in this place) fetch_rv = self.send_apdu_checksw('80120000' + last_sw[2:], sw) + # Setting this in case we later decide not to send a terminal + # response immediately unconditionally -- the card may still have + # something pending even though the last command was not processed + # yet. last_sw = fetch_rv[1] - print("FETCH: %s" % fetch_rv[0]) + # parse the proactive command + pcmd = ProactiveCommand() + parsed = pcmd.from_tlv(h2b(fetch_rv[0])) + print("FETCH: %s (%s)" % (fetch_rv[0], type(parsed).__name__)) + result = Result() if self.proactive_handler: - self.proactive_handler.receive_fetch_raw(fetch_rv[0]) + # Extension point: If this does return a list of TLV objects, + # they could be appended after the Result; if the first is a + # Result, that cuold replace the one built here. + self.proactive_handler.receive_fetch_raw(pcmd, parsed) + result.from_dict({'general_result': 'performed_successfully', 'additional_information': ''}) + else: + result.from_dict({'general_result': 'command_beyond_terminal_capability', 'additional_information': ''}) + + # Send response immediately, thus also flushing out any further + # proactive commands that the card already wants to send + # + # Structure as per TS 102 223 V4.4.0 Section 6.8 + + # The Command Details are echoed from the command that has been processed. + (command_details,) = [c for c in pcmd.decoded.children if isinstance(c, CommandDetails)] + # The Device Identities are fixed. (TS 102 223 V4.0.0 Section 6.8.2) + device_identities = DeviceIdentities() + device_identities.from_dict({'source_dev_id': 'terminal', 'dest_dev_id': 'uicc'}) + + # Testing hint: The value of tail does not influence the behavior + # of an SJA2 that sent ans SMS, so this is implemented only + # following TS 102 223, and not fully tested. + tail = command_details.to_tlv() + device_identities.to_tlv() + result.to_tlv() + # Testing hint: In contrast to the above, this part is positively + # essential to get the SJA2 to provide the later parts of a + # multipart SMS in response to an OTA RFM command. + terminal_response = '80140000' + b2h(len(tail).to_bytes(1, 'big') + tail) + + terminal_response_rv = self.send_apdu(terminal_response) + last_sw = terminal_response_rv[1] + if not sw_match(rv[1], sw): raise SwMatchError(rv[1], sw.lower(), self.sw_interpreter) return rv