lists.osmocom.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

gerrit-log

Thread Start a new thread
Download
Threads by month
  • ----- 2026 -----
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2025 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
gerrit-log@lists.osmocom.org

July 2023

  • 1 participants
  • 3051 discussions
[M] Change in pysim[master]: Introduce concept of CardProfileAddon
by laforge 18 Jul '23

18 Jul '23
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/33699 ) Change subject: Introduce concept of CardProfileAddon ...................................................................... Introduce concept of CardProfileAddon We have a strict "one CardProfile per card" rule. For a modern UICC without legacy SIM support, that works great, as all applications have AID and ADF and can hence be enumerated/detected that way. However, in reality there are mostly UICC that have legacy SIM, GSM-R or even CDMA support, all of which are not proper UICC applications for historical reasons. So instead of having hard-coded hacks in various places, let's introduce the new concept of a CardProfileAddon. Every profile can have any number of those. When building up the RuntimeState, we iterate over the CardProfile addons, and probe which of those are actually on the card. For those discovered, we add their files to the filesystem hierarchy. Change-Id: I5866590b6d48f85eb889c9b1b8ab27936d2378b9 --- M pySim-shell.py M pySim-trace.py M pySim/cdma_ruim.py M pySim/filesystem.py M pySim/gsm_r.py M pySim/profile.py M pySim/ts_102_221.py M pySim/ts_51_011.py 8 files changed, 128 insertions(+), 15 deletions(-) Approvals: Jenkins Builder: Verified laforge: Looks good to me, approved diff --git a/pySim-shell.py b/pySim-shell.py index 4d4f2e2..b48abc7 100755 --- a/pySim-shell.py +++ b/pySim-shell.py @@ -137,11 +137,6 @@ # Create runtime state with card profile rs = RuntimeState(card, profile) - # FIXME: This is an GSM-R related file, it needs to be added throughout, - # the profile. At the moment we add it for all cards, this won't hurt, - # but regular SIM and UICC will not have it and fail to select it. - rs.mf.add_file(DF_EIRENE()) - CardModel.apply_matching_models(scc, rs) # inform the transport that we can do context-specific SW interpretation diff --git a/pySim-trace.py b/pySim-trace.py index 4c8696d..ba1568c 100755 --- a/pySim-trace.py +++ b/pySim-trace.py @@ -11,7 +11,7 @@ from pySim.cards import UiccCardBase from pySim.commands import SimCardCommands from pySim.profile import CardProfile -from pySim.ts_102_221 import CardProfileUICCSIM +from pySim.ts_102_221 import CardProfileUICC from pySim.ts_31_102 import CardApplicationUSIM from pySim.ts_31_103 import CardApplicationISIM from pySim.transport import LinkBase @@ -70,8 +70,9 @@ class Tracer: def __init__(self, **kwargs): - # we assume a generic SIM + UICC + USIM + ISIM card - profile = CardProfileUICCSIM() + # we assume a generic UICC profile; as all APDUs return 9000 in DummySimLink above, + # all CardProfileAddon (including SIM) will probe successful. + profile = CardProfileUICC() profile.add_application(CardApplicationUSIM()) profile.add_application(CardApplicationISIM()) scc = SimCardCommands(transport=DummySimLink()) diff --git a/pySim/cdma_ruim.py b/pySim/cdma_ruim.py index 8b66490..b254403 100644 --- a/pySim/cdma_ruim.py +++ b/pySim/cdma_ruim.py @@ -22,7 +22,7 @@ from pySim.utils import * from pySim.filesystem import * from pySim.profile import match_ruim -from pySim.profile import CardProfile +from pySim.profile import CardProfile, CardProfileAddon from pySim.ts_51_011 import CardProfileSIM from pySim.ts_51_011 import DF_TELECOM, DF_GSM from pySim.ts_51_011 import EF_ServiceTable @@ -191,3 +191,14 @@ @staticmethod def match_with_card(scc: SimCardCommands) -> bool: return match_ruim(scc) + +class AddonRUIM(CardProfileAddon): + """An Addon that can be found on on a combined SIM + RUIM or UICC + RUIM to support CDMA.""" + def __init__(self): + files = [ + DF_CDMA() + ] + super().__init__('RUIM', desc='CDMA RUIM', files_in_mf=files) + + def probe(self, card: 'CardBase') -> bool: + return card.file_exists(self.files_in_mf[0].fid) diff --git a/pySim/filesystem.py b/pySim/filesystem.py index 22ff60d..cb3b403 100644 --- a/pySim/filesystem.py +++ b/pySim/filesystem.py @@ -1307,6 +1307,16 @@ self.card.set_apdu_parameter( cla=self.profile.cla, sel_ctrl=self.profile.sel_ctrl) + for addon_cls in self.profile.addons: + addon = addon_cls() + if addon.probe(self.card): + print("Detected %s Add-on \"%s\"" % (self.profile, addon)) + for f in addon.files_in_mf: + self.mf.add_file(f) + + # go back to MF before the next steps (addon probing might have changed DF) + self.card._scc.select_file('3F00') + # add application ADFs + MF-files from profile apps = self._match_applications() for a in apps: diff --git a/pySim/gsm_r.py b/pySim/gsm_r.py index 389a8cb..cd111d6 100644 --- a/pySim/gsm_r.py +++ b/pySim/gsm_r.py @@ -35,8 +35,8 @@ from pySim.construct import * import enum +from pySim.profile import CardProfileAddon from pySim.filesystem import * -import pySim.ts_102_221 import pySim.ts_51_011 ###################################################################### @@ -362,3 +362,15 @@ desc='Free Number Call Type 0 and 8'), ] self.add_files(files) + + +class AddonGSMR(CardProfileAddon): + """An Addon that can be found on either classic GSM SIM or on UICC to support GSM-R.""" + def __init__(self): + files = [ + DF_EIRENE() + ] + super().__init__('GSM-R', desc='Railway GSM', files_in_mf=files) + + def probe(self, card: 'CardBase') -> bool: + return card.file_exists(self.files_in_mf[0].fid) diff --git a/pySim/profile.py b/pySim/profile.py index e464e1f..0d09e81 100644 --- a/pySim/profile.py +++ b/pySim/profile.py @@ -88,6 +88,7 @@ shell_cmdsets : List of cmd2 shell command sets of profile-specific commands cla : class byte that should be used with cards of this profile sel_ctrl : selection control bytes class byte that should be used with cards of this profile + addons: List of optional CardAddons that a card of this profile might have """ self.name = name self.desc = kw.get("desc", None) @@ -97,6 +98,8 @@ self.shell_cmdsets = kw.get("shell_cmdsets", []) self.cla = kw.get("cla", "00") self.sel_ctrl = kw.get("sel_ctrl", "0004") + # list of optional addons that a card of this profile might have + self.addons = kw.get("addons", []) def __str__(self): return self.name @@ -161,3 +164,34 @@ return p() return None + + def add_addon(self, addon: 'CardProfileAddon'): + assert(addon not in self.addons) + # we don't install any additional files, as that is happening in the RuntimeState. + self.addons.append(addon) + +class CardProfileAddon(abc.ABC): + """A Card Profile Add-on is something that is not a card application or a full stand-alone + card profile, but an add-on to an existing profile. Think of GSM-R specific files existing + on what is otherwise a SIM or USIM+SIM card.""" + + def __init__(self, name: str, **kw): + """ + Args: + desc (str) : Description + files_in_mf : List of CardEF instances present in MF + shell_cmdsets : List of cmd2 shell command sets of profile-specific commands + """ + self.name = name + self.desc = kw.get("desc", None) + self.files_in_mf = kw.get("files_in_mf", []) + self.shell_cmdsets = kw.get("shell_cmdsets", []) + pass + + def __str__(self): + return self.name + + @abc.abstractmethod + def probe(self, card: 'CardBase') -> bool: + """Probe a given card to determine whether or not this add-on is present/supported.""" + pass diff --git a/pySim/ts_102_221.py b/pySim/ts_102_221.py index b6c003b..df8b842 100644 --- a/pySim/ts_102_221.py +++ b/pySim/ts_102_221.py @@ -31,7 +31,9 @@ # A UICC will usually also support 2G functionality. If this is the case, we # need to add DF_GSM and DF_TELECOM along with the UICC related files -from pySim.ts_51_011 import DF_GSM, DF_TELECOM +from pySim.ts_51_011 import DF_GSM, DF_TELECOM, AddonSIM +from pySim.gsm_r import AddonGSMR +from pySim.cdma_ruim import AddonRUIM ts_102_22x_cmdset = CardCommandSet('TS 102 22x', [ # TS 102 221 Section 10.1.2 Table 10.5 "Coding of Instruction Byte" @@ -768,6 +770,11 @@ # FIXME: DF.CD EF_UMPC(), ] + addons = [ + AddonSIM, + AddonGSMR, + AddonRUIM, + ] sw = { 'Normal': { '9000': 'Normal ending of the command', @@ -839,7 +846,7 @@ super().__init__(name, desc='ETSI TS 102 221', cla="00", sel_ctrl="0004", files_in_mf=files, sw=sw, - shell_cmdsets = [self.AddlShellCommands()]) + shell_cmdsets = [self.AddlShellCommands()], addons = addons) @staticmethod def decode_select_response(resp_hex: str) -> object: @@ -895,4 +902,5 @@ @staticmethod def match_with_card(scc: SimCardCommands) -> bool: - return match_uicc(scc) and match_sim(scc) + # don't ever select this profile, we only use this from pySim-trace + return False diff --git a/pySim/ts_51_011.py b/pySim/ts_51_011.py index 1f98e72..c81bfdf 100644 --- a/pySim/ts_51_011.py +++ b/pySim/ts_51_011.py @@ -30,9 +30,10 @@ # from pySim.profile import match_sim -from pySim.profile import CardProfile +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 +from pySim.gsm_r import AddonGSMR import enum from pySim.construct import * from construct import Optional as COptional @@ -1047,8 +1048,12 @@ }, } + addons = [ + AddonGSMR, + ] + super().__init__('SIM', desc='GSM SIM Card', cla="a0", - sel_ctrl="0000", files_in_mf=[DF_TELECOM(), DF_GSM()], sw=sw) + sel_ctrl="0000", files_in_mf=[DF_TELECOM(), DF_GSM()], sw=sw, addons = addons) @staticmethod def decode_select_response(resp_hex: str) -> object: @@ -1104,3 +1109,17 @@ @staticmethod def match_with_card(scc: SimCardCommands) -> bool: return match_sim(scc) + + +class AddonSIM(CardProfileAddon): + """An add-on that can be found on a UICC in order to support classic GSM SIM.""" + def __init__(self): + files = [ + DF_GSM(), + DF_TELECOM(), + ] + super().__init__('SIM', desc='GSM SIM', files_in_mf=files) + + def probe(self, card:'CardBase') -> bool: + # we assume the add-on to be present in case DF.GSM is found on the card + return card.file_exists(self.files_in_mf[0].fid) -- To view, visit https://gerrit.osmocom.org/c/pysim/+/33699 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: I5866590b6d48f85eb889c9b1b8ab27936d2378b9 Gerrit-Change-Number: 33699 Gerrit-PatchSet: 6 Gerrit-Owner: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-CC: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-MessageType: merged
1 0
0 0
[S] Change in pysim[master]: pySim/filesystem.py: remove unused class FileData
by laforge 18 Jul '23

18 Jul '23
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/33701 ) ( 2 is the latest approved patch-set. No files were changed between the latest approved patch-set and the submitted one. )Change subject: pySim/filesystem.py: remove unused class FileData ...................................................................... pySim/filesystem.py: remove unused class FileData Change-Id: I62eb446e4995a532227a45c8cc521f5f80535d93 --- M pySim/filesystem.py 1 file changed, 9 insertions(+), 8 deletions(-) Approvals: dexter: Looks good to me, approved fixeria: Looks good to me, but someone else must approve Jenkins Builder: Verified diff --git a/pySim/filesystem.py b/pySim/filesystem.py index cb3b403..2bcd363 100644 --- a/pySim/filesystem.py +++ b/pySim/filesystem.py @@ -1765,14 +1765,6 @@ cmd_app.unregister_command_set(c) -class FileData: - """Represent the runtime, on-card data.""" - - def __init__(self, fdesc): - self.desc = fdesc - self.fcp = None - - def interpret_sw(sw_data: dict, sw: str): """Interpret a given status word. -- To view, visit https://gerrit.osmocom.org/c/pysim/+/33701 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: I62eb446e4995a532227a45c8cc521f5f80535d93 Gerrit-Change-Number: 33701 Gerrit-PatchSet: 4 Gerrit-Owner: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de> Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-MessageType: merged
1 0
0 0
[S] Change in pysim[master]: pySim-shell: Add a mode where a pySim-shell cmd can be passed by shell
by laforge 18 Jul '23

18 Jul '23
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/33705 ) ( 1 is the latest approved patch-set. No files were changed between the latest approved patch-set and the submitted one. )Change subject: pySim-shell: Add a mode where a pySim-shell cmd can be passed by shell ...................................................................... pySim-shell: Add a mode where a pySim-shell cmd can be passed by shell This adds a new operation mode for pySim-shell, where a single command can be passed to pySim-shell, which then is executed before pySim-shell terminates. Example: ./pySim-shell.py -p0 export --json Change-Id: I0ed379b23a4b1126006fd8f9e7ba2ba07fb01ada Closes: OS#6088 --- M pySim-shell.py 1 file changed, 25 insertions(+), 1 deletion(-) Approvals: dexter: Looks good to me, approved fixeria: Looks good to me, but someone else must approve Jenkins Builder: Verified diff --git a/pySim-shell.py b/pySim-shell.py index 213f057..3b56bfd 100755 --- a/pySim-shell.py +++ b/pySim-shell.py @@ -982,6 +982,11 @@ adm_group.add_argument('-A', '--pin-adm-hex', metavar='PIN_ADM1_HEX', dest='pin_adm_hex', default=None, help='ADM PIN used for provisioning, as hex string (16 characters long)') +option_parser.add_argument("command", nargs='?', + help="A pySim-shell command that would optionally be executed at startup") +option_parser.add_argument('command_args', nargs=argparse.REMAINDER, + help="Optional Arguments for command") + if __name__ == '__main__': @@ -1045,4 +1050,7 @@ except Exception as e: print(e) - app.cmdloop() + if opts.command: + app.onecmd_plus_hooks('{} {}'.format(opts.command, ' '.join(opts.command_args))) + else: + app.cmdloop() -- To view, visit https://gerrit.osmocom.org/c/pysim/+/33705 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: I0ed379b23a4b1126006fd8f9e7ba2ba07fb01ada Gerrit-Change-Number: 33705 Gerrit-PatchSet: 3 Gerrit-Owner: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de> Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-MessageType: merged
1 0
0 0
[XL] Change in pysim[master]: move Runtime{State,Lchan} from pySim.filesystem to new pySim.runtime
by laforge 18 Jul '23

18 Jul '23
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/33702 ) ( 2 is the latest approved patch-set. No files were changed between the latest approved patch-set and the submitted one. )Change subject: move Runtime{State,Lchan} from pySim.filesystem to new pySim.runtime ...................................................................... move Runtime{State,Lchan} from pySim.filesystem to new pySim.runtime Those two are really separate concepts, so let's keep them in separate source code files. Change-Id: I9ec54304dd8f4a4cba9487054a8eb8d265c2d340 --- M pySim-shell.py M pySim-trace.py M pySim/apdu/__init__.py M pySim/apdu/ts_102_221.py M pySim/filesystem.py A pySim/runtime.py M pySim/sysmocom_sja2.py 7 files changed, 537 insertions(+), 497 deletions(-) Approvals: dexter: Looks good to me, approved fixeria: Looks good to me, but someone else must approve Jenkins Builder: Verified diff --git a/pySim-shell.py b/pySim-shell.py index 5281eab..213f057 100755 --- a/pySim-shell.py +++ b/pySim-shell.py @@ -55,7 +55,8 @@ from pySim.utils import sanitize_pin_adm, tabulate_str_list, boxed_heading_str, Hexstr from pySim.card_handler import CardHandler, CardHandlerAuto -from pySim.filesystem import RuntimeState, CardDF, CardADF, CardModel, CardApplication +from pySim.filesystem import CardDF, CardADF, CardModel, CardApplication +from pySim.runtime import RuntimeState from pySim.profile import CardProfile from pySim.cdma_ruim import CardProfileRUIM from pySim.ts_102_221 import CardProfileUICC diff --git a/pySim-trace.py b/pySim-trace.py index ba1568c..d457bf4 100755 --- a/pySim-trace.py +++ b/pySim-trace.py @@ -6,7 +6,7 @@ from pprint import pprint as pp from pySim.apdu import * -from pySim.filesystem import RuntimeState +from pySim.runtime import RuntimeState from pySim.cards import UiccCardBase from pySim.commands import SimCardCommands diff --git a/pySim/apdu/__init__.py b/pySim/apdu/__init__.py index 1d1174d..cc0f701 100644 --- a/pySim/apdu/__init__.py +++ b/pySim/apdu/__init__.py @@ -35,7 +35,7 @@ from construct import Optional as COptional from pySim.construct import * from pySim.utils import * -from pySim.filesystem import RuntimeLchan, RuntimeState, lchan_nr_from_cla +from pySim.runtime import RuntimeLchan, RuntimeState, lchan_nr_from_cla from pySim.filesystem import CardADF, CardFile, TransparentEF, LinFixedEF """There are multiple levels of decode: diff --git a/pySim/apdu/ts_102_221.py b/pySim/apdu/ts_102_221.py index cd246b1..3780c8a 100644 --- a/pySim/apdu/ts_102_221.py +++ b/pySim/apdu/ts_102_221.py @@ -20,6 +20,7 @@ import logging from pySim.construct import * from pySim.filesystem import * +from pySim.runtime import RuntimeLchan from pySim.apdu import ApduCommand, ApduCommandSet from typing import Optional, Dict, Tuple diff --git a/pySim/filesystem.py b/pySim/filesystem.py index 2bcd363..9f3ee17 100644 --- a/pySim/filesystem.py +++ b/pySim/filesystem.py @@ -51,18 +51,6 @@ Size = Tuple[int, Optional[int]] -def lchan_nr_from_cla(cla: int) -> int: - """Resolve the logical channel number from the CLA byte.""" - # TS 102 221 10.1.1 Coding of Class Byte - if cla >> 4 in [0x0, 0xA, 0x8]: - # Table 10.3 - return cla & 0x03 - elif cla & 0xD0 in [0x40, 0xC0]: - # Table 10.4a - return 4 + (cla & 0x0F) - else: - raise ValueError('Could not determine logical channel for CLA=%2X' % cla) - class CardFile: """Base class for all objects in the smart card filesystem. Serve as a common ancestor to all other file types; rarely used directly. @@ -1285,486 +1273,6 @@ self.size = size self.shell_commands = [self.ShellCommands()] - -class RuntimeState: - """Represent the runtime state of a session with a card.""" - - def __init__(self, card, profile: 'CardProfile'): - """ - Args: - card : pysim.cards.Card instance - profile : CardProfile instance - """ - self.mf = CardMF(profile=profile) - self.card = card - self.profile = profile - self.lchan = {} - # the basic logical channel always exists - self.lchan[0] = RuntimeLchan(0, self) - - # make sure the class and selection control bytes, which are specified - # by the card profile are used - self.card.set_apdu_parameter( - cla=self.profile.cla, sel_ctrl=self.profile.sel_ctrl) - - for addon_cls in self.profile.addons: - addon = addon_cls() - if addon.probe(self.card): - print("Detected %s Add-on \"%s\"" % (self.profile, addon)) - for f in addon.files_in_mf: - self.mf.add_file(f) - - # go back to MF before the next steps (addon probing might have changed DF) - self.card._scc.select_file('3F00') - - # add application ADFs + MF-files from profile - apps = self._match_applications() - for a in apps: - if a.adf: - self.mf.add_application_df(a.adf) - for f in self.profile.files_in_mf: - self.mf.add_file(f) - self.conserve_write = True - - # make sure that when the runtime state is created, the card is also - # in a defined state. - self.reset() - - def _match_applications(self): - """match the applications from the profile with applications on the card""" - apps_profile = self.profile.applications - - # When the profile does not feature any applications, then we are done already - if not apps_profile: - return [] - - # Read AIDs from card and match them against the applications defined by the - # card profile - aids_card = self.card.read_aids() - apps_taken = [] - if aids_card: - aids_taken = [] - print("AIDs on card:") - for a in aids_card: - for f in apps_profile: - if f.aid in a: - print(" %s: %s (EF.DIR)" % (f.name, a)) - aids_taken.append(a) - apps_taken.append(f) - aids_unknown = set(aids_card) - set(aids_taken) - for a in aids_unknown: - print(" unknown: %s (EF.DIR)" % a) - else: - print("warning: EF.DIR seems to be empty!") - - # Some card applications may not be registered in EF.DIR, we will actively - # probe for those applications - for f in set(apps_profile) - set(apps_taken): - try: - data, sw = self.card.select_adf_by_aid(f.aid) - if sw == "9000": - print(" %s: %s" % (f.name, f.aid)) - apps_taken.append(f) - except (SwMatchError, ProtocolError): - pass - return apps_taken - - def reset(self, cmd_app=None) -> Hexstr: - """Perform physical card reset and obtain ATR. - Args: - cmd_app : Command Application State (for unregistering old file commands) - """ - # delete all lchan != 0 (basic lchan) - for lchan_nr in self.lchan.keys(): - if lchan_nr == 0: - continue - del self.lchan[lchan_nr] - atr = i2h(self.card.reset()) - # select MF to reset internal state and to verify card really works - self.lchan[0].select('MF', cmd_app) - self.lchan[0].selected_adf = None - return atr - - def add_lchan(self, lchan_nr: int) -> 'RuntimeLchan': - """Add a logical channel to the runtime state. You shouldn't call this - directly but always go through RuntimeLchan.add_lchan().""" - if lchan_nr in self.lchan.keys(): - raise ValueError('Cannot create already-existing lchan %d' % lchan_nr) - self.lchan[lchan_nr] = RuntimeLchan(lchan_nr, self) - return self.lchan[lchan_nr] - - def del_lchan(self, lchan_nr: int): - if lchan_nr in self.lchan.keys(): - del self.lchan[lchan_nr] - return True - else: - return False - - def get_lchan_by_cla(self, cla) -> Optional['RuntimeLchan']: - lchan_nr = lchan_nr_from_cla(cla) - if lchan_nr in self.lchan.keys(): - return self.lchan[lchan_nr] - else: - return None - - -class RuntimeLchan: - """Represent the runtime state of a logical channel with a card.""" - - def __init__(self, lchan_nr: int, rs: RuntimeState): - self.lchan_nr = lchan_nr - self.rs = rs - self.selected_file = self.rs.mf - self.selected_adf = None - self.selected_file_fcp = None - self.selected_file_fcp_hex = None - - def add_lchan(self, lchan_nr: int) -> 'RuntimeLchan': - """Add a new logical channel from the current logical channel. Just affects - internal state, doesn't actually open a channel with the UICC.""" - new_lchan = self.rs.add_lchan(lchan_nr) - # See TS 102 221 Table 8.3 - if self.lchan_nr != 0: - new_lchan.selected_file = self.get_cwd() - new_lchan.selected_adf = self.selected_adf - return new_lchan - - def selected_file_descriptor_byte(self) -> dict: - return self.selected_file_fcp['file_descriptor']['file_descriptor_byte'] - - def selected_file_shareable(self) -> bool: - return self.selected_file_descriptor_byte()['shareable'] - - def selected_file_structure(self) -> str: - return self.selected_file_descriptor_byte()['structure'] - - def selected_file_type(self) -> str: - return self.selected_file_descriptor_byte()['file_type'] - - def selected_file_num_of_rec(self) -> Optional[int]: - return self.selected_file_fcp['file_descriptor'].get('num_of_rec') - - def get_cwd(self) -> CardDF: - """Obtain the current working directory. - - Returns: - CardDF instance - """ - if isinstance(self.selected_file, CardDF): - return self.selected_file - else: - return self.selected_file.parent - - def get_application_df(self) -> Optional[CardADF]: - """Obtain the currently selected application DF (if any). - - Returns: - CardADF() instance or None""" - # iterate upwards from selected file; check if any is an ADF - node = self.selected_file - while node.parent != node: - if isinstance(node, CardADF): - return node - node = node.parent - return None - - def interpret_sw(self, sw: str): - """Interpret a given status word relative to the currently selected application - or the underlying card profile. - - Args: - sw : Status word as string of 4 hex digits - - Returns: - Tuple of two strings - """ - res = None - adf = self.get_application_df() - if adf: - app = adf.application - # The application either comes with its own interpret_sw - # method or we will use the interpret_sw method from the - # card profile. - if app and hasattr(app, "interpret_sw"): - res = app.interpret_sw(sw) - return res or self.rs.profile.interpret_sw(sw) - - def probe_file(self, fid: str, cmd_app=None): - """Blindly try to select a file and automatically add a matching file - object if the file actually exists.""" - if not is_hex(fid, 4, 4): - raise ValueError( - "Cannot select unknown file by name %s, only hexadecimal 4 digit FID is allowed" % fid) - - try: - (data, sw) = self.rs.card._scc.select_file(fid) - except SwMatchError as swm: - k = self.interpret_sw(swm.sw_actual) - if not k: - raise(swm) - raise RuntimeError("%s: %s - %s" % (swm.sw_actual, k[0], k[1])) - - select_resp = self.selected_file.decode_select_response(data) - if (select_resp['file_descriptor']['file_descriptor_byte']['file_type'] == 'df'): - f = CardDF(fid=fid, sfid=None, name="DF." + str(fid).upper(), - desc="dedicated file, manually added at runtime") - else: - if (select_resp['file_descriptor']['file_descriptor_byte']['structure'] == 'transparent'): - f = TransparentEF(fid=fid, sfid=None, name="EF." + str(fid).upper(), - desc="elementary file, manually added at runtime") - else: - f = LinFixedEF(fid=fid, sfid=None, name="EF." + str(fid).upper(), - desc="elementary file, manually added at runtime") - - self.selected_file.add_files([f]) - self.selected_file = f - return select_resp, data - - def _select_pre(self, cmd_app): - # unregister commands of old file - if cmd_app and self.selected_file.shell_commands: - for c in self.selected_file.shell_commands: - cmd_app.unregister_command_set(c) - - def _select_post(self, cmd_app): - # register commands of new file - if cmd_app and self.selected_file.shell_commands: - for c in self.selected_file.shell_commands: - cmd_app.register_command_set(c) - - def select_file(self, file: CardFile, cmd_app=None): - """Select a file (EF, DF, ADF, MF, ...). - - Args: - file : CardFile [or derived class] instance - cmd_app : Command Application State (for unregistering old file commands) - """ - # we need to find a path from our self.selected_file to the destination - inter_path = self.selected_file.build_select_path_to(file) - if not inter_path: - raise RuntimeError('Cannot determine path from %s to %s' % (self.selected_file, file)) - - self._select_pre(cmd_app) - - for p in inter_path: - try: - if isinstance(p, CardADF): - (data, sw) = self.rs.card.select_adf_by_aid(p.aid) - self.selected_adf = p - else: - (data, sw) = self.rs.card._scc.select_file(p.fid) - self.selected_file = p - except SwMatchError as swm: - self._select_post(cmd_app) - raise(swm) - - self._select_post(cmd_app) - - def select(self, name: str, cmd_app=None): - """Select a file (EF, DF, ADF, MF, ...). - - Args: - name : Name of file to select - cmd_app : Command Application State (for unregistering old file commands) - """ - # handling of entire paths with multiple directories/elements - if '/' in name: - prev_sel_file = self.selected_file - pathlist = name.split('/') - # treat /DF.GSM/foo like MF/DF.GSM/foo - if pathlist[0] == '': - pathlist[0] = 'MF' - try: - for p in pathlist: - self.select(p, cmd_app) - return - except Exception as e: - # if any intermediate step fails, go back to where we were - self.select_file(prev_sel_file, cmd_app) - raise e - - sels = self.selected_file.get_selectables() - if is_hex(name): - name = name.lower() - - self._select_pre(cmd_app) - - if name in sels: - f = sels[name] - try: - if isinstance(f, CardADF): - (data, sw) = self.rs.card.select_adf_by_aid(f.aid) - else: - (data, sw) = self.rs.card._scc.select_file(f.fid) - self.selected_file = f - except SwMatchError as swm: - k = self.interpret_sw(swm.sw_actual) - if not k: - raise(swm) - raise RuntimeError("%s: %s - %s" % (swm.sw_actual, k[0], k[1])) - select_resp = f.decode_select_response(data) - else: - (select_resp, data) = self.probe_file(name, cmd_app) - - # store the raw + decoded FCP for later reference - self.selected_file_fcp_hex = data - self.selected_file_fcp = select_resp - - self._select_post(cmd_app) - return select_resp - - def status(self): - """Request STATUS (current selected file FCP) from card.""" - (data, sw) = self.rs.card._scc.status() - return self.selected_file.decode_select_response(data) - - def get_file_for_selectable(self, name: str): - sels = self.selected_file.get_selectables() - return sels[name] - - def activate_file(self, name: str): - """Request ACTIVATE FILE of specified file.""" - sels = self.selected_file.get_selectables() - f = sels[name] - data, sw = self.rs.card._scc.activate_file(f.fid) - return data, sw - - def read_binary(self, length: int = None, offset: int = 0): - """Read [part of] a transparent EF binary data. - - Args: - length : Amount of data to read (None: as much as possible) - offset : Offset into the file from which to read 'length' bytes - Returns: - binary data read from the file - """ - if not isinstance(self.selected_file, TransparentEF): - raise TypeError("Only works with TransparentEF") - return self.rs.card._scc.read_binary(self.selected_file.fid, length, offset) - - def read_binary_dec(self) -> Tuple[dict, str]: - """Read [part of] a transparent EF binary data and decode it. - - Args: - length : Amount of data to read (None: as much as possible) - offset : Offset into the file from which to read 'length' bytes - Returns: - abstract decode data read from the file - """ - (data, sw) = self.read_binary() - dec_data = self.selected_file.decode_hex(data) - return (dec_data, sw) - - def update_binary(self, data_hex: str, offset: int = 0): - """Update transparent EF binary data. - - Args: - data_hex : hex string of data to be written - offset : Offset into the file from which to write 'data_hex' - """ - if not isinstance(self.selected_file, TransparentEF): - raise TypeError("Only works with TransparentEF") - return self.rs.card._scc.update_binary(self.selected_file.fid, data_hex, offset, conserve=self.rs.conserve_write) - - def update_binary_dec(self, data: dict): - """Update transparent EF from abstract data. Encodes the data to binary and - then updates the EF with it. - - Args: - data : abstract data which is to be encoded and written - """ - data_hex = self.selected_file.encode_hex(data) - return self.update_binary(data_hex) - - def read_record(self, rec_nr: int = 0): - """Read a record as binary data. - - Args: - rec_nr : Record number to read - Returns: - hex string of binary data contained in record - """ - if not isinstance(self.selected_file, LinFixedEF): - raise TypeError("Only works with Linear Fixed EF") - # returns a string of hex nibbles - return self.rs.card._scc.read_record(self.selected_file.fid, rec_nr) - - def read_record_dec(self, rec_nr: int = 0) -> Tuple[dict, str]: - """Read a record and decode it to abstract data. - - Args: - rec_nr : Record number to read - Returns: - abstract data contained in record - """ - (data, sw) = self.read_record(rec_nr) - return (self.selected_file.decode_record_hex(data, rec_nr), sw) - - def update_record(self, rec_nr: int, data_hex: str): - """Update a record with given binary data - - Args: - rec_nr : Record number to read - data_hex : Hex string binary data to be written - """ - if not isinstance(self.selected_file, LinFixedEF): - raise TypeError("Only works with Linear Fixed EF") - return self.rs.card._scc.update_record(self.selected_file.fid, rec_nr, data_hex, conserve=self.rs.conserve_write) - - def update_record_dec(self, rec_nr: int, data: dict): - """Update a record with given abstract data. Will encode abstract to binary data - and then write it to the given record on the card. - - Args: - rec_nr : Record number to read - data_hex : Abstract data to be written - """ - data_hex = self.selected_file.encode_record_hex(data, rec_nr) - return self.update_record(rec_nr, data_hex) - - def retrieve_data(self, tag: int = 0): - """Read a DO/TLV as binary data. - - Args: - tag : Tag of TLV/DO to read - Returns: - hex string of full BER-TLV DO including Tag and Length - """ - if not isinstance(self.selected_file, BerTlvEF): - raise TypeError("Only works with BER-TLV EF") - # returns a string of hex nibbles - return self.rs.card._scc.retrieve_data(self.selected_file.fid, tag) - - def retrieve_tags(self): - """Retrieve tags available on BER-TLV EF. - - Returns: - list of integer tags contained in EF - """ - if not isinstance(self.selected_file, BerTlvEF): - raise TypeError("Only works with BER-TLV EF") - data, sw = self.rs.card._scc.retrieve_data(self.selected_file.fid, 0x5c) - tag, length, value, remainder = bertlv_parse_one(h2b(data)) - return list(value) - - def set_data(self, tag: int, data_hex: str): - """Update a TLV/DO with given binary data - - Args: - tag : Tag of TLV/DO to be written - data_hex : Hex string binary data to be written (value portion) - """ - if not isinstance(self.selected_file, BerTlvEF): - raise TypeError("Only works with BER-TLV EF") - return self.rs.card._scc.set_data(self.selected_file.fid, tag, data_hex, conserve=self.rs.conserve_write) - - def unregister_cmds(self, cmd_app=None): - """Unregister all file specific commands.""" - if cmd_app and self.selected_file.shell_commands: - for c in self.selected_file.shell_commands: - cmd_app.unregister_command_set(c) - - def interpret_sw(sw_data: dict, sw: str): """Interpret a given status word. @@ -1828,7 +1336,7 @@ @classmethod @abc.abstractmethod - def add_files(cls, rs: RuntimeState): + def add_files(cls, rs: 'RuntimeState'): """Add model specific files to given RuntimeState.""" @classmethod @@ -1843,7 +1351,7 @@ return False @staticmethod - def apply_matching_models(scc: SimCardCommands, rs: RuntimeState): + def apply_matching_models(scc: SimCardCommands, rs: 'RuntimeState'): """Check if any of the CardModel sub-classes 'match' the currently inserted card (by ATR or overriding the 'match' method). If so, call their 'add_files' method.""" diff --git a/pySim/runtime.py b/pySim/runtime.py new file mode 100644 index 0000000..5d181e8 --- /dev/null +++ b/pySim/runtime.py @@ -0,0 +1,517 @@ +# coding=utf-8 +"""Representation of the runtime state of an application like pySim-shell. +""" + +# (C) 2021 by Harald Welte <laforge(a)osmocom.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from typing import Optional, Tuple + +from pySim.utils import sw_match, h2b, i2h, is_hex, bertlv_parse_one, Hexstr +from pySim.exceptions import * +from pySim.filesystem import * + +def lchan_nr_from_cla(cla: int) -> int: + """Resolve the logical channel number from the CLA byte.""" + # TS 102 221 10.1.1 Coding of Class Byte + if cla >> 4 in [0x0, 0xA, 0x8]: + # Table 10.3 + return cla & 0x03 + elif cla & 0xD0 in [0x40, 0xC0]: + # Table 10.4a + return 4 + (cla & 0x0F) + else: + raise ValueError('Could not determine logical channel for CLA=%2X' % cla) + +class RuntimeState: + """Represent the runtime state of a session with a card.""" + + def __init__(self, card, profile: 'CardProfile'): + """ + Args: + card : pysim.cards.Card instance + profile : CardProfile instance + """ + self.mf = CardMF(profile=profile) + self.card = card + self.profile = profile + self.lchan = {} + # the basic logical channel always exists + self.lchan[0] = RuntimeLchan(0, self) + + # make sure the class and selection control bytes, which are specified + # by the card profile are used + self.card.set_apdu_parameter( + cla=self.profile.cla, sel_ctrl=self.profile.sel_ctrl) + + for addon_cls in self.profile.addons: + addon = addon_cls() + if addon.probe(self.card): + print("Detected %s Add-on \"%s\"" % (self.profile, addon)) + for f in addon.files_in_mf: + self.mf.add_file(f) + + # go back to MF before the next steps (addon probing might have changed DF) + self.card._scc.select_file('3F00') + + # add application ADFs + MF-files from profile + apps = self._match_applications() + for a in apps: + if a.adf: + self.mf.add_application_df(a.adf) + for f in self.profile.files_in_mf: + self.mf.add_file(f) + self.conserve_write = True + + # make sure that when the runtime state is created, the card is also + # in a defined state. + self.reset() + + def _match_applications(self): + """match the applications from the profile with applications on the card""" + apps_profile = self.profile.applications + + # When the profile does not feature any applications, then we are done already + if not apps_profile: + return [] + + # Read AIDs from card and match them against the applications defined by the + # card profile + aids_card = self.card.read_aids() + apps_taken = [] + if aids_card: + aids_taken = [] + print("AIDs on card:") + for a in aids_card: + for f in apps_profile: + if f.aid in a: + print(" %s: %s (EF.DIR)" % (f.name, a)) + aids_taken.append(a) + apps_taken.append(f) + aids_unknown = set(aids_card) - set(aids_taken) + for a in aids_unknown: + print(" unknown: %s (EF.DIR)" % a) + else: + print("warning: EF.DIR seems to be empty!") + + # Some card applications may not be registered in EF.DIR, we will actively + # probe for those applications + for f in set(apps_profile) - set(apps_taken): + try: + data, sw = self.card.select_adf_by_aid(f.aid) + if sw == "9000": + print(" %s: %s" % (f.name, f.aid)) + apps_taken.append(f) + except (SwMatchError, ProtocolError): + pass + return apps_taken + + def reset(self, cmd_app=None) -> Hexstr: + """Perform physical card reset and obtain ATR. + Args: + cmd_app : Command Application State (for unregistering old file commands) + """ + # delete all lchan != 0 (basic lchan) + for lchan_nr in self.lchan.keys(): + if lchan_nr == 0: + continue + del self.lchan[lchan_nr] + atr = i2h(self.card.reset()) + # select MF to reset internal state and to verify card really works + self.lchan[0].select('MF', cmd_app) + self.lchan[0].selected_adf = None + return atr + + def add_lchan(self, lchan_nr: int) -> 'RuntimeLchan': + """Add a logical channel to the runtime state. You shouldn't call this + directly but always go through RuntimeLchan.add_lchan().""" + if lchan_nr in self.lchan.keys(): + raise ValueError('Cannot create already-existing lchan %d' % lchan_nr) + self.lchan[lchan_nr] = RuntimeLchan(lchan_nr, self) + return self.lchan[lchan_nr] + + def del_lchan(self, lchan_nr: int): + if lchan_nr in self.lchan.keys(): + del self.lchan[lchan_nr] + return True + else: + return False + + def get_lchan_by_cla(self, cla) -> Optional['RuntimeLchan']: + lchan_nr = lchan_nr_from_cla(cla) + if lchan_nr in self.lchan.keys(): + return self.lchan[lchan_nr] + else: + return None + + +class RuntimeLchan: + """Represent the runtime state of a logical channel with a card.""" + + def __init__(self, lchan_nr: int, rs: RuntimeState): + self.lchan_nr = lchan_nr + self.rs = rs + self.selected_file = self.rs.mf + self.selected_adf = None + self.selected_file_fcp = None + self.selected_file_fcp_hex = None + + def add_lchan(self, lchan_nr: int) -> 'RuntimeLchan': + """Add a new logical channel from the current logical channel. Just affects + internal state, doesn't actually open a channel with the UICC.""" + new_lchan = self.rs.add_lchan(lchan_nr) + # See TS 102 221 Table 8.3 + if self.lchan_nr != 0: + new_lchan.selected_file = self.get_cwd() + new_lchan.selected_adf = self.selected_adf + return new_lchan + + def selected_file_descriptor_byte(self) -> dict: + return self.selected_file_fcp['file_descriptor']['file_descriptor_byte'] + + def selected_file_shareable(self) -> bool: + return self.selected_file_descriptor_byte()['shareable'] + + def selected_file_structure(self) -> str: + return self.selected_file_descriptor_byte()['structure'] + + def selected_file_type(self) -> str: + return self.selected_file_descriptor_byte()['file_type'] + + def selected_file_num_of_rec(self) -> Optional[int]: + return self.selected_file_fcp['file_descriptor'].get('num_of_rec') + + def get_cwd(self) -> CardDF: + """Obtain the current working directory. + + Returns: + CardDF instance + """ + if isinstance(self.selected_file, CardDF): + return self.selected_file + else: + return self.selected_file.parent + + def get_application_df(self) -> Optional[CardADF]: + """Obtain the currently selected application DF (if any). + + Returns: + CardADF() instance or None""" + # iterate upwards from selected file; check if any is an ADF + node = self.selected_file + while node.parent != node: + if isinstance(node, CardADF): + return node + node = node.parent + return None + + def interpret_sw(self, sw: str): + """Interpret a given status word relative to the currently selected application + or the underlying card profile. + + Args: + sw : Status word as string of 4 hex digits + + Returns: + Tuple of two strings + """ + res = None + adf = self.get_application_df() + if adf: + app = adf.application + # The application either comes with its own interpret_sw + # method or we will use the interpret_sw method from the + # card profile. + if app and hasattr(app, "interpret_sw"): + res = app.interpret_sw(sw) + return res or self.rs.profile.interpret_sw(sw) + + def probe_file(self, fid: str, cmd_app=None): + """Blindly try to select a file and automatically add a matching file + object if the file actually exists.""" + if not is_hex(fid, 4, 4): + raise ValueError( + "Cannot select unknown file by name %s, only hexadecimal 4 digit FID is allowed" % fid) + + try: + (data, sw) = self.rs.card._scc.select_file(fid) + except SwMatchError as swm: + k = self.interpret_sw(swm.sw_actual) + if not k: + raise(swm) + raise RuntimeError("%s: %s - %s" % (swm.sw_actual, k[0], k[1])) + + select_resp = self.selected_file.decode_select_response(data) + if (select_resp['file_descriptor']['file_descriptor_byte']['file_type'] == 'df'): + f = CardDF(fid=fid, sfid=None, name="DF." + str(fid).upper(), + desc="dedicated file, manually added at runtime") + else: + if (select_resp['file_descriptor']['file_descriptor_byte']['structure'] == 'transparent'): + f = TransparentEF(fid=fid, sfid=None, name="EF." + str(fid).upper(), + desc="elementary file, manually added at runtime") + else: + f = LinFixedEF(fid=fid, sfid=None, name="EF." + str(fid).upper(), + desc="elementary file, manually added at runtime") + + self.selected_file.add_files([f]) + self.selected_file = f + return select_resp, data + + def _select_pre(self, cmd_app): + # unregister commands of old file + if cmd_app and self.selected_file.shell_commands: + for c in self.selected_file.shell_commands: + cmd_app.unregister_command_set(c) + + def _select_post(self, cmd_app): + # register commands of new file + if cmd_app and self.selected_file.shell_commands: + for c in self.selected_file.shell_commands: + cmd_app.register_command_set(c) + + def select_file(self, file: CardFile, cmd_app=None): + """Select a file (EF, DF, ADF, MF, ...). + + Args: + file : CardFile [or derived class] instance + cmd_app : Command Application State (for unregistering old file commands) + """ + # we need to find a path from our self.selected_file to the destination + inter_path = self.selected_file.build_select_path_to(file) + if not inter_path: + raise RuntimeError('Cannot determine path from %s to %s' % (self.selected_file, file)) + + self._select_pre(cmd_app) + + for p in inter_path: + try: + if isinstance(p, CardADF): + (data, sw) = self.rs.card.select_adf_by_aid(p.aid) + self.selected_adf = p + else: + (data, sw) = self.rs.card._scc.select_file(p.fid) + self.selected_file = p + except SwMatchError as swm: + self._select_post(cmd_app) + raise(swm) + + self._select_post(cmd_app) + + def select(self, name: str, cmd_app=None): + """Select a file (EF, DF, ADF, MF, ...). + + Args: + name : Name of file to select + cmd_app : Command Application State (for unregistering old file commands) + """ + # handling of entire paths with multiple directories/elements + if '/' in name: + prev_sel_file = self.selected_file + pathlist = name.split('/') + # treat /DF.GSM/foo like MF/DF.GSM/foo + if pathlist[0] == '': + pathlist[0] = 'MF' + try: + for p in pathlist: + self.select(p, cmd_app) + return + except Exception as e: + # if any intermediate step fails, go back to where we were + self.select_file(prev_sel_file, cmd_app) + raise e + + sels = self.selected_file.get_selectables() + if is_hex(name): + name = name.lower() + + self._select_pre(cmd_app) + + if name in sels: + f = sels[name] + try: + if isinstance(f, CardADF): + (data, sw) = self.rs.card.select_adf_by_aid(f.aid) + else: + (data, sw) = self.rs.card._scc.select_file(f.fid) + self.selected_file = f + except SwMatchError as swm: + k = self.interpret_sw(swm.sw_actual) + if not k: + raise(swm) + raise RuntimeError("%s: %s - %s" % (swm.sw_actual, k[0], k[1])) + select_resp = f.decode_select_response(data) + else: + (select_resp, data) = self.probe_file(name, cmd_app) + + # store the raw + decoded FCP for later reference + self.selected_file_fcp_hex = data + self.selected_file_fcp = select_resp + + self._select_post(cmd_app) + return select_resp + + def status(self): + """Request STATUS (current selected file FCP) from card.""" + (data, sw) = self.rs.card._scc.status() + return self.selected_file.decode_select_response(data) + + def get_file_for_selectable(self, name: str): + sels = self.selected_file.get_selectables() + return sels[name] + + def activate_file(self, name: str): + """Request ACTIVATE FILE of specified file.""" + sels = self.selected_file.get_selectables() + f = sels[name] + data, sw = self.rs.card._scc.activate_file(f.fid) + return data, sw + + def read_binary(self, length: int = None, offset: int = 0): + """Read [part of] a transparent EF binary data. + + Args: + length : Amount of data to read (None: as much as possible) + offset : Offset into the file from which to read 'length' bytes + Returns: + binary data read from the file + """ + if not isinstance(self.selected_file, TransparentEF): + raise TypeError("Only works with TransparentEF") + return self.rs.card._scc.read_binary(self.selected_file.fid, length, offset) + + def read_binary_dec(self) -> Tuple[dict, str]: + """Read [part of] a transparent EF binary data and decode it. + + Args: + length : Amount of data to read (None: as much as possible) + offset : Offset into the file from which to read 'length' bytes + Returns: + abstract decode data read from the file + """ + (data, sw) = self.read_binary() + dec_data = self.selected_file.decode_hex(data) + return (dec_data, sw) + + def update_binary(self, data_hex: str, offset: int = 0): + """Update transparent EF binary data. + + Args: + data_hex : hex string of data to be written + offset : Offset into the file from which to write 'data_hex' + """ + if not isinstance(self.selected_file, TransparentEF): + raise TypeError("Only works with TransparentEF") + return self.rs.card._scc.update_binary(self.selected_file.fid, data_hex, offset, conserve=self.rs.conserve_write) + + def update_binary_dec(self, data: dict): + """Update transparent EF from abstract data. Encodes the data to binary and + then updates the EF with it. + + Args: + data : abstract data which is to be encoded and written + """ + data_hex = self.selected_file.encode_hex(data) + return self.update_binary(data_hex) + + def read_record(self, rec_nr: int = 0): + """Read a record as binary data. + + Args: + rec_nr : Record number to read + Returns: + hex string of binary data contained in record + """ + if not isinstance(self.selected_file, LinFixedEF): + raise TypeError("Only works with Linear Fixed EF") + # returns a string of hex nibbles + return self.rs.card._scc.read_record(self.selected_file.fid, rec_nr) + + def read_record_dec(self, rec_nr: int = 0) -> Tuple[dict, str]: + """Read a record and decode it to abstract data. + + Args: + rec_nr : Record number to read + Returns: + abstract data contained in record + """ + (data, sw) = self.read_record(rec_nr) + return (self.selected_file.decode_record_hex(data, rec_nr), sw) + + def update_record(self, rec_nr: int, data_hex: str): + """Update a record with given binary data + + Args: + rec_nr : Record number to read + data_hex : Hex string binary data to be written + """ + if not isinstance(self.selected_file, LinFixedEF): + raise TypeError("Only works with Linear Fixed EF") + return self.rs.card._scc.update_record(self.selected_file.fid, rec_nr, data_hex, conserve=self.rs.conserve_write) + + def update_record_dec(self, rec_nr: int, data: dict): + """Update a record with given abstract data. Will encode abstract to binary data + and then write it to the given record on the card. + + Args: + rec_nr : Record number to read + data_hex : Abstract data to be written + """ + data_hex = self.selected_file.encode_record_hex(data, rec_nr) + return self.update_record(rec_nr, data_hex) + + def retrieve_data(self, tag: int = 0): + """Read a DO/TLV as binary data. + + Args: + tag : Tag of TLV/DO to read + Returns: + hex string of full BER-TLV DO including Tag and Length + """ + if not isinstance(self.selected_file, BerTlvEF): + raise TypeError("Only works with BER-TLV EF") + # returns a string of hex nibbles + return self.rs.card._scc.retrieve_data(self.selected_file.fid, tag) + + def retrieve_tags(self): + """Retrieve tags available on BER-TLV EF. + + Returns: + list of integer tags contained in EF + """ + if not isinstance(self.selected_file, BerTlvEF): + raise TypeError("Only works with BER-TLV EF") + data, sw = self.rs.card._scc.retrieve_data(self.selected_file.fid, 0x5c) + tag, length, value, remainder = bertlv_parse_one(h2b(data)) + return list(value) + + def set_data(self, tag: int, data_hex: str): + """Update a TLV/DO with given binary data + + Args: + tag : Tag of TLV/DO to be written + data_hex : Hex string binary data to be written (value portion) + """ + if not isinstance(self.selected_file, BerTlvEF): + raise TypeError("Only works with BER-TLV EF") + return self.rs.card._scc.set_data(self.selected_file.fid, tag, data_hex, conserve=self.rs.conserve_write) + + def unregister_cmds(self, cmd_app=None): + """Unregister all file specific commands.""" + if cmd_app and self.selected_file.shell_commands: + for c in self.selected_file.shell_commands: + cmd_app.unregister_command_set(c) + + + diff --git a/pySim/sysmocom_sja2.py b/pySim/sysmocom_sja2.py index 1bd4a8a..bfd0ff5 100644 --- a/pySim/sysmocom_sja2.py +++ b/pySim/sysmocom_sja2.py @@ -21,6 +21,7 @@ from struct import pack, unpack from pySim.utils import * from pySim.filesystem import * +from pySim.runtime import RuntimeState from pySim.ts_102_221 import CardProfileUICC from pySim.construct import * from construct import * -- To view, visit https://gerrit.osmocom.org/c/pysim/+/33702 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: I9ec54304dd8f4a4cba9487054a8eb8d265c2d340 Gerrit-Change-Number: 33702 Gerrit-PatchSet: 4 Gerrit-Owner: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de> Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-MessageType: merged
1 0
0 0
[S] Change in pysim[master]: pySim-shell: Iterate over CardApplication sub-classes
by laforge 18 Jul '23

18 Jul '23
Attention is currently required from: fixeria. laforge has posted comments on this change. ( https://gerrit.osmocom.org/c/pysim/+/33700 ) Change subject: pySim-shell: Iterate over CardApplication sub-classes ...................................................................... Patch Set 4: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/c/pysim/+/33700 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: Ia6918e49d73d80acfaf09506e604d4929d37f1b6 Gerrit-Change-Number: 33700 Gerrit-PatchSet: 4 Gerrit-Owner: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de> Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Comment-Date: Tue, 18 Jul 2023 06:29:27 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes Gerrit-MessageType: comment
1 0
0 0
[S] Change in pysim[master]: ts_102_221: Remove CardProfileUICCSIM
by laforge 18 Jul '23

18 Jul '23
laforge has posted comments on this change. ( https://gerrit.osmocom.org/c/pysim/+/33724 ) Change subject: ts_102_221: Remove CardProfileUICCSIM ...................................................................... Patch Set 2: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/c/pysim/+/33724 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: I45cec68d72f2003123da4c3f86ed6a5a90988bd8 Gerrit-Change-Number: 33724 Gerrit-PatchSet: 2 Gerrit-Owner: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Comment-Date: Tue, 18 Jul 2023 06:29:25 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes Gerrit-MessageType: comment
1 0
0 0
[M] Change in pysim[master]: Introduce concept of CardProfileAddon
by laforge 18 Jul '23

18 Jul '23
Attention is currently required from: fixeria. laforge has posted comments on this change. ( https://gerrit.osmocom.org/c/pysim/+/33699 ) Change subject: Introduce concept of CardProfileAddon ...................................................................... Patch Set 6: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/c/pysim/+/33699 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: I5866590b6d48f85eb889c9b1b8ab27936d2378b9 Gerrit-Change-Number: 33699 Gerrit-PatchSet: 6 Gerrit-Owner: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-CC: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Comment-Date: Tue, 18 Jul 2023 06:29:20 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes Gerrit-MessageType: comment
1 0
0 0
[S] Change in pysim[master]: cards: All derived of SimCardBase use CLA=A0; all UiccCardBase use CL...
by laforge 18 Jul '23

18 Jul '23
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/33695 ) ( 3 is the latest approved patch-set. No files were changed between the latest approved patch-set and the submitted one. )Change subject: cards: All derived of SimCardBase use CLA=A0; all UiccCardBase use CLA=00 ...................................................................... cards: All derived of SimCardBase use CLA=A0; all UiccCardBase use CLA=00 Change-Id: Id61b549f68410631529349ee62b08a102f609405 --- M pySim/cards.py M pySim/legacy/cards.py 2 files changed, 15 insertions(+), 4 deletions(-) Approvals: fixeria: Looks good to me, approved Jenkins Builder: Verified diff --git a/pySim/cards.py b/pySim/cards.py index 3acc7aa..d720413 100644 --- a/pySim/cards.py +++ b/pySim/cards.py @@ -83,6 +83,10 @@ any higher-layer processing.""" name = 'SIM' + def __init__(self, scc: LinkBase): + super(SimCardBase, self).__init__(scc) + self._scc.cla_byte = "A0" + def probe(self) -> bool: df_gsm = DF_GSM() return self.file_exists(df_gsm.fid) @@ -93,7 +97,8 @@ def __init__(self, ssc: LinkBase): super(UiccCardBase, self).__init__(ssc) - # See also: ETSI TS 102 221, Table 9.3 + self._scc.cla_byte = "00" + # See also: ETSI TS 102 221, Table 9.3 self._adm_chv_num = 0xA0 def probe(self) -> bool: diff --git a/pySim/legacy/cards.py b/pySim/legacy/cards.py index ae5cf79..d4e5862 100644 --- a/pySim/legacy/cards.py +++ b/pySim/legacy/cards.py @@ -893,7 +893,6 @@ def __init__(self, ssc): super(SysmoUSIMSJS1, self).__init__(ssc) - self._scc.cla_byte = "00" self._scc.sel_ctrl = "0004" # request an FCP @classmethod @@ -1206,7 +1205,6 @@ def __init__(self, ssc): super(WavemobileSim, self).__init__(ssc) self._adm_chv_num = 0x0A - self._scc.cla_byte = "00" self._scc.sel_ctrl = "0004" # request an FCP @classmethod @@ -1301,7 +1299,6 @@ def __init__(self, ssc): super(SysmoISIMSJA2, self).__init__(ssc) - self._scc.cla_byte = "00" self._scc.sel_ctrl = "0004" # request an FCP @classmethod -- To view, visit https://gerrit.osmocom.org/c/pysim/+/33695 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: Id61b549f68410631529349ee62b08a102f609405 Gerrit-Change-Number: 33695 Gerrit-PatchSet: 5 Gerrit-Owner: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-MessageType: merged
1 0
0 0
[L] Change in pysim[master]: ts_31_102, ts_31_103: Move legacy-only code to pySim.legacy
by laforge 18 Jul '23

18 Jul '23
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/33694 ) Change subject: ts_31_102, ts_31_103: Move legacy-only code to pySim.legacy ...................................................................... ts_31_102, ts_31_103: Move legacy-only code to pySim.legacy Change-Id: Ifebfbbc00ef0d01cafd6f058a32d243d3696e97e --- M pySim-read.py M pySim/legacy/cards.py A pySim/legacy/ts_31_102.py A pySim/legacy/ts_31_103.py M pySim/ts_31_102.py M pySim/ts_31_103.py 6 files changed, 193 insertions(+), 137 deletions(-) Approvals: Jenkins Builder: Verified laforge: Looks good to me, approved diff --git a/pySim-read.py b/pySim-read.py index 74bb35a..bafaf26 100755 --- a/pySim-read.py +++ b/pySim-read.py @@ -28,10 +28,13 @@ import random import re import sys + from pySim.ts_51_011 import EF_SST_map, EF_AD from pySim.legacy.ts_51_011 import EF, DF -from pySim.ts_31_102 import EF_UST_map, EF_USIM_ADF_map -from pySim.ts_31_103 import EF_IST_map, EF_ISIM_ADF_map +from pySim.ts_31_102 import EF_UST_map +from pySim.legacy.ts_31_102 import EF_USIM_ADF_map +from pySim.ts_31_103 import EF_IST_map +from pySim.legacy.ts_31_103 import EF_ISIM_ADF_map from pySim.commands import SimCardCommands from pySim.transport import init_reader, argparse_add_reader_args diff --git a/pySim/legacy/cards.py b/pySim/legacy/cards.py index bb3e8a5..ae5cf79 100644 --- a/pySim/legacy/cards.py +++ b/pySim/legacy/cards.py @@ -14,10 +14,10 @@ from pySim.legacy.utils import enc_ePDGSelection, format_xplmn_w_act, format_xplmn, dec_st, enc_st from pySim.legacy.utils import format_ePDGSelection from pySim.legacy.ts_51_011 import EF, DF +from pySim.legacy.ts_31_102 import EF_USIM_ADF_map +from pySim.legacy.ts_31_103 import EF_ISIM_ADF_map from pySim.ts_51_011 import EF_AD, EF_SPN -from pySim.ts_31_102 import EF_USIM_ADF_map -from pySim.ts_31_103 import EF_ISIM_ADF_map def format_addr(addr: str, addr_type: str) -> str: """ diff --git a/pySim/legacy/ts_31_102.py b/pySim/legacy/ts_31_102.py new file mode 100644 index 0000000..c4a829e --- /dev/null +++ b/pySim/legacy/ts_31_102.py @@ -0,0 +1,134 @@ +# -*- coding: utf-8 -*- + +""" +Various constants from 3GPP TS 31.102 V17.9.0 usd by *legacy* code +""" + +# +# Copyright (C) 2020 Supreeth Herle <herlesupreeth(a)gmail.com> +# Copyright (C) 2021-2023 Harald Welte <laforge(a)osmocom.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +EF_USIM_ADF_map = { + 'LI': '6F05', + 'ARR': '6F06', + 'IMSI': '6F07', + 'Keys': '6F08', + 'KeysPS': '6F09', + 'DCK': '6F2C', + 'HPPLMN': '6F31', + 'CNL': '6F32', + 'ACMmax': '6F37', + 'UST': '6F38', + 'ACM': '6F39', + 'FDN': '6F3B', + 'SMS': '6F3C', + 'GID1': '6F3E', + 'GID2': '6F3F', + 'MSISDN': '6F40', + 'PUCT': '6F41', + 'SMSP': '6F42', + 'SMSS': '6F42', + 'CBMI': '6F45', + 'SPN': '6F46', + 'SMSR': '6F47', + 'CBMID': '6F48', + 'SDN': '6F49', + 'EXT2': '6F4B', + 'EXT3': '6F4C', + 'BDN': '6F4D', + 'EXT5': '6F4E', + 'CCP2': '6F4F', + 'CBMIR': '6F50', + 'EXT4': '6F55', + 'EST': '6F56', + 'ACL': '6F57', + 'CMI': '6F58', + 'START-HFN': '6F5B', + 'THRESHOLD': '6F5C', + 'PLMNwAcT': '6F60', + 'OPLMNwAcT': '6F61', + 'HPLMNwAcT': '6F62', + 'PSLOCI': '6F73', + 'ACC': '6F78', + 'FPLMN': '6F7B', + 'LOCI': '6F7E', + 'ICI': '6F80', + 'OCI': '6F81', + 'ICT': '6F82', + 'OCT': '6F83', + 'AD': '6FAD', + 'VGCS': '6FB1', + 'VGCSS': '6FB2', + 'VBS': '6FB3', + 'VBSS': '6FB4', + 'eMLPP': '6FB5', + 'AAeM': '6FB6', + 'ECC': '6FB7', + 'Hiddenkey': '6FC3', + 'NETPAR': '6FC4', + 'PNN': '6FC5', + 'OPL': '6FC6', + 'MBDN': '6FC7', + 'EXT6': '6FC8', + 'MBI': '6FC9', + 'MWIS': '6FCA', + 'CFIS': '6FCB', + 'EXT7': '6FCC', + 'SPDI': '6FCD', + 'MMSN': '6FCE', + 'EXT8': '6FCF', + 'MMSICP': '6FD0', + 'MMSUP': '6FD1', + 'MMSUCP': '6FD2', + 'NIA': '6FD3', + 'VGCSCA': '6FD4', + 'VBSCA': '6FD5', + 'GBAP': '6FD6', + 'MSK': '6FD7', + 'MUK': '6FD8', + 'EHPLMN': '6FD9', + 'GBANL': '6FDA', + 'EHPLMNPI': '6FDB', + 'LRPLMNSI': '6FDC', + 'NAFKCA': '6FDD', + 'SPNI': '6FDE', + 'PNNI': '6FDF', + 'NCP-IP': '6FE2', + 'EPSLOCI': '6FE3', + 'EPSNSC': '6FE4', + 'UFC': '6FE6', + 'UICCIARI': '6FE7', + 'NASCONFIG': '6FE8', + 'PWC': '6FEC', + 'FDNURI': '6FED', + 'BDNURI': '6FEE', + 'SDNURI': '6FEF', + 'IWL': '6FF0', + 'IPS': '6FF1', + 'IPD': '6FF2', + 'ePDGId': '6FF3', + 'ePDGSelection': '6FF4', + 'ePDGIdEm': '6FF5', + 'ePDGSelectionEm': '6FF6', +} + +LOCI_STATUS_map = { + 0: 'updated', + 1: 'not updated', + 2: 'plmn not allowed', + 3: 'locatation area not allowed' +} diff --git a/pySim/legacy/ts_31_103.py b/pySim/legacy/ts_31_103.py new file mode 100644 index 0000000..f500f08 --- /dev/null +++ b/pySim/legacy/ts_31_103.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- + +""" +Various constants from 3GPP TS 31.103 V16.1.0 used by *legacy* code only +""" + +# Copyright (C) 2020 Supreeth Herle <herlesupreeth(a)gmail.com> +# Copyright (C) 2021 Harald Welte <laforge(a)osmocom.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +EF_ISIM_ADF_map = { + 'IST': '6F07', + 'IMPI': '6F02', + 'DOMAIN': '6F03', + 'IMPU': '6F04', + 'AD': '6FAD', + 'ARR': '6F06', + 'PCSCF': '6F09', + 'GBAP': '6FD5', + 'GBANL': '6FD7', + 'NAFKCA': '6FDD', + 'UICCIARI': '6FE7', + 'SMS': '6F3C', + 'SMSS': '6F43', + 'SMSR': '6F47', + 'SMSP': '6F42', + 'FromPreferred': '6FF7', + 'IMSConfigData': '6FF8', + 'XCAPConfigData': '6FFC', + 'WebRTCURI': '6FFA' +} diff --git a/pySim/ts_31_102.py b/pySim/ts_31_102.py index e7ae8f0..5db3e88 100644 --- a/pySim/ts_31_102.py +++ b/pySim/ts_31_102.py @@ -209,117 +209,6 @@ 3: 'APN Control List (ACL)' } -LOCI_STATUS_map = { - 0: 'updated', - 1: 'not updated', - 2: 'plmn not allowed', - 3: 'locatation area not allowed' -} - -EF_USIM_ADF_map = { - 'LI': '6F05', - 'ARR': '6F06', - 'IMSI': '6F07', - 'Keys': '6F08', - 'KeysPS': '6F09', - 'DCK': '6F2C', - 'HPPLMN': '6F31', - 'CNL': '6F32', - 'ACMmax': '6F37', - 'UST': '6F38', - 'ACM': '6F39', - 'FDN': '6F3B', - 'SMS': '6F3C', - 'GID1': '6F3E', - 'GID2': '6F3F', - 'MSISDN': '6F40', - 'PUCT': '6F41', - 'SMSP': '6F42', - 'SMSS': '6F42', - 'CBMI': '6F45', - 'SPN': '6F46', - 'SMSR': '6F47', - 'CBMID': '6F48', - 'SDN': '6F49', - 'EXT2': '6F4B', - 'EXT3': '6F4C', - 'BDN': '6F4D', - 'EXT5': '6F4E', - 'CCP2': '6F4F', - 'CBMIR': '6F50', - 'EXT4': '6F55', - 'EST': '6F56', - 'ACL': '6F57', - 'CMI': '6F58', - 'START-HFN': '6F5B', - 'THRESHOLD': '6F5C', - 'PLMNwAcT': '6F60', - 'OPLMNwAcT': '6F61', - 'HPLMNwAcT': '6F62', - 'PSLOCI': '6F73', - 'ACC': '6F78', - 'FPLMN': '6F7B', - 'LOCI': '6F7E', - 'ICI': '6F80', - 'OCI': '6F81', - 'ICT': '6F82', - 'OCT': '6F83', - 'AD': '6FAD', - 'VGCS': '6FB1', - 'VGCSS': '6FB2', - 'VBS': '6FB3', - 'VBSS': '6FB4', - 'eMLPP': '6FB5', - 'AAeM': '6FB6', - 'ECC': '6FB7', - 'Hiddenkey': '6FC3', - 'NETPAR': '6FC4', - 'PNN': '6FC5', - 'OPL': '6FC6', - 'MBDN': '6FC7', - 'EXT6': '6FC8', - 'MBI': '6FC9', - 'MWIS': '6FCA', - 'CFIS': '6FCB', - 'EXT7': '6FCC', - 'SPDI': '6FCD', - 'MMSN': '6FCE', - 'EXT8': '6FCF', - 'MMSICP': '6FD0', - 'MMSUP': '6FD1', - 'MMSUCP': '6FD2', - 'NIA': '6FD3', - 'VGCSCA': '6FD4', - 'VBSCA': '6FD5', - 'GBAP': '6FD6', - 'MSK': '6FD7', - 'MUK': '6FD8', - 'EHPLMN': '6FD9', - 'GBANL': '6FDA', - 'EHPLMNPI': '6FDB', - 'LRPLMNSI': '6FDC', - 'NAFKCA': '6FDD', - 'SPNI': '6FDE', - 'PNNI': '6FDF', - 'NCP-IP': '6FE2', - 'EPSLOCI': '6FE3', - 'EPSNSC': '6FE4', - 'UFC': '6FE6', - 'UICCIARI': '6FE7', - 'NASCONFIG': '6FE8', - 'PWC': '6FEC', - 'FDNURI': '6FED', - 'BDNURI': '6FEE', - 'SDNURI': '6FEF', - 'IWL': '6FF0', - 'IPS': '6FF1', - 'IPD': '6FF2', - 'ePDGId': '6FF3', - 'ePDGSelection': '6FF4', - 'ePDGIdEm': '6FF5', - 'ePDGSelectionEm': '6FF6', -} - # 3gPP TS 31.102 Section 7.5.2.1 class SUCI_TlvDataObject(BER_TLV_IE, tag=0xA1): _construct = HexAdapter(GreedyBytes) diff --git a/pySim/ts_31_103.py b/pySim/ts_31_103.py index f1c8dd7..5f374cb 100644 --- a/pySim/ts_31_103.py +++ b/pySim/ts_31_103.py @@ -56,28 +56,6 @@ 21: 'MuD and MiD configuration data', } -EF_ISIM_ADF_map = { - 'IST': '6F07', - 'IMPI': '6F02', - 'DOMAIN': '6F03', - 'IMPU': '6F04', - 'AD': '6FAD', - 'ARR': '6F06', - 'PCSCF': '6F09', - 'GBAP': '6FD5', - 'GBANL': '6FD7', - 'NAFKCA': '6FDD', - 'UICCIARI': '6FE7', - 'SMS': '6F3C', - 'SMSS': '6F43', - 'SMSR': '6F47', - 'SMSP': '6F42', - 'FromPreferred': '6FF7', - 'IMSConfigData': '6FF8', - 'XCAPConfigData': '6FFC', - 'WebRTCURI': '6FFA' -} - # TS 31.103 Section 4.2.2 class EF_IMPI(TransparentEF): _test_de_encode = [ -- To view, visit https://gerrit.osmocom.org/c/pysim/+/33694 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: Ifebfbbc00ef0d01cafd6f058a32d243d3696e97e Gerrit-Change-Number: 33694 Gerrit-PatchSet: 5 Gerrit-Owner: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-MessageType: merged
1 0
0 0
[S] Change in pysim[master]: cards: all UICC should use sel_ctrl="0400" and SIM "0000"
by laforge 18 Jul '23

18 Jul '23
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/33697 ) ( 3 is the latest approved patch-set. No files were changed between the latest approved patch-set and the submitted one. )Change subject: cards: all UICC should use sel_ctrl="0400" and SIM "0000" ...................................................................... cards: all UICC should use sel_ctrl="0400" and SIM "0000" Hence move this from the derived classes into the respective base classes SimCardBase and UiccCardBase Change-Id: Iad197c2b560c5ea05c54a122144361de5742aafd --- M pySim/cards.py M pySim/legacy/cards.py 2 files changed, 14 insertions(+), 6 deletions(-) Approvals: dexter: Looks good to me, approved fixeria: Looks good to me, but someone else must approve Jenkins Builder: Verified diff --git a/pySim/cards.py b/pySim/cards.py index 772ea52..c6a68fc 100644 --- a/pySim/cards.py +++ b/pySim/cards.py @@ -86,6 +86,7 @@ def __init__(self, scc: LinkBase): super(SimCardBase, self).__init__(scc) self._scc.cla_byte = "A0" + self._scc.sel_ctrl = "0000" def probe(self) -> bool: df_gsm = DF_GSM() @@ -98,6 +99,7 @@ def __init__(self, scc: LinkBase): super(UiccCardBase, self).__init__(scc) self._scc.cla_byte = "00" + self._scc.sel_ctrl = "0004" # request an FCP # See also: ETSI TS 102 221, Table 9.3 self._adm_chv_num = 0xA0 diff --git a/pySim/legacy/cards.py b/pySim/legacy/cards.py index d4e5862..e64b5c3 100644 --- a/pySim/legacy/cards.py +++ b/pySim/legacy/cards.py @@ -893,7 +893,6 @@ def __init__(self, ssc): super(SysmoUSIMSJS1, self).__init__(ssc) - self._scc.sel_ctrl = "0004" # request an FCP @classmethod def autodetect(kls, scc): @@ -1205,7 +1204,6 @@ def __init__(self, ssc): super(WavemobileSim, self).__init__(ssc) self._adm_chv_num = 0x0A - self._scc.sel_ctrl = "0004" # request an FCP @classmethod def autodetect(kls, scc): @@ -1297,10 +1295,6 @@ name = 'sysmoISIM-SJA2' - def __init__(self, ssc): - super(SysmoISIMSJA2, self).__init__(ssc) - self._scc.sel_ctrl = "0004" # request an FCP - @classmethod def autodetect(kls, scc): try: -- To view, visit https://gerrit.osmocom.org/c/pysim/+/33697 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: Iad197c2b560c5ea05c54a122144361de5742aafd Gerrit-Change-Number: 33697 Gerrit-PatchSet: 5 Gerrit-Owner: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de> Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-MessageType: merged
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • ...
  • 306
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.