diff --git a/brutefid.py b/brutefid.py index 4161ba8..4ec18b7 100755 --- a/brutefid.py +++ b/brutefid.py @@ -1,7 +1,6 @@ #!/usr/bin/env python # -*- coding: iso-8859-1 -*- -from utils import pycsc import utils, cards, TLV_utils, sys, binascii, time, traceback STATUS_INTERVAL = 10 @@ -21,8 +20,8 @@ if __name__ == "__main__": top_level = ("".join( ["".join(e.split()) for e in arguments] )).split("/") top_level = [binascii.unhexlify(e) for e in top_level] - pycsc_card = c.connect() - card = cards.new_card_object(pycsc_card) + card_object = c.connect() + card = cards.new_card_object(card_object) cards.generic_card.DEBUG = False print >>sys.stderr, "Using %s" % card.DRIVER_NAME diff --git a/cards/generic_card.py b/cards/generic_card.py index 023cbfa..f54d0d6 100644 --- a/cards/generic_card.py +++ b/cards/generic_card.py @@ -1,4 +1,4 @@ -from utils import pycsc +import smartcard import TLV_utils, crypto_utils, utils, binascii, fnmatch, re from utils import C_APDU, R_APDU @@ -122,14 +122,12 @@ class Card: } TLV_OBJECTS[TLV_utils.context_FCI] = TLV_OBJECTS[TLV_utils.context_FCP] - def __init__(self, card = None, reader = None): - if card is None: - if reader is None: - self.card = pycsc.pycsc(protocol = pycsc.SCARD_PROTOCOL_ANY) - else: - self.card = pycsc.pycsc(protocol = pycsc.SCARD_PROTOCOL_ANY, reader = reader) - else: + def __init__(self, card): + if not hasattr(card, "connection"): self.card = card + else: + self.card = card.connection + self.cardservice = card self._i = 0 self.last_apdu = None @@ -156,7 +154,8 @@ class Card: def cmd_reset(self): """Reset the card.""" - self.card.reconnect(init=pycsc.SCARD_RESET_CARD) + # FIXME + raise NotImplementedException def cmd_parsetlv(self, start = None, end = None): "Decode the TLV data in the last response, start and end are optional" @@ -190,14 +189,20 @@ class Card: "parse_tlv": cmd_parsetlv, "show_applications": cmd_show_applications, } - + + PROTOMAP = { + 0: smartcard.scard.SCARD_PCI_T0, + 1: smartcard.scard.SCARD_PCI_T1, + } def _real_send(self, apdu): apdu_binary = apdu.render() if DEBUG: print ">> " + utils.hexdump(apdu_binary, indent = 3) - result_binary = self.card.transmit(apdu_binary) + apdu_bytes = map(lambda x: ord(x), apdu_binary) + data, sw1, sw2 = self.card.transmit(apdu_bytes, protocol=self.PROTOMAP[self.get_protocol()]) + result_binary = map(lambda x: chr(x), data + [sw1,sw2]) result = R_APDU(result_binary) self.last_apdu = apdu @@ -249,8 +254,11 @@ class Card: return self.card.status().get("ATR","") def can_handle(cls, card): - """Determine whether this class can handle a given pycsc object.""" - ATR = card.status().get("ATR","") + """Determine whether this class can handle a given card/connection object.""" + if hasattr(card, "connection"): + ATR = smartcard.util.toASCIIString(card.connection.getATR()) + else: + ATR = smartcard.util.toASCIIString(card.getATR()) def match_list(atr, list): for (knownatr, mask) in list: if mask is None: @@ -310,7 +318,8 @@ class Card: return "%s (SW %s)" % (retval, binascii.b2a_hex(self.last_sw)) def get_protocol(self): - return ((self.card.status()["Protocol"] == pycsc.SCARD_PROTOCOL_T0) and (0,) or (1,))[0] + hresult, reader, state, protocol, atr = smartcard.scard.SCardStatus( self.card.component.hcard ) + return ((protocol == smartcard.scard.SCARD_PROTOCOL_T0) and (0,) or (1,))[0] def get_driver_name(self): if len(self.DRIVER_NAME) > 1: @@ -321,4 +330,8 @@ class Card: def close_card(self): "Disconnect from a card" - del self.card # FIXME: anything else to do? + self.card.disconnect() + if hasattr(self, "cardservice"): + del self.cardservice + del self.card + diff --git a/cyberflex-shell.py b/cyberflex-shell.py index 1f28cca..b775f55 100755 --- a/cyberflex-shell.py +++ b/cyberflex-shell.py @@ -1,8 +1,6 @@ #!/usr/bin/env python # -*- coding: iso-8859-1 -*- -from utils import pycsc - import crypto_utils, utils, cards, os, re, binascii, sys, exceptions, traceback, getopt, datetime from shell import Shell @@ -342,8 +340,8 @@ class Cyberflex_Shell(Shell): if reader is None: reader = self.reader - pycsc_card = utils.CommandLineArgumentHelper.connect_to(reader) - self.card = cards.new_card_object(pycsc_card) + card_object = utils.CommandLineArgumentHelper.connect_to(reader) + self.card = cards.new_card_object(card_object) self.unregister_commands(self, self.NOCARD_COMMANDS) self.register_commands(self, self.CARD_COMMANDS) diff --git a/fingerpass.py b/fingerpass.py index 6f689c8..b87a038 100755 --- a/fingerpass.py +++ b/fingerpass.py @@ -1,7 +1,6 @@ #!/usr/bin/env python # -*- coding: iso-8859-1 -*- -from utils import pycsc import utils, cards, TLV_utils, sys, binascii, time, traceback, re def fingerprint_rfid(card): @@ -184,8 +183,8 @@ if __name__ == "__main__": c = utils.CommandLineArgumentHelper() (options, arguments) = c.getopt(sys.argv[1:]) - pycsc_card = c.connect() - card = cards.new_card_object(pycsc_card) + card_object = c.connect() + card = cards.new_card_object(card_object) cards.generic_card.DEBUG = False print >>sys.stderr, "Using %s" % card.DRIVER_NAME diff --git a/readpass.py b/readpass.py index 1e36ba2..ad38508 100755 --- a/readpass.py +++ b/readpass.py @@ -1,7 +1,6 @@ #!/usr/bin/env python # -*- coding: iso-8859-1 -*- -from utils import pycsc import utils, cards, TLV_utils, sys, binascii, time, traceback OPTIONS = "GW:R:" @@ -25,8 +24,8 @@ if __name__ == "__main__": read_files = value if read_files is None: - pycsc_card = c.connect() - card = cards.new_card_object(pycsc_card) + card_object = c.connect() + card = cards.new_card_object(card_object) cards.generic_card.DEBUG = False print >>sys.stderr, "Using %s" % card.DRIVER_NAME diff --git a/utils.py b/utils.py index 430f219..0162c46 100644 --- a/utils.py +++ b/utils.py @@ -1,14 +1,13 @@ -try: - import pycsc -except ImportError,e: - try: - import PyCSC - from PyCSC import pycsc # Windows - pycsc.SCARD_PROTOCOL_ANY = PyCSC.SCARD_PROTOCOL_ANY - except ImportError: - raise e # raise the original exception, masking the windows-only attempt - import string, binascii, sys, re, getopt +try: + import smartcard, smartcard.CardRequest +except ImportError: + print >>sys.stderr, """Could not import smartcard module. Please install pyscard +from http://pyscard.sourceforge.net/ +If you can't install pyscard and want to continue using +pycsc you'll need to downgrade to SVN revision 246. +""" + raise class CommandLineArgumentHelper: OPTIONS = "r:l" @@ -17,7 +16,7 @@ class CommandLineArgumentHelper: reader = None def list_readers(): - for index, name in enumerate(pycsc.listReader()): + for index, name in enumerate(smartcard.System.readers()): print "%i: %s" % (index, name) list_readers = staticmethod(list_readers) @@ -32,48 +31,48 @@ class CommandLineArgumentHelper: def connect_to(reader): "Open the connection to a reader" + readerObject = None + if isinstance(reader, int) or reader.isdigit(): reader = int(reader) - readerName = pycsc.listReader()[reader] + readerObject = smartcard.System.readers()[reader] else: - readerName = reader + for r in smartcard.System.readers(): + if str(r).startswith(reader): + readerObject = r - newState = pycsc.getStatusChange(ReaderStates=[ - {'Reader': readerName, 'CurrentState':pycsc.SCARD_STATE_UNAWARE} - ] - ) + if readerObject is None: + readerObject = smartcard.System.readers()[0] - print "Using reader: %s" % readerName - print "Card present: %s" % ((newState[0]['EventState'] & pycsc.SCARD_STATE_PRESENT) and "yes" or "no") - - if not newState[0]['EventState'] & pycsc.SCARD_STATE_PRESENT: - print "Please insert card ..." - - last_was_mute = False - - while not newState[0]['EventState'] & pycsc.SCARD_STATE_PRESENT \ - or newState[0]['EventState'] & pycsc.SCARD_STATE_MUTE: + print "Using reader: %s" % readerObject + unpatched = False + printed = False + while True: + try: + if not unpatched: + cardrequest = smartcard.CardRequest.CardRequest( readers=[readerObject], timeout=0.1 ) + else: + cardrequest = smartcard.CardRequest.CardRequest( readers=[readerObject], timeout=1 ) - try: - newState = pycsc.getStatusChange(ReaderStates=[ - {'Reader': readerName, 'CurrentState':newState[0]['EventState']} - ], Timeout = 100 - ) ## 100 ms latency from Ctrl-C to abort should be almost unnoticeable by the user - except pycsc.PycscException, e: - if e.args[0] == 'Command timeout.': pass ## ugly - else: raise - - if newState[0]['EventState'] & pycsc.SCARD_STATE_MUTE: - if not last_was_mute: - print "Card is mute, please retry ..." - last_was_mute = True - else: - last_was_mute = False - - print "Card present: %s" % ((newState[0]['EventState'] & pycsc.SCARD_STATE_PRESENT) and "yes" or "no") + cardservice = cardrequest.waitforcard() + cardservice.connection.connect() + break + except TypeError: + unpatched = True + except (KeyboardInterrupt, SystemExit): + raise + except smartcard.Exceptions.CardRequestException: + if sys.exc_info()[1].message.endswith("Command timeout."): + if not printed: + print "Please insert card ..." + printed = True + else: + raise + except smartcard.Exceptions.NoCardException: + print "Card is mute or absent. Please retry." - print "ATR: %s" % hexdump(newState[0]['Atr'], short = True) - return pycsc.pycsc(reader = readerName, protocol = pycsc.SCARD_PROTOCOL_ANY) + print "ATR: %s" % hexdump(smartcard.util.toASCIIString(cardservice.connection.getATR()), short = True) + return cardservice connect_to = staticmethod(connect_to) def getopt(self, argv, opts="", long_opts=[]):