aboutsummaryrefslogtreecommitdiffstats
path: root/fingerpass.py
diff options
context:
space:
mode:
authorhploetz <hploetz@f711b948-2313-0410-aaa9-d29f33439f0b>2007-05-30 16:48:35 +0000
committerhploetz <hploetz@f711b948-2313-0410-aaa9-d29f33439f0b>2007-05-30 16:48:35 +0000
commit92e16bef2ca46a56a4439a150751cb3ecccbaaaa (patch)
treeff6cd66066efd0e80b20797a90e9863d464b1410 /fingerpass.py
parent10a9dab1effb32cb9b91290b472eece10788ebd9 (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-xfingerpass.py203
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
+