diff --git a/cards/generic_card.py b/cards/generic_card.py index 0bbf77a..d04db85 100644 --- a/cards/generic_card.py +++ b/cards/generic_card.py @@ -1,15 +1,18 @@ -import crypto_utils, utils, pycsc, binascii, fnmatch +import crypto_utils, utils, pycsc, binascii, fnmatch, sre from utils import C_APDU, R_APDU DEBUG = True #DEBUG = False class Card: + DRIVER_NAME = "Generic" APDU_GET_RESPONSE = C_APDU("\x00\xC0\x00\x00") APDU_VERIFY_PIN = C_APDU("\x00\x20\x00\x00") SW_OK = '\x90\x00' + ## Note: an item in this list must be a tuple of (atr, mask) where atr is a binary + ## string and mask a binary mask. Alternatively mask may be None, then ATR must be a regex + ## to match on the ATRs hexlify representation ATRS = [] - DRIVER_NAME = "Generic" ## Note: a key in this dictionary may either be a two-byte string containing ## a binary status word, or a four-byte string containing a hexadecimal ## status word, possibly with ? characters marking variable nibbles. @@ -102,10 +105,14 @@ class Card: """Determine whether this class can handle a given pycsc object.""" ATR = card.status().get("ATR","") for (knownatr, mask) in cls.ATRS: - if len(knownatr) != len(ATR): - continue - if crypto_utils.andstring(knownatr, mask) == crypto_utils.andstring(ATR, mask): - return True + if mask is None: + if sre.match(knownatr, binascii.hexlify(ATR), sre.I): + return True + else: + if len(knownatr) != len(ATR): + continue + if crypto_utils.andstring(knownatr, mask) == crypto_utils.andstring(ATR, mask): + return True return False can_handle = classmethod(can_handle) @@ -118,10 +125,10 @@ class Card: else: retval = None - desc = self.STATUS_WORDS.get(self.last_sw) - if desc is not None: - retval = desc - else: + retval = self.STATUS_WORDS.get(self.last_sw) + if retval is None: + retval = self.STATUS_WORDS.get(binascii.hexlify(self.last_sw).upper()) + if retval is None: target = binascii.b2a_hex(self.last_sw).upper() for (key, value) in self.STATUS_WORDS.items(): if fnmatch.fnmatch(target, key): diff --git a/cards/iso_7816_4_card.py b/cards/iso_7816_4_card.py index 5feec1d..7725829 100644 --- a/cards/iso_7816_4_card.py +++ b/cards/iso_7816_4_card.py @@ -5,9 +5,9 @@ class ISO_7816_4_Card(Card): APDU_SELECT_FILE = C_APDU("\x00\xa4\x00\x00") DRIVER_NAME = "ISO 7816-4" - def can_handle(cls, card): - return True - can_handle = classmethod(can_handle) +## def can_handle(cls, card): +## return True +## can_handle = classmethod(can_handle) def select_file(self, p1, p2, fid): result = self.send_apdu( @@ -29,7 +29,13 @@ class ISO_7816_4_Card(Card): print TLV_utils.decode(result.data) def cmd_parsetlv(self): - print BER_utils.decode(self.last_result) + "Decode the TLV data in the last response" + print TLV_utils.decode(self.last_result) + + ATRS = list(Card.ATRS) + ATRS.extend( [ + (".*", None), ## For now we accept any card + ] ) COMMANDS = dict(Card.COMMANDS) COMMANDS.update( { diff --git a/cards/tcos_card.py b/cards/tcos_card.py new file mode 100644 index 0000000..cc6cce7 --- /dev/null +++ b/cards/tcos_card.py @@ -0,0 +1,38 @@ +import utils +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") + + def list_x(self, x): + "Get a list of x objects, where x is one of 1 (DFs) or 2 (EFs)" + result = self.send_apdu(C_APDU(self.APDU_LIST_X, p1=x)) + + tail = result.data + result_list = [] + while len(tail) > 0: + head, tail = tail[:2], tail[2:] + result_list.append(head) + return result_list + + def cmd_listdirs(self): + "List DFs in current DF" + result = self.list_x(1) + print "DFs: " + ", ".join([utils.hexdump(a, short=True) for a in result]) + + def cmd_listfiles(self): + "List EFs in current DF" + result = self.list_x(2) + print "EFs: " + ", ".join([utils.hexdump(a, short=True) for a in result]) + + ATRS = list(Card.ATRS) + ATRS.extend( [ + ("3bba96008131865d0064057b0203318090007d", None), + ] ) + + COMMANDS = dict(ISO_7816_4_Card.COMMANDS) + COMMANDS.update( { + "list_dirs": cmd_listdirs, + "list_files": cmd_listfiles, + } )