diff --git a/pySim/cdma_ruim.py b/pySim/cdma_ruim.py index 747a0d25..f5382c9d 100644 --- a/pySim/cdma_ruim.py +++ b/pySim/cdma_ruim.py @@ -24,7 +24,6 @@ from osmocom.utils import * from osmocom.construct import * from pySim.filesystem import * -from pySim.profile import match_ruim from pySim.profile import CardProfile, CardProfileAddon from pySim.ts_51_011 import CardProfileSIM from pySim.ts_51_011 import DF_TELECOM, DF_GSM @@ -191,8 +190,11 @@ class CardProfileRUIM(CardProfile): return CardProfileSIM.decode_select_response(data_hex) @classmethod - def match_with_card(cls, scc: SimCardCommands) -> bool: - return match_ruim(scc) + def _try_match_card(cls, scc: SimCardCommands) -> None: + """ Try to access MF/DF.CDMA via 2G APDUs (3GPP TS 11.11), if this works, + the card is considered an R-UIM card for CDMA.""" + cls._mf_select_test(scc, "a0", "0000", ["3f00", "7f25"]) + class AddonRUIM(CardProfileAddon): """An Addon that can be found on on a combined SIM + RUIM or UICC + RUIM to support CDMA.""" diff --git a/pySim/profile.py b/pySim/profile.py index ae9e19fe..ffb748e6 100644 --- a/pySim/profile.py +++ b/pySim/profile.py @@ -25,54 +25,11 @@ import abc import operator from typing import List +from pySim.exceptions import SwMatchError from pySim.commands import SimCardCommands from pySim.filesystem import CardApplication, interpret_sw from pySim.utils import all_subclasses -def _mf_select_test(scc: SimCardCommands, - cla_byte: str, sel_ctrl: str, - fids: List[str]) -> bool: - cla_byte_bak = scc.cla_byte - sel_ctrl_bak = scc.sel_ctrl - scc.reset_card() - - scc.cla_byte = cla_byte - scc.sel_ctrl = sel_ctrl - rc = True - try: - for fid in fids: - scc.select_file(fid) - except: - rc = False - - scc.reset_card() - scc.cla_byte = cla_byte_bak - scc.sel_ctrl = sel_ctrl_bak - return rc - - -def match_uicc(scc: SimCardCommands) -> bool: - """ Try to access MF via UICC APDUs (3GPP TS 102.221), if this works, the - card is considered a UICC card. - """ - return _mf_select_test(scc, "00", "0004", ["3f00"]) - - -def match_sim(scc: SimCardCommands) -> bool: - """ Try to access MF via 2G APDUs (3GPP TS 11.11), if this works, the card - is also a simcard. This will be the case for most UICC cards, but there may - also be plain UICC cards without 2G support as well. - """ - return _mf_select_test(scc, "a0", "0000", ["3f00"]) - - -def match_ruim(scc: SimCardCommands) -> bool: - """ Try to access MF/DF.CDMA via 2G APDUs (3GPP TS 11.11), if this works, - the card is considered an R-UIM card for CDMA. - """ - return _mf_select_test(scc, "a0", "0000", ["3f00", "7f25"]) - - class CardProfile: """A Card Profile describes a card, it's filesystem hierarchy, an [initial] list of applications as well as profile-specific SW and shell commands. Every card has @@ -137,14 +94,40 @@ class CardProfile: """ return data_hex + @staticmethod + def _mf_select_test(scc: SimCardCommands, + cla_byte: str, sel_ctrl: str, + fids: List[str]) -> bool: + """Helper function used by some derived _try_match_card() methods.""" + scc.reset_card() + + scc.cla_byte = cla_byte + scc.sel_ctrl = sel_ctrl + for fid in fids: + scc.select_file(fid) + @classmethod @abc.abstractmethod - def match_with_card(cls, scc: SimCardCommands) -> bool: - """Check if the specific profile matches the card. This method is a + def _try_match_card(cls, scc: SimCardCommands) -> None: + """Try to see if the specific profile matches the card. This method is a placeholder that is overloaded by specific dirived classes. The method actively probes the card to make sure the profile class matches the physical card. This usually also means that the card is reset during the process, so this method must not be called at random times. It may + only be called on startup. If there is no exception raised, we assume + the card matches the profile. + + Args: + scc: SimCardCommands class + """ + pass + + @classmethod + def match_with_card(cls, scc: SimCardCommands) -> bool: + """Check if the specific profile matches the card. The method + actively probes the card to make sure the profile class matches the + physical card. This usually also means that the card is reset during + the process, so this method must not be called at random times. It may only be called on startup. Args: @@ -152,7 +135,17 @@ class CardProfile: Returns: match = True, no match = False """ - return False + sel_backup = scc.sel_ctrl + cla_backup = scc.cla_byte + try: + cls._try_match_card(scc) + return True + except SwMatchError: + return False + finally: + scc.sel_ctrl = sel_backup + scc.cla_byte = cla_backup + scc.reset_card() @staticmethod def pick(scc: SimCardCommands): diff --git a/pySim/ts_102_221.py b/pySim/ts_102_221.py index c1c1388b..9fed6af5 100644 --- a/pySim/ts_102_221.py +++ b/pySim/ts_102_221.py @@ -27,7 +27,6 @@ from osmocom.tlv import * from pySim.utils import * from pySim.filesystem import * from pySim.profile import CardProfile -from pySim.profile import match_uicc from pySim import iso7816_4 # A UICC will usually also support 2G functionality. If this is the case, we @@ -885,8 +884,10 @@ class CardProfileUICC(CardProfile): return flatten_dict_lists(d['fcp_template']) @classmethod - def match_with_card(cls, scc: SimCardCommands) -> bool: - return match_uicc(scc) + def _try_match_card(cls, scc: SimCardCommands) -> None: + """ Try to access MF via UICC APDUs (3GPP TS 102.221), if this works, the + card is considered a UICC card.""" + cls._mf_select_test(scc, "00", "0004", ["3f00"]) @with_default_category('TS 102 221 Specific Commands') class AddlShellCommands(CommandSet): diff --git a/pySim/ts_51_011.py b/pySim/ts_51_011.py index 69c8c79b..8cbca581 100644 --- a/pySim/ts_51_011.py +++ b/pySim/ts_51_011.py @@ -41,7 +41,6 @@ from osmocom.construct import * from pySim.utils import dec_iccid, enc_iccid, dec_imsi, enc_imsi, dec_plmn, enc_plmn, dec_xplmn_w_act from pySim.utils import dec_msisdn, enc_msisdn -from pySim.profile import match_sim from pySim.profile import CardProfile, CardProfileAddon from pySim.filesystem import * from pySim.ts_31_102_telecom import DF_PHONEBOOK, DF_MULTIMEDIA, DF_MCS, DF_V2X @@ -1193,8 +1192,8 @@ class CardProfileSIM(CardProfile): return ret @classmethod - def match_with_card(cls, scc: SimCardCommands) -> bool: - return match_sim(scc) + def _try_match_card(cls, scc: SimCardCommands) -> None: + cls._mf_select_test(scc, "a0", "0000", ["3f00"]) class AddonSIM(CardProfileAddon):