âť— Important! Before you proceed, please read the EUDI Wallet Reference Implementation project description
This repository contains the EUDI Wallet Kit library for iOS. The library is a part of the EUDI Wallet Reference Implementation project.
This library acts as a coordinator by orchestrating the various components that are required to implement the EUDI Wallet functionality. On top of that, it provides a simplified API that can be used by the application to implement the EUDI Wallet functionality.
graph TD;
A[eudi-lib-ios-wallet-kit]
B[eudi-lib-ios-wallet-storage] --> |Wallet Storage|A
C[eudi-lib-ios-iso18013-data-transfer] --> |Transfer Manager|A
D[eudi-lib-ios-openid4vci-swift] --> |OpenId4Vci Manager|A
E[eudi-lib-ios-siop-openid4vp-swift] --> |OpenId4Vp Manager|A
F[eudi-lib-ios-iso18013-security] --> |Mdoc Security|C
G[eudi-lib-ios-iso18013-data-model] --> |Mdoc Data Model|C
H[eudi-lib-ios-presentation-exchange-swift] --> E
The library provides the following functionality:
- Document management
- Storage encryption
- Using iOS Secure Enclave for generating/storing documents' keypair
- Enforcing device user authentication when retrieving documents' private keys
- Document issuance
- Support for OpenId4VCI document issuance
- Authorization Code Flow
- Pre-authorization Code Flow
- Support for mso_mdoc format
- Support for sd-jwt-vc format
- Support credential offer
- Support for DPoP JWT in authorization
- Support for JWT and CWT proof types
- Support for deferred issuing
- Support for OpenId4VCI document issuance
- Proximity document presentation
- Support for ISO-18013-5 device retrieval
- QR device engagement
- BLE data transfer
- Support for ISO-18013-5 device retrieval
- Remote document presentation
- OpenId4VP document transfer
- For pre-registered verifiers
- Dynamic registration of verifiers
- OpenId4VP document transfer
The library is written in Swift and is compatible with iOS 14 or higher. It is distributed as a Swift package and can be included in any iOS project.
It is based on the following specifications:
- ISO/IEC 18013-5 – Published
- Presentation Exchange v2.0.0 - Published
- OpenID4VP – Draft 18
- SIOPv2 – Draft
The released software is a initial development release version:
- The initial development release is an early endeavor reflecting the efforts of a short timeboxed period, and by no means can be considered as the final product.
- The initial development release may be changed substantially over time, might introduce new features but also may change or remove existing ones, potentially breaking compatibility with your existing code.
- The initial development release is limited in functional scope.
- The initial development release may contain errors or design flaws and other problems that could cause system or other failures and data loss.
- The initial development release has reduced security, privacy, availability, and reliability standards relative to future releases. This could make the software slower, less reliable, or more vulnerable to attacks than mature software.
- The initial development release is not yet comprehensively documented.
- Users of the software must perform sufficient engineering and additional testing in order to properly evaluate their application and determine whether any of the open-sourced components is suitable for use in that application.
- We strongly recommend to not put this version of the software into production use.
- Only the latest version of the software will be supported
To use EUDI Wallet Kit, add the following dependency to your Package.swift:
dependencies: [
.package(url: "https://github.com/eu-digital-identity-wallet/eudi-lib-ios-wallet-kit.git", .upToNextMajor(from: "0.5.6"))
]
Then add the Eudi Wallet package to your target's dependencies:
dependencies: [
.product(name: "EudiWalletKit", package: "eudi-lib-ios-wallet-kit"),
]
The EudiWallet class provides a unified API for the two user attestation presentation flows. It is initialized with a document storage manager instance. For SwiftUI apps, the wallet instance can be added as an environmentObject
to be accessible from all views. A KeyChain implementation of document storage is available.
let wallet = EudiWallet.standard
wallet.userAuthenticationRequired = true
wallet.trustedReaderCertificates = [...] // array of der certificate data
wallet.openId4VpVerifierApiUri = "https:// ... verifier api uri ..."
wallet.verifierApiUri = configLogic.verifierConfig.apiUri
wallet.verifierLegalName = configLogic.verifierConfig.legalName
wallet.openID4VciIssuerUrl = configLogic.vciConfig.issuerUrl
wallet.openID4VciClientId = configLogic.vciConfig.clientId
wallet.openID4VciRedirectUri = configLogic.vciConfig.redirectUri
wallet.loadDocuments()
The read-only property storage
is an instance of a StorageManager
Currently the keychain implementation is used. It provides document management functionality using the iOS KeyChain.
The storage model provides the following models for the supported well-known document types:
DocType | Model |
---|---|
eu.europa.ec.eudiw.pid.1 | EuPidModel |
org.iso.18013.5.1.mDL | IsoMdlModel |
For other document types the GenericMdocModel is provided.
The library provides a set of methods to work with documents.
The EudiWallet.loadDocuments
method that returns the list of documents stored in the library.
The following example shows how to retrieve issued documents:
public func loadDocuments() async throws {
let documents = try await wallet.loadDocuments()
}
The EudiWallet.loadDocument(id:)
method that returns a document with the given id.
The following example shows how to retrieve a document:
let document = try await wallet.loadDocument(id: documentId)
The EudiWallet.deleteDocument(id:)
method that deletes a document with the given id.
The following example shows how to delete a document:
try await wallet.deleteDocument(id: documentId)
The library provides the functionality to issue documents using OpenID4VCI. To issue a document
using this functionality, EudiWallet must be property initialized.
If userAuthenticationRequired
is true, user authentication is required. The authentication prompt message has localisation key "issue_document".
After issuing a document, the document data and corresponding private key are stored in the wallet storage.
When the document docType to be issued use the issueDocument(docType:format:)
method.
Important Notes:
- Currently, only mso_mdoc format is supported
- Currently, only ES256 algorithm is supported for signing OpenId4CVI proof of possession of the publicKey.
The following example shows how to issue an EUDI Personal ID document using OpenID4VCI:
wallet.openID4VciIssuerUrl = "https://eudi.netcompany-intrasoft.com/pid-issuer"
wallet.openID4VciClientId = "wallet-dev"
wallet.openID4VciRedirectUri = "eudi-openid4ci://authorize/"
do {
let doc = try await userWallet.issueDocument(docType: EuPidModel.euPidDocType, format: .cbor)
// document has been added to wallet storage, you can display it
}
catch {
// display error
}
The library provides the resolveOfferUrlDocTypes(uriOffer:)
method that resolves the credential offer URI.
The method returns the resolved OfferedIssueModel
object that contains the offer's data (offered document types, issuer name and transaction code specification for pre-authorized flow). The offer's data can be displayed to the
user.
The following example shows how to resolve a credential offer:
func resolveOfferUrlDocTypes(uriOffer: String) async throws -> OfferedIssueModel {
return try await wallet.resolveOfferUrlDocTypes(uriOffer: uriOffer)
}
After user acceptance of the offer, the selected documents can be issued using the issueDocumentsByOfferUrl(offerUri:docTypes:txCodeValue:format:)
method.
The txCodeValue
parameter is not used in the case of the authorization code flow.
The following example shows how to issue documents by offer URL:
let documents = try await walletController.issueDocumentsByOfferUrl(offerUri: uri, docTypes: docOffers, format: .cbor, txCodeValue: txCodeValue )
For the authorization code flow to work, the redirect URI must be specified specified by setting the the openID4VciRedirectUri
property.
The user is redirected in an authorization web view to the issuer's authorization endpoint. After the user authenticates and authorizes the request, the issuer redirects the user back to the application with an authorization code. The library exchanges the authorization code for an access token and issues the document.
When Issuer supports the pre-authorization code flow, the resolved offer will also contain the corresponding
information. Specifically, the txCodeSpec
field in the OfferedIssueModel
object will contain:
- The input mode, whether it is NUMERIC or TEXT
- The expected length of the input
- The description of the input
From the user's perspective, the application must provide a way to input the transaction code.
After user acceptance of the offer, the selected documents can be issued using the issueDocumentsByOfferUrl(offerUri:docTypes:txCodeValue:format:)
method.
When the transaction code is provided, the issuance process can be resumed by calling the above-mentioned method and passing the transaction code in the txCodeValue
parameter.
The presentation service protocol abstracts the presentation flow. The BlePresentationService and OpenId4VpService classes implement the proximity and remote presentation flows respectively. The PresentationSession class is used to wrap the presentation service and provide @Published properties for SwiftUI screens. The following example code demonstrates the initialization of a SwiftUI view with a new presentation session of a selected flow type.
let session = eudiWallet.beginPresentation(flow: flow)
// pass the session to a SwiftUI view
ShareView(presentationSession: session)
On view appearance the attestations are presented with the receiveRequest method. For the BLE (proximity) case the deviceEngagement property is populated with the QR code to be displayed on the holder device.
.task {
if presentationSession.flow.isProximity { await presentationSession.startQrEngagement() }
_ = await presentationSession.receiveRequest()
}
After the request is received the presentationSession.disclosedDocuments
contains the requested attested items. The selected state of the items can be modified via UI binding. Finally, the response is sent with the following code:
// Send the disclosed document items after biometric authentication (FaceID or TouchID)
// if the user cancels biometric authentication, onCancel method is called
await presentationSession.sendResponse(userAccepted: true,
itemsToSend: presentationSession.disclosedDocuments.items, onCancel: { dismiss() }, onSuccess: {
if let url = $0 { presentSafariView(url) }
})
Detailed documentation is provided here
The detailed functionality of the wallet kit is implemented in the following Swift Packages: MdocDataModel18013, MdocSecurity18013, MdocDataTransfer18013 and SiopOpenID4VP OpenID4VCI
A sample application that demonstrates the usage of this library is App Wallet UI.
We welcome contributions to this project. To ensure that the process is smooth for everyone involved, follow the guidelines found in CONTRIBUTING.md.
Copyright (c) 2023 European Commission
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.