From 60c80e35c7abbfcacd01f64fe42726e7155eac16 Mon Sep 17 00:00:00 2001 From: hploetz Date: Fri, 19 May 2006 02:24:48 +0000 Subject: [PATCH] nicer TLV parsing, (more ugly code) git-svn-id: svn+ssh://localhost/home/henryk/svn/cyberflex-shell/trunk@59 f711b948-2313-0410-aaa9-d29f33439f0b --- TLV_utils.py | 76 +++++++++++++++++++++++++++++++++++++++- cards/iso_7816_4_card.py | 2 +- utils.py | 36 +++++++++++++++++++ 3 files changed, 112 insertions(+), 2 deletions(-) diff --git a/TLV_utils.py b/TLV_utils.py index 5aa3378..680ab32 100644 --- a/TLV_utils.py +++ b/TLV_utils.py @@ -8,6 +8,77 @@ binary = object() number = object() ascii = object() +file_descriptor_byte_descriptions = [ + #byte mask no match match + (0x80, 0x80, None, "RFU"), + (0xC0, 0x40, "non shareable", "shareable"), + + (0xB8, 0x00, None, "working EF"), + (0xB8, 0x08, None, "internal EF"), + (0xB8, 0x10, None, "Reserved for proprietary uses"), + (0xB8, 0x18, None, "Reserved for proprietary uses"), + (0xB8, 0x20, None, "Reserved for proprietary uses"), + (0xB8, 0x28, None, "Reserved for proprietary uses"), + (0xB8, 0x30, None, "Reserved for proprietary uses"), + (0xB8, 0x38, None, "DF"), + + ##(0x87, 0x00, None, "No EF structure information given"), + (0x87, 0x01, None, "Transparent"), + (0x87, 0x02, None, "Linear fixed, no further info"), + (0x87, 0x03, None, "Linear fixed, SIMPLE-TLV"), + (0x87, 0x04, None, "Linear variable, no further info"), + (0x87, 0x05, None, "Linear variable, SIMPLE-TLV"), + (0x87, 0x06, None, "Cyclic, no further info"), + (0x87, 0x07, None, "Cyclic, SIMPLE-TLV"), +] + +data_coding_byte_descriptions = [ + (0x60, 0x00, None, "one-time write"), + (0x60, 0x20, None, "proprietary"), + (0x60, 0x40, None, "write OR"), + (0x60, 0x60, None, "write AND"), +] + +def decode_file_descriptor_byte(value, verbose = True): + result = " %s" % utils.hexdump(value, short=True) + + if not verbose: + attributes = utils.parse_binary(ord(value[0]), file_descriptor_byte_descriptions, False) + if len(value) > 1: + attributes.append( + "data coding byte, behavior of write functions: %s, data unit size in in nibbles: %i" % ( + "".join( utils.parse_binary(ord(value[1]), data_coding_byte_descriptions) ), + 2 ** (ord(value[1])&0x07) + ) + ) + + if len(value) > 2: + i = 0 + for j in value[2:]: + i = i * 256 + ord(j) + attributes.append( + "maximum record length: %s" % i + ) + + return result + " (%s)" % "; ".join(attributes) + else: + result = result + "\nFile descriptor byte:\n" + result = result + "\t" + "\n\t".join( + utils.parse_binary(ord(value[0]), file_descriptor_byte_descriptions, True) + ) + if len(value) > 1: + result = result + "\nData coding byte (0x%02X):\n" % ord(value[1]) + result = result + "\tBehavior of write functions: %s\n\tData unit size in in nibbles: %i" % ( + "".join( utils.parse_binary(ord(value[1]), data_coding_byte_descriptions) ), + 2 ** (ord(value[1])&0x07) + ) + if len(value) > 2: + i = 0 + for j in value[2:]: + i = i * 256 + ord(j) + result = result + "\nMaximum record length: %s" % i + return result + tags = { None: { 0x62: (recurse, "File Control Parameters", context_FCP), @@ -15,7 +86,7 @@ tags = { 0x6F: (recurse, "File Control Information", context_FCI), 0x80: (number, "Number of data bytes in the file, excluding structural information"), 0x81: (number, "Number of data bytes in the file, including structural information"), - 0x82: (binary, "File descriptor byte"), + 0x82: (decode_file_descriptor_byte, "File descriptor byte"), 0x83: (binary, "File identifier"), 0x84: (binary, "DF name"), 0x85: (binary, "Proprietary information"), @@ -54,6 +125,8 @@ def decode(data, context = None, level = 0): current.append( " %s" % value) elif interpretation[0] is binary: current.append( " %s" % utils.hexdump(value, short=True)) + elif callable(interpretation[0]): + current.append( ("\n"+"\t"*(level+1)).join(interpretation[0](value).splitlines()) ) result.append( "".join(current) ) @@ -66,3 +139,4 @@ if __name__ == "__main__": decoded = decode(test) print decoded + diff --git a/cards/iso_7816_4_card.py b/cards/iso_7816_4_card.py index 7725829..cb49202 100644 --- a/cards/iso_7816_4_card.py +++ b/cards/iso_7816_4_card.py @@ -30,7 +30,7 @@ class ISO_7816_4_Card(Card): def cmd_parsetlv(self): "Decode the TLV data in the last response" - print TLV_utils.decode(self.last_result) + print TLV_utils.decode(self.last_result.data) ATRS = list(Card.ATRS) ATRS.extend( [ diff --git a/utils.py b/utils.py index eae4982..62902a8 100644 --- a/utils.py +++ b/utils.py @@ -1,5 +1,41 @@ import pycsc, string, binascii, sys +def represent_binary_fancy(len, value, mask = 0): + result = [] + for i in range(len): + if i%4 == 0: + result.append( " " ) + if i%8 == 0: + result.append( " " ) + if mask & 0x01: + result.append( str(value & 0x01) ) + else: + result.append( "." ) + mask = mask >> 1 + value = value >> 2 + result.reverse() + + return "".join(result).strip() + +def parse_binary(value, bytemasks, verbose = False, value_len = 8): + ## Parses a binary structure and gives information back + ## bytemasks is a sequence of (mask, value, string_if_no_match, string_if_match) tuples + result = [] + for mask, byte, nonmatch, match in bytemasks: + + if verbose: + prefix = represent_binary_fancy(value_len, byte, mask) + ": " + else: + prefix = "" + if (value & mask) == (byte & mask): + if match is not None: + result.append(prefix + match) + else: + if nonmatch is not None: + result.append(prefix + nonmatch) + + return result + _myprintable = " " + string.letters + string.digits + string.punctuation def hexdump(data, indent = 0, short = False): r"""Generates a nice hexdump of data and returns it. Consecutive lines will