/pymrtd

Python implementation of ICAO 9303 biometric passport standard

Primary LanguagePython

Python library for ICAO Machine Readable Travel Documents standard - Biometric Passport

tests

The PyMRTD is python implementation of ICAO 9303 standard. It implements only parts of standard needed for Port server. That is, parsing (re-serializing) some of MRTD logical data structures (LDS) files and verifying eMRTD trustchain including verification of signature made by MRTD (AA signature). This library doesn't provide APIs and functionalities needed to send commands to and extract data from MRTD.

Library structure

Library is divided into two modules:

Dependencies

 pip3 install asn1crypto
  pip3 install cryptography

Usage

Parsing and serializing data stuctures

All data structures that can be parsed from raw byte array (SOD, DG1, CscaCertificate etc...) have defined static member function load and member function dump to serialize data back to byte array (following the interface of library asn1crypto).

Example of loading CscaCertificate from file:

f = open('csca.cer', 'rb')
csca = CscaCertificate.load(f.read())

print(csca.issuerCountry)
print(csca.subjectKey.hex())
print(csca.fingerprint)
print(csca.dump().hex())

Verifying and validating

All certificate classes (Certificate, CscaCertificate, DocumentSignerCertificate, MasterListSignerCertificate) and also classes implementing MRTD CMS data structure (RFC 5652) have member function verify defined which verifies digital signature made over an object. Classes implementing class Certificate has also defined member function isValidOn(datetime) which returns True if certificate is valid on particular date and time.

Example of validating MRTD trustchain:

# 1. Parse SOD and get signing certificates (DSC, CSCA)
sod = SOD.load(...)
if len(sod.dscCertificates) == 0: # SOD is not required to store it's signer DSC certificate.
  raise Exception("Can't verify SOD, no DSC found")

dsc  = sod.dscCertificates[0] # SOD can store more than 1 DSC certificate by definition
csca = fetchCscaForDsc(sod.dscCertificates[0])
if csca is None:
  raise Exception("Can't verify DSC, no CSCA found")

# 2. Validate trust chain by verifying digital signatures and expiration time of certificates
if not csca.isValidOn(utils.time_now()):
  raise Exception("CSCA has expired")

if not dsc.isValidOn(utils.time_now()):
  raise Exception("DSC has expired")

try:
  for si in sod.signers:
    # Note: certificate conformance check (checkConformance) is not done by default
    #       because not all countries follow the standard strictly
    dsc.verify(issuing_cert=csca, checkConformance=True/False)
    sod.verify(si=si, issuerCert=dsc)
    return success
except:
  raise Exception("MRTD turstchain verification failed")

Example of verifying MRTD digital signature:

sod  = SOD.load(...)
dg15 = DG15.load(...)

# First verify DG15 was issued by country
# Note: SOD object should be validated into trustchain at this point
if not sod.ldsSecurityObject.contains(dg15):
  raise Exception("Can't verify signature, invalid EF.DG15 file")

# If ECC signature, get ECC signature algorithm from EF.DG14 file
sigAlgo = None
if dg15.aaPublicKey.isEcKey():
  dg14 = SOD.load(...)
  if not sod.ldsSecurityObject.contains(dg14): # Verify EF.DG14 was issued by country
    raise Exception("Can't verify signature, invalid EF.DG14 file")
  elif dg14.aaSignatureAlgo is None: # sanity check
    raise Exception("Missing ActiveAuthenticationInfo in DG14 file")
  sigAlgo = dg14.aaSignatureAlgo

# Verify signature made by MRTD
try:
  dg15.aaPublicKey.verifySignature(msg, sig, sigAlgo):
catch:
  raise Exception("Signature verification failed")

Other documentation