EUDI Wallet Link Governance and Implementation Hints¶
Recommendations on the use of a joint invocation mechanism for both Android and iOS
Introduction¶
The purpose of this document is to provide guidance and advice on the use of a joint wallet invocation mechanism among member states EUDI wallet apps and their respective implementations on both iOS and Android.
Motivation¶
As part of the EU Digital Identity (EUDI) Wallet pilot initiative, each EU member state will offer a wallet app to its citizens, capable of performing various administrative formalities.
Regulation requires interoperability among wallets, requiring reliant digital services to accept all wallets from participating EU member states. Interoperability can either be achieved by having each member state's wallet support every other authentication scheme, resulting in 27 implementations in each wallet. Alternatively, every reliant service would have to support 27 schemes and offer some kind of selection, enabling a user to pick their wallet solution. This would result in a sub-par user experience.
This can be avoided by the use of a single common invocation mechanism. Every member state would still have to implement said scheme, but the interoperability requirement would essentially be reduced from 27 to 1, as every wallet supports just one authentication scheme.
Joint Scheme/Domain¶
All wallet solutions are based on a redirection from a given relying party into a user's wallet app in order to identify the user.
So far, as an example, the German eID solution used a custom protocol scheme (Example: eID://auth/12345
).
Custom protocol schemes are prone to hijacking, as any app could just implement said protocol and potentially redirect the user to a malicious app. Another option is the use of regular web URLs, as both Android and iOS support linking web URLs to respective native apps.
Figure 1: Example joint authentication URLThe ownership of a given domain can be asserted by placing a verification file online (Android Asset Links or iOS Entitled Domain Verification).
Wallet apps of individual member states could rely on a joint domain name like wallet.eudi.example
and individual wallet solutions could perform their respective tasks using said domain to provide a secure redirection from websites into respective wallet apps.
Governance¶
Ownership of the shared domain involves administrative duties and long-term oversight.
Acquisition & Renewal¶
A domain name must be acquired for joint efforts of operating wallet solutions. It cannot be changed, changing is only possible when all member states agree on a new common domain and implement it accordingly. Furthermore, domain registrations must be renewed at least yearly, so financial means should be available to ensure long-term sustainability of a joint domain name.
There is a risk in the domain name expiring if not renewed in time. Given the aspiration of attracting millions of users, an attacker could potentially buy the joint domain name and use it for malicious purposes such as redirecting to a phishing app.
Web Hosting & Scaling¶
Although only smaller, static files need to be hosted under the joint domain name, the intended goal is to provide it to millions of users from all the member states at once, therefore proper hosting, scaling and long-term operation must be guaranteed.
Given all member states rely on a joint domain name, it should resolve quickly for every member state, ensuring smooth operation wherever a user may reside.
Onboarding & Key management¶
A process must be in place allowing member states to add, modify and remove a signing key. The hosted configuration files must be updated in a timely manner to allow member states to roll out their respective app. Furthermore, keys may expire, be stolen or lost, therefore, a process must be in place to modify or remove compromised keys from the configuration files in a timely manner.
A verification tool should be used whenever edits to the configuration files are made, as a faulty configuration file will disable the redirection for every member state. It is a single point of failure.
Appropriate Error and Help Pages¶
As shown in Figure 1, should a redirection to a given wallet app fail, the user would just access said authentication URL in a browser. Therefore, an appropriate website should be shown under the relevant URL, enabling helpful guidance on how to properly set up a respective wallet.
Also, a retry button should be shown enabling a user to retry a given authentication after installing respective apps. The install-state of an appropriate wallet app can be determined using the "Get Installed Related Apps API".
SSL/TLS¶
Given the joint domain name should only be accessible using HTTPS, appropriate configuration must be in place to ensure a valid SSL/TLS certificate is always issued and installed properly.
It is imperative the SSL configuration does not expire, that is to say it is renewed in time, given an invalid configuration will result in the redirection failing for every member state (Single point of failure).
Implementation Details¶
Both Android and iOS are major mobile operating systems and feature linking web content to native apps. The use of a domain name for linking web content to native apps is their assertion of ownership. While a custom scheme serves its purpose, any malicious app could implement the scheme, while a domain name's ownership can be established by placing appropriate configuration files on the web.
iOS¶
iOS Client Side¶
Apple refers to the system as "Associated Domain Entitlement". It consists of providing said domain entitlement as a key value pair in the bundle resources of an iOS app.
Key: com.apple.developer.associated-domains
Value: Array of strings, each formatted as <service>:<fully qualified domain>
The service we're targeting is referred to as "applinks". The full example of a value string should look as follows:
Figure 2 iOS client-side exampleAs a side note during development: an alternate mode must be set as follows:
applinks:wallet.eudi.example?mode=developer
iOS Server Side¶
The associated domain entitlement is complemented on the server side through a file called "apple-app-site-association" placed under the following URL:
https://wallet.eudi.example/.well-known/apple-app-site-association
Its content should reflect the associated app IDs of member states as well as a mapping of URLs that should be opened in the wallet app.
{
"applinks": {
"details": [
{
"appIDs": [ "ABCDE12345.com.example.app", "ABCDE12345.com.example.app2" ],
"components": [
{
"/": "/auth/*",
"?": { "token": "????" },
"comment": "Matches any URL with a path that starts with /auth/ and that has a query item with name 'token' and a value of exactly four characters."
}
]
}
]
}
}
As shown above, the "appIDs" entry must be updatable to reflect respective member states' wallet apps.
Reference: https://developer.apple.com/documentation/xcode/supporting-associated-domains?language=objc
Android¶
Similarly to iOS, the Android system refers to establishing ownership of a domain as Android App Links on the client and "Google Digital Asset Links" on the server side. The following example will illustrate their use.
Android Client Side¶
For an Android app, its "AndroidManifest.xml" must be modified in order to register an "intent-filter" enabling the Android system to redirect registered URLs to it.
<application>
...
<activity android:name="MainActivity">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
<data android:host="wallet.eudi.example" />
</intent-filter>
</activity>
...
</application>
As shown in Figure 4, the entry consists of specifying an appropriate host using the "android:host" tag attribute. Furthermore, the scheme should only bind to "https" as it's the only method of ensuring an encrypted resolution of the digital asset links file.
Lastly, note the "android:autoVerify" tag. It instructs the Android system to resolve appropriate digital asset links configuration files automatically as well as their verification enabling the user to be redirected without additional prompts.
Android Server-Side Configuration¶
Similarly to iOS, a special configuration file must be published under the joint target domain. The following example will illustrate how to properly define this file.
The contents of Figure 5 must be accessible publicly under the following URL: https://wallet.example.org/.well-known/assetlinks.json
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.meberstate1.app",
"sha256_cert_fingerprints": ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
}
},
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.memberstate2.app",
"sha256_cert_fingerprints": ["15:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E6"]
}
}]
As shown in Figure 5, multiple apps may be configured. The "package-name" must match the package ID defined in the respective AndroidManifest.xml on the client side. Furthermore, the hash of the signing key must be included. Multiple signing keys may be defined for e.g., a development key or a transitional phase to a new signing key.
The appropriate SHA256 hash of a signing key can be obtained using the following console command:
Reference: https://developer.android.com/training/app-links/verify-android-applinks
Scheme Collision¶
Users can have more than one wallet app installed, e.g., when they are citizens of more than one EU member state. Since Android and iOS behave differently when more than one app is registered for the same domain, it is still to be discussed how this case should be handled.