<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>