diff --git a/pySim-shell.py b/pySim-shell.py index 50deea2a..39678fdd 100755 --- a/pySim-shell.py +++ b/pySim-shell.py @@ -136,8 +136,7 @@ Online manual available at https://downloads.osmocom.org/docs/pysim/master/html/ self.add_settable(Settable2Compat('apdu_trace', bool, 'Trace and display APDUs exchanged with card', self, onchange_cb=self._onchange_apdu_trace)) self.add_settable(Settable2Compat('apdu_strict', bool, - 'Enforce APDU responses according to ISO/IEC 7816-3, table 12', self, - onchange_cb=self._onchange_apdu_strict)) + 'Strictly apply APDU format according to ISO/IEC 7816-3, table 12', self)) self.add_settable(Settable2Compat('verbose', bool, 'Enable/disable verbose logging', self, onchange_cb=self._onchange_verbose)) @@ -218,13 +217,6 @@ Online manual available at https://downloads.osmocom.org/docs/pysim/master/html/ else: self.card._scc._tp.apdu_tracer = None - def _onchange_apdu_strict(self, param_name, old, new): - if self.card: - if new == True: - self.card._scc._tp.apdu_strict = True - else: - self.card._scc._tp.apdu_strict = False - def _onchange_verbose(self, param_name, old, new): PySimLogger.set_verbose(new) if new == True: @@ -295,9 +287,9 @@ Online manual available at https://downloads.osmocom.org/docs/pysim/master/html/ # can be executed without the presence of a runtime state (self.rs) object. However, this also means that # self.lchan is also not present (see method equip). if opts.raw or self.lchan is None: - data, sw = self.card._scc.send_apdu(opts.APDU, apply_lchan = False) + data, sw = self.card._scc.send_apdu(opts.APDU, apply_lchan = False, apdu_strict = self.apdu_strict) else: - data, sw = self.lchan.scc.send_apdu(opts.APDU, apply_lchan = False) + data, sw = self.lchan.scc.send_apdu(opts.APDU, apply_lchan = False, apdu_strict = self.apdu_strict) if data: self.poutput("SW: %s, RESP: %s" % (sw, data)) else: diff --git a/pySim/commands.py b/pySim/commands.py index 066a2c48..b973b939 100644 --- a/pySim/commands.py +++ b/pySim/commands.py @@ -87,7 +87,7 @@ class SimCardCommands: else: return 255 - def send_apdu(self, pdu: Hexstr, apply_lchan:bool = True) -> ResTuple: + def send_apdu(self, pdu: Hexstr, apply_lchan:bool = True, apdu_strict: bool = True) -> ResTuple: """Sends an APDU and auto fetch response data Args: @@ -101,11 +101,12 @@ class SimCardCommands: if apply_lchan: pdu = cla_with_lchan(pdu[0:2], self.lchan_nr) + pdu[2:] if self.scp: - return self.scp.send_apdu_wrapper(self._tp.send_apdu, pdu) + return self.scp.send_apdu_wrapper(self._tp.send_apdu, pdu, apdu_strict = apdu_strict) else: - return self._tp.send_apdu(pdu) + return self._tp.send_apdu(pdu, apdu_strict = apdu_strict) - def send_apdu_checksw(self, pdu: Hexstr, sw: SwMatchstr = "9000", apply_lchan:bool = True) -> ResTuple: + def send_apdu_checksw(self, pdu: Hexstr, sw: SwMatchstr = "9000", apply_lchan:bool = True, + apdu_strict: bool = True) -> ResTuple: """Sends an APDU and check returned SW Args: @@ -121,12 +122,13 @@ class SimCardCommands: if apply_lchan: pdu = cla_with_lchan(pdu[0:2], self.lchan_nr) + pdu[2:] if self.scp: - return self.scp.send_apdu_wrapper(self._tp.send_apdu_checksw, pdu, sw) + return self.scp.send_apdu_wrapper(self._tp.send_apdu_checksw, pdu, sw, apdu_strict = apdu_strict) else: - return self._tp.send_apdu_checksw(pdu, sw) + return self._tp.send_apdu_checksw(pdu, sw, apdu_strict = apdu_strict) def send_apdu_constr(self, cla: Hexstr, ins: Hexstr, p1: Hexstr, p2: Hexstr, cmd_constr: Construct, - cmd_data: Hexstr, resp_constr: Construct, apply_lchan:bool = True) -> Tuple[dict, SwHexstr]: + cmd_data: Hexstr, resp_constr: Construct, apply_lchan:bool = True, + apdu_strict: bool = True) -> Tuple[dict, SwHexstr]: """Build and sends an APDU using a 'construct' definition; parses response. Args: @@ -145,7 +147,7 @@ class SimCardCommands: lc = i2h([len(cmd)]) if cmd_data else '' le = '00' if resp_constr else '' pdu = ''.join([cla, ins, p1, p2, lc, b2h(cmd), le]) - (data, sw) = self.send_apdu(pdu, apply_lchan = apply_lchan) + (data, sw) = self.send_apdu(pdu, apply_lchan = apply_lchan, apdu_strict = apdu_strict) if data: # filter the resulting dict to avoid '_io' members inside rsp = filter_dict(resp_constr.parse(h2b(data))) @@ -155,7 +157,8 @@ class SimCardCommands: def send_apdu_constr_checksw(self, cla: Hexstr, ins: Hexstr, p1: Hexstr, p2: Hexstr, cmd_constr: Construct, cmd_data: Hexstr, resp_constr: Construct, - sw_exp: SwMatchstr="9000", apply_lchan:bool = True) -> Tuple[dict, SwHexstr]: + sw_exp: SwMatchstr="9000", apply_lchan:bool = True, + apdu_strict: bool = True) -> Tuple[dict, SwHexstr]: """Build and sends an APDU using a 'construct' definition; parses response. Args: @@ -171,7 +174,7 @@ class SimCardCommands: Tuple of (decoded_data, sw) """ (rsp, sw) = self.send_apdu_constr(cla, ins, p1, p2, cmd_constr, cmd_data, resp_constr, - apply_lchan = apply_lchan) + apply_lchan = apply_lchan, apdu_strict = apdu_strict) if not sw_match(sw, sw_exp): raise SwMatchError(sw, sw_exp.lower(), self._tp.sw_interpreter) return (rsp, sw) diff --git a/pySim/transport/__init__.py b/pySim/transport/__init__.py index f19790c7..68070484 100644 --- a/pySim/transport/__init__.py +++ b/pySim/transport/__init__.py @@ -90,7 +90,6 @@ class LinkBase(abc.ABC): self.sw_interpreter = sw_interpreter self.apdu_tracer = apdu_tracer self.proactive_handler = proactive_handler - self.apdu_strict = False @abc.abstractmethod def __str__(self) -> str: @@ -141,11 +140,12 @@ class LinkBase(abc.ABC): self.apdu_tracer.trace_reset() return self._reset_card() - def send_apdu(self, apdu: Hexstr) -> ResTuple: + def send_apdu(self, apdu: Hexstr, apdu_strict: bool = True) -> ResTuple: """Sends an APDU with minimal processing Args: apdu : string of hexadecimal characters (ex. "A0A40000023F00", must comply to ISO/IEC 7816-3, section 12.1) + apdu_strict : strictly apply APDU format according to ISO/IEC 7816-3, table 12 Returns: tuple(data, sw), where data : string (in hex) of returned data (ex. "074F4EFFFF") @@ -174,26 +174,27 @@ class LinkBase(abc.ABC): if len(data) > 0 and (case == 3 or case == 1): exeption_str = 'received unexpected response data, incorrect APDU-case ' + \ '(%d, should be %d, missing Le field?)!' % (case, case + 1) - if self.apdu_strict: + if apdu_strict: raise ValueError(exeption_str) else: log.warning(exeption_str) return (data, sw) - def send_apdu_checksw(self, apdu: Hexstr, sw: SwMatchstr = "9000") -> ResTuple: + def send_apdu_checksw(self, apdu: Hexstr, sw: SwMatchstr = "9000", apdu_strict: bool = True) -> ResTuple: """Sends an APDU and check returned SW Args: apdu : string of hexadecimal characters (ex. "A0A40000023F00", must comply to ISO/IEC 7816-3, section 12.1) - sw : string of 4 hexadecimal characters (ex. "9000"). The user may mask out certain - digits using a '?' to add some ambiguity if needed. + sw : string of 4 hexadecimal characters (ex. "9000"). The user may mask out certain digits using a '?' + to add some ambiguity if needed. + apdu_strict : strictly apply APDU format according to ISO/IEC 7816-3, table 12 Returns: tuple(data, sw), where data : string (in hex) of returned data (ex. "074F4EFFFF") sw : string (in hex) of status word (ex. "9000") """ - rv = self.send_apdu(apdu) + rv = self.send_apdu(apdu, apdu_strict) last_sw = rv[1] while sw == '9000' and sw_match(last_sw, '91xx'):