diff options
author | Harald Welte <laforge@osmocom.org> | 2021-05-02 21:28:12 +0200 |
---|---|---|
committer | Harald Welte <laforge@osmocom.org> | 2021-05-04 13:24:01 +0200 |
commit | 90441436a03538deed57c95fb6e6311b5cfff9a9 (patch) | |
tree | b045c9ea7edf1fbbf3284ff3754e3be1cdcad07f | |
parent | 3de6ca2d20b2ef3641f44d655f2e05144ea7e730 (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.py | 66 |
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 |