Tool to read full passport information. Call without arguments to try without bac, or with mrz1 mrz2 or mrz2 to try with bac

git-svn-id: svn+ssh://localhost/home/henryk/svn/cyberflex-shell/trunk@224 f711b948-2313-0410-aaa9-d29f33439f0b
This commit is contained in:
hploetz 2007-06-08 00:55:16 +00:00
parent 918eaf3f40
commit 3fa2f88419
4 changed files with 86 additions and 52 deletions

View File

@ -133,10 +133,11 @@ class Passport_Application(Application):
if verbose:
print "Kenc = %s" % hexdump(Kenc)
print "Kmac = %s" % hexdump(Kmac)
print
print
result = self.send_apdu(self.APDU_GET_RANDOM)
assert self.check_sw(result.sw)
if not self.check_sw(result.sw):
raise BACError, "SW after GET RANDOM was %02x%02x. Card refused to send rcd_icc. Should NEVER happen." % (result.sw1, result.sw2)
rnd_icc = result.data
if verbose:
@ -155,11 +156,12 @@ class Passport_Application(Application):
if verbose:
print "Eifd = %s" % hexdump(Eifd, indent=10)
print "Mifd = %s" % hexdump(Mifd)
print
print
auth_apdu = C_APDU(self.APDU_MUTUAL_AUTHENTICATE, data = Eifd + Mifd)
result = self.send_apdu(auth_apdu)
assert self.check_sw(result.sw)
if not self.check_sw(result.sw):
raise BACError, "SW after MUTUAL AUTHENTICATE was %02x%02x. Card did not accept our BAC attempt" % (result.sw1, result.sw2)
resp_data = result.data
Eicc = resp_data[:-8]
@ -176,9 +178,9 @@ class Passport_Application(Application):
if verbose:
print "R = %s" % hexdump(R, indent=10)
if not R[:8] == rnd_icc:
raise ValueError, "Passport authentication failed: Wrong RND.icc on incoming data during Mutual Authenticate"
raise BACError, "Passport authentication failed: Wrong RND.icc on incoming data during Mutual Authenticate"
if not R[8:16] == rnd_ifd:
raise ValueError, "Passport authentication failed: Wrong RND.ifd on incoming data during Mutual Authenticate"
raise BACError, "Passport authentication failed: Wrong RND.ifd on incoming data during Mutual Authenticate"
Kicc = R[16:]
if verbose:
@ -513,6 +515,8 @@ class CBEFF:
class PassportParseError(Exception):
pass
class BACError(Exception):
pass
_default_empty_mrz_data = ("","")
class Passport(object):
@ -796,9 +800,9 @@ class Passport(object):
if not isinstance(card, ISO_7816_4_Card):
raise ValueError, "card must be a Passport_Application object or a ISO_7816_4_Card object, not %s" % type(card)
else:
result = card.select_application("mrtd")
result = card.select_application(card.resolve_symbolic_aid("mrtd"))
if not card.check_sw(result.sw):
raise EnvironmentError, "card did not accept SELECT APPLICATION, sw was %s" % result.sw
raise EnvironmentError, "card did not accept SELECT APPLICATION, sw was %02x %02x" % (result.sw1, result.sw2)
assert isinstance(card, Passport_Application)
p = cls(mrz_data, ignore_mrz_parse_error=True)
@ -807,8 +811,6 @@ class Passport(object):
p.result_map_select = {}
p.result_map_read = {}
generic_card.DEBUG = False
for name, fid in card.INTERESTING_FILES:
result = card.open_file(fid, 0x0C)
if not card.check_sw(result.sw) and not tried_bac and not mrz_data is _default_empty_mrz_data:
@ -880,46 +882,53 @@ class Passport(object):
self.document_no, self.nationality, self.date_of_birth, self.sex, self.expiration_date, self.optional = "", "", "", "", "", ""
if mrz_data[0].strip() != "":
mrz1 = mrz_data[0].replace("<", " ")
self.type = mrz1[0:2].strip()
self.issuer = mrz1[2:5].strip()
n = mrz1[5:].strip().split(" ", 1)
self.name = [n[0]]
self.name = self.name + n[1].split(" ")
try:
mrz1 = mrz_data[0].replace("<", " ")
self.type = mrz1[0:2].strip()
self.issuer = mrz1[2:5].strip()
n = mrz1[5:].strip().split(" ", 1)
self.name = [n[0]]
self.name = self.name + n[1].split(" ")
except IndexError:
raise PassportParseError, "Some index error while parsing mrz1"
if mrz_data[1].strip() != "":
mrz2 = mrz_data[1]
self.document_no = mrz2[:9].strip("<")
if mrz2[9] == "<": # document number check digit, or filler character to indicate document number longer than 9 characters
expanded_document_no = True
else:
expanded_document_no = False
self.calculate_check_digit(mrz2[:9], mrz2[9], "Document number")
self.nationality = mrz2[10:13].strip("<")
self.date_of_birth = mrz2[13:19]
self.calculate_check_digit(mrz2[13:19], mrz2[19], "Date of birth")
self.sex = mrz2[20]
self.expiration_date = mrz2[21:27]
self.calculate_check_digit(mrz2[21:27], mrz2[27], "Date of expiration")
opt_field = mrz2[28:-2]
if not expanded_document_no:
self.optional = opt_field.strip("<")
if mrz2[-2] != "<":
self.calculate_check_digit(opt_field, mrz2[-2], "Optional data")
else:
splitted_opt_field = opt_field.split("<", 1)
self.document_no = self.document_no + splitted_opt_field[0][:-1]
self.calculate_check_digit(self.document_no, splitted_opt_field[0][-1], "Expanded document number")
try:
mrz2 = mrz_data[1]
self.document_no = mrz2[:9].strip("<")
if mrz2[9] == "<": # document number check digit, or filler character to indicate document number longer than 9 characters
expanded_document_no = True
else:
expanded_document_no = False
self.calculate_check_digit(mrz2[:9], mrz2[9], "Document number")
self.nationality = mrz2[10:13].strip("<")
if len(splitted_opt_field) > 1:
self.optional = splitted_opt_field[1].strip("<")
self.date_of_birth = mrz2[13:19]
self.calculate_check_digit(mrz2[13:19], mrz2[19], "Date of birth")
self.sex = mrz2[20]
self.expiration_date = mrz2[21:27]
self.calculate_check_digit(mrz2[21:27], mrz2[27], "Date of expiration")
opt_field = mrz2[28:-2]
if not expanded_document_no:
self.optional = opt_field.strip("<")
if mrz2[-2] != "<":
self.calculate_check_digit(splitted_opt_field[1], mrz2[-2], "Optional data")
self.calculate_check_digit(mrz2[0:10]+mrz2[13:20]+mrz2[21:43], mrz2[-1], "Second line of machine readable zone")
self.calculate_check_digit(opt_field, mrz2[-2], "Optional data")
else:
splitted_opt_field = opt_field.split("<", 1)
self.document_no = self.document_no + splitted_opt_field[0][:-1]
self.calculate_check_digit(self.document_no, splitted_opt_field[0][-1], "Expanded document number")
if len(splitted_opt_field) > 1:
self.optional = splitted_opt_field[1].strip("<")
if mrz2[-2] != "<":
self.calculate_check_digit(splitted_opt_field[1], mrz2[-2], "Optional data")
self.calculate_check_digit(mrz2[0:10]+mrz2[13:20]+mrz2[21:43], mrz2[-1], "Second line of machine readable zone")
except:
raise PassportParseError, "Some index error while parsing mrz2"
if __name__ == "__main__":

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Project SYSTEM "Project-3.7.dtd">
<!-- Project file for project cyberflex-shell -->
<!-- Saved: 2007-06-01, 02:47:04 -->
<!-- Saved: 2007-06-08, 02:40:24 -->
<!-- Copyright (C) 2007 Henryk Plötz, henryk@ploetzli.ch -->
<Project version="3.7">
<ProgLanguage mixed="0">Python</ProgLanguage>
@ -102,6 +102,9 @@
<Dir>cards</Dir>
<Name>rfid_card.py</Name>
</Source>
<Source>
<Name>readpass.py</Name>
</Source>
</Sources>
<Forms>
</Forms>

View File

@ -4,8 +4,6 @@
from utils import pycsc
import utils, cards, TLV_utils, sys, binascii, time, traceback, re
STATUS_INTERVAL = 10
def fingerprint_rfid(card):
# Need RFID
if not isinstance(card, cards.rfid_card.RFID_Card):

24
readpass.py Executable file
View File

@ -0,0 +1,24 @@
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
from utils import pycsc
import utils, cards, TLV_utils, sys, binascii, time, traceback
if __name__ == "__main__":
c = utils.CommandLineArgumentHelper()
(options, arguments) = c.getopt(sys.argv[1:])
pycsc_card = c.connect()
card = cards.new_card_object(pycsc_card)
cards.generic_card.DEBUG = False
print >>sys.stderr, "Using %s" % card.DRIVER_NAME
if len(arguments) > 1:
p = cards.passport_application.Passport.from_card(card, arguments[:2])
elif len(arguments) == 1:
p = cards.passport_application.Passport.from_card(card, ["",arguments[0]])
else:
p = cards.passport_application.Passport.from_card(card)