<p>dexter has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/pysim/+/26043">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">pySim-shell: add method to probe for UICC<br><br>UICC and old SIM cards can be difficult to tell apart without prior<br>knowledge of the card. The ATR won't tell if the card is UICC or not.<br>The only remaining option is to try out if the card is able to handle<br>UICC APDUs. The same is true for 2G SIM cards. It is not guranteed that<br>every UICC card will have 2G functionality.<br><br>Lets add functionality that probes the card type and then decide which<br>profile is suitable.<br><br>Change-Id: I535bef35847140e611d4fa95ed2859ee81cce605<br>Related: OS#5274<br>---<br>M pySim-shell.py<br>M pySim/filesystem.py<br>A pySim/probe.py<br>M pySim/ts_102_221.py<br>M pySim/ts_51_011.py<br>5 files changed, 119 insertions(+), 12 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/43/26043/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/pySim-shell.py b/pySim-shell.py</span><br><span>index 3fc5859..555ddac 100755</span><br><span>--- a/pySim-shell.py</span><br><span>+++ b/pySim-shell.py</span><br><span>@@ -58,6 +58,8 @@</span><br><span> </span><br><span> from pySim.card_key_provider import CardKeyProviderCsv, card_key_provider_register, card_key_provider_get_field</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+from pySim.probe import probe_card</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> def init_card(sl):</span><br><span>     """</span><br><span>   Detect card in reader and setup card profile and runtime state. This</span><br><span>@@ -79,19 +81,36 @@</span><br><span> </span><br><span>       card = card_detect("auto", scc)</span><br><span>    if card is None:</span><br><span style="color: hsl(0, 100%, 40%);">-                print("Could not detect card type!")</span><br><span style="color: hsl(0, 100%, 40%);">-          return None, None;</span><br><span style="color: hsl(120, 100%, 40%);">+            print("Warning: Could not detect card type - assuming a generic card type...")</span><br><span style="color: hsl(120, 100%, 40%);">+              card = SimCard(scc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        card_is_uicc = probe_card(card, ['UICC'])</span><br><span style="color: hsl(120, 100%, 40%);">+     card_is_sim = probe_card(card, ['SIM'])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if card_is_uicc:</span><br><span style="color: hsl(120, 100%, 40%);">+              if card_is_sim:</span><br><span style="color: hsl(120, 100%, 40%);">+                       print("Info: Card is of type SIM and UICC")</span><br><span style="color: hsl(120, 100%, 40%);">+         else:</span><br><span style="color: hsl(120, 100%, 40%);">+                 print("Info: Card is of type UICC")</span><br><span style="color: hsl(120, 100%, 40%);">+         profile = CardProfileUICC()</span><br><span style="color: hsl(120, 100%, 40%);">+           profile.add_application(CardApplicationUSIM())</span><br><span style="color: hsl(120, 100%, 40%);">+                profile.add_application(CardApplicationISIM())</span><br><span style="color: hsl(120, 100%, 40%);">+        elif card_is_sim:</span><br><span style="color: hsl(120, 100%, 40%);">+             print("Info: Card is of type SIM")</span><br><span style="color: hsl(120, 100%, 40%);">+          profile = CardProfileSIM()</span><br><span style="color: hsl(120, 100%, 40%);">+    else:</span><br><span style="color: hsl(120, 100%, 40%);">+         print("Unsupported card type!")</span><br><span style="color: hsl(120, 100%, 40%);">+             return None, None</span><br><span> </span><br><span>        # Create runtime state with card profile</span><br><span style="color: hsl(0, 100%, 40%);">-        profile = CardProfileUICC()</span><br><span style="color: hsl(0, 100%, 40%);">-     profile.add_application(CardApplicationUSIM())</span><br><span style="color: hsl(0, 100%, 40%);">-  profile.add_application(CardApplicationISIM())</span><br><span>       rs = RuntimeState(card, profile)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    # FIXME: do this dynamically</span><br><span style="color: hsl(0, 100%, 40%);">-    rs.mf.add_file(DF_TELECOM())</span><br><span style="color: hsl(0, 100%, 40%);">-    rs.mf.add_file(DF_GSM())</span><br><span style="color: hsl(0, 100%, 40%);">-        rs.mf.add_file(DF_EIRENE())</span><br><span style="color: hsl(120, 100%, 40%);">+   # The card is an UICC, but can also be used a 2G SIM, so we must add the SIM</span><br><span style="color: hsl(120, 100%, 40%);">+  # SIM related bits manaully because they are not part of the UICC profile</span><br><span style="color: hsl(120, 100%, 40%);">+     if card_is_uicc and card_is_sim:</span><br><span style="color: hsl(120, 100%, 40%);">+              rs.mf.add_file(DF_TELECOM())</span><br><span style="color: hsl(120, 100%, 40%);">+          rs.mf.add_file(DF_GSM())</span><br><span style="color: hsl(120, 100%, 40%);">+              rs.mf.add_file(DF_EIRENE())</span><br><span> </span><br><span>      CardModel.apply_matching_models(scc, rs)</span><br><span> </span><br><span>diff --git a/pySim/filesystem.py b/pySim/filesystem.py</span><br><span>index dcc2608..bf4025c 100644</span><br><span>--- a/pySim/filesystem.py</span><br><span>+++ b/pySim/filesystem.py</span><br><span>@@ -1033,6 +1033,11 @@</span><br><span>         self.card = card</span><br><span>         self.selected_file = self.mf # type: CardDF</span><br><span>         self.profile = profile</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # make sure the class and selection control bytes, which are specified</span><br><span style="color: hsl(120, 100%, 40%);">+        # by the card profile are used</span><br><span style="color: hsl(120, 100%, 40%);">+        self.card.set_apdu_parameter(cla=self.profile.cla, sel_ctrl=self.profile.sel_ctrl)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # add application ADFs + MF-files from profile</span><br><span>         apps = self._match_applications()</span><br><span>         for a in apps:</span><br><span>@@ -1042,11 +1047,22 @@</span><br><span>             self.mf.add_file(f)</span><br><span>         self.conserve_write = True</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        # make sure that when the runtime state is created, the card is also</span><br><span style="color: hsl(120, 100%, 40%);">+        # in a defined state.</span><br><span style="color: hsl(120, 100%, 40%);">+        self.reset()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def _match_applications(self):</span><br><span>         """match the applications from the profile with applications on the card"""</span><br><span>         apps_profile = self.profile.applications</span><br><span style="color: hsl(0, 100%, 40%);">-        aids_card = self.card.read_aids()</span><br><span>         apps_taken = []</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # When the profile does not feature any applications, then we are done already</span><br><span style="color: hsl(120, 100%, 40%);">+        if not apps_profile:</span><br><span style="color: hsl(120, 100%, 40%);">+            return []</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # Read AIDs from card and match them against the applications defined by the</span><br><span style="color: hsl(120, 100%, 40%);">+        # card profile</span><br><span style="color: hsl(120, 100%, 40%);">+        aids_card = self.card.read_aids()</span><br><span>         if aids_card:</span><br><span>             aids_taken = []</span><br><span>             print("AIDs on card:")</span><br><span>@@ -1407,6 +1423,8 @@</span><br><span>             applications : List of CardApplications present on card</span><br><span>             sw : List of status word definitions</span><br><span>             shell_cmdsets : List of cmd2 shell command sets of profile-specific commands</span><br><span style="color: hsl(120, 100%, 40%);">+            cla : class byte that should be used with cards of this profile</span><br><span style="color: hsl(120, 100%, 40%);">+            sel_ctrl : selection control bytes class byte that should be used with cards of this profile</span><br><span>         """</span><br><span>         self.name = name</span><br><span>         self.desc = kw.get("desc", None)</span><br><span>@@ -1414,6 +1432,8 @@</span><br><span>         self.sw = kw.get("sw", [])</span><br><span>         self.applications = kw.get("applications", [])</span><br><span>         self.shell_cmdsets = kw.get("shell_cmdsets", [])</span><br><span style="color: hsl(120, 100%, 40%);">+        self.cla = kw.get("cla", "00")</span><br><span style="color: hsl(120, 100%, 40%);">+        self.sel_ctrl = kw.get("sel_ctrl", "0004")</span><br><span> </span><br><span>     def __str__(self):</span><br><span>         return self.name</span><br><span>diff --git a/pySim/probe.py b/pySim/probe.py</span><br><span>new file mode 100644</span><br><span>index 0000000..4348c21</span><br><span>--- /dev/null</span><br><span>+++ b/pySim/probe.py</span><br><span>@@ -0,0 +1,68 @@</span><br><span style="color: hsl(120, 100%, 40%);">+# -*- coding: utf-8 -*-</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+""" pySim: tell old 2G SIMs apart from UICC</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%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# (C) 2021 by Sysmocom s.f.m.c. GmbH</span><br><span style="color: hsl(120, 100%, 40%);">+# All Rights Reserved</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.cards import SimCard</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def _test_ts_11_11_apdu(card:SimCard) -> bool:</span><br><span style="color: hsl(120, 100%, 40%);">+   """ Try to access MF via 2G APDUs (3GPP TS 11.11) """</span><br><span style="color: hsl(120, 100%, 40%);">+   card.set_apdu_parameter(cla="a0", sel_ctrl="0000")</span><br><span style="color: hsl(120, 100%, 40%);">+        card.reset()</span><br><span style="color: hsl(120, 100%, 40%);">+  try:</span><br><span style="color: hsl(120, 100%, 40%);">+          card._scc.select_file('3f00')</span><br><span style="color: hsl(120, 100%, 40%);">+ except:</span><br><span style="color: hsl(120, 100%, 40%);">+               return False</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return True</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def _test_uicc_apdu(card:SimCard) -> bool:</span><br><span style="color: hsl(120, 100%, 40%);">+  """ Try to access MF via UICC APDUs """</span><br><span style="color: hsl(120, 100%, 40%);">+ card.set_apdu_parameter(cla="00", sel_ctrl="0004")</span><br><span style="color: hsl(120, 100%, 40%);">+        card.reset()</span><br><span style="color: hsl(120, 100%, 40%);">+  try:</span><br><span style="color: hsl(120, 100%, 40%);">+          card._scc.select_file('3f00')</span><br><span style="color: hsl(120, 100%, 40%);">+ except:</span><br><span style="color: hsl(120, 100%, 40%);">+               return False</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return True</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def probe_card(card:SimCard, card_is:list=['SIM','UICC']) -> bool:</span><br><span style="color: hsl(120, 100%, 40%);">+  """ Find out whether the card is of type UICC """</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = []</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     # back up CLA byte and SEL control bytes</span><br><span style="color: hsl(120, 100%, 40%);">+      cla_byte_bak, sel_ctrl_bak = card.get_apdu_parameter()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if 'SIM' in card_is:</span><br><span style="color: hsl(120, 100%, 40%);">+          rc.append(_test_ts_11_11_apdu(card))</span><br><span style="color: hsl(120, 100%, 40%);">+  if 'UICC' in card_is:</span><br><span style="color: hsl(120, 100%, 40%);">+         rc.append(_test_uicc_apdu(card))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    # Leave with a defined state</span><br><span style="color: hsl(120, 100%, 40%);">+  card.reset()</span><br><span style="color: hsl(120, 100%, 40%);">+  card.set_apdu_parameter(cla=cla_byte_bak, sel_ctrl=sel_ctrl_bak)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if False in rc:</span><br><span style="color: hsl(120, 100%, 40%);">+               return False</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return True</span><br><span>diff --git a/pySim/ts_102_221.py b/pySim/ts_102_221.py</span><br><span>index 3665939..403daec 100644</span><br><span>--- a/pySim/ts_102_221.py</span><br><span>+++ b/pySim/ts_102_221.py</span><br><span>@@ -683,4 +683,4 @@</span><br><span>             },</span><br><span>           }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        super().__init__('UICC', desc='ETSI TS 102 221', files_in_mf=files, sw=sw)</span><br><span style="color: hsl(120, 100%, 40%);">+        super().__init__('UICC', desc='ETSI TS 102 221', cla="00", sel_ctrl="0004", files_in_mf=files, sw=sw)</span><br><span>diff --git a/pySim/ts_51_011.py b/pySim/ts_51_011.py</span><br><span>index 743c14b..fa70661 100644</span><br><span>--- a/pySim/ts_51_011.py</span><br><span>+++ b/pySim/ts_51_011.py</span><br><span>@@ -982,4 +982,4 @@</span><br><span> </span><br><span> class CardProfileSIM(CardProfile):</span><br><span>     def __init__(self):</span><br><span style="color: hsl(0, 100%, 40%);">-        super().__init__('SIM', desc='GSM SIM Card', files_in_mf=[DF_TELECOM(), DF_GSM()])</span><br><span style="color: hsl(120, 100%, 40%);">+        super().__init__('SIM', desc='GSM SIM Card', cla="a0", sel_ctrl="0000", files_in_mf=[DF_TELECOM(), DF_GSM()])</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/pysim/+/26043">change 26043</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/+/26043"/><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: I535bef35847140e611d4fa95ed2859ee81cce605 </div>
<div style="display:none"> Gerrit-Change-Number: 26043 </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>