From f5e42ca71b25d4f4182b0067a160f02d1cb1d328 Mon Sep 17 00:00:00 2001 From: hploetz Date: Thu, 18 May 2006 06:37:06 +0000 Subject: New APDUs basically feature complete git-svn-id: svn+ssh://localhost/home/henryk/svn/cyberflex-shell/trunk@52 f711b948-2313-0410-aaa9-d29f33439f0b --- utils.py | 221 ++++++++------------------------------------------------------- 1 file changed, 27 insertions(+), 194 deletions(-) (limited to 'utils.py') diff --git a/utils.py b/utils.py index 4d9c66b..7494d9d 100644 --- a/utils.py +++ b/utils.py @@ -233,7 +233,21 @@ class C_APDU(APDU): return self._format_parts(fields) - + def render(self): + "Return this APDU as a binary string" + buffer = [] + + for i in self.CLA, self.INS, self.P1, self.P2: + buffer.append(chr(i)) + + if len(self.data) > 0: + buffer.append(chr(self.Lc)) + buffer.append(self.data) + + if hasattr(self, "_Le"): + buffer.append(chr(self.Le)) + + return "".join(buffer) class R_APDU(APDU): "Class for a response APDU" @@ -261,6 +275,10 @@ class R_APDU(APDU): fields = ["SW1", "SW2"] return self._format_parts(fields) + def render(self): + "Return this APDU as a binary string" + return self.data + self.sw + class TPDU: "Base class for TPDUs" @@ -275,199 +293,6 @@ class TPDU_T0(TPDU): class TPDU_T1(TPDU): "Class for T=1 TPDU" protocol = 1 - -class APDU_old: - """Class for an APDU..""" - OFFSET_CLA = 0 - OFFSET_INS = 1 - OFFSET_P1 = 2 - OFFSET_P2 = 3 - OFFSET_LE = 4 - OFFSET_LC = 4 - - def __init__(self, *args, **kwargs): - """Creates a new APDU instance. Can be given positional parameters which - must be sequences of either strings (or strings themselves) or integers - specifying byte values that will be concatenated in order. Alternatively - you may give exactly one positional argument that is an APDU instance. - After all the positional arguments have been concatenated they must - form a valid APDU! - - The keyword arguments can then be used to override those values. - Keywords recognized are: cla, ins, p1, p2, lc, le, content. - - If protocol is set to 0 then the APDU will be parsed as a T=0 APDU.""" - - initbuff = list() - - if len(args) == 1 and isinstance(args[0], APDU): - initbuff.extend(args[0].get_string()) - else: - for arg in args: - if type(arg) == str: - initbuff.extend(arg) - elif hasattr(arg, "__iter__"): - for elem in arg: - if hasattr(elem, "__iter__"): - initbuff.extend(elem) - else: - initbuff.append(elem) - else: - initbuff.append(arg) - - for i in range(len(initbuff)): - t = type(initbuff[i]) - if t == str: - initbuff[i] = ord(initbuff[i]) - elif t != int: - raise TypeError, "APDU must consist of ints or one-byte strings, not %s (index %s)" % (t, i) - - if len(initbuff) < 4: - initbuff.extend( [0] * (4-len(initbuff)) ) - - self.__dict__.update( { - "cla": initbuff[self.OFFSET_CLA], - "ins": initbuff[self.OFFSET_INS], - "p1": initbuff[self.OFFSET_P1], - "p2": initbuff[self.OFFSET_P2] - } ) - - lc_was_set = False - - if kwargs.get("protocol", None) == 0: - if len(initbuff) == 4: ## ISO case 1 - self.le = 0 - self.lc = 0 - self.content = list() - elif len(initbuff) == 5: ## ISO case 2 - self.le = initbuff[self.OFFSET_LE] - self.lc = 0 - self.content = list() - elif len(initbuff) > 5: - self.lc = initbuff[self.OFFSET_LC] - lc_was_set = True - if len(initbuff) == 5 + self.lc: ## ISO case 3 - self.le = 0 - self.content = initbuff[5:5+self.lc] - elif len(initbuff) == 5 + self.lc + 1: ## ISO case 4 - self.le = initbuff[-1] - self.content = initbuff[5:5+self.lc] - else: - raise ValueError, "Invalid APDU, length(%i) != 4 + 1 + lc(%i) + 1" % (len(initbuff), self.lc) - else: - raise ValueError, "Invalid APDU, impossible" - else: - self.le = 0 - self.lc = len(initbuff)-4 - self.content = initbuff[4:] - - for (kw_orig, arg) in kwargs.items(): - kw = kw_orig.lower() - if kw == "cla": - self.cla = arg - elif kw == "ins": - self.ins = arg - elif kw == "p1": - self.p1 = arg - elif kw == "p2": - self.p2 = arg - elif kw == "lc": - self.lc = arg - lc_was_set = True - elif kw == "le": - self.le = arg - elif kw == "content": - self.content = arg - else: - raise TypeError, "Got an unexpected keyword argument '%s'" % kw_orig - - if not lc_was_set: - self.lc = len(self.content) - - def __str__(self): - result = len(self.content) != self.lc and "Invalid " or "" - result = result + "APDU(CLA=0x%x, INS=0x%x, P1=0x%x, P2=0x%x" % ( - self.cla, self.ins, self.p1, self.p2) - if self.lc == 0 and self.le == 0: ## ISO case 1 - result = result + ")" - elif self.lc == 0 and self.le > 0: ## ISO case 2: - result = result + ", LE=0x%x)" % self.le - elif self.lc > 0 and self.le == 0: ## ISO case 3 - result = result + ", LC=0x%x)" % self.lc - elif self.lc > 0 and self.le > 0: ## ISO case 4: - result = result + ", LC=0x%x, LE=0x%x)" % ( - self.lc, self.le - ) - else: - raise ValueError, "Impossible error. Call the X files." - - if len(self.content) > 0: - result = result + " with %i(0x%x) bytes of contents" % ( - len(self.content), len(self.content) - ) - - return result + ":\n" + hexdump(self.get_string()) - - def __repr__(self): - result = "APDU(CLA=0x%x, INS=0x%x, P1=0x%x, P2=0x%x" % ( - self.cla, self.ins, self.p1, self.p2) - if self.lc == 0 and self.le == 0: ## ISO case 1 - pass - elif self.lc == 0 and self.le > 0: ## ISO case 2: - result = result + ", LE=0x%x" % self.le - elif self.lc > 0 and self.le == 0: ## ISO case 3 - result = result + ", LC=0x%x" % self.lc - elif self.lc > 0 and self.le > 0: ## ISO case 4: - result = result + ", LC=0x%x, LE=0x%x" % ( - self.lc, self.le - ) - else: - raise ValueError, "Impossible error. Call the X files." - - if len(self.content) > 0: - result = result + ", content=%r)" % self.content - else: - result = result + ")" - - return result - - _bytevars = ("cla", "ins", "p1", "p2", "lc", "le") - _bytelistvars = ("content",) - def __setattr__(self, name, value): - namelower = name.lower() - if namelower in self._bytevars: - if isinstance(value, int): - self.__dict__[namelower] = value - elif isinstance(value, str): - self.__dict__[namelower] = ord(value) - else: - raise ValueError, "'%s' attribute can only be a byte, that is: int or str, not %s" % (namelower, type(value)) - elif namelower in self._bytelistvars: - if isinstance(value, str): - self.__dict__[namelower] = [ord(e) for e in value] - elif isinstance(value, list): - self.__dict__[namelower] = [int(e) for e in value] - else: - raise ValueError, "'%s' attribute can only be a byte list, that is: list of int or str, not %s" (namelower, type(value)) - else: - self.__dict__[name] = value - - def get_string(self, protocol=None): - """Return the contents of this APDU as a binary string. - If protocol is set to 0 then the APDU will be rendered as a T=0 APDU.""" - contents = [self.cla, self.ins, self.p1, self.p2] - if protocol == 0: - if self.lc > 0: - contents.extend( [self.lc] + self.content) - if self.le > 0: - contents.append( self.le ) - else: - contents.extend( self.content ) - return "".join([i is not None and chr(i) or "?" for i in contents]) - - def append_content(self, string): - self.content = self.content + string - self.lc = len(self.content) if __name__ == "__main__": response = """ @@ -536,6 +361,10 @@ if __name__ == "__main__": print repr(c) print repr(d) + print + for i in a, b, c, d: + print hexdump(i.render()) + print e = R_APDU(0x90,0) f = R_APDU("foo\x67\x00") @@ -546,3 +375,7 @@ if __name__ == "__main__": print print repr(e) print repr(f) + + print + for i in e, f: + print hexdump(i.render()) -- cgit v1.2.3