laforge has submitted this change. ( 
https://gerrit.osmocom.org/c/pysim/+/40914?usp=email )

Change subject: Identify cards by Historical bytes of ATR
......................................................................

Identify cards by Historical bytes of ATR

- try to identify the CardModel by just comparing the Historical Bytes if 
matching by Whole ATR failed
- add decompose ATR code from pyscard-contrib

Related: OS#6837
Change-Id: Id7555e42290d232a0e0efc47e7d97575007d846f
---
M pySim/filesystem.py
M pySim/utils.py
2 files changed, 137 insertions(+), 1 deletion(-)

Approvals:
  laforge: Looks good to me, approved
  Jenkins Builder: Verified




diff --git a/pySim/filesystem.py b/pySim/filesystem.py
index 6712755..1d71e08 100644
--- a/pySim/filesystem.py
+++ b/pySim/filesystem.py
@@ -39,7 +39,7 @@
 from osmocom.tlv import bertlv_parse_one
 from osmocom.construct import filter_dict, parse_construct, build_construct

-from pySim.utils import sw_match
+from pySim.utils import sw_match, decomposeATR
 from pySim.jsonpath import js_path_modify
 from pySim.commands import SimCardCommands
 from pySim.exceptions import SwMatchError
@@ -1545,6 +1545,13 @@
             if atr == card_atr:
                 print("Detected CardModel:", cls.__name__)
                 return True
+        # if nothing found try to just compare the Historical Bytes of the ATR
+        card_atr_hb = decomposeATR(card_atr)['hb']
+        for atr in cls._atrs:
+            atr_hb = decomposeATR(atr)['hb']
+            if atr_hb == card_atr_hb:
+                print("Detected CardModel:", cls.__name__)
+                return True
         return False

     @staticmethod
diff --git a/pySim/utils.py b/pySim/utils.py
index 48a9998..b0443c8 100644
--- a/pySim/utils.py
+++ b/pySim/utils.py
@@ -15,6 +15,7 @@

 # Copyright (C) 2009-2010  Sylvain Munaut <t...@246tnt.com>
 # Copyright (C) 2021 Harald Welte <lafo...@osmocom.org>
+# Copyright (C) 2009-2022   Ludovic Rousseau
 #
 # 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
@@ -585,6 +586,134 @@
         raise ValueError('invalid APDU (%s), too short!' % b2h(apdu))


+# ATR handling code under GPL from parseATR: 
https://github.com/LudovicRousseau/pyscard-contrib
+def normalizeATR(atr):
+    """Transform an ATR in list of integers.
+    valid input formats are
+    "3B A7 00 40 18 80 65 A2 08 01 01 52"
+    "3B:A7:00:40:18:80:65:A2:08:01:01:52"
+
+    Args:
+        atr: string
+    Returns:
+        list of bytes
+
+    >>> normalize("3B:A7:00:40:18:80:65:A2:08:01:01:52")
+    [59, 167, 0, 64, 24, 128, 101, 162, 8, 1, 1, 82]
+    """
+    atr = atr.replace(":", "")
+    atr = atr.replace(" ", "")
+
+    res = []
+    while len(atr) >= 2:
+        byte, atr = atr[:2], atr[2:]
+        res.append(byte)
+    if len(atr) > 0:
+        raise ValueError("warning: odd string, remainder: %r" % atr)
+
+    atr = [int(x, 16) for x in res]
+    return atr
+
+
+# ATR handling code under GPL from parseATR: 
https://github.com/LudovicRousseau/pyscard-contrib
+def decomposeATR(atr_txt):
+    """Decompose the ATR in elementary fields
+
+        Args:
+            atr_txt: ATR as a hex bytes string
+        Returns:
+            dictionary of field and values
+
+        >>> decomposeATR("3B A7 00 40 18 80 65 A2 08 01 01 52")
+    { 'T0': {'value': 167},
+      'TB': {1: {'value': 0}},
+      'TC': {2: {'value': 24}},
+      'TD': {1: {'value': 64}},
+      'TS': {'value': 59},
+      'atr': [59, 167, 0, 64, 24, 128, 101, 162, 8, 1, 1, 82],
+      'hb': {'value': [128, 101, 162, 8, 1, 1, 82]},
+      'hbn': 7}
+    """
+    ATR_PROTOCOL_TYPE_T0 = 0
+    atr_txt = normalizeATR(atr_txt)
+    atr = {}
+
+    # the ATR itself as a list of integers
+    atr["atr"] = atr_txt
+
+    # store TS and T0
+    atr["TS"] = {"value": atr_txt[0]}
+    TDi = atr_txt[1]
+    atr["T0"] = {"value": TDi}
+    hb_length = TDi & 15
+    pointer = 1
+    # protocol number
+    pn = 1
+
+    # store number of historical bytes
+    atr["hbn"] = TDi & 0xF
+
+    while pointer < len(atr_txt):
+        # Check TAi is present
+        if (TDi | 0xEF) == 0xFF:
+            pointer += 1
+            if "TA" not in atr:
+                atr["TA"] = {}
+            atr["TA"][pn] = {"value": atr_txt[pointer]}
+
+        # Check TBi is present
+        if (TDi | 0xDF) == 0xFF:
+            pointer += 1
+            if "TB" not in atr:
+                atr["TB"] = {}
+            atr["TB"][pn] = {"value": atr_txt[pointer]}
+
+        # Check TCi is present
+        if (TDi | 0xBF) == 0xFF:
+            pointer += 1
+            if "TC" not in atr:
+                atr["TC"] = {}
+            atr["TC"][pn] = {"value": atr_txt[pointer]}
+
+        # Check TDi is present
+        if (TDi | 0x7F) == 0xFF:
+            pointer += 1
+            if "TD" not in atr:
+                atr["TD"] = {}
+            TDi = atr_txt[pointer]
+            atr["TD"][pn] = {"value": TDi}
+            if (TDi & 0x0F) != ATR_PROTOCOL_TYPE_T0:
+                atr["TCK"] = True
+            pn += 1
+        else:
+            break
+
+    # Store historical bytes
+    atr["hb"] = {"value": atr_txt[pointer + 1 : pointer + 1 + hb_length]}
+
+    # Store TCK
+    last = pointer + 1 + hb_length
+    if "TCK" in atr:
+        try:
+            atr["TCK"] = {"value": atr_txt[last]}
+        except IndexError:
+            atr["TCK"] = {"value": -1}
+        last += 1
+
+    if len(atr_txt) > last:
+        atr["extra"] = atr_txt[last:]
+
+    if len(atr["hb"]["value"]) < hb_length:
+        missing = hb_length - len(atr["hb"]["value"])
+        if missing > 1:
+            (t1, t2) = ("s", "are")
+        else:
+            (t1, t2) = ("", "is")
+        atr["warning"] = "ATR is truncated: %d byte%s %s missing" % (missing, 
t1, t2)
+
+    return atr
+
+
 class DataObject(abc.ABC):
     """A DataObject (DO) in the sense of ISO 7816-4.  Contrary to 'normal' 
TLVs where one
     simply has any number of different TLVs that may occur in any order at any 
point, ISO 7816

--
To view, visit https://gerrit.osmocom.org/c/pysim/+/40914?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: merged
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: Id7555e42290d232a0e0efc47e7d97575007d846f
Gerrit-Change-Number: 40914
Gerrit-PatchSet: 3
Gerrit-Owner: bjoern <bjoern...@nixda.biz>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <lafo...@osmocom.org>
Gerrit-CC: dexter <pma...@sysmocom.de>
Gerrit-CC: fixeria <vyanits...@sysmocom.de>
Gerrit-CC: pespin <pes...@sysmocom.de>

Reply via email to