New APDUs basically feature complete

git-svn-id: svn+ssh://localhost/home/henryk/svn/cyberflex-shell/trunk@52 f711b948-2313-0410-aaa9-d29f33439f0b
This commit is contained in:
hploetz 2006-05-18 06:37:06 +00:00
parent 95ccd90742
commit f5e42ca71b
1 changed files with 27 additions and 194 deletions

221
utils.py
View File

@ -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())