diff options
author | hploetz <hploetz@f711b948-2313-0410-aaa9-d29f33439f0b> | 2007-05-30 16:48:35 +0000 |
---|---|---|
committer | hploetz <hploetz@f711b948-2313-0410-aaa9-d29f33439f0b> | 2007-05-30 16:48:35 +0000 |
commit | 92e16bef2ca46a56a4439a150751cb3ecccbaaaa (patch) | |
tree | ff6cd66066efd0e80b20797a90e9863d464b1410 /fingerpass.py | |
parent | 10a9dab1effb32cb9b91290b472eece10788ebd9 (diff) |
Add fingerpass for passport fingerprinting
git-svn-id: svn+ssh://localhost/home/henryk/svn/cyberflex-shell/trunk@193 f711b948-2313-0410-aaa9-d29f33439f0b
Diffstat (limited to 'fingerpass.py')
-rwxr-xr-x | fingerpass.py | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/fingerpass.py b/fingerpass.py new file mode 100755 index 0000000..f4c2484 --- /dev/null +++ b/fingerpass.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python +# -*- coding: iso-8859-1 -*- + +import pycsc, utils, cards, TLV_utils, sys, binascii, time, getopt, traceback + +STATUS_INTERVAL = 10 + +OPTIONS = "r:l" +LONG_OPTIONS = ["reader=", "list-readers"] +exit_now = False +reader = None + +def list_readers(): + for index, name in enumerate(pycsc.listReader()): + print "%i: %s" % (index, name) + +def connect(reader = None): + "Open the connection to a card" + + if reader is None: + reader = 0 + + if isinstance(reader, int) or reader.isdigit(): + reader = int(reader) + readerName = pycsc.listReader()[reader] + else: + readerName = reader + + newState = pycsc.getStatusChange(ReaderStates=[ + {'Reader': readerName, 'CurrentState':pycsc.SCARD_STATE_UNAWARE} + ] + ) + + 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: + + 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") + + print "ATR: %s" % utils.hexdump(newState[0]['Atr'], short = True) + return pycsc.pycsc(reader = readerName, protocol = pycsc.SCARD_PROTOCOL_ANY) + +def fingerprint_7816(card): + # Need ISO 7816-4 + if not isinstance(card, cards.iso_7816_4_card.ISO_7816_4_Card): + return [] + + # Try a select MF, just in case ... + try: + card.change_dir() + except (SystemExit, KeyboardInterrupt): + raise + except: + traceback.print_exc() + + SHORT_SW_MAP = { + "\x90\x00": 0, + "\x69\x82": 1, # Security status not satisfied + "\x6a\x82": 2, # File not found + None: 3, + } + SHORT_SW_WIDTH = 2 + + def detect_bac(card): + "Check whether BAC is active and if yes what type of card-os (select not allowed, select allowed but read not allowed)" + result = card.open_file("\x01\x01", 0x0c) # EF.DG1 + + if result.sw == "\x90\x00": + prefix = str(SHORT_SW_MAP[result.sw]) + result = card.send_apdu(utils.C_APDU(card.APDU_READ_BINARY, p1=0, p2=0, le=1)) + else: + prefix = "" + + if SHORT_SW_MAP.has_key(result.sw): + return prefix + str(SHORT_SW_MAP[result.sw]) + else: + return prefix + "%s:%s" % (SHORT_SW_MAP[None], binascii.b2a_hex(result.sw) ) + + def map_dg(card): + "Get a map of which DGs exist and are readable/unreadable and with which SW they are unreadable" + # Try to read 1 byte from each DG through READ BINARY with short file identifier + responses = [card.send_apdu(utils.C_APDU(card.APDU_READ_BINARY, p1=i|0x80, p2=0, le=1)) for i in range(1,17)] + + result = [] + exceptional = [] + for response in responses: + if SHORT_SW_MAP.has_key( response.sw ): + result.append( SHORT_SW_MAP[response.sw] ) + else: + result.append( SHORT_SW_MAP[None] ) + exceptional.append(response.sw) + + compressed = [] + current = 0 + count = 0 + for r in result: + if count >= 8: + compressed.append( current ) + current = count = 0 + current = (current << SHORT_SW_WIDTH) | r + count = count + SHORT_SW_WIDTH + + if count > 0: + compressed.append( current ) + current = count = 0 + + + return "".join( ["%02X" % r for r in compressed] ) + ":".join( (len(exceptional) > 0 and [""] or []) + [binascii.b2a_hex(e) for e in exceptional] ) + + result = [] + test_icao = card.select_application(card.resolve_symbolic_aid("mrtd"), le=None) + if not card.check_sw(test_icao.sw, card.PURPOSE_SUCCESS): + result.append("N") # Not an ICAO MRTD + else: + result.append("P") # An ICAO MRTD + + bac = detect_bac(card) + result.append(bac) # BAC status + + dgmap = map_dg(card) + result.append(dgmap) # Data Group map + + return result + +def fingerprint(card): + def compress_atr(atr): + numhist = ord(atr[1]) & 0x0f + if binascii.a2b_hex( "3B8%X8001" % numhist ) == atr[:4]: + # Contactless, conforming to PC/SC part 3 section 3.1.3.2.3 + + if atr[4:6] == "\x80\x4f": # Status indicator in compact-tlv object + si_len = ord(atr[6]) + aid = atr[7:7+si_len] + + if aid[:5] == "\xa0\x00\x00\x03\x06": # RID of PC/SC Workgroup + standard_and_name = aid[5:] + if standard_and_name[3:] == "\x00" * (len(standard_and_name)-3): + return "1:%s" % binascii.b2a_hex(standard_and_name[:3]) # RFU bytes unset + else: + return "2:%s" % binascii.b2a_hex(standard_and_name[:3]) # RFU bytes set + + return "0:%s" % binascii.b2a_hex(atr[4:]) + else: + # Not contactless (or not conforming) + return "3:%s" % binascii.b2a_hex(atr) + return "" + + result = [] + + catr = compress_atr(card.get_atr()) + print catr + result.append( catr ) + result.extend( fingerprint_7816(card) ) + + return ",".join(result) + +if __name__ == "__main__": + + (options, arguments) = getopt.gnu_getopt(sys.argv[1:], OPTIONS, LONG_OPTIONS) + + for (option, value) in options: + if option in ("-r","--reader"): + reader = value + if option in ("-l","--list-readers"): + list_readers() + exit_now = True + + if exit_now: + sys.exit() + del exit_now + + pycsc_card = connect(reader) + card = cards.new_card_object(pycsc_card) + #cards.generic_card.DEBUG = False + + print >>sys.stderr, "Using %s" % card.DRIVER_NAME + + fp = fingerprint(card) + print "Fingerprint: %s" % fp + |