From 77659befd1e3e9e81eda71878af58167ab2e1138 Mon Sep 17 00:00:00 2001 From: hploetz Date: Sun, 21 May 2006 13:04:48 +0000 Subject: [PATCH] generalize file operations, specialise for starcos git-svn-id: svn+ssh://localhost/home/henryk/svn/cyberflex-shell/trunk@67 f711b948-2313-0410-aaa9-d29f33439f0b --- cards/iso_7816_4_card.py | 70 ++++++++++++++++++++++++++++++++++++++++ cards/starcos_card.py | 19 +++++++++++ cards/tcos_card.py | 47 --------------------------- utils.py | 3 +- 4 files changed, 91 insertions(+), 48 deletions(-) create mode 100644 cards/starcos_card.py diff --git a/cards/iso_7816_4_card.py b/cards/iso_7816_4_card.py index cb49202..c9b6410 100644 --- a/cards/iso_7816_4_card.py +++ b/cards/iso_7816_4_card.py @@ -3,7 +3,9 @@ from generic_card import * class ISO_7816_4_Card(Card): APDU_SELECT_FILE = C_APDU("\x00\xa4\x00\x00") + APDU_READ_BINARY = C_APDU("\x00\xb0\x00\x00\x00") DRIVER_NAME = "ISO 7816-4" + FID_MF = "\x3f\x00" ## def can_handle(cls, card): ## return True @@ -16,6 +18,71 @@ class ISO_7816_4_Card(Card): data = fid, le = 0) ) return result + def change_dir(self, fid = None): + "Change to a child DF. Alternatively, change to MF if fid is None." + if fid is None: + return self.select_file(0x00, 0x00, "") + else: + return self.select_file(0x01, 0x00, fid) + + def cmd_cd(self, dir = None): + "Change into a DF, or into the MF if no dir is given" + + if dir is None: + result = self.change_dir() + else: + fid = binascii.a2b_hex("".join(dir.split())) + result = self.change_dir(fid) + + if len(result.data) > 0: + print utils.hexdump(result.data) + print TLV_utils.decode(result.data) + + def open_file(self, fid): + "Open an EF under the current DF" + return self.select_file(0x02, 0x00, fid) + + def cmd_open(self, file): + "Open a file" + fid = binascii.a2b_hex("".join(file.split())) + + result = self.open_file(fid) + if len(result.data) > 0: + print utils.hexdump(result.data) + print TLV_utils.decode(result.data) + + def read_binary_file(self, offset = 0): + """Read from the currently selected EF. + Repeat calls to READ BINARY as necessary to get the whole EF.""" + + if offset >= 1<<15: + raise ValueError, "offset is limited to 15 bits" + contents = "" + had_one = False + + while True: + command = C_APDU(self.APDU_READ_BINARY, p1 = offset >> 8, p2 = (offset & 0xff)) + result = self.send_apdu(command) + if len(result.data) > 0: + contents = contents + result.data + offset = offset + len(result.data) + + if result.sw != self.SW_OK: + break + else: + had_one = True + + if had_one: ## If there was at least one successful pass, ignore any error SW. It probably only means "end of file" + self.sw_changed = False + + return contents + + def cmd_cat(self): + "Print a hexdump of the currently selected file (e.g. consecutive READ BINARY)" + contents = self.read_binary_file() + self.last_result = R_APDU(contents + self.last_sw) + print utils.hexdump(contents) + def cmd_selectfile(self, p1, p2, fid): """Select a file on the card.""" @@ -40,6 +107,9 @@ class ISO_7816_4_Card(Card): COMMANDS = dict(Card.COMMANDS) COMMANDS.update( { "select_file": cmd_selectfile, + "cd": cmd_cd, + "cat": cmd_cat, + "open": cmd_open, "parse_tlv": cmd_parsetlv, } ) diff --git a/cards/starcos_card.py b/cards/starcos_card.py new file mode 100644 index 0000000..9368435 --- /dev/null +++ b/cards/starcos_card.py @@ -0,0 +1,19 @@ +import utils +from iso_7816_4_card import * + +class Starcos_Card(ISO_7816_4_Card): + DRIVER_NAME = "Starcos" + APDU_READ_BINARY = C_APDU("\x00\xb0\x00\x00\xfe") + + def change_dir(self, fid = None): + "Change to a child DF. Alternatively, change to MF if fid is None." + if fid is None: + return self.select_file(0x00, 0x0C, self.FID_MF) + else: + return self.select_file(0x00, 0x0C, fid) + + ATRS = list(Card.ATRS) + ATRS.extend( [ + ("3bb794008131fe6553504b32339000d1", None), + ] ) + diff --git a/cards/tcos_card.py b/cards/tcos_card.py index 661fe74..fad0850 100644 --- a/cards/tcos_card.py +++ b/cards/tcos_card.py @@ -4,7 +4,6 @@ from iso_7816_4_card import * class TCOS_Card(ISO_7816_4_Card): DRIVER_NAME = "TCOS" APDU_LIST_X = C_APDU("\x80\xaa\x01\x00\x00") - APDU_READ_BINARY = C_APDU("\x00\xb0\x00\x00") def list_x(self, x): "Get a list of x objects, where x is one of 1 (DFs) or 2 (EFs)" @@ -17,32 +16,6 @@ class TCOS_Card(ISO_7816_4_Card): result_list.append(head) return result_list - def read_binary_file(self, offset = 0): - """Read from the currently selected EF. - Repeat calls to READ BINARY as necessary to get the whole EF.""" - - if offset >= 1<<15: - raise ValueError, "offset is limited to 15 bits" - contents = "" - had_one = False - - while True: - command = C_APDU(self.APDU_READ_BINARY, p1 = offset >> 8, p2 = (offset & 0xff), le = 0) - result = self.send_apdu(command) - if len(result.data) > 0: - contents = contents + result.data - offset = offset + len(result.data) - - if result.sw != self.SW_OK: - break - else: - had_one = True - - if had_one: ## If there was at least one successful pass, ignore any error SW. It probably only means "end of file" - self.sw_changed = False - - return contents - def cmd_listdirs(self): "List DFs in current DF" result = self.list_x(1) @@ -61,23 +34,6 @@ class TCOS_Card(ISO_7816_4_Card): print "\n".join( ["[%s]" % utils.hexdump(a, short=True) for a in dirs] + [" %s " % utils.hexdump(a, short=True) for a in files] ) - def cmd_cd(self, dir = None): - "Change into a DF, or into the MF if no dir is given" - if dir is None: - return self.cmd_selectfile("00", "00", "") - else: - return self.cmd_selectfile("01", "00", dir) - - def cmd_open(self, file): - "Shortcut for 'select_file 02 00 file'" - return self.cmd_selectfile("02", "00", file) - - def cmd_cat(self): - "Print a hexdump of the currently selected file (e.g. consecutive READ BINARY)" - contents = self.read_binary_file() - self.last_result = R_APDU(contents + self.last_sw) - print utils.hexdump(contents) - ATRS = list(Card.ATRS) ATRS.extend( [ ("3bba96008131865d0064057b0203318090007d", None), @@ -88,7 +44,4 @@ class TCOS_Card(ISO_7816_4_Card): "list_dirs": cmd_listdirs, "list_files": cmd_listfiles, "ls": cmd_list, - "cd": cmd_cd, - "open": cmd_open, - "cat": cmd_cat, } ) diff --git a/utils.py b/utils.py index f5d81d6..09fe00d 100644 --- a/utils.py +++ b/utils.py @@ -172,7 +172,8 @@ class APDU(object): self.parse( initbuff ) for (name, value) in kwargs.items(): - setattr(self, name, value) + if value is not None: + setattr(self, name, value) def _getdata(self): return self._data