NFC chip reading
The chip on Turkish ID cards and passports is read with PassportReader. Accessing the chip needs the document’s serial number, date of birth and expiry date; take them from the document capture result (capturedData) and let the user confirm them.
iOS shows its own NFC sheet while reading; the SDK sets its texts. Set up the NFC capability first.
1. Set up the reader
Section titled “1. Set up the reader”import passport_readerimport ProveIDApiClient
final class NFCViewController: UIViewController { var transactionId = "" var documentNumber = "" // capturedData.sno var birthDate = "" // capturedData.bdat, dd.MM.yyyy var expireDate = "" // capturedData.edat, dd.MM.yyyy
private var passportReader: PassportReader?
override func viewDidLoad() { super.viewDidLoad()
PassportReader.PACE_ENABLED = true LocalNFCCommandTransmitter.NFC_START_MESSAGE = "Place the top of your phone on the middle of your ID card and hold still."
passportReader = PassportReader(commandTransmitter: LocalNFCCommandTransmitter(), progressMessage: { input in ProgressMessageOutput(alertMessage: "Reading…") }, errorMessage: { input in ErrorMessageOutput(alertMessage: "Reading failed.", suppressError: false) }) startReading() }}progressMessage and errorMessage set the text on the iOS NFC sheet. input.nfcOperationType and input.progress tell you how far reading has got; input.error the error (see Errors).
2. Get a nonce and read the chip
Section titled “2. Get a nonce and read the chip”Get a transaction-specific nonce from Prove ID for active authentication, then start reading:
func startReading() { IDServiceAPI.generateNonce(body: NonceGeneratorModel(transactionId: transactionId)) { result in switch result { case .success(let response): DispatchQueue.main.async { self.read(nonce: response.nonce) } case .failure(let error): showError(error) } }}
func read(nonce: String?) { let formatter = DateFormatter() formatter.dateFormat = "dd.MM.yyyy" formatter.timeZone = TimeZone(secondsFromGMT: 0)
guard let birth = formatter.date(from: birthDate), let expire = formatter.date(from: expireDate) else { // Ask the user to correct the dates return }
passportReader?.read(documentNumber: documentNumber, birthDate: birth, expireDate: expire, nonce: nonce, callback: self)}extension NFCViewController: PassportReaderCallback { func result(passportModel: PassportModel) { // Send the chip data for validation (below) }
func progress(progressType: NFCOperationType, progress: Double) { // START, AUTHENTICATION, DG1, DG2, DG11, DG12, DG14, DG15, SOD, ACTIVE_AUTHENTICATON, CHIP_AUTHENTICATION, SUCCESS }
func error(error: Error) { // See Errors }}3. Validate the chip data
Section titled “3. Validate the chip data”let validation = IDValidationModel(dg1: passportModel.getDg1()!, dg2: passportModel.getDg2()!, sod: passportModel.getSod()!, dg11: passportModel.getDg11(), dg12: passportModel.getDg12(), dg14: passportModel.getDg14(), dg15: passportModel.getDg15(), nonce: passportModel.getNonce(), signedData: passportModel.getSignedData(), mseResp: passportModel.getCaMseResponse(), gaResp: passportModel.getCaGaResponse(), probeResp: passportModel.getCaProbeResponse(), accessProtocol: passportModel.getAccessProtocol()?.value)
let body = ValidationInputModel(validationInformation: validation, idType: "IDCARD", transactionId: transactionId)
IDServiceAPI.validateAndSaveIDCard(body: body) { result in switch result { case .success(let response): let controls = response.controlResults showNfcResult(controls) case .failure(let error): showError(error) }}Chip authentication
Section titled “Chip authentication”With chip authentication the chip proves it is genuine and not cloned. The keys for it are kept on Prove ID, never in the app: the SDK asks your ChipAuthenticationBackend to prepare the commands, and you forward the request to Prove ID.
final class ChipAuthenticationBackendImpl: ChipAuthenticationBackend { var transactionId = ""
func prepareCA(dg14Bytes: String, completed: @escaping (ChipAuthenticationPlan?, Error?) -> Void) { let body = CAPrepareInputModel(transactionId: transactionId, dg14: dg14Bytes) IDServiceAPI.prepareCA(body: body) { result in switch result { case .success(let output): guard let mse = output.mseApdu, let ga = output.gaApdu, let probe = output.probeApdu else { completed(nil, NSError(domain: "ChipAuthentication", code: -1, userInfo: [NSLocalizedDescriptionKey: output.message ?? ""])) return } completed(ChipAuthenticationPlan(mseApdu: mse, gaApdu: ga, smProbeApdu: probe), nil) case .failure(let error): completed(nil, error) } } }}let backend = ChipAuthenticationBackendImpl() // keep a strong referencebackend.transactionId = transactionId
PassportReader.DO_CHIP_AUTHENTICATION = truePassportReader.CHIP_AUTHENTICATION_BACKEND = backendThe chip authentication responses are sent with the chip data in IDValidationModel (mseResp, gaResp, probeResp).
Reader settings
Section titled “Reader settings”| Setting | Description |
|---|---|
PassportReader.PACE_ENABLED |
Uses PACE to access the chip when the document supports it |
PassportReader.DO_CHIP_AUTHENTICATION |
Runs chip authentication |
PassportReader.CHIP_AUTHENTICATION_BACKEND |
Your ChipAuthenticationBackend |
PassportReader.SUPPRESS_ACTIVE_AUTH |
Continues reading if active authentication fails |
PassportReader.SUPPRESS_CHIP_AUTHENTICATION |
Continues reading if chip authentication fails |
LocalNFCCommandTransmitter.NFC_START_MESSAGE |
Text on the iOS NFC sheet when reading starts |
PassportReaderEvent.logLevel |
Log level of the SDK (.none in production) |
PassportReaderEvent.listener |
An EventListener that receives the SDK’s log events |