From 3fa2f884191bcbac2994fcba964bbceb1087bc10 Mon Sep 17 00:00:00 2001 From: hploetz Date: Fri, 8 Jun 2007 00:55:16 +0000 Subject: [PATCH] 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 --- cards/passport_application.py | 107 ++++++++++++++++++---------------- cyberflex-shell.e3p | 5 +- fingerpass.py | 2 - readpass.py | 24 ++++++++ 4 files changed, 86 insertions(+), 52 deletions(-) create mode 100755 readpass.py diff --git a/cards/passport_application.py b/cards/passport_application.py index 8da6971..7f8600d 100644 --- a/cards/passport_application.py +++ b/cards/passport_application.py @@ -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__": diff --git a/cyberflex-shell.e3p b/cyberflex-shell.e3p index 3657ed5..8d10629 100644 --- a/cyberflex-shell.e3p +++ b/cyberflex-shell.e3p @@ -1,7 +1,7 @@ - + Python @@ -102,6 +102,9 @@ cards rfid_card.py + + readpass.py + diff --git a/fingerpass.py b/fingerpass.py index e034b07..6f689c8 100755 --- a/fingerpass.py +++ b/fingerpass.py @@ -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): diff --git a/readpass.py b/readpass.py new file mode 100755 index 0000000..c6c50f5 --- /dev/null +++ b/readpass.py @@ -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) +