Change in pysim[master]: ts_102_221: put select response decoder into separate file

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

dexter gerrit-no-reply at lists.osmocom.org
Mon Nov 8 15:46:24 UTC 2021


dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/26160 )


Change subject: ts_102_221: put select response decoder into separate file
......................................................................

ts_102_221: put select response decoder into separate file

The decoder function that decodes the select response has become more
and more complex over time, so it makes sense to put the code into a
separate file, lets also mark the functions we only call from inside the
decoder as private. This makes the code more readable and also helps to
prevent circular dependencies.

Change-Id: If5fae46bb40d0f285236a6ab287070125c69ed70
---
M pySim/ts_102_221.py
A pySim/ts_102_221_select.py
M pySim/ts_31_102.py
M pySim/ts_31_103.py
M pySim/ts_51_011.py
5 files changed, 182 insertions(+), 155 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/60/26160/1

diff --git a/pySim/ts_102_221.py b/pySim/ts_102_221.py
index 3665939..8b1f7da 100644
--- a/pySim/ts_102_221.py
+++ b/pySim/ts_102_221.py
@@ -17,7 +17,7 @@
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 """
 
-from pytlv.TLV import *
+#from pytlv.TLV import *
 from construct import *
 from pySim.construct import *
 from pySim.utils import *
@@ -70,138 +70,11 @@
     ])
 
 
-FCP_TLV_MAP = {
-    '82': 'file_descriptor',
-    '83': 'file_identifier',
-    '84': 'df_name',
-    'A5': 'proprietary_info',
-    '8A': 'life_cycle_status_int',
-    '8B': 'security_attrib_ref_expanded',
-    '8C': 'security_attrib_compact',
-    'AB': 'security_attrib_espanded',
-    'C6': 'pin_status_template_do',
-    '80': 'file_size',
-    '81': 'total_file_size',
-    '88': 'short_file_id',
-    }
-
-# ETSI TS 102 221 11.1.1.4.6
-FCP_Proprietary_TLV_MAP = {
-    '80': 'uicc_characteristics',
-    '81': 'application_power_consumption',
-    '82': 'minimum_app_clock_freq',
-    '83': 'available_memory',
-    '84': 'file_details',
-    '85': 'reserved_file_size',
-    '86': 'maximum_file_size',
-    '87': 'suported_system_commands',
-    '88': 'specific_uicc_env_cond',
-    '89': 'p2p_cat_secured_apdu',
-    # Additional private TLV objects (bits b7 and b8 of the first byte of the tag set to '1')
-    }
-
-# ETSI TS 102 221 11.1.1.4.3
-def interpret_file_descriptor(in_hex):
-    in_bin = h2b(in_hex)
-    out = {}
-    ft_dict = {
-        0: 'working_ef',
-        1: 'internal_ef',
-        7: 'df'
-    }
-    fs_dict = {
-        0: 'no_info_given',
-        1: 'transparent',
-        2: 'linear_fixed',
-        6: 'cyclic',
-     0x39: 'ber_tlv',
-    }
-    fdb = in_bin[0]
-    ftype = (fdb >> 3) & 7
-    if fdb & 0xbf == 0x39:
-        fstruct = 0x39
-    else:
-        fstruct = fdb & 7
-    out['shareable'] = True if fdb & 0x40 else False
-    out['file_type'] = ft_dict[ftype] if ftype in ft_dict else ftype
-    out['structure'] = fs_dict[fstruct] if fstruct in fs_dict else fstruct
-    if len(in_bin) >= 5:
-        out['record_len'] = int.from_bytes(in_bin[2:4], 'big')
-        out['num_of_rec'] = int.from_bytes(in_bin[4:5], 'big')
-    return out
-
-# ETSI TS 102 221 11.1.1.4.9
-def interpret_life_cycle_sts_int(in_hex):
-    lcsi = int(in_hex, 16)
-    if lcsi == 0x00:
-        return 'no_information'
-    elif lcsi == 0x01:
-        return 'creation'
-    elif lcsi == 0x03:
-        return 'initialization'
-    elif lcsi & 0x05 == 0x05:
-        return 'operational_activated'
-    elif lcsi & 0x05 == 0x04:
-        return 'operational_deactivated'
-    elif lcsi & 0xc0 == 0xc0:
-        return 'termination'
-    else:
-        return in_hex
-
-# ETSI TS 102 221 11.1.1.4.10
-FCP_Pin_Status_TLV_MAP = {
-    '90': 'ps_do',
-    '95': 'usage_qualifier',
-    '83': 'key_reference',
-    }
-
-def interpret_ps_templ_do(in_hex):
-    # cannot use the 'TLV' parser due to repeating tags
-    #psdo_tlv = TLV(FCP_Pin_Status_TLV_MAP)
-    #return psdo_tlv.parse(in_hex)
-    return in_hex
-
-# 'interpreter' functions for each tag
-FCP_interpreter_map = {
-    '80': lambda x: int(x, 16),
-    '82': interpret_file_descriptor,
-    '8A': interpret_life_cycle_sts_int,
-    'C6': interpret_ps_templ_do,
-    }
-
-FCP_prorietary_interpreter_map = {
-    '83': lambda x: int(x, 16),
-    }
-
-# pytlv unfortunately doesn't have a setting using which we can make it
-# accept unknown tags.  It also doesn't raise a specific exception type but
-# just the generic ValueError, so we cannot ignore those either.  Instead,
-# we insert a dict entry for every possible proprietary tag permitted
-def fixup_fcp_proprietary_tlv_map(tlv_map):
-    if 'D0' in tlv_map:
-        return
-    for i in range(0xc0, 0xff):
-        i_hex = i2h([i]).upper()
-        tlv_map[i_hex] = 'proprietary_' + i_hex
-    # Other non-standard TLV objects found on some cards
-    tlv_map['9B'] = 'target_ef' # for sysmoUSIM-SJS1
 
 
-def tlv_key_replace(inmap, indata):
-    def newkey(inmap, key):
-        if key in inmap:
-            return inmap[key]
-        else:
-            return key
-    return {newkey(inmap, d[0]): d[1] for d in indata.items()}
 
-def tlv_val_interpret(inmap, indata):
-    def newval(inmap, key, val):
-        if key in inmap:
-            return inmap[key](val)
-        else:
-            return val
-    return {d[0]: newval(inmap, d[0], d[1]) for d in indata.items()}
+
+
 
 # ETSI TS 102 221 Section 9.2.7 + ISO7816-4 9.3.3/9.3.4
 
@@ -466,28 +339,6 @@
 SC_DO = DataObjectChoice('security_condition', 'Security Condition',
                          members=[Always_DO, Never_DO, SecCondByte_DO(), SecCondByte_DO(0x9e), CRT_DO()])
 
-
-# ETSI TS 102 221 Section 11.1.1.3
-def decode_select_response(resp_hex):
-    fixup_fcp_proprietary_tlv_map(FCP_Proprietary_TLV_MAP)
-    resp_hex = resp_hex.upper()
-    # outer layer
-    fcp_base_tlv = TLV(['62'])
-    fcp_base = fcp_base_tlv.parse(resp_hex)
-    # actual FCP
-    fcp_tlv = TLV(FCP_TLV_MAP)
-    fcp = fcp_tlv.parse(fcp_base['62'])
-    # further decode the proprietary information
-    if fcp['A5']:
-        prop_tlv = TLV(FCP_Proprietary_TLV_MAP)
-        prop = prop_tlv.parse(fcp['A5'])
-        fcp['A5'] = tlv_val_interpret(FCP_prorietary_interpreter_map, prop)
-        fcp['A5'] = tlv_key_replace(FCP_Proprietary_TLV_MAP, fcp['A5'])
-    # finally make sure we get human-readable keys in the output dict
-    r = tlv_val_interpret(FCP_interpreter_map, fcp)
-    return tlv_key_replace(FCP_TLV_MAP, r)
-
-
 # TS 102 221 Section 13.1
 class EF_DIR(LinFixedEF):
     def __init__(self, fid='2f00', sfid=0x1e, name='EF.DIR', desc='Application Directory'):
diff --git a/pySim/ts_102_221_select.py b/pySim/ts_102_221_select.py
new file mode 100644
index 0000000..74ede38
--- /dev/null
+++ b/pySim/ts_102_221_select.py
@@ -0,0 +1,173 @@
+# coding=utf-8
+"""Utilities / Functions related to ETSI TS 102 221, section 11.1.1 SELECT.
+
+(C) 2021 by Harald Welte <laforge at 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 pySim.utils import i2h, h2b, bertlv_parse_one
+from pytlv.TLV import *
+
+FCP_TLV_MAP = {
+    '82': 'file_descriptor',
+    '83': 'file_identifier',
+    '84': 'df_name',
+    'A5': 'proprietary_info',
+    '8A': 'life_cycle_status_int',
+    '8B': 'security_attrib_ref_expanded',
+    '8C': 'security_attrib_compact',
+    'AB': 'security_attrib_espanded',
+    'C6': 'pin_status_template_do',
+    '80': 'file_size',
+    '81': 'total_file_size',
+    '88': 'short_file_id',
+    }
+
+# ETSI TS 102 221 11.1.1.4.6
+FCP_Proprietary_TLV_MAP = {
+    '80': 'uicc_characteristics',
+    '81': 'application_power_consumption',
+    '82': 'minimum_app_clock_freq',
+    '83': 'available_memory',
+    '84': 'file_details',
+    '85': 'reserved_file_size',
+    '86': 'maximum_file_size',
+    '87': 'suported_system_commands',
+    '88': 'specific_uicc_env_cond',
+    '89': 'p2p_cat_secured_apdu',
+    # Additional private TLV objects (bits b7 and b8 of the first byte of the tag set to '1')
+    }
+
+# ETSI TS 102 221 11.1.1.4.3
+def _interpret_file_descriptor(in_hex):
+    in_bin = h2b(in_hex)
+    out = {}
+    ft_dict = {
+        0: 'working_ef',
+        1: 'internal_ef',
+        7: 'df'
+    }
+    fs_dict = {
+        0: 'no_info_given',
+        1: 'transparent',
+        2: 'linear_fixed',
+        6: 'cyclic',
+     0x39: 'ber_tlv',
+    }
+    fdb = in_bin[0]
+    ftype = (fdb >> 3) & 7
+    if fdb & 0xbf == 0x39:
+        fstruct = 0x39
+    else:
+        fstruct = fdb & 7
+    out['shareable'] = True if fdb & 0x40 else False
+    out['file_type'] = ft_dict[ftype] if ftype in ft_dict else ftype
+    out['structure'] = fs_dict[fstruct] if fstruct in fs_dict else fstruct
+    if len(in_bin) >= 5:
+        out['record_len'] = int.from_bytes(in_bin[2:4], 'big')
+        out['num_of_rec'] = int.from_bytes(in_bin[4:5], 'big')
+    return out
+
+# ETSI TS 102 221 11.1.1.4.9
+def _interpret_life_cycle_sts_int(in_hex):
+    lcsi = int(in_hex, 16)
+    if lcsi == 0x00:
+        return 'no_information'
+    elif lcsi == 0x01:
+        return 'creation'
+    elif lcsi == 0x03:
+        return 'initialization'
+    elif lcsi & 0x05 == 0x05:
+        return 'operational_activated'
+    elif lcsi & 0x05 == 0x04:
+        return 'operational_deactivated'
+    elif lcsi & 0xc0 == 0xc0:
+        return 'termination'
+    else:
+        return in_hex
+
+# ETSI TS 102 221 11.1.1.4.10
+FCP_Pin_Status_TLV_MAP = {
+    '90': 'ps_do',
+    '95': 'usage_qualifier',
+    '83': 'key_reference',
+    }
+
+def _interpret_ps_templ_do(in_hex):
+    # cannot use the 'TLV' parser due to repeating tags
+    #psdo_tlv = TLV(FCP_Pin_Status_TLV_MAP)
+    #return psdo_tlv.parse(in_hex)
+    return in_hex
+
+# 'interpreter' functions for each tag
+FCP_interpreter_map = {
+    '80': lambda x: int(x, 16),
+    '82': _interpret_file_descriptor,
+    '8A': _interpret_life_cycle_sts_int,
+    'C6': _interpret_ps_templ_do,
+    }
+
+FCP_prorietary_interpreter_map = {
+    '83': lambda x: int(x, 16),
+    }
+
+# pytlv unfortunately doesn't have a setting using which we can make it
+# accept unknown tags.  It also doesn't raise a specific exception type but
+# just the generic ValueError, so we cannot ignore those either.  Instead,
+# we insert a dict entry for every possible proprietary tag permitted
+def _fixup_fcp_proprietary_tlv_map(tlv_map):
+    if 'D0' in tlv_map:
+        return
+    for i in range(0xc0, 0xff):
+        i_hex = i2h([i]).upper()
+        tlv_map[i_hex] = 'proprietary_' + i_hex
+    # Other non-standard TLV objects found on some cards
+    tlv_map['9B'] = 'target_ef' # for sysmoUSIM-SJS1
+
+def _tlv_key_replace(inmap, indata):
+    def newkey(inmap, key):
+        if key in inmap:
+            return inmap[key]
+        else:
+            return key
+    return {newkey(inmap, d[0]): d[1] for d in indata.items()}
+
+def _tlv_val_interpret(inmap, indata):
+    def newval(inmap, key, val):
+        if key in inmap:
+            return inmap[key](val)
+        else:
+            return val
+    return {d[0]: newval(inmap, d[0], d[1]) for d in indata.items()}
+
+# ETSI TS 102 221 Section 11.1.1.3
+def decode_select_response(resp_hex):
+    _fixup_fcp_proprietary_tlv_map(FCP_Proprietary_TLV_MAP)
+    resp_hex = resp_hex.upper()
+    # outer layer
+    fcp_base_tlv = TLV(['62'])
+    fcp_base = fcp_base_tlv.parse(resp_hex)
+    # actual FCP
+    fcp_tlv = TLV(FCP_TLV_MAP)
+    fcp = fcp_tlv.parse(fcp_base['62'])
+    # further decode the proprietary information
+    if fcp['A5']:
+        prop_tlv = TLV(FCP_Proprietary_TLV_MAP)
+        prop = prop_tlv.parse(fcp['A5'])
+        fcp['A5'] = _tlv_val_interpret(FCP_prorietary_interpreter_map, prop)
+        fcp['A5'] = _tlv_key_replace(FCP_Proprietary_TLV_MAP, fcp['A5'])
+    # finally make sure we get human-readable keys in the output dict
+    r = _tlv_val_interpret(FCP_interpreter_map, fcp)
+    return _tlv_key_replace(FCP_TLV_MAP, r)
diff --git a/pySim/ts_31_102.py b/pySim/ts_31_102.py
index 14d7ec1..83c281c 100644
--- a/pySim/ts_31_102.py
+++ b/pySim/ts_31_102.py
@@ -294,6 +294,7 @@
 from pySim.ts_51_011 import EF_MMSN, EF_MMSICP, EF_MMSUP, EF_MMSUCP, EF_VGCS, EF_VGCSS, EF_NIA
 from pySim.ts_51_011 import EF_ACMmax, EF_AAeM, EF_eMLPP, EF_CMI
 
+import pySim.ts_51_011
 import pySim.ts_102_221
 
 # 3GPP TS 31.102 Section 4.4.11.4 (EF_5GS3GPPNSC)
@@ -1067,7 +1068,7 @@
         self.add_files(files)
 
     def decode_select_response(self, data_hex):
-        return pySim.ts_102_221.decode_select_response(data_hex)
+        return pySim.ts_102_221_select.decode_select_response(data_hex)
 
     @with_default_category('Application-Specific Commands')
     class AddlShellCommands(CommandSet):
diff --git a/pySim/ts_31_103.py b/pySim/ts_31_103.py
index 63ef99e..3fd6629 100644
--- a/pySim/ts_31_103.py
+++ b/pySim/ts_31_103.py
@@ -28,6 +28,7 @@
 from pySim.ts_51_011 import EF_AD, EF_SMS, EF_SMSS, EF_SMSR, EF_SMSP
 from pySim.ts_31_102 import ADF_USIM, EF_FromPreferred
 import pySim.ts_102_221
+import pySim.ts_102_221_select
 from pySim.ts_102_221 import EF_ARR
 
 # Mapping between ISIM Service Number and its description
@@ -213,7 +214,7 @@
         self.shell_commands += [ADF_USIM.AddlShellCommands()]
 
     def decode_select_response(self, data_hex):
-        return pySim.ts_102_221.decode_select_response(data_hex)
+        return pySim.ts_102_221_select.decode_select_response(data_hex)
 
 # TS 31.103 Section 7.1
 sw_isim = {
diff --git a/pySim/ts_51_011.py b/pySim/ts_51_011.py
index 743c14b..c7168e8 100644
--- a/pySim/ts_51_011.py
+++ b/pySim/ts_51_011.py
@@ -333,6 +333,7 @@
 
 from pySim.filesystem import *
 import pySim.ts_102_221
+import pySim.ts_102_221_select
 
 ######################################################################
 # DF.TELECOM
@@ -942,7 +943,7 @@
 def decode_select_response(resp_hex):
     resp_bin = h2b(resp_hex)
     if resp_bin[0] == 0x62:
-        return pySim.ts_102_221.decode_select_response(resp_hex)
+        return pySim.ts_102_221_select.decode_select_response(resp_hex)
     struct_of_file_map = {
         0: 'transparent',
         1: 'linear_fixed',

-- 
To view, visit https://gerrit.osmocom.org/c/pysim/+/26160
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: If5fae46bb40d0f285236a6ab287070125c69ed70
Gerrit-Change-Number: 26160
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier at sysmocom.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20211108/c264c755/attachment.htm>


More information about the gerrit-log mailing list