GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — GitHub - AndyQ/NFCPassportReader: NFCPassportReader for iOS 13

BranchesTags
Open more actions menu

Latest commit

 

History

278 Commits
278 Commits

Folders and files

NameName
Last commit message
Last commit date
Examples/Example_SPM
Examples/Example_SPM
 
 
Sources/NFCPassportReader
Sources/NFCPassportReader
 
 
Tests/NFCPassportReaderTests
Tests/NFCPassportReaderTests
 
 
scripts
scripts
 
 
.gitattributes
.gitattributes
 
 
.gitignore
.gitignore
 
 
CHANGELOG
CHANGELOG
 
 
CODE_OF_CONDUCT.md
CODE_OF_CONDUCT.md
 
 
LICENSE
LICENSE
 
 
Package.swift
Package.swift
 
 
readme.md
readme.md
 
 

Repository files navigation

NFCPassportReader

This package handles reading an NFC Enabled passport using iOS 15 CoreNFC APIS

Version 3 contains breaking changes - mainly around log handling. OSLog is no longer written to by default - see the logging section below

In addition, initial PACE-IM support has been implemented - but NOT yet tested against real passports

NOTE: Cocoapods is no longer supported and the Cocapods sample code has been removed. If you wish to contnue to use Cocoapods please refer to the 2.x branches.

Supported features:

  • Basic Access Control (BAC)
  • Secure Messaging
  • Reads DG1 (MRZ data) and DG2 (Image) in both JPEG and JPEG2000 formats, DG7, DG11, DG12, DG14 and DG15 (also SOD and COM datagroups)
  • Passive Authentication
  • Active Authentication
  • Chip Authentication (ECDH DES and AES keys tested, DH DES AES keys implemented ad should work but currently not tested)
  • PACE - ECDH Generic Mapping (GM) and Integrated Mapping (IM) with the MRZ password
  • Ability to dump passport stream and read it back in
  • Uses Async/Await

The code is by no means perfect and there are still some rough edges - there ARE most definitely bugs and I'm sure I'm not doing things perfectly.

It reads and verifies my passport (and others I've been able to test) fine, however your mileage may vary.

Installation

Swift Package Manager

NFCPassportReader may be installed via Swift Package Manager, by pointing to this repo's URL.

Usage

To use, you first need to create the Passport MRZ Key which consists of the passport number, date of birth and expiry date (including the checksums). Dates are in YYMMDD format

For example:

<passport number><passport number checksum><date of birth><date of birth checksum><expiry date><expiry date checksum>

e.g. for Passport nr 12345678, Date of birth 27-Jan-1998, Expiry 30-Aug-2025 the MRZ Key would be:

Passport number - 12345678
Passport number checksum - 8
Date Of birth - 980127
Date of birth checksum - 7
Expiry date - 250830
Expiry date checksum - 5

mrzKey = "12345678898012772508315"

Then on an instance of PassportReader, call the readPassport method passing in the mrzKey, the datagroups to read and a completion block.
e.g.

passportReader.readPassport(mrzKey: mrzKey, tags: [.COM, .DG1, .DG2], completed: { (error) in
   ...
}

Currently the datagroups supported are: COM, DG1, DG2, DG7, DG11, DG12, DG14 (partial), DG15, and SOD

This will then handle the reading of the passport, and image and will call the completion block either with an TagError error if there was an error of some kind, or nil if successful.

If successful, the passportReader object will then contain valid data for the passportMRZ and passportImage fields. Note - JPEG2000 images are currently unsupported - access to the raw data is available if you need to implement support for those.

In addition, you can customise the messages displayed in the NFC Session Reader by providing a customDisplayMessage callback e.g. to override just the initial request to present passport message:

passportReader.readPassport(mrzKey: mrzKey, tags: [.COM, .DG1, .DG2],
    customDisplayMessage: { (displayMessage) in
        switch displayMessage {
            case .requestPresentPassport:
                return "Hold your iPhone near an NFC enabled passport."
            default: 
                return nil
    }, completed: { (error) in
        ...
}

Extended mode reads (not supported by all passports) can be enabled by passing in the useExtendedMode flag to the readPassport function. This will increase the number of bytes that can be read in a call and may be required for some passports that use long AA keys (some Australian passports for example).

A custom Active Authentiion challenge can be provided to the PassportReader to ensure that the challenge/response was specifically executed in the session and not replayed. The app could then send the activeAuthenticationSignature to a backend, along with the rest of the chip data to perform validation.

Logging

The library sends structured log and protocol-trace events through one pipeline: logHandler. Logging is off unless you set logHandler — the library never writes to the system log itself. For the previous Console output use PassportLogHandlers.osLog():

reader.logHandler = PassportLogHandlers.osLog()
// or fan out to several handlers:
reader.logHandler = PassportLogHandlers.combine(PassportLogHandlers.osLog(), myTraceHandler)

A custom handler receives each PassportLogEvent directly:

let reader = PassportReader()
reader.logConfiguration = PassportLogConfiguration(
    minimumLevel: .debug,
    enabledComponents: [.pace, .tagReader],
    includeSensitiveDataInHandler: false
)
reader.logHandler = { event in
    print("[\(event.level)] [\(event.component)] \(event.summary)")
}

The handler is @Sendable and runs synchronously inside the APDU loop on the reader's thread; hand events off quickly and dispatch to the main queue before updating UI. Sensitive details are redacted from handler events by default. Enable includeSensitiveDataInHandler only for controlled debugging: traces may then contain authentication material or passport data. PassportLogHandlers.osLog() marks sensitive content private.

APDU command/response traces are logged at .debug, so set minimumLevel: .debug to see them.

Logs emitted outside a read (for example from NFCPassportModel(from:) or a direct verifyPassport call) go to PassportReader.defaultLogHandler, filtered by PassportReader.defaultLogConfiguration:

PassportReader.defaultLogHandler = PassportLogHandlers.osLog()

Other info

PassiveAuthentication

Passive Authentication is now part of the main library and can be used to ensure that an E-Passport is valid and hasn't been tampered with.

It requires a set of CSCA certificates in PEM format from a master list (either from a country that publishes their master list, or the ICAO PKD repository). See the scripts folder for details on how to get and create this file.

The masterList.pem file included in the Sample app is purely there to ensure no compiler warnings and contains only a single PEM file that was self-generated and won't be able to verify anything!

Sample app

There is a sample app included in the repo which demonstrates the functionality.

Troubleshooting

  • If when doing the initial Mutual Authenticate challenge, you get an error with and SW1 code 0x63, SW2 code 0x00, reason: No information given, then this is usualy because your MRZ key is incorrect, and possibly because your passport number is not quite right. If your passport number in the MRZ contains a '<' then you need to include this in the MRZKey - the checksum should work out correct too. For more details, check out App-D2 in the ICAO 9303 Part 11 document (https://www.icao.int/publications/Documents/9303_p11_cons_en.pdf)

    e.g. if the bottom line on the MRZ looks like: 12345678<8AUT7005233M2507237<<<<<<<<<<<<<<06

    In this case the passport number is 12345678 but is padded out with an additonal <. This needs to be included in the MRZ key used for BAC. e.g. 12345678<870052332507237 would be the key used.

To do

There are a number of things I'd like to implement in no particular order:

  • Finish off PACE authentication (CAM, DH-IM)

Thanks

I'd like to thank the writers of pypassport (Jean-Francois Houzard and Olivier Roger - can't find their website but referenced from https://github.com/andrew867/epassportviewer) who's work this is based on.

The EPassport section on YobiWiki (http://wiki.yobi.be/wiki/EPassport) This has been an invaluable resource especially around Passive Authentication.

Marcin Krzyżanowski for his OpenSSL-Universal repo.

About

NFCPassportReader for iOS 13

Topics

epassportios-swiftios13nfcpassportswift

Resources

Readme
MIT license

Code of conduct

Code of conduct
Activity

Stars

868 stars

Watchers

46 watching

Forks

336 forks
Report repository

Releases

Packages

Used by

Contributors

Languages

You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.