SDK for iOS
Introduction
The IDEMIA VerifyPro SDK for iOS provides customers with the resources to customize the SDK to their preferred user-experience and integrate it within an existing mobile application. The IDEMIA Mobile ID Verify App works in conjunction with the IDEMIA Mobile ID App allowing verifiers to authenticate the user's physical ID or digital credential (i.e., drivers license or identity card).
You can use the iOS SDK to:
-
**Create and design your preferred user-experience and UI while leveraging the IDEMIA VerifyPro functionalities **
You can build a custom mobile application that implements your user-experience design and leverages all of the SDK functionalities allowing you to apply your branding and preferred user flow. Maintain complete control over the display and functionality of the application.
-
**Embed IDEMIA VerifyPro into an existing application **
You can automatically integrate an existing mobile application with IDEMIA by adding the SDK frameworks, which removes the need to use and maintain an additional application to leverage the Mobile ID's functionalities.
Get started
Skills required
The integration tasks require developers to have knowledge of:
- iOS frameworks built in Xcode 15.1 or higher
- Swift 5.0 or higher
- Mac OS 14.1 or higher
Resources required
The tools required for integration on macOS are:
- Xcode 15.1 or above
- iOS SDK tools: release 15.x to 18 Beta
- Physical iOS device (simulator is not supported)
Other requirements
External Libraries
- pod 'SwiftCBOR', '0.4.7'
- pod 'EventsEmitter', '0.0.2'
User permission
When designing your app,consider that your iOS app must handle user permissions to protect the resources on the target mobile device. Specifically, you must verify that the app permissions are granted by the user. If the required permissions are not granted, the SDK will throw an exception or error and may even crash.
The following user permission are required:
- Camera permission for the QR code scan
- Bluetooth permission for the BLE data transfer
- NFC permission for the device engagement
The required permissions in the app info.plist
file are:
- Privacy: Bluetooth Always Usage Description
- Privacy: Bluetooth Peripheral Usage Description
- Privacy: Camera Usage Description
- Privacy: NFC Usage Description
Capability
If the integrator wants to use NFC as Device Engagement.
The following steps are required:
Project Target -> Signing & Capabilities -> + Capability -> Near Field Communication Tag Reading
Create your own app
If you already have access for Mi-Artifactory, download the sample app: https://mi-artifactory.otlabs.fr/artifactory/verify-pro-sdk-ios-release/com/idemia/idverify/ios/4.2.0/Sample/4.2.0-sample-ios.zip
To create your own app, you must add the following SDK libraries to your project. You can add these libraries manually as shown in Option A, or through CocoaPods as shown in Option B.
Add SDK libraries
The Podfile specifies the dependencies of each target, and the SDK pods are used to declare a specific dependency. The target
scopes the pod dependencies to specific targets in your Xcode project.
Required pods
- pod 'SwiftCBOR', '0.4.7'
- pod 'EventsEmitter', '0.0.2'
Option A: Import VerifyPro SDK manually
The manual method allows you to import the SDK files using VerifyPro.framework
using the steps below:
-
Download the
VerifyPro.framework
andTester app
from the mi-artifactory: https://mi-artifactory.otlabs.fr/artifactory/webapp/#/artifacts/browse/tree/General/verify-pro-sdk-ios-release/com/idemia/idverify/ios/ -
Add the
VerifyPro.framework
file to your project by pasting this file in project folder at path:~/Frameworks/VerifyPro.framework
. -
Link and Embedd
VerifyPro.framework
to your project by dragging and dropping it on Project Settings (General > Frameworks, Libraries, and Embedded Content). -
At the top of your project
Podfile
add the lines shown in the snippet:Swift1plugin 'cocoapods-art', :sources => [2 'master' # so it could resolve dependencies from master repo (the main one)3] -
Add following pod dependency (Follow the 1,2 steps from section Option B for repository access)
- pod 'SwiftCBOR', '0.4.7'
- pod 'EventsEmitter', '0.0.2'
-
Add the following line in end of your Podfile (refer the sample code) to avoid linker error of any pod dependencies of VerifyPro.
Swift1post_install do |installer|2 installer.pods_project.targets.each do |target|3 target.build_configurations.each do |config|4 config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET'5 config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'6 end7 end8 end
Option B: Import VerifyPro SDK through CocoaPods with other dependencies (Recomended option)
Alternatively, the CocoaPods method allows you import the SDK files using CocoaPods (along with cocoapods-artplugin) using these steps.
-
If you don't already have CocoaPods with the Artifactory tool, install it by running the following command as shown in the snippet:
Swift1gem install cocoapods-art -
The plugin uses authentication that is specified in a standard .netrc file, as shown in the snippet:
Swift1machine mi-artifactory.otlabs.fr2login ##USERNAME##3password ##PASSWORD## -
At the top of your project
Podfile
add the lines shown in the snippet:Swift1plugin 'cocoapods-art', :sources => [2 'verify-pro-sdk-ios-release', # so it could resolve dependencies for VerifyPro3 'master' # so it could resolve dependencies from master repo (the main one)4]NOTE: If you do not have podfile already created, use the following commands to create one
Swift1pod init -
Once set, add our repository to your CocoaPod's dependency management system as shown in the snippet:
Swift1pod repo-art add verify-pro-sdk-ios-release "https://mi-artifactory.otlabs.fr/artifactory/api/pods/verify-pro-sdk-ios-release" -
Add the
VerifyPro
SDK in yourPodfile
in one of its pod's version, as shown in the snippet:Swift1pod 'VerifyPro', '~> 4.2.0.131' # VerifyPro SDK -
Now
install
orupdate
as shown in the snippet:Swift1pod install or pod updateNOTE: If you are already using our repository, and you cannot resolve some dependency, try to update the specs:
Swift1pod repo-art update verify-pro-sdk-ios-release -
Add the following line in end of your Podfile (refer the sample code) to avoid linker error of any third party dependencies of Verify.
Swift1post_install do |installer|2 installer.pods_project.targets.each do |target|3 target.build_configurations.each do |config|4 config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'5 end6 end7 end
SDK API’s and methods
The SDK is made up of following components:
IDVerify
Acts as the Entry Point for initializing device engagement, sending the request, by preparing a connection to the Mobile ID holder, receiving a response, and sending parsed model back to the calling app
-
initializeSdk
Language not specified1/* Call this method to initialize the sdk. It's manadatory to call this api before calling any other api. This API should be called before calling any other api.2 @param lkmsConfigs: License configs object containing valid credentials.3 @param Parameter callback: LicenseCallback object to be retuened based on the result.4 */5 public static func initializeSdk(lkmsConfigs: LkmsConfig, callback: LicenseCallback) {6 } -
initDeviceEngagement
Language not specified1/* Call this method from UI Application to parse the scanned qrcode2- @param configParams: Send the parameters e.g. inputData, license attribute params e.g. AGE_OVER_NN3- @param responseCallback: callback to receive the model object/errors corresponding to the passed-in QRCode4*/5public func initDeviceEngagement(apiConfig configParams: ApiConfigs?, responseCallback: UIViewController) -
prepareConnection
Language not specified1/* Initialize and setup connection components as per`ConnectionConfigs` configurations supplied2- @param configParams: configurations for connection related information3- @param callback: callback to connection status back to app4- Create communication channel (BLE) as per device engagement data5 */6 public func prepareConnection(configParams: ConnectionConfig?, responseCallback: (Any)?) -
sendRequest
Language not specified1/* send request to Mobile ID based on the use case selected by user in Verify application2- @param apiConfigs: configurations and optional MID request params3- @param callback: callback to send progress and response data back to app4- 1. create Mobile ID request based on supplied USECASE or parameres/configs5- 2. onCreate communication channel (BLE/NFC/wifiAware ...) as per engagement data6- 3. send request to Mobile ID on communication chanel7- Note- In future we may also use USECASE : use case identifier required to prepare desired request data8 */9 public func sendRequest(apiConfig configParams: ApiConfigs?, responseCallback: UIViewController) -
terminateConnection
Language not specified1/* Terminate connection available with Mobile ID.2- @param responseCallback: callback to receive the model object/errors corresponding to the passed-in qrcode3- @param cancellationReason: Send the enum of cancellationReason e.g. TIMEOUT, CANCELED_BY_USER, CONNECTION_ERROR and NONE4 */5 public func terminateConnection(responseCallback: Any?, cancellationReason: CancellationReason) -
terminateSession
Language not specified1/* It terminate the current session and terminate the connection as well.2- @param responseCallback: callback to receive the model object/errors corresponding to the passed-in qrcode3- @param cancellationReason: Send the enum of cancellationReason e.g. TIMEOUT, CANCELED_BY_USER, CONNECTION_ERROR and NONE4 */5 public func terminateSession(responseCallback: Any?, cancellationReason: CancellationReason) -
loadCertificates
Language not specified1/* Load IACA certificates from given path by application (libraryDirectory path)2 - @param path is the Directory (libraryDirectory type) folder name(created by integrator)from where SDK will load the certificate, refer the sample.3 - @param responseCallback is callback to return success(will return loaded certificate count) or error4 */5 public func loadCertificates(path: String?, responseCallback: Any?)67* Using the direct IACA certificates loading.8How to create directory structure for hosting IACA files for your Reader app?9- Create the libraryDirectory named "idemiacerts" which should be accecisble at runtime10- Copy or download IACA files at the libraryDirectory named "idemiacerts"11- Refer the sample application for code snippet.[Class - VenderCertificateManager.swift]121314* Using Vical Structure for IACA loading15How to create directory structure for hosting vical files for your Reader app?16- Create the libraryDirectory named "idemiavical" which should be accecisble at runtime17- Copy below directory structure containing vical files in "idemiavical" folder.18- Create new directory Vical inside "idemiavical" and copy .vical and .pem files for each environment as per below structure.19- Refer the sample application for code snippet.[Class - VenderCertificateManager.swift]20 idemiavical/Vical21 /Dev22 - iaca.vical23 - iaca.vical.pem24 /UAT25 - iaca.vical26 - iaca.vical.pem27 /PROD28 - iaca.vical29 - iaca.vical.pem3031 How To configure vical from app directory?32- Create 'BundleFolder/Vical' folder in app bundle. Refer the sample application.33- Copy vical file and corresponding ca cert file per environment similar to structure defined above.34- Set value as "idemiavical" for `path` while calling `loadCertificates` api and verifySDK will get the file from "idemiavical" library path folder.
Api implementation steps
- Initialize the ID Verify SDK by providing a valid license information in
initializeSDK
API. Best way to do it is when your application's Home View Controller is loaded:
Swift1HomeViewController: LicenseCallback {23 override func viewDidLoad() {4 // Use following code to initialize SDK with your license configuration provided5 let lkmsConfig = LkmsConfig(serverUrl: LICENSE_URL, profileId: PROFILEID, apiKey: APIKEY)6 IDVerify.initializeSdk(lkmsConfigs: lkmsConfig, callback: self)7 }89 //MARK: onSuccess10 func onSuccess() {11 print("License retrieved successfully")12 }1314 //MARK: onError15 func onError(error: Any?) {16 print("License error")17 }18}
-
Scan the QR codes or NFC Tags as shown in the snippet:
Swift1/**2 * Response callback for parse engagement QR code data or **Mobile ID** credential holder3 */4 //MARK: parsed QRCode5 func parsedDataForQRCode(trimmedQRCode: String){6 DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + 0.2) {7 let config = self.formAndReturnAppConfigsParamForAPI(qrString: trimmedQRCode)8 sharedVSDKClient?.initDeviceEngagement(apiConfig: config, responseCallback: self)9 }10 }1112 // Returns ApiConfigs with all the parameters13 func formAndReturnAppConfigsParamForAPI(qrString qr: String?) -> ApiConfigs? {14 guard let tempQRString = qr else {15 return nil16 }1718 // Build app configs for BLE19 let apiConfigs = ApiConfigs.ConfigBuilder()20 .withData(inputData:tempQRString)21 .build()22 return apiConfigs2324 // Build app configs for NFC Engagement25 let apiConfigs = ApiConfigs.ConfigBuilder()26 .useNFC()27 .build()28 return apiConfigs29 } -
After scanning the QR successfully, you will get the result response in
onSuccess
as shown in the snippet:Swift1func onSuccess(response: Any?){2 }3 func onError(error: VerifyError){4 } -
Call prepareConnection API
The
prepareConnection()
method will prepare the connection based on device engagement with Mobile ID credential. If it received successfully, Integrator can send the request on prepared connection channel.Swift1// Set 'ConnectionConfig' as follows for setting the connection related information.23let connectionConfig = ConnectionConfig()4 .setConnectionType(type: ConnectionType.BLE)5sharedVSDKClient?.prepareConnection(configParams: connectionConfig, responseCallback: self)Swift1// Set 'setL2CapRequestSupport' as true to enable L2CAP mode during BLE communication.23let connectionConfig = ConnectionConfig()4 .setConnectionType(type: ConnectionType.BLE)5 .setL2CapRequestSupport(l2CapRequestSupportEnable: true)6sharedVSDKClient?.prepareConnection(configParams: connectionConfig, responseCallback: self)Swift1// prepareConnection api by using `connectionConfig` which you set earlier2sharedVSDKClient?.prepareConnection(configParams: connectionConfig, responseCallback: self)
Callback for the prepareConnection
API to receive connection status**.
Language not specified1```Swift23 /**4 * Request callback for the `prepareConnection` SDK API to receive connection status.5 */67 func connectionSuccessful(connectionType: ConnectionType) {8 }910 func connectionError(error: Any?) {11 }1213 func currentStatus(currentState: TransferState){14 }1516 func onConnectionCanceled(response: Any?) {17 }1819```
5. Send a request to the Mobile ID App to get the license details as shown in the snippet:
Language not specified1The `sendRequest()` method will return the response from the end-user's **Mobile ID** credential. If it's received it successfully, then all the attributes of the **Mobile ID App** response appear in the view controller.23```Swift4// Set 'appConfig' as follows if you want to use all attributes as optional parameters5var dataItems = getMandatoryParams()6dataItems.append(contentsOf: getOptionalParams())78let apiConfigs = AppConfigs.MIDRequestBuilder()9 .addParam(listParams: dataItems)10 .build()11```1213```Swift14// Set 'appConfig' as follows if you want to use only the suggested attributes as optional parameters15var dataItems = getOptionalParams() let apiConfigs =16AppConfigs.MIDRequestBuilder() .addParam(listParams: paramsList, useDefaults:17true) .build()18```1920```Swift21//Send the request by using `appConfig` which you set earlier22sharedVSDKClient?.sendRequest(apiConfig: apiConfigs, responseCallback: self)23}24```2526```Swift27// Sample code for L2Cap Support in Api config. Set L2CapRequestSupportEnable as true for enabling L2cap support.28let apiConfigs = ApiConfigs.MIDRequestBuilder()29 .version(version: MIDParamConstants.REQUEST_VERSION)30 .setL2CapRerquestInfo(L2CapRequestSupportEnable: true)31 .addParams(MIDParamConstants.NAMESPACE_18013_5,isoParamsList)32 .build()33```3435```Swift36// send request using new namespace and paramList support37 func sendrequest(){3839 var aamvaParamsList = [MIDRequestParam]()40 var namespaceParamList = [String: [MIDRequestParam]]()41 var isoParamsList = [MIDRequestParam]()42 isoParamsList.append(MIDRequestParam(paramName: MIDParamConstants.GIVEN_NAME))43 isoParamsList.append(MIDRequestParam(paramName: MIDParamConstants.FAMILY_NAME))44 isoParamsList.append(MIDRequestParam(paramName: MIDParamConstants.RESIDENT_ADDRESS))45 isoParamsList.append(MIDRequestParam(paramName: MIDParamConstants.RESIDENT_CITY))46 isoParamsList.append(MIDRequestParam(paramName: MIDParamConstants.RESIDENT_CITY))4748 namespaceParamList[MIDParamConstants.DOCTYPE_ORG_AAMVA_US] = aamvaParamsList49 namespaceParamList[MIDParamConstants.NAMESPACE_18013_5 ] = isoParamsList5051 let apiConfigs = ApiConfigs.MIDRequestBuilder()52 .version(version: MIDParamConstants.REQUEST_VERSION)53 .addDocType(docType: "my.cusom.docType.custom1") //example docType15455 //1. add56 .addParams(namespaceParamList)57 // add again to test if duplicates are removed58 .addParams(MIDParamConstants.NAMESPACE_18013_5,isoParamsList)59 //2. add more params one by one with custom namespce60 .addParam(MIDParamConstants.NAMESPACE_18013_5,MIDRequestParam(paramName: "custom_param1"))61 .addParam("my.custom.namespace",MIDRequestParam(paramName: "custom_param1"))6263 .addParam("my.custom.namespace",MIDRequestParam(paramName: "custom_param2"))64 .addParam("my.custom.namespace",MIDRequestParam(paramName: "custom_param3"))65 //duplicates will be removed66 .addParam("my.custom.namespace",MIDRequestParam(paramName: "custom_param1"))67 .addParam("my.custom.namespace",MIDRequestParam(paramName: "custom_param3"))68 //3. or add a custom namespace like this69 .addParams("my.custom.namespace2", [70 MIDRequestParam(paramName: "custom_param_nm21"),71 MIDRequestParam(paramName: "custom_param_nm22"),72 MIDRequestParam(paramName: "custom_param_nm23"),73 MIDRequestParam(paramName: "custom_param_nm21") ]//duplicate74 )7576 .buildDoc() //build doctype177 .addDocType(docType: "my.cusom.docType.custom2") //example docType278 .addParams("my.custom.namespace2", [79 MIDRequestParam(paramName: "custom_param_nm21"),80 MIDRequestParam(paramName: "custom_param_nm22"),81 MIDRequestParam(paramName: "custom_param_nm23"),82 MIDRequestParam(paramName: "custom_param_nm21") ]//duplicate83 )84 .buildDoc() //build doctype28586 .build()8788 //call sendRequest API89 sharedVSDKClient?.sendRequest(apiConfig: apiConfigs, responseCallback: self)90 // 3. Read request params supplied from app and make the request structure accordingly.9192}93```
6. Callback for the sendRequest
API to receive and display the response data from the Mobile ID App.
Language not specified1```Swift2/**3 * Request callback for the `sendRequest` SDK API to receive and display the response data from the mDL.4 */56func onSuccess(response: Any?){7}8func onError(error: VerifyError){9}10func onRequestCanceled(response: Any?){11}12func onProgress(totalBytesRecived: Int){13}14func onRequestSent(status: Bool?){15}16func currentBLEStatus(currentState: TransferState){17}1819// onSuccess callback method for handling Multi request reqsponse20func onSuccess(response: Any?, callback:MultiRequestCallback?) {21}2223// On next callback is used for sending next request in same session.24func onNext(apiConfigs:ApiConfigs){25}2627// Terminate connection method is used for terminate session in Multirequest.28func onTerminateConnection() {29}3031 /**Set Multi Request Info.32 - Parameter multiRequestEnable: Set for identify request is Multi Request supported33 - Returns: MIDRequestBuilder object34 */35public func setMultiRerquestInfo(multiRequestEnable: Bool) -> MIDRequestBuilder {36 self.isMultiRequest = multiRequestEnable37 return self38}3940// Sample code for multi request Api config41let apiConfigs = ApiConfigs.MIDRequestBuilder()42 .version(version: MIDParamConstants.REQUEST_VERSION)43 .setMultiRerquestInfo(multiRequestEnable: VerifyAppManager.sharedInstance.getMultiRequestMode() ?? false)44 .addDocType(docType: MIDParamConstants.DOCTYPE_18013_5)45 .addParams(MIDParamConstants.NAMESPACE_18013_5,isoParamsList)46 .addParams(MIDParamConstants.NAMESPACE_ORG_AAMVA_US,aamvaParamsList)47 .addRequestInfo(key: "attributesInfo", value: attributeInfoMap())48 .build()49 ```
Step and sample code for Reader Authentication(Signature only)[optional].
11. Add/Enable the callback in the RequestBuilder.232. Implement the readerAuthSignerCallback at app side. readerAuthSignerCallback provides the interface to perform signing of readerAuthentication structure. Verify SDK will call doSignRequest with the readerAuthentication structure to sign by the integrator with the reader private key. They will sign the bytes using certificate private key and return ReaderAuthSign data model with generated signature, algorithm used to sign and a x509 certificate with the corresponding public key of the private key that the readerAuthenticationBytes structure is signed.[Refer 9.1.4 mdoc reader authentication ISO/IEC FDIS 18013-5:2021(E) page 54]453. List the required resources e.g cert, keys at Integrator side.6An mdocReader private key to sign the Reader Auth structure. the resulting signature and algorithm used to sign shall be included within the mdoc request to be sent to mdoc.7CA signer certificate containing the corresponding public key of the private key used in signing which shall be sent to mdoc within the mdoc request. Integrator would submit a CSR to a valid CA to get a signer certificate.8(Optional) CA root certificate from CA which shall be shared by Reader to mDoc Holder which they can use to authenticate the signer certificate received within Reader Request
- You can cancel / terminate a transaction any time if an error occurs in the app as shown in the snippet:
Swift1sharedVSDKClient?.terminateConnection(responseCallback: Any?, cancellationReason: CancellationReason)
6.1. To terminate the running connection and session use terminateSession API. This API is available only in IDVerify client
Swift1sharedVSDKClient?.terminateSession(responseCallback: Any?, cancellationReason: CancellationReason)
-
You can get the SDK version by calling it directly with the class name as shown in the snippet:
Swift1IDVerify.version -
Added new configuration
setReaderAuthInfo
for reader authentication; here is a sample code snippet:Swift1let apiConfigs = ApiConfigs.MIDRequestBuilder()2 .version(version: MIDParamConstants.REQUEST_VERSION)3 .addDocType(docType: "org.iso.18013.5.1.mDL")4 .addParams(namespaceParamList)5 .buildDoc()6 .setReaderAuthInfo(readerAuthSignerCallback: self.callbackReceiverVC, signingAlgo: .ALGO_SHA256WITHECDSA)7 .withData(inputData: MOCK_QR_CODE_DATA_N1938)8 .build() -
Added new protocol
ReaderAuthSignerCallback
for reader authentication callback; here is a sample code snippet of implementation:Swift1extension ViewController: ReaderAuthSignerCallback {2 func doSignItemRequest(readerAuthenticationBytes: Data, docType: String) -> ReaderAuthSign? {3 //Generating Public Private KeyPair4 let keyPairDict = try? ECUtils.generateKeyPair()5 let privateKey = keyPairDict?["private"]6 //Generating Signature7 let signedDataSignature = (try? EncyptionDecryption.createSignature(privateKey: privateKey, dataToSign: readerAuthenticationBytes, algorithm: .ecdsaSignatureDigestX962SHA256)) ?? Data()8 //returning Signature and Certificate9 return ReaderAuthSign(signature: signedDataSignature, x509Certificate: x509CertSample.bytes.getData())10 }11} -
Call
loadCertificates()
API to load IACA certificates from given path(libraryDirectory path) and provides the number of certificats loaded as response(Int). This step is necessary for a successful transaction since VerifyPro SDK will validate the mDL response against the certificates from supplied path. Refer sample Application.
Swift1sharedVSDKClient?.loadCertificates(path: "CERTIFICATEDIRECTORY_NAME", responseCallback: self())2 func onSuccess(response: Any?){3 print("Certificate load success \(response)")4 }5 func onError(error: Any?){6 print(error)7 }
- Call
setDisconnectBleTimeout()
method to set BLE disconnect timeout time from app side. Default timeout is 3 sec.
Swift1let sharedClient = self.getVerifySDKClient()2 let configs = ApiConfigs.ConfigBuilder().withData(inputData: "").useBLE().setDisconnectBleTimeout(time: 5).build()
Step and sample code for CRL Data Downloader Callback [optional].
-
Added configuration
This integer specifies the timeout duration in seconds. If the CRL download takes longer than this period, the operation will be aborted to avoid delaying the transaction verification. This ensures that your application remains responsive even if the CRL download encounters issues. The default value of timeout is 3 seconds by SDK. here is a sample code snippet:setCRLDataDownloaderCallback
for IACA's CRL data download and send back to sdk for verification. "crLDownloaderCallback": The callback handler, This might be a delegate or a class that implements a specific method for processing the downloaded CRL data. "isCrlForceDownload": true or false: This parameter indicates whether the CRL should be downloaded forcefully, bypassing any cache or previously stored CRL data, the default value for isCrlForceDownload is false. timeoutSwift1public func setCRLDataDownloaderCallback(crLDownloaderCallback: CRLDataDelegate, timeout: Int, isCrlForceDownload: Bool) -> MIDRequestBuilderSwift1let apiConfigs = ApiConfigs.MIDRequestBuilder()2 .version(version: MIDParamConstants.REQUEST_VERSION)3 .addDocType(docType: "org.iso.18013.5.1.mDL")4 .addParams(namespaceParamList).buildDoc()5 .setCRLDataDownloaderCallback(crLDownloaderCallback: self, timeout: 5, isCrlForceDownload: true)6 .build() -
Added protocol
CRLDataDelegate
for CRL Data Downloader callback; here is a sample code snippet of implementation - you can refere the class "CRLDataCacheUtility.swift" from sample application. Returns Result with CRL data list or error if any.
Swift1extension ViewController: CRLDataDelegate {2 func fetchCRLData(from urls: [URL], completion: @escaping (Result<[Data], Error>) -> Void) {3 ///Here integrator can download the CRL data from given URL or uRLs and send back to SDK4 CRLDataCacheUtility().downloadData(from: urls, completion: completion)5 }6 }
Test and production apps
The VerifyPro SDK allows you to create a test app with the steps below. You can also use these steps to create your production application by changing the target
definition in your Podfile
to your Xcode production project.
-
Open your terminal and type the command "cd project_path" (the path to the project file where .xcodeproj file is located) and press
. -
Type the command "pod init" and press
. -
Go to the finder and open the pod file (in the same place where your .xcodeproj file is located).
-
Type the following in podfile under your target. In our case, the target is
VerifyIDTestApp
; change it according to your target in podfile and add the snippet shown:Language not specified1target 'VerifyIDTestApp' do2 use_frameworks!3 pod 'VerifyPro', '~> 4.2.0.131'45 target 'VerifyIDTestAppTests' do6 inherit! :search_paths7 # Pods for testing8 end910 target 'VerifyIDTestAppUITests' do11 # Pods for testing12 end -
Type the command “pod install” and then press
. -
Open .xcworkspace (i.e., at the same place where your .xcodeproj file is located).
-
Call
IDVerify.getClient
and initialize theIDVerify
shared object in theAppDelegate.swift
file as shown in the snippet:Swift1let config = Configs.Builder()2 .enableDebug(isDebuggable: isDebuggable)3 .build()45 sharedVSDKClient = IDVerify.getClient(configs: config)
Swift1/**2 * LogLevel enum : Option to set log levels. Integrator can pass multiple values as LogLevel Array.3 */4 VERBOSE - Use this option for all logs5 TRANSACTION_TIME - Use this option for time logs6 TROUBLESHOOTING - Use this option for troubleshooting logs7 DEBUG_NO_PII - Use this option for all NO-PII logs8 NONE - Use this option for No logs (Default Log level)
-
Use
enableDebug(logLevelArr: [LogLevel.VERBOSE])
for debugging purposes only if needed, as shown in the snippet:Swift1let config = Configs.Builder()2 .enableDebug(logLevelArr: [LogLevel.VERBOSE]) // multiple option can be passed. Default is LogLevel.NONE3 .build()456 **To get instance of IDVerify-**7 sharedVSDKClient = IDVerify.getClient(configs: config)
Request Parameters
The following table provides a list of attributes which can be configured for sendRequest
API.
Item# | Identifier | Param Name | CBOR Type |
---|---|---|---|
Namespace= "org.iso.18013.5.1" | |||
1 | ADMINISTRATIVE_NUMBER | administrative_number | Major type 3 |
2 | SEX | sex | Major type 3 |
3 | HEIGHT | height | Major type 0 |
4 | WEIGHT | weight | Major type 0 |
5 | EYE_COLOR | eye_color | Major type 3 |
6 | HAIR_COLOR | hair_color | Major type 3 |
7 | BIRTH_PLACE | birthplace | Major type 3 |
8 | RESIDENT_ADDRESS | resident_address | Major type 3 |
9 | PORTRAIT_CAPTURE_DATE | portrait_capture_date | Tag value 0 of major type 6 |
10 | AGE_IN_YEARS | age_in_years | Major type 0 |
11 | AGE_BIRTH_YEAR | age_birth_year | Major type 0 |
12 | AGE_OVER_NN | age_over_NN | Value 20/21 of major type 7 |
13 | ISSUING_JURISDICTION | issuing_jurisdiction | Major Type 3 |
14 | NATIONALITY | nationality | Major type 3 |
15 | RESIDENT_CITY | resident_city | Major type 3 |
16 | RESIDENT_STATE | resident_state | Major type 3 |
17 | RESIDENT_POSTAL_CODE | resident_postal_code | Major type 3 |
18 | BIOMETRIC_TEMPLATE_XX | biometric_template_xx | Major type 2 |
19 | NAME_NAT_CHAR | name_nat_char | Major type 3 |
20 | MGMT_NEXT_UPDATE | mgmt_nextupdate | Tag value 0 of major type 6 |
21 | FAMILY_NAME | family_name | Major type 3 |
22 | GIVEN_NAME | given_name | Tag value 0 of major type 6 |
23 | BIRTHDATE | birthdate | Tag value 0 of major type 6 |
24 | ISSUE_DATE | issue_date | Tag value 0 of major type 6 |
25 | EXPIRY_DATE | expiry_date | Major type 3 |
26 | ISSUING_COUNTRY | issuing_country | Major type 3 |
27 | ISSUING_AUTHORITY | issuing_authority | Major type 3 |
28 | DOCUMENT_NUMBER | document_number | Major type 3 |
29 | PORTRAIT | portrait | Major type 2 |
30 | MGMT_LAST_UPDATE | mgmt_lastupdate | Tag value 0 of major type 6 |
31 | MGMT_VALIDITY | mgmt_validity | Tag value 0 of major type 6 |
32 | ONLINE_TOKEN_XXXX | online_token_xxxx | Major type 3 |
34 | DRIVING_PRIVILEGES | driving_privileges | Major type 4 |
35 | SIGNATURE_USUAL_MARK | signature_usual_mark | Major type 3 |
36 | ONLINE_URL_XXXX | online_url_xxxx | Major type 3 |
37 | BIRTHDATE | birth_date | Major type 3 |
38 | BIRTH_PLACE | birth_place | Major type 3 |
39 | NAME_NAT_CHAR | name_national_character | Major type 3 |
40 | FAMILY_NAME_NATIONAL_CHAR | family_name_national_character | Major type 3 //added in N19xx |
41 | GIVEN_NAME_NATIONAL_CHAR | given_name_national_character | Major type 3 //added in N19xx |
Namespace= "org.iso.18013.5.1.aamva" | //based on mDL-Implementation-Guidelines-1-0_2021.pdf | ||
1 | DOMESTIC_DRIVING_PRIVILEGES | domestic_driving_privileges | Major type 3 |
2 | DHS_COMPLIANCE | DHS_compliance | Major type 3 |
3 | NAME_SUFFIX | name_suffix | Major type 3 |
4 | ORGAN_DONOR | organ_donor | Major type 0 |
5 | VETERAN | veteran | Major type 0 |
6 | FAMILY_NAME_TRUNCATION | family_name_truncation | Major type 3 |
7 | GIVEN_NAME_TRUNCATION | given_name_truncation | Major type 3 |
8 | AKA_FAMILY_NAME_V2 | aka_family_name.v2 | Major type 3 |
9 | AKA_GIVEN_NAME_V2 | aka_given_name.v2 | Major type 3 |
10 | AKA_SUFFIX | aka_suffix | Major type 3 |
11 | WEIGHT_RANGE | weight_range | Major type 0 |
12 | RACE_ETHNICITY | race_ethnicity | Major type 3 |
13 | EDL_CREDENTIAL | EDL_credential | Major type 0 |
14 | SEX | sex | Major type 0 |
15 | RESIDENT_COUNTY | resident_county | Major type 3 |
16 | HAZMAT_ENDORSEMENT_EXPIRATION_DATE | hazmat_endorsement_expiration_date | Major type 3 |
17 | DHS_TEMPORARY_LAWFUL_STATUS | DHS_temporary_lawful_status | Major type 0 |
Expected Results
QR code
Below are expected response from the sendRequest
API with the expected data type.
Data Fields | Data type/Unit | Sample Value |
---|---|---|
Namespace= "org.iso.18013.5.1" | ||
administrative_number | Text/String | "1234453" |
gender | Text/String | "M" |
height | Integer/Centimeter | "157" |
weight | Integer/Kg | "56" |
eye_color | Text/String | "BLU" |
hair_color | Text/String | "BLACK" |
birthplace | Text/String | "NY" |
resident_address | Text/String | "123, ABC Street" |
portrait_capture_date | DateTime/RFC3339 | "1985-04-12T23:20:50Z" |
age_in_years | Integer/String | "34" |
age_birth_year | Integer/String | "1978" |
age_over_NN | Boolean/String | "true" |
issuing_jurisdiction | Text/String | "NY" |
nationality | Text/String | "US" |
resident_city | Text/String | "NY" |
resident_state | Text/String | "NY" |
resident_postal_code | Text/String | "58773" |
name_nat_char | Text/String | "US" |
mgmt_nextupdate | DateTime/RFC3339 | "1985-04-12T23:20:50Z" |
family_name | Text/String | "Sample" |
given_name | Text/String | "Joe" |
birthdate | DateTime/RFC3339 | "1985-04-12T23:20:50Z" |
issue_date | DateTime/RFC3339 | "1985-04-12T23:20:50Z" |
expiry_date | DateTime/RFC3339 | "1985-04-12T23:20:50Z" |
issuing_country | Text/String | "US" |
issuing_authority | Text/String | "NY" |
document_number | Int/String | "782593823" |
portrait | ByteArray/Bytes | |
mgmt_lastupdate | DateTime/RFC3339 | "1985-04-12T23:20:50Z" |
mgmt_validity | DateTime/RFC3339 | "1985-04-12T23:20:50Z" |
driving_privileges | Text/String | "[{"codes":[{"sign":"Sign","value":"value","code":"C"}],"issue_date":"2018-08-09","vehicle_category_code":"A","expiry_date":"2024-06-11"}]" |
RealID | Boolean/String | true |
signature_usual_mark | ByteArray/Bytes | |
birth_date | DateTime/RFC3339 | "1985-04-12T23:20:50Z" |
birth_place | Text/String | "NY" |
name_national_character | Text/String | "US" |
given_name_national_character | Text/String | "US" |
family_name_national_character | Text/String | "US" |
Namespace = "org.iso.18013.1.aamva" | ||
DHS_compliance | Text/String | “F” = fully compliant “N” = non-compliant |
domestic_driving_privileges | Text/String | [{"domestic_vehicle_class": {"expiry_date": "2027-08-12", "issuer_date":"2019-10-12", "domestic_vehicle_class_code": "A", "domestic_vehicle_class_description": "vehicle category description"}, "domestic_vehicle_endorsements": [{"domestic_vehicle_endorsement_code": "E", "domestic_vehicle_endorsement_description": "vehicle endorsement description"}], "domestic_vehicle_restrictions": [{"domestic_vehicle_restriction_code": "C", "domestic_vehicle_restriction_description": "vehicle restrictions description"}]}] |
name_suffix | Text/String | “SR” |
organ_donor | Integer | 1 |
veteran | Integer | 1 |
family_name_truncation | Text/String | “N” |
given_name_truncation | Text/String | “N” |
aka_family_name.v2 | Text/String | “N” |
aka_given_name.v2 | Text/String | “S” |
aka_suffix | Text/String | “N” |
weight_range | Integer | “3” //Indicates the approxi- mate weight range of the credential holder: 0 = up to 31 kg; 1 = 32 – 45 kg ; 2 = 46 - 59 kg ; 3 = 60 - 70 kg |
race_ethnicity | Text/String | “A” //Codes for race or eth- nicity of the creden- tial holder, as defined in AAMVA D20. |
EDL_credential | Integer | 1 //This field is either absent or has one of the following values: 1: Driver’s license, 2: Identification card (Applicable only in the US. ) |
sex | Integer | 1 |
resident_county | Text/String | "107" //The 3-digit county code of the county where the credential holder lives, as per the 2010 FIPS Codes for Counties and County Equivalent Entitiesf. (Applicable only in the US. ) |
hazmat_endorsement_expiration_date | Text/String | "2024-01-11" |
DHS_temporary_lawful_status | Integer | 1 // This field is either absent or has value= 1: Temporary lawful status (Applicable only in the US. ) |
IACA certificate file format support
- Supports following formats for IACA certificates - (.pem, .crt, .der).
Elliptic curve support
Operation | Curve | Specification | Curve Identifier |
---|---|---|---|
ECDH/ECDSA | P-256 | FIPS-PUB 186-4 | IANA COSE Registry |
ECDH/ECDSA | P-384 | FIPS-PUB 186-4 | IANA COSE Registry |
ECDH/ECDSA | P-521 | FIPS-PUB 186-4 | IANA COSE Registry |
ISO-18013-5 specification support
ISO Version | Supported |
---|---|
N2448 (1.1 Draft7) | Yes |
N1985 (published 1.0) | Yes |
N1938 | Yes |
N1818 | Yes |
N1677 | Yes |
Additions and updates
- ISO Amendments N2448 (v1.1 Draft7):
- Device engagement implementation for N2448 with backwards compatibility support
- NFC Static+L2cap PSM functionality for mdoc Peripheral mode
- ReaderAuthAll Implementation for N2448
- Implemented callback for downloading CRL data from the integrators application
- Compatible with iOS 18 Beta
- Bug fixes and Improvements
Notes:
- IDEMIA has many IACA certificates added to our Verify App, so we must categorize these certificates, such as Production, Demo, UAT, in our App. This allows the Verify App integrator to know which certificate matches pertain to which environment at any time during a transaction.
- A certificate validation match is performed with the Mobile ID credential, and a certification tag is created for every certificate. This flag is used used in the Verify SDK to distinguish between different purposes of the certifications, leading to indicators in the Verify App results screen that some Mobile IDs credentials are “Not for Official Use”. If a certificate is not in production, then it is not meant for official use.
- A popup/updated UI on the Verify App displays whether the Mobile ID credential is applicable for official use or not, based on the matched IACA certificate. Currently, for integrators, this provides additional information for IACA certificate matching.
- The classification of these certificates is shown in this link: https://idemiadigitallabs.atlassian.net/wiki/spaces/MI/pages/478052581/IACA+Certificates
- Verify SDK support following file formats for IACA certificates - (.pem, .crt, .der)
- NFC implementation for Device Engagement (It only supports Static Device Engagement)
Error codes
This table contains the list of data error codes, messages, descriptions, and actions required.
Error Code | Error Code Message | Description | Action Required |
---|---|---|---|
101 | Invalid QR Code | Please try again. | Try Again. |
102 | QR Data item is missing or found any issue | If item type is not as expected. | Try Again. |
103 | QR Data item is missing or found any issue | If DataItem(Map) is empty. | Try Again. |
104 | QR Data item is missing or found any issue | If DataItem(Array) is empty. | Try Again. |
105 | QR code scan error | Unable to Scan QR code may be because of invalid data or bad encoding. | Try Again. |
109 | Invalid cipher suit. | Invalid cipher suit: only cipher suit 1 (EC algorithm) is supported. | Try Again. |
110 | Invalid EDeviceKey. | mDoc ephemeral public point in the EDeviceKey in the deviceEngagement structure sent by the mdoc is not on the indicated curve. | Try Again. |
111 | Invalid EDeviceKey | Not supported or unspecified curve Id in DeviceEngagement structure sent by the mdoc | Try Again |
123 | Parsing Error | Error in compact mode qr code parsing and verification | Try Again. |
124 | Image Conversion Error | Error in convert image from bitmap to Image | Try Again. |
141 | Invalid NFC Tag, unable to read data | Please try again | Try Again. |
142 | Incorrect types for ac record,carrier record and auxiliary record. | Please try again. | Try Again. |
143 | Reference length indicated longer than available bytes. | Please try again. | Try Again. |
144 | Tag was lost. | Main Error during APDU transmission, tag may be out of field. | Try Again. |
145 | ISO-DEP is not supported. | Main Tag is not supporting ISO-DEP technology. | Try Again. |
146 | Exception when initializing TT4. | Error with TT4 configuration. | Try Again. |
147 | Wrongly formatted Service Parameter record | Please try again. | Try Again. |
148 | Error with Carrier Configuration record linking. | ConnectionHandoverException with Carrier Configuration record linking. | Try Again. |
149 | Main Initial message is null. | Please try again. | Try Again. |
150 | NFC Connection Timeout | NFC scanning has timedout. | Try Again. |
151 | NFC not supported | NFC not supported on this device. | Try Again. |
186 | NFC Session cancelled by user | NFC Reader Session invalidated by user | Try Again. |
187 | NFC Capability is not added. | Session invalidated unexpectedly. Please add NFC capability. | Try Again. |
201 | Unable to initialize BLE | Error in initializing BLE feature of this | The Mobile ID reader is not able to get BLE. The Mobile ID credential reader may abort the transaction. |
202 | Device Doesn't Support BLE | This device doesn't support the BLE feature. | The Mobile ID reader is not able to get BLE. The Mobile ID reader may abort the transaction. |
203 | BLE Scanning Error | Scanning of the BLE devices failed. | The Mobile ID reader is not able to scan the BLE devices. The Mobile ID reader may abort the transaction. |
204 | Bluetooth is OFF | This device's Bluetooth is off. | The Bluetooth of the device is not enabled. The Mobile ID credential reader may abort the transaction. |
205 | BLE Scanning Error | Please provide the BLUETOOTH permissions. | |
206 | BLE Connection Timeout | Unable to create BLE communication channel with the Mobile ID device. | BLE connection failure. The Mobile ID reader may abort the transaction. |
209 | BLE L2CAP Read Error | BLE L2CAP connection error while reading. | |
210 | BLE L2CAP Write Error | BLE L2CAP connection error while writing. | |
211 | BLE L2CAP Channel Creation Error | L2CAP channel creation error, Using fallback. | |
301 | Transaction Cancelled | The transaction has been cancelled by the end-user. | Unable to scan the QR code. |
302 | Device Disconnected | Unfortunately device has disconnected. Maybe the device is not in the range of BLE. | The Mobile ID credential reader may abort the transaction. |
303 | Timed Out, Please try again | BLE connection failure. The Mobile ID credential reader may abort the transaction. | |
304 | Request Incomplete. | Please select one or more attributes to be included in the request to the Mobile ID credential. | The Mobile ID credential reader may inspect the request, ensure request is complete, and resend. The Mobile ID credential reader may abort the transaction. |
305 | Incomplete Request | An Mobile ID comes to an end of data when expecting more data. For example, an Mobile ID expects certain length, number of arrays elements, or map entries but instead encounters the end of the data. The Mobile ID does not return any data but the error message. | The Mobile ID credential reader may inspect the request, ensure request is complete, and resend. The Mobile ID credential reader may abort the transaction. |
306 | Request Rejected | The Mobile ID App indicates that the request is rejected. | The Mobile ID credential reader may inspect the problem. The Mobile ID credential reader may continue the transaction. |
307 | Mobile ID Reader Authentication Failed | The Mobile ID indicates there is an error with Mobile ID Reader authentication | The Mobile ID credential reader may inspect the problem. The Mobile ID credential reader may continue the transaction. |
308 | General Error | The Mobile ID App returns an error without any given reason. | The Mobile ID credential reader may inspect the request, ensure request is complete, and resend. The Mobile ID credential reader may abort the transaction. |
309 | Invalid Request | Request can't contain more than 2 age_over_nn as request attributes. | |
310 | Error in Reader Authentication | ReaderAuthSign Signature or Certificate cannot be null or empty. | |
401 | Parsing Error | A Mobile ID credential request encountered a data element that is not well-formed (e.g., invalid initial byte) and failed decoding data. The Mobile ID App does not return any data but the error message. | The Mobile ID credential reader may inspect the request, ensure request is complete, and resend. The Mobile ID credential reader may abort the transaction. |
402 | Invalid Format | The Mobile ID App cannot process the requested data element due to a formatting error. | |
403 | Data Not Found | The requested NameSpace or data element within a NameSpace is not found. | |
404 | Data Request Denied | The release of requested data element was rejected by the Mobile ID credential holder. | |
405 | Data Not Returned | The Mobile ID App does not provide the requested data element without any given reason. | |
406 | CBOR decoding error | The mdoc indicates an error during CBOR decoding that the data received is not valid CBOR.. Returning this status code is optional. | |
407 | CBOR validation error | The mdoc indicates an error during CBOR validation, e.g. wrong CBOR structures. Returning this status code is optional. | |
451 | Certificate Path Error | Either Path is invalid or inaccessible or not a folder path or folder is empty. | |
801 | License Validation Failure | Some of the arguments are not right. Please check the arguments and Try Again! | |
802 | Network Error | No internet connection available.Please turn on your internet connection and Try Again! | |
804 | Request Validation Failure | Request validation problem.Please check your request and Try Again! | |
807 | Bad Configurations | The specified resource is not available. Profile or apikey or both are invalid or that an unknown service exception happened.Try Again! | |
808 | License Expired | Your license is expired.Please renew your license and Try Again! | |
809 | License Validation Failure | Error while fetching data. Generic exception. Try Again! | |
810 | License Not Available | No license available, Please retrieve the license! | |
811 | License Feature Not Available | Requested feature is not available! | |
482 | IACA DS Validation Error | Transaction not authenticated due to non-compliant or invalid DS or IACA certificate. | |
483 | Vical Loading Error | Error while loading vical file. | |
484 | Vical Authentication Error | Vical can’t be authenticated using given certificate. |
Test samples
QR + BLE sample
The following screen shows a scan of QR code in the IDEMIA Mobile ID App.
Note: This is for device engagement QR code testing. The full QR code + BLE scenario will only work with a real device using the IDEMIA Mobile ID App.