aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2021-05-02 21:28:12 +0200
committerHarald Welte <laforge@osmocom.org>2021-05-04 13:24:01 +0200
commit90441436a03538deed57c95fb6e6311b5cfff9a9 (patch)
treeb045c9ea7edf1fbbf3284ff3754e3be1cdcad07f
parent3de6ca2d20b2ef3641f44d655f2e05144ea7e730 (diff)
utils: Introduce CommandSet abstraction
This will allow us to match INS -> name and add more related bits in the future (e.g. for decoding APDU traces) Change-Id: I314ff15186dc05778ea12363cac0a310b6c7713c
-rw-r--r--pySim/utils.py66
1 files changed, 66 insertions, 0 deletions
diff --git a/pySim/utils.py b/pySim/utils.py
index fc6ebfd..3e67386 100644
--- a/pySim/utils.py
+++ b/pySim/utils.py
@@ -1216,3 +1216,69 @@ class DataObjectSequence:
encoded += e.encode(decoded[i])
i += 1
return encoded
+
+class CardCommand:
+ """A single card command / instruction."""
+ def __init__(self, name, ins, cla_list=None, desc=None):
+ self.name = name
+ self.ins = ins
+ self.cla_list = cla_list or []
+ self.cla_list = [x.lower() for x in self.cla_list]
+ self.desc = desc
+
+ def __str__(self):
+ return self.name
+
+ def __repr__(self):
+ return '%s(INS=%02x,CLA=%s)' % (self.name, self.ins, self.cla_list)
+
+ def match_cla(self, cla):
+ """Does the given CLA match the CLA list of the command?."""
+ if not isinstance(cla, str):
+ cla = '%02u' % cla
+ cla = cla.lower()
+ for cla_match in self.cla_list:
+ cla_masked = ""
+ for i in range(0, 2):
+ if cla_match[i] == 'x':
+ cla_masked += 'x'
+ else:
+ cla_masked += cla[i]
+ if cla_masked == cla_match:
+ return True
+ return False
+
+
+class CardCommandSet:
+ """A set of card instructions, typically specified within one spec."""
+ def __init__(self, name, cmds=[]):
+ self.name = name
+ self.cmds = { c.ins : c for c in cmds }
+
+ def __str__(self):
+ return self.name
+
+ def __getitem__(self, idx):
+ return self.cmds[idx]
+
+ def __add__(self, other):
+ if isinstance(other, CardCommand):
+ if other.ins in self.cmds:
+ raise ValueError('%s: INS 0x%02x already defined: %s' %
+ (self, other.ins, self.cmds[other.ins]))
+ self.cmds[other.ins] = other
+ elif isinstance(other, CardCommandSet):
+ for c in other.cmds.keys():
+ self.cmds[c] = other.cmds[c]
+ else:
+ raise ValueError('%s: Unsupported type to add operator: %s' % (self, other))
+
+ def lookup(self, ins, cla=None):
+ """look-up the command within the CommandSet."""
+ ins = int(ins)
+ if not ins in self.cmds:
+ return None
+ cmd = self.cmds[ins]
+ if cla and not cmd.match_cla(cla):
+ return None
+ return cmd