A library for reading and evaluating VDS-NC as defined by ICAO Doc 9303 in iOS apps

VDS-NC Checker iOS Library

This library handles parsing and verifying the authenticity of VDS-NC JSON data as defined in the VDS-NC Visible Digital Seal for non-constrained environments specification

Requirements

  • Swift 5.0
  • iOS 13.0+ | macOS 10.15+
  • Xcode 13

Usage

Swift

  1. In order to make the framework available, add import VDSNCChecker at the top of the Swift source file

import VDSNCChecker

Certificate Repository

Before any VDS verification occurs, there must be CSCA certificates set up in the certificate repository.

let cscaCertData = Data() // CSCA certificate data
let cscaCertSHA256Hash = "..." // SHA256 hash of the CSCA certificate data (as a lowercase hex string)
let crlData = Data() // CRL data 

CertificateRepository.shared().cscaCertificates = []
               
// create CRL object, with some intial data, and the URL that will be used to make sure the data is updated
let ausCrl = CRL.init(updatingURL:ausCrlUrl, initialCrlData: crlData)

// create a CSCA certificate, with the CRL we just set up
let cscaCertificate = CSCACertificate(data: cscaCertData, integrityHash: cscaCertSHA256Hash, crl: ausCrl)

// add the CSCA certificate to the repositiory
CertificateRepository.shared().cscaCertificates.append(cscaCertificate)

// start auto updating CRLs using the default time between updates
CertificateRepository.shared().startAutoUpdatingCRLData()

If you want to manually configure the time between CRL updates, or specify the time period of where the CRL update is deemed overdue:

// specify the time period in which the update becomes overdue as every 3 days
CertificateRepository.shared().maxSecondsBeforeOverdue = 86400 * 3

// specify the time between updates as every 1 day
CertificateRepository.shared().startAutoUpdatingCRLData(secondsBetweenUpdates: 86400) 

Conform to the CertificateRepositoryDelegate protocol to be notified when a CRL data update has been performed:

extension YourViewController: CertificateRepositoryDelegate {
    public func didUpdateCRLData() {
        // do something
    }
}

Scanning and auto-validating a VDS

First, ensure you have requested permission to use the camera before using the ScanViewController, please see the example app for more.

Configure the ScanViewController, and display:

// configure
var configuration = ScanViewController.Configuration()
configuration.navigationTitle = "VDS-NC Checker"
configuration.hidesBackButton = false
configuration.torchEnabled = true
configuration.zoomEnabled = true
configuration.dimBackground = false
configuration.invalidVdsNcLabelText = "This code is not a VDS-NC"
configuration.guideLabelText = "Align QR code within frame"

// show scan screen
let scanViewController = ScanViewController(configuration: configuration, delegate: self)
navigationController?.pushViewController(scanViewController, animated: animated)

Make sure that your view controller conforms to the ScanViewControllerDelegate protocol:

extension YourViewController: ScanViewControllerDelegate {
    func didTapRightBarButton() {
   
    }
    
    func didDetectNonVdsQrCode() {
        // Not a VDS
        print("This is not a VDS.")
    }
    
    func didFailVDSVerification(vdsVerificationError: VDSVerifyError?) {
        // VDS is not authentic
        print("This is not an authentic VDS. It may have been tampered with.")
    }
    
    func didSuccessfullyVerifyVds(vds: VDS) {
        // VDS is authentic

        // Access data from the VDS
        print("This is an authentic VDS. The name of the person stored in the VDS is \(vds.data.msg.pid.n)")

    }
}

Validating a VDS manually

If you have the VDS JSON string via from another QR scanning implementation, you can simply use only the verification, and pass in the CSCA certificates.

let vdsJson = "..." // VDS JSON string obtained from reading the QR code

// Decode VDS from the JSON string
let vds = try? VDSReader().decodeVDSFrom(jsonString: vdsJson)

// Authenticate VDS
let vdsAuthenticator = VDSAuthenticator()
if let vds = vds {
    // Verify VDS using the CSCA certificates
    if let _ = try? vdsAuthenticator.verify(
        vds: vds,
        cscaCertificates: CertificateRepository.shared().cscaCertificates
    ) {
        // VDS is authentic

        // Access data from the VDS
        print("This is an authentic VDS. The name of the person stored in the VDS is \(vds.data.msg.pid.n)")
    } else {
        // VDS is not authentic
        print("This is not an authentic VDS. It may have been tampered with.")
    }
} else {
    // JSON is not a VDS
    print("This is not a VDS.")
}

Please see VDSNCCheckerTests.swift for a full list of test scenarios and example VDS, CSCA certificate and CRL data.

Displaying a VDS

The VDS class is a model class that stores the data parsed from VDS-NC JSON data. It has the following properties:

Property Purpose
VDS
data Data. The actual data for the VDS, including version, person info, vaccination info, etc.
sig Signature. The cryptographic signature used to verify the authenticity of the data.
Data
data.hdr Header. Includes type of data, version and issuing country.
data.msg Message. Includes person and vaccination info.
Header
data.hdr.t Type of data. Can be either icao.test or icao.vacc. Other types possible in the future. Required.
data.hdr.v Version. Required.
data.hdr.hdrIs Issuing country. In 3 letter country code format (e.g. AUS). Required.
Message
data.msg.uvci Unique vaccination certificate identifier. Required.
data.msg.pid Person identification info. Required.
data.msg.ve Array of vaccination events. Required.
data.msg.pid.dob Date of birth. In yyyy-MM-dd format. Required if i (travel document number) is not provided.
data.msg.pid.n Name. A double space separates first and last name (e.g. JANE CITIZEN). May be truncated. Required.
data.msg.pid.sex Sex. M for male, F for female or X for unspecified.
data.msg.pid.i Unique travel document number.
data.msg.pid.ai Additional identifier at discretion of issuer.
Vaccination Events
data.msg.ve.des Vaccine type/subtype. Required.
data.msg.ve.nam Brand name. Required.
data.msg.ve.dis Disease targeted by vaccine. Required.
data.msg.ve.vd Array of vaccination details. Required.
Vaccination Details
data.msg.ve.vd.dvc Date of vaccination. In yyyy-MM-dd format. Required.
data.msg.ve.vd.seq Dose sequence number. Required.
data.msg.ve.vd.ctr Country of vaccination. In 3 letter country code format (e.g. AUS). Required.
data.msg.ve.vd.adm Administering center. Required.
data.msg.ve.vd.lot Vaccine lot number. Required.
data.msg.ve.vd.dvn Vaccine lot number. Required.
Signature
sig.alg Crypto algorithm used for the signature. Can be either ES256, ES384 or ES512 (typically ES256). Required.
sig.cer Certificate used for the signature. In Base64 URL encoding (not the same as normal Base64!). Required.
sig.sigvl Signature value. In Base64 URL encoding (not the same as normal Base64!). Required.

Glossary

BSC – Barcode signing certificate. This is the certificate used by issuing authorities to sign the barcode data in a VDS to ensure it’s authentic.

CRL – Certificate Revocation List. A certificate may be revoked by its issuing authority in the instance of the certificates private key becoming compromised, as which point any data signed with said certificate can no longer be trusted. Further information here.

CSCA – Country Signing Certificate Authority. ​Each State issuing an ePassport establishes a single Country Signing Certification Authority (CSCA) as its national trust point in the context of ePassports. Further information here.

VDS – Visible Digital Seal. This is the visible, scannable code on a document which can be machine read to verify the integrity of the document. Full specification here.

API Definition

See Documentation in Xcode for full API definition of this library.

Acknowledgements

This library uses:

GitHub

View Github