Skip to content

Usage Guide

Quick Start

Initialize EmrtdReader, load a CSCA master list, and call readAndVerify:

swift
import KinegramEmrtd

// master list containing Country Certificates from a trusted source.
let masterListURL = Bundle.main.url(forResource: "masterlist", withExtension: "ml")!

// Initialize EmrtdReader
let emrtdReader = EmrtdReader() 
try emrtdReader.readMasterlist(from: masterListURL) 

// Access Key values from the MRZ
let mrzKey = MRZKey(
    documentNumber: "123456789",
    birthDateyyMMdd: "970101",
    expiryDateyyMMdd: "211212"
)

do {
    let emrtdResult = try await emrtdReader.readAndVerify(accessKey: mrzKey) 

    // MRZ Info from mandatory DataGroup 1
    if let dg1File: DataGroup1File = emrtdResult.dg1File {
        let documentNumber = dg1File.documentNumber
        // ...
    }

    // Photo of the face from mandatory DataGroup 2
    if let faceInfo: BiometricFaceImageInfo = emrtdResult.dg2File?.faceInfos?.first {
        let faceUIImage: UIImage? = faceInfo.uiImage
    }

    // Integrity and Authenticity of the read DataGroups
    let passiveAuthentication = emrtdResult.passiveAuthenticationResult
    // Active Authentication Result { SUCCESS, FAILED, UNAVAILABLE }
    let activeAuthentication = emrtdResult.activeAuthenticationResult
    // Chip Authentication Result { SUCCESS, FAILED, UNAVAILABLE }
    let chipAuthentication = emrtdResult.chipAuthenticationResult
} catch {
    // Handle EmrtdReaderError
    print("Error reading eMRTD: \(error)")
}

INFO

CSCA master list You must provide a CSCA master list to verify the eMRTD (ICAO Doc 9303 Part 12). The German Federal Office for Information Security (BSI) publishes an extensive and regularly updated CSCA master list.

Using With CAN

For documents that support PACE with a Card Access Number (a 6-digit number printed on the document):

swift
let canKey = CANKey(can: "123456")
let emrtdResult = try await emrtdReader.readAndVerify(accessKey: canKey)

INFO

CAN authentication only works with documents that support PACE (Password Authenticated Connection Establishment). It cannot be used with BAC (Basic Access Control).

Reading Without Verification

If you only need to read the data without verifying authenticity:

swift
let emrtdResult = try await emrtdReader.read(accessKey: mrzKey)

Reading Selected Data Groups

By default, a read returns DG1 (MRZ), DG2 (face image), and the optional data groups a document commonly carries. If you only need some of them, pass a DataGroupSet — reading less is faster, because DG2 alone accounts for most of the reading time:

swift
// MRZ and face image only
let emrtdResult = try await emrtdReader.readAndVerify(
    accessKey: mrzKey,
    filesToRead: .minimalKYC 
)

The same parameter is available on read. Besides the predefined selections you can combine data groups freely, e.g. [.dg1, .dg11].

SelectionData GroupsUse Case
.minimalDG1MRZ data alone, no biometrics
.minimalKYCDG1, DG2MRZ plus face image
.standardDG1, DG2, DG7, DG11, DG12Same as a read without a selection
.allDG1 – DG16All sixteen data groups

How a selection behaves:

  • The SOD is always read, and Passive Authentication covers the data groups that were actually read.
  • Selected data groups the document does not contain are skipped.
  • DG1 and DG2 must read successfully while they are part of the selection, otherwise the call fails with EmrtdReaderError.IncompleteRead.

INFO

DG14 and DG15 are inputs to Chip and Active Authentication: readAndVerify reads them whenever the document carries them, no matter what the selection says. Only the non-verifying read treats them as ordinary data files that are read when selected — .standard does not include them.

See Relevant Data Groups for what each data group contains.

Reading PACE-Enabled Documents

Some identity documents require PACE polling to be detected. This includes French ID cards (FRA ID), Omani ID cards (OMN ID), and newer generation Netherlands passports.

To read these documents, use the usePACEPolling parameter (requires iOS 16+):

swift
let canKey = CANKey(can: "123456")
do {
    let emrtdResult = try await emrtdReader.readAndVerify(
        accessKey: canKey,
        usePACEPolling: true
    )
    // Process result...
} catch EmrtdReaderError.PACEPollingNotAvailable {
    // PACE polling requires iOS 16 or later
    print("PACE polling is not available on this iOS version")
} catch {
    print("Error reading document: \(error)")
}

WARNING

PACE polling is only available on iOS 16 and later. The SDK will throw a PACEPollingNotAvailable error if you attempt to use it on iOS 15 or earlier. PACE polling cannot detect standard passports, use it only when you know the document requires it.

Error Handling

The SDK uses Swift's native error handling. Errors are thrown as EmrtdReaderError:

swift
do {
    let emrtdResult = try await emrtdReader.readAndVerify(accessKey: mrzKey)
} catch EmrtdReaderError.IncorrectAccessKey {
    print("Wrong MRZ/CAN values")
} catch EmrtdReaderError.ConnectionLost {
    print("NFC connection lost - hold phone steady")
} catch EmrtdReaderError.PaceOrBacFailed(let error) {
    print("Access Control failed: \(error)")
} catch EmrtdReaderError.FileReadFailed(let error, let files) {
    print("Failed to read files: \(files)")
} catch {
    print("Error: \(error)")
}

Error Types

ErrorDescription
NFCNotSupportedNFC is not supported on this device
MoreThanOneTagFoundMore than one NFC tag was found
WrongTagWrong NFC tag was found (expected ISO 7816 tag)
UserInvalidatedSessionSession was canceled by the user
SessionInvalidatedNFC session was invalidated (e.g. timeout)
ConnectingFailedFailed to connect to chip
ConnectionLostChip connection lost
PaceOrBacFailedAccess Control failed
IncorrectAccessKeyAccess Key is incorrect
FileReadFailedFailed to read file(s) from the chip
IncompleteReadMandatory file(s) missing after reading
PACEPollingNotAvailablePACE polling requires iOS 16 or later

Localization

The SDK displays English messages in the NFC dialog by default. You can customize these by providing localization closures when initializing EmrtdReader:

swift
func errorLocalization(error: EmrtdReaderError) -> String {
    switch error {
    case .NFCNotSupported(_):
        return ""
    case .MoreThanOneTagFound:
        return ""
    case .WrongTag:
        return ""
    case .UserInvalidatedSession:
        return ""
    case .SessionInvalidated(let errorCode):
        return ""
    case .ConnectingFailed(let error):
        return ""
    case .ConnectionLost:
        return ""
    case .PaceOrBacFailed(let error):
        return ""
    case .FileReadFailed(let error, let files):
        return ""
    case .IncorrectAccessKey:
        return ""
    case .PACEPollingNotAvailable:
        return ""
    @unknown default:
        return "Unknown Error"
    }
}

func stepLocalization(step: ReadAndVerifyStep) -> String {
    switch step {
    case .waitingForPassport:
        return ""
    case .readFileAtrInfo:
        return ""
    case .readFileCardAccess:
        return ""
    case .doPaceOrBac(_):
        return ""
    case .readFileSOD:
        return ""
    case .readFileDG14:
        return ""
    case .doChipAuthenticationIfAvailable(_):
        return ""
    case .readFileDG15:
        return ""
    case .doActiveAuthentication(_):
        return ""
    case .readRemainingElementaryFiles:
        return ""
    case .doPassiveAuthentication:
        return ""
    case .done:
        return ""
    @unknown default:
        return "Unknown Step"
    }
}

func fileReadProgressLocalization(
        fileName: ElementaryFileName,
        readBytes: Int,
        totalBytes: Int) -> String {
    return "Reading File \(fileName) (\(readBytes)/\(totalBytes) Bytes)"
}

let emrtdReader = EmrtdReader(
    errorLocalization: errorLocalization,
    stepLocalization: stepLocalization,
    fileReadProgressLocalization: fileReadProgressLocalization
)

Default Step Messages

StepDefault Message
waitingForPassport"Place the iPhone with direct contact to the document"
readFileAtrInfo"Reading File AtrInfo"
readFileCardAccess"Reading File CardAccess"
doPaceOrBac"Performing Access Control"
readFileSOD"Reading File SOD"
readFileDG14"Reading File DG14"
doChipAuthenticationIfAvailable"Performing Chip Authentication"
readFileDG15"Reading File DG15"
doActiveAuthentication"Performing Active Authentication"
readRemainingElementaryFiles"Reading Elementary Files"
doPassiveAuthentication"Finishing Verification"
done"Done"