<p>dexter has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/pysim/+/26160">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">ts_102_221: put select response decoder into separate file<br><br>The decoder function that decodes the select response has become more<br>and more complex over time, so it makes sense to put the code into a<br>separate file, lets also mark the functions we only call from inside the<br>decoder as private. This makes the code more readable and also helps to<br>prevent circular dependencies.<br><br>Change-Id: If5fae46bb40d0f285236a6ab287070125c69ed70<br>---<br>M pySim/ts_102_221.py<br>A pySim/ts_102_221_select.py<br>M pySim/ts_31_102.py<br>M pySim/ts_31_103.py<br>M pySim/ts_51_011.py<br>5 files changed, 182 insertions(+), 155 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/60/26160/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/pySim/ts_102_221.py b/pySim/ts_102_221.py</span><br><span>index 3665939..8b1f7da 100644</span><br><span>--- a/pySim/ts_102_221.py</span><br><span>+++ b/pySim/ts_102_221.py</span><br><span>@@ -17,7 +17,7 @@</span><br><span> along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span> """</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-from pytlv.TLV import *</span><br><span style="color: hsl(120, 100%, 40%);">+#from pytlv.TLV import *</span><br><span> from construct import *</span><br><span> from pySim.construct import *</span><br><span> from pySim.utils import *</span><br><span>@@ -70,138 +70,11 @@</span><br><span>     ])</span><br><span> </span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-FCP_TLV_MAP = {</span><br><span style="color: hsl(0, 100%, 40%);">-    '82': 'file_descriptor',</span><br><span style="color: hsl(0, 100%, 40%);">-    '83': 'file_identifier',</span><br><span style="color: hsl(0, 100%, 40%);">-    '84': 'df_name',</span><br><span style="color: hsl(0, 100%, 40%);">-    'A5': 'proprietary_info',</span><br><span style="color: hsl(0, 100%, 40%);">-    '8A': 'life_cycle_status_int',</span><br><span style="color: hsl(0, 100%, 40%);">-    '8B': 'security_attrib_ref_expanded',</span><br><span style="color: hsl(0, 100%, 40%);">-    '8C': 'security_attrib_compact',</span><br><span style="color: hsl(0, 100%, 40%);">-    'AB': 'security_attrib_espanded',</span><br><span style="color: hsl(0, 100%, 40%);">-    'C6': 'pin_status_template_do',</span><br><span style="color: hsl(0, 100%, 40%);">-    '80': 'file_size',</span><br><span style="color: hsl(0, 100%, 40%);">-    '81': 'total_file_size',</span><br><span style="color: hsl(0, 100%, 40%);">-    '88': 'short_file_id',</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-# ETSI TS 102 221 11.1.1.4.6</span><br><span style="color: hsl(0, 100%, 40%);">-FCP_Proprietary_TLV_MAP = {</span><br><span style="color: hsl(0, 100%, 40%);">-    '80': 'uicc_characteristics',</span><br><span style="color: hsl(0, 100%, 40%);">-    '81': 'application_power_consumption',</span><br><span style="color: hsl(0, 100%, 40%);">-    '82': 'minimum_app_clock_freq',</span><br><span style="color: hsl(0, 100%, 40%);">-    '83': 'available_memory',</span><br><span style="color: hsl(0, 100%, 40%);">-    '84': 'file_details',</span><br><span style="color: hsl(0, 100%, 40%);">-    '85': 'reserved_file_size',</span><br><span style="color: hsl(0, 100%, 40%);">-    '86': 'maximum_file_size',</span><br><span style="color: hsl(0, 100%, 40%);">-    '87': 'suported_system_commands',</span><br><span style="color: hsl(0, 100%, 40%);">-    '88': 'specific_uicc_env_cond',</span><br><span style="color: hsl(0, 100%, 40%);">-    '89': 'p2p_cat_secured_apdu',</span><br><span style="color: hsl(0, 100%, 40%);">-    # Additional private TLV objects (bits b7 and b8 of the first byte of the tag set to '1')</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-# ETSI TS 102 221 11.1.1.4.3</span><br><span style="color: hsl(0, 100%, 40%);">-def interpret_file_descriptor(in_hex):</span><br><span style="color: hsl(0, 100%, 40%);">-    in_bin = h2b(in_hex)</span><br><span style="color: hsl(0, 100%, 40%);">-    out = {}</span><br><span style="color: hsl(0, 100%, 40%);">-    ft_dict = {</span><br><span style="color: hsl(0, 100%, 40%);">-        0: 'working_ef',</span><br><span style="color: hsl(0, 100%, 40%);">-        1: 'internal_ef',</span><br><span style="color: hsl(0, 100%, 40%);">-        7: 'df'</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-    fs_dict = {</span><br><span style="color: hsl(0, 100%, 40%);">-        0: 'no_info_given',</span><br><span style="color: hsl(0, 100%, 40%);">-        1: 'transparent',</span><br><span style="color: hsl(0, 100%, 40%);">-        2: 'linear_fixed',</span><br><span style="color: hsl(0, 100%, 40%);">-        6: 'cyclic',</span><br><span style="color: hsl(0, 100%, 40%);">-     0x39: 'ber_tlv',</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-    fdb = in_bin[0]</span><br><span style="color: hsl(0, 100%, 40%);">-    ftype = (fdb >> 3) & 7</span><br><span style="color: hsl(0, 100%, 40%);">-    if fdb & 0xbf == 0x39:</span><br><span style="color: hsl(0, 100%, 40%);">-        fstruct = 0x39</span><br><span style="color: hsl(0, 100%, 40%);">-    else:</span><br><span style="color: hsl(0, 100%, 40%);">-        fstruct = fdb & 7</span><br><span style="color: hsl(0, 100%, 40%);">-    out['shareable'] = True if fdb & 0x40 else False</span><br><span style="color: hsl(0, 100%, 40%);">-    out['file_type'] = ft_dict[ftype] if ftype in ft_dict else ftype</span><br><span style="color: hsl(0, 100%, 40%);">-    out['structure'] = fs_dict[fstruct] if fstruct in fs_dict else fstruct</span><br><span style="color: hsl(0, 100%, 40%);">-    if len(in_bin) >= 5:</span><br><span style="color: hsl(0, 100%, 40%);">-        out['record_len'] = int.from_bytes(in_bin[2:4], 'big')</span><br><span style="color: hsl(0, 100%, 40%);">-        out['num_of_rec'] = int.from_bytes(in_bin[4:5], 'big')</span><br><span style="color: hsl(0, 100%, 40%);">-    return out</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-# ETSI TS 102 221 11.1.1.4.9</span><br><span style="color: hsl(0, 100%, 40%);">-def interpret_life_cycle_sts_int(in_hex):</span><br><span style="color: hsl(0, 100%, 40%);">-    lcsi = int(in_hex, 16)</span><br><span style="color: hsl(0, 100%, 40%);">-    if lcsi == 0x00:</span><br><span style="color: hsl(0, 100%, 40%);">-        return 'no_information'</span><br><span style="color: hsl(0, 100%, 40%);">-    elif lcsi == 0x01:</span><br><span style="color: hsl(0, 100%, 40%);">-        return 'creation'</span><br><span style="color: hsl(0, 100%, 40%);">-    elif lcsi == 0x03:</span><br><span style="color: hsl(0, 100%, 40%);">-        return 'initialization'</span><br><span style="color: hsl(0, 100%, 40%);">-    elif lcsi & 0x05 == 0x05:</span><br><span style="color: hsl(0, 100%, 40%);">-        return 'operational_activated'</span><br><span style="color: hsl(0, 100%, 40%);">-    elif lcsi & 0x05 == 0x04:</span><br><span style="color: hsl(0, 100%, 40%);">-        return 'operational_deactivated'</span><br><span style="color: hsl(0, 100%, 40%);">-    elif lcsi & 0xc0 == 0xc0:</span><br><span style="color: hsl(0, 100%, 40%);">-        return 'termination'</span><br><span style="color: hsl(0, 100%, 40%);">-    else:</span><br><span style="color: hsl(0, 100%, 40%);">-        return in_hex</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-# ETSI TS 102 221 11.1.1.4.10</span><br><span style="color: hsl(0, 100%, 40%);">-FCP_Pin_Status_TLV_MAP = {</span><br><span style="color: hsl(0, 100%, 40%);">-    '90': 'ps_do',</span><br><span style="color: hsl(0, 100%, 40%);">-    '95': 'usage_qualifier',</span><br><span style="color: hsl(0, 100%, 40%);">-    '83': 'key_reference',</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-def interpret_ps_templ_do(in_hex):</span><br><span style="color: hsl(0, 100%, 40%);">-    # cannot use the 'TLV' parser due to repeating tags</span><br><span style="color: hsl(0, 100%, 40%);">-    #psdo_tlv = TLV(FCP_Pin_Status_TLV_MAP)</span><br><span style="color: hsl(0, 100%, 40%);">-    #return psdo_tlv.parse(in_hex)</span><br><span style="color: hsl(0, 100%, 40%);">-    return in_hex</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-# 'interpreter' functions for each tag</span><br><span style="color: hsl(0, 100%, 40%);">-FCP_interpreter_map = {</span><br><span style="color: hsl(0, 100%, 40%);">-    '80': lambda x: int(x, 16),</span><br><span style="color: hsl(0, 100%, 40%);">-    '82': interpret_file_descriptor,</span><br><span style="color: hsl(0, 100%, 40%);">-    '8A': interpret_life_cycle_sts_int,</span><br><span style="color: hsl(0, 100%, 40%);">-    'C6': interpret_ps_templ_do,</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-FCP_prorietary_interpreter_map = {</span><br><span style="color: hsl(0, 100%, 40%);">-    '83': lambda x: int(x, 16),</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-# pytlv unfortunately doesn't have a setting using which we can make it</span><br><span style="color: hsl(0, 100%, 40%);">-# accept unknown tags.  It also doesn't raise a specific exception type but</span><br><span style="color: hsl(0, 100%, 40%);">-# just the generic ValueError, so we cannot ignore those either.  Instead,</span><br><span style="color: hsl(0, 100%, 40%);">-# we insert a dict entry for every possible proprietary tag permitted</span><br><span style="color: hsl(0, 100%, 40%);">-def fixup_fcp_proprietary_tlv_map(tlv_map):</span><br><span style="color: hsl(0, 100%, 40%);">-    if 'D0' in tlv_map:</span><br><span style="color: hsl(0, 100%, 40%);">-        return</span><br><span style="color: hsl(0, 100%, 40%);">-    for i in range(0xc0, 0xff):</span><br><span style="color: hsl(0, 100%, 40%);">-        i_hex = i2h([i]).upper()</span><br><span style="color: hsl(0, 100%, 40%);">-        tlv_map[i_hex] = 'proprietary_' + i_hex</span><br><span style="color: hsl(0, 100%, 40%);">-    # Other non-standard TLV objects found on some cards</span><br><span style="color: hsl(0, 100%, 40%);">-    tlv_map['9B'] = 'target_ef' # for sysmoUSIM-SJS1</span><br><span> </span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def tlv_key_replace(inmap, indata):</span><br><span style="color: hsl(0, 100%, 40%);">-    def newkey(inmap, key):</span><br><span style="color: hsl(0, 100%, 40%);">-        if key in inmap:</span><br><span style="color: hsl(0, 100%, 40%);">-            return inmap[key]</span><br><span style="color: hsl(0, 100%, 40%);">-        else:</span><br><span style="color: hsl(0, 100%, 40%);">-            return key</span><br><span style="color: hsl(0, 100%, 40%);">-    return {newkey(inmap, d[0]): d[1] for d in indata.items()}</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def tlv_val_interpret(inmap, indata):</span><br><span style="color: hsl(0, 100%, 40%);">-    def newval(inmap, key, val):</span><br><span style="color: hsl(0, 100%, 40%);">-        if key in inmap:</span><br><span style="color: hsl(0, 100%, 40%);">-            return inmap[key](val)</span><br><span style="color: hsl(0, 100%, 40%);">-        else:</span><br><span style="color: hsl(0, 100%, 40%);">-            return val</span><br><span style="color: hsl(0, 100%, 40%);">-    return {d[0]: newval(inmap, d[0], d[1]) for d in indata.items()}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> </span><br><span> # ETSI TS 102 221 Section 9.2.7 + ISO7816-4 9.3.3/9.3.4</span><br><span> </span><br><span>@@ -466,28 +339,6 @@</span><br><span> SC_DO = DataObjectChoice('security_condition', 'Security Condition',</span><br><span>                          members=[Always_DO, Never_DO, SecCondByte_DO(), SecCondByte_DO(0x9e), CRT_DO()])</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-# ETSI TS 102 221 Section 11.1.1.3</span><br><span style="color: hsl(0, 100%, 40%);">-def decode_select_response(resp_hex):</span><br><span style="color: hsl(0, 100%, 40%);">-    fixup_fcp_proprietary_tlv_map(FCP_Proprietary_TLV_MAP)</span><br><span style="color: hsl(0, 100%, 40%);">-    resp_hex = resp_hex.upper()</span><br><span style="color: hsl(0, 100%, 40%);">-    # outer layer</span><br><span style="color: hsl(0, 100%, 40%);">-    fcp_base_tlv = TLV(['62'])</span><br><span style="color: hsl(0, 100%, 40%);">-    fcp_base = fcp_base_tlv.parse(resp_hex)</span><br><span style="color: hsl(0, 100%, 40%);">-    # actual FCP</span><br><span style="color: hsl(0, 100%, 40%);">-    fcp_tlv = TLV(FCP_TLV_MAP)</span><br><span style="color: hsl(0, 100%, 40%);">-    fcp = fcp_tlv.parse(fcp_base['62'])</span><br><span style="color: hsl(0, 100%, 40%);">-    # further decode the proprietary information</span><br><span style="color: hsl(0, 100%, 40%);">-    if fcp['A5']:</span><br><span style="color: hsl(0, 100%, 40%);">-        prop_tlv = TLV(FCP_Proprietary_TLV_MAP)</span><br><span style="color: hsl(0, 100%, 40%);">-        prop = prop_tlv.parse(fcp['A5'])</span><br><span style="color: hsl(0, 100%, 40%);">-        fcp['A5'] = tlv_val_interpret(FCP_prorietary_interpreter_map, prop)</span><br><span style="color: hsl(0, 100%, 40%);">-        fcp['A5'] = tlv_key_replace(FCP_Proprietary_TLV_MAP, fcp['A5'])</span><br><span style="color: hsl(0, 100%, 40%);">-    # finally make sure we get human-readable keys in the output dict</span><br><span style="color: hsl(0, 100%, 40%);">-    r = tlv_val_interpret(FCP_interpreter_map, fcp)</span><br><span style="color: hsl(0, 100%, 40%);">-    return tlv_key_replace(FCP_TLV_MAP, r)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> # TS 102 221 Section 13.1</span><br><span> class EF_DIR(LinFixedEF):</span><br><span>     def __init__(self, fid='2f00', sfid=0x1e, name='EF.DIR', desc='Application Directory'):</span><br><span>diff --git a/pySim/ts_102_221_select.py b/pySim/ts_102_221_select.py</span><br><span>new file mode 100644</span><br><span>index 0000000..74ede38</span><br><span>--- /dev/null</span><br><span>+++ b/pySim/ts_102_221_select.py</span><br><span>@@ -0,0 +1,173 @@</span><br><span style="color: hsl(120, 100%, 40%);">+# coding=utf-8</span><br><span style="color: hsl(120, 100%, 40%);">+"""Utilities / Functions related to ETSI TS 102 221, section 11.1.1 SELECT.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+(C) 2021 by Harald Welte <laforge@osmocom.org></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+This program is free software: you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+the Free Software Foundation, either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+(at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+You should have received a copy of the GNU General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+"""</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from pySim.utils import i2h, h2b, bertlv_parse_one</span><br><span style="color: hsl(120, 100%, 40%);">+from pytlv.TLV import *</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+FCP_TLV_MAP = {</span><br><span style="color: hsl(120, 100%, 40%);">+    '82': 'file_descriptor',</span><br><span style="color: hsl(120, 100%, 40%);">+    '83': 'file_identifier',</span><br><span style="color: hsl(120, 100%, 40%);">+    '84': 'df_name',</span><br><span style="color: hsl(120, 100%, 40%);">+    'A5': 'proprietary_info',</span><br><span style="color: hsl(120, 100%, 40%);">+    '8A': 'life_cycle_status_int',</span><br><span style="color: hsl(120, 100%, 40%);">+    '8B': 'security_attrib_ref_expanded',</span><br><span style="color: hsl(120, 100%, 40%);">+    '8C': 'security_attrib_compact',</span><br><span style="color: hsl(120, 100%, 40%);">+    'AB': 'security_attrib_espanded',</span><br><span style="color: hsl(120, 100%, 40%);">+    'C6': 'pin_status_template_do',</span><br><span style="color: hsl(120, 100%, 40%);">+    '80': 'file_size',</span><br><span style="color: hsl(120, 100%, 40%);">+    '81': 'total_file_size',</span><br><span style="color: hsl(120, 100%, 40%);">+    '88': 'short_file_id',</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# ETSI TS 102 221 11.1.1.4.6</span><br><span style="color: hsl(120, 100%, 40%);">+FCP_Proprietary_TLV_MAP = {</span><br><span style="color: hsl(120, 100%, 40%);">+    '80': 'uicc_characteristics',</span><br><span style="color: hsl(120, 100%, 40%);">+    '81': 'application_power_consumption',</span><br><span style="color: hsl(120, 100%, 40%);">+    '82': 'minimum_app_clock_freq',</span><br><span style="color: hsl(120, 100%, 40%);">+    '83': 'available_memory',</span><br><span style="color: hsl(120, 100%, 40%);">+    '84': 'file_details',</span><br><span style="color: hsl(120, 100%, 40%);">+    '85': 'reserved_file_size',</span><br><span style="color: hsl(120, 100%, 40%);">+    '86': 'maximum_file_size',</span><br><span style="color: hsl(120, 100%, 40%);">+    '87': 'suported_system_commands',</span><br><span style="color: hsl(120, 100%, 40%);">+    '88': 'specific_uicc_env_cond',</span><br><span style="color: hsl(120, 100%, 40%);">+    '89': 'p2p_cat_secured_apdu',</span><br><span style="color: hsl(120, 100%, 40%);">+    # Additional private TLV objects (bits b7 and b8 of the first byte of the tag set to '1')</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# ETSI TS 102 221 11.1.1.4.3</span><br><span style="color: hsl(120, 100%, 40%);">+def _interpret_file_descriptor(in_hex):</span><br><span style="color: hsl(120, 100%, 40%);">+    in_bin = h2b(in_hex)</span><br><span style="color: hsl(120, 100%, 40%);">+    out = {}</span><br><span style="color: hsl(120, 100%, 40%);">+    ft_dict = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 'working_ef',</span><br><span style="color: hsl(120, 100%, 40%);">+        1: 'internal_ef',</span><br><span style="color: hsl(120, 100%, 40%);">+        7: 'df'</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+    fs_dict = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 'no_info_given',</span><br><span style="color: hsl(120, 100%, 40%);">+        1: 'transparent',</span><br><span style="color: hsl(120, 100%, 40%);">+        2: 'linear_fixed',</span><br><span style="color: hsl(120, 100%, 40%);">+        6: 'cyclic',</span><br><span style="color: hsl(120, 100%, 40%);">+     0x39: 'ber_tlv',</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+    fdb = in_bin[0]</span><br><span style="color: hsl(120, 100%, 40%);">+    ftype = (fdb >> 3) & 7</span><br><span style="color: hsl(120, 100%, 40%);">+    if fdb & 0xbf == 0x39:</span><br><span style="color: hsl(120, 100%, 40%);">+        fstruct = 0x39</span><br><span style="color: hsl(120, 100%, 40%);">+    else:</span><br><span style="color: hsl(120, 100%, 40%);">+        fstruct = fdb & 7</span><br><span style="color: hsl(120, 100%, 40%);">+    out['shareable'] = True if fdb & 0x40 else False</span><br><span style="color: hsl(120, 100%, 40%);">+    out['file_type'] = ft_dict[ftype] if ftype in ft_dict else ftype</span><br><span style="color: hsl(120, 100%, 40%);">+    out['structure'] = fs_dict[fstruct] if fstruct in fs_dict else fstruct</span><br><span style="color: hsl(120, 100%, 40%);">+    if len(in_bin) >= 5:</span><br><span style="color: hsl(120, 100%, 40%);">+        out['record_len'] = int.from_bytes(in_bin[2:4], 'big')</span><br><span style="color: hsl(120, 100%, 40%);">+        out['num_of_rec'] = int.from_bytes(in_bin[4:5], 'big')</span><br><span style="color: hsl(120, 100%, 40%);">+    return out</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# ETSI TS 102 221 11.1.1.4.9</span><br><span style="color: hsl(120, 100%, 40%);">+def _interpret_life_cycle_sts_int(in_hex):</span><br><span style="color: hsl(120, 100%, 40%);">+    lcsi = int(in_hex, 16)</span><br><span style="color: hsl(120, 100%, 40%);">+    if lcsi == 0x00:</span><br><span style="color: hsl(120, 100%, 40%);">+        return 'no_information'</span><br><span style="color: hsl(120, 100%, 40%);">+    elif lcsi == 0x01:</span><br><span style="color: hsl(120, 100%, 40%);">+        return 'creation'</span><br><span style="color: hsl(120, 100%, 40%);">+    elif lcsi == 0x03:</span><br><span style="color: hsl(120, 100%, 40%);">+        return 'initialization'</span><br><span style="color: hsl(120, 100%, 40%);">+    elif lcsi & 0x05 == 0x05:</span><br><span style="color: hsl(120, 100%, 40%);">+        return 'operational_activated'</span><br><span style="color: hsl(120, 100%, 40%);">+    elif lcsi & 0x05 == 0x04:</span><br><span style="color: hsl(120, 100%, 40%);">+        return 'operational_deactivated'</span><br><span style="color: hsl(120, 100%, 40%);">+    elif lcsi & 0xc0 == 0xc0:</span><br><span style="color: hsl(120, 100%, 40%);">+        return 'termination'</span><br><span style="color: hsl(120, 100%, 40%);">+    else:</span><br><span style="color: hsl(120, 100%, 40%);">+        return in_hex</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# ETSI TS 102 221 11.1.1.4.10</span><br><span style="color: hsl(120, 100%, 40%);">+FCP_Pin_Status_TLV_MAP = {</span><br><span style="color: hsl(120, 100%, 40%);">+    '90': 'ps_do',</span><br><span style="color: hsl(120, 100%, 40%);">+    '95': 'usage_qualifier',</span><br><span style="color: hsl(120, 100%, 40%);">+    '83': 'key_reference',</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def _interpret_ps_templ_do(in_hex):</span><br><span style="color: hsl(120, 100%, 40%);">+    # cannot use the 'TLV' parser due to repeating tags</span><br><span style="color: hsl(120, 100%, 40%);">+    #psdo_tlv = TLV(FCP_Pin_Status_TLV_MAP)</span><br><span style="color: hsl(120, 100%, 40%);">+    #return psdo_tlv.parse(in_hex)</span><br><span style="color: hsl(120, 100%, 40%);">+    return in_hex</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# 'interpreter' functions for each tag</span><br><span style="color: hsl(120, 100%, 40%);">+FCP_interpreter_map = {</span><br><span style="color: hsl(120, 100%, 40%);">+    '80': lambda x: int(x, 16),</span><br><span style="color: hsl(120, 100%, 40%);">+    '82': _interpret_file_descriptor,</span><br><span style="color: hsl(120, 100%, 40%);">+    '8A': _interpret_life_cycle_sts_int,</span><br><span style="color: hsl(120, 100%, 40%);">+    'C6': _interpret_ps_templ_do,</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+FCP_prorietary_interpreter_map = {</span><br><span style="color: hsl(120, 100%, 40%);">+    '83': lambda x: int(x, 16),</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# pytlv unfortunately doesn't have a setting using which we can make it</span><br><span style="color: hsl(120, 100%, 40%);">+# accept unknown tags.  It also doesn't raise a specific exception type but</span><br><span style="color: hsl(120, 100%, 40%);">+# just the generic ValueError, so we cannot ignore those either.  Instead,</span><br><span style="color: hsl(120, 100%, 40%);">+# we insert a dict entry for every possible proprietary tag permitted</span><br><span style="color: hsl(120, 100%, 40%);">+def _fixup_fcp_proprietary_tlv_map(tlv_map):</span><br><span style="color: hsl(120, 100%, 40%);">+    if 'D0' in tlv_map:</span><br><span style="color: hsl(120, 100%, 40%);">+        return</span><br><span style="color: hsl(120, 100%, 40%);">+    for i in range(0xc0, 0xff):</span><br><span style="color: hsl(120, 100%, 40%);">+        i_hex = i2h([i]).upper()</span><br><span style="color: hsl(120, 100%, 40%);">+        tlv_map[i_hex] = 'proprietary_' + i_hex</span><br><span style="color: hsl(120, 100%, 40%);">+    # Other non-standard TLV objects found on some cards</span><br><span style="color: hsl(120, 100%, 40%);">+    tlv_map['9B'] = 'target_ef' # for sysmoUSIM-SJS1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def _tlv_key_replace(inmap, indata):</span><br><span style="color: hsl(120, 100%, 40%);">+    def newkey(inmap, key):</span><br><span style="color: hsl(120, 100%, 40%);">+        if key in inmap:</span><br><span style="color: hsl(120, 100%, 40%);">+            return inmap[key]</span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span style="color: hsl(120, 100%, 40%);">+            return key</span><br><span style="color: hsl(120, 100%, 40%);">+    return {newkey(inmap, d[0]): d[1] for d in indata.items()}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def _tlv_val_interpret(inmap, indata):</span><br><span style="color: hsl(120, 100%, 40%);">+    def newval(inmap, key, val):</span><br><span style="color: hsl(120, 100%, 40%);">+        if key in inmap:</span><br><span style="color: hsl(120, 100%, 40%);">+            return inmap[key](val)</span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span style="color: hsl(120, 100%, 40%);">+            return val</span><br><span style="color: hsl(120, 100%, 40%);">+    return {d[0]: newval(inmap, d[0], d[1]) for d in indata.items()}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# ETSI TS 102 221 Section 11.1.1.3</span><br><span style="color: hsl(120, 100%, 40%);">+def decode_select_response(resp_hex):</span><br><span style="color: hsl(120, 100%, 40%);">+    _fixup_fcp_proprietary_tlv_map(FCP_Proprietary_TLV_MAP)</span><br><span style="color: hsl(120, 100%, 40%);">+    resp_hex = resp_hex.upper()</span><br><span style="color: hsl(120, 100%, 40%);">+    # outer layer</span><br><span style="color: hsl(120, 100%, 40%);">+    fcp_base_tlv = TLV(['62'])</span><br><span style="color: hsl(120, 100%, 40%);">+    fcp_base = fcp_base_tlv.parse(resp_hex)</span><br><span style="color: hsl(120, 100%, 40%);">+    # actual FCP</span><br><span style="color: hsl(120, 100%, 40%);">+    fcp_tlv = TLV(FCP_TLV_MAP)</span><br><span style="color: hsl(120, 100%, 40%);">+    fcp = fcp_tlv.parse(fcp_base['62'])</span><br><span style="color: hsl(120, 100%, 40%);">+    # further decode the proprietary information</span><br><span style="color: hsl(120, 100%, 40%);">+    if fcp['A5']:</span><br><span style="color: hsl(120, 100%, 40%);">+        prop_tlv = TLV(FCP_Proprietary_TLV_MAP)</span><br><span style="color: hsl(120, 100%, 40%);">+        prop = prop_tlv.parse(fcp['A5'])</span><br><span style="color: hsl(120, 100%, 40%);">+        fcp['A5'] = _tlv_val_interpret(FCP_prorietary_interpreter_map, prop)</span><br><span style="color: hsl(120, 100%, 40%);">+        fcp['A5'] = _tlv_key_replace(FCP_Proprietary_TLV_MAP, fcp['A5'])</span><br><span style="color: hsl(120, 100%, 40%);">+    # finally make sure we get human-readable keys in the output dict</span><br><span style="color: hsl(120, 100%, 40%);">+    r = _tlv_val_interpret(FCP_interpreter_map, fcp)</span><br><span style="color: hsl(120, 100%, 40%);">+    return _tlv_key_replace(FCP_TLV_MAP, r)</span><br><span>diff --git a/pySim/ts_31_102.py b/pySim/ts_31_102.py</span><br><span>index 14d7ec1..83c281c 100644</span><br><span>--- a/pySim/ts_31_102.py</span><br><span>+++ b/pySim/ts_31_102.py</span><br><span>@@ -294,6 +294,7 @@</span><br><span> from pySim.ts_51_011 import EF_MMSN, EF_MMSICP, EF_MMSUP, EF_MMSUCP, EF_VGCS, EF_VGCSS, EF_NIA</span><br><span> from pySim.ts_51_011 import EF_ACMmax, EF_AAeM, EF_eMLPP, EF_CMI</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+import pySim.ts_51_011</span><br><span> import pySim.ts_102_221</span><br><span> </span><br><span> # 3GPP TS 31.102 Section 4.4.11.4 (EF_5GS3GPPNSC)</span><br><span>@@ -1067,7 +1068,7 @@</span><br><span>         self.add_files(files)</span><br><span> </span><br><span>     def decode_select_response(self, data_hex):</span><br><span style="color: hsl(0, 100%, 40%);">-        return pySim.ts_102_221.decode_select_response(data_hex)</span><br><span style="color: hsl(120, 100%, 40%);">+        return pySim.ts_102_221_select.decode_select_response(data_hex)</span><br><span> </span><br><span>     @with_default_category('Application-Specific Commands')</span><br><span>     class AddlShellCommands(CommandSet):</span><br><span>diff --git a/pySim/ts_31_103.py b/pySim/ts_31_103.py</span><br><span>index 63ef99e..3fd6629 100644</span><br><span>--- a/pySim/ts_31_103.py</span><br><span>+++ b/pySim/ts_31_103.py</span><br><span>@@ -28,6 +28,7 @@</span><br><span> from pySim.ts_51_011 import EF_AD, EF_SMS, EF_SMSS, EF_SMSR, EF_SMSP</span><br><span> from pySim.ts_31_102 import ADF_USIM, EF_FromPreferred</span><br><span> import pySim.ts_102_221</span><br><span style="color: hsl(120, 100%, 40%);">+import pySim.ts_102_221_select</span><br><span> from pySim.ts_102_221 import EF_ARR</span><br><span> </span><br><span> # Mapping between ISIM Service Number and its description</span><br><span>@@ -213,7 +214,7 @@</span><br><span>         self.shell_commands += [ADF_USIM.AddlShellCommands()]</span><br><span> </span><br><span>     def decode_select_response(self, data_hex):</span><br><span style="color: hsl(0, 100%, 40%);">-        return pySim.ts_102_221.decode_select_response(data_hex)</span><br><span style="color: hsl(120, 100%, 40%);">+        return pySim.ts_102_221_select.decode_select_response(data_hex)</span><br><span> </span><br><span> # TS 31.103 Section 7.1</span><br><span> sw_isim = {</span><br><span>diff --git a/pySim/ts_51_011.py b/pySim/ts_51_011.py</span><br><span>index 743c14b..c7168e8 100644</span><br><span>--- a/pySim/ts_51_011.py</span><br><span>+++ b/pySim/ts_51_011.py</span><br><span>@@ -333,6 +333,7 @@</span><br><span> </span><br><span> from pySim.filesystem import *</span><br><span> import pySim.ts_102_221</span><br><span style="color: hsl(120, 100%, 40%);">+import pySim.ts_102_221_select</span><br><span> </span><br><span> ######################################################################</span><br><span> # DF.TELECOM</span><br><span>@@ -942,7 +943,7 @@</span><br><span> def decode_select_response(resp_hex):</span><br><span>     resp_bin = h2b(resp_hex)</span><br><span>     if resp_bin[0] == 0x62:</span><br><span style="color: hsl(0, 100%, 40%);">-        return pySim.ts_102_221.decode_select_response(resp_hex)</span><br><span style="color: hsl(120, 100%, 40%);">+        return pySim.ts_102_221_select.decode_select_response(resp_hex)</span><br><span>     struct_of_file_map = {</span><br><span>         0: 'transparent',</span><br><span>         1: 'linear_fixed',</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/pysim/+/26160">change 26160</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/pysim/+/26160"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: pysim </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: If5fae46bb40d0f285236a6ab287070125c69ed70 </div>
<div style="display:none"> Gerrit-Change-Number: 26160 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: dexter <pmaier@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>