This repository was archived by the owner on Aug 11, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
Update suggested API. #5
Open
agl
wants to merge
6
commits into
WICG:main
Choose a base branch
from
agl:identityapi
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
0609c97
Update suggested API.
agl 6d80fa1
Adam's work-in-progress prior to handoff to me
RByers 0d5d31c
Add agl to authors
RByers 7498741
Update to match latest IdentityCredential proposal
RByers 49961ad
Move retention to a double per @othermaciej feedback
RByers b68274e
Update proposed mdoc dictionary name
RByers File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,7 +6,8 @@ | |
| - [@dcrousso](https://github.com/dcrousso) | ||
| - [@hlozi](https://github.com/hlozi) | ||
| - [@martijnharing](https://github.com/martijnharing) | ||
|
|
||
| - [@agl](https://github.com/agl) | ||
| - [@samuelgoto](https://github.com/samuelgoto) | ||
|
|
||
| ## Participate | ||
|
|
||
|
|
@@ -15,47 +16,115 @@ | |
|
|
||
| ## Introduction | ||
|
|
||
| This is a proposal for a new web API that allows websites to request a mobile document as defined in ISO/IEC 18013-5 using structures defined in the same ISO in order to achieve an online presentment. The API would protect the mobile document credential data, supports selective disclosure, and allow the user to control the release of credential data. | ||
|
|
||
| The ISO/IEC 18013-5:2021 standard specifies how a driver license (mDL) is represented on a mobile device and how it is presented to a physical reader. Users who chose to have their mDL on device can present it to compatible readers instead of the physical driver license. The ISO standard defines the protocols and the exchanges between the mDL and the mDL reader for different physical uses case (e.g. TSA, Hotel, store,... ). The ISO standard provides building blocks to allow remote presentment of the the mobile driver’s license over the Web such as data structures and operational phases. The ISO standard ISO/IEC 18013-5:2021 for mobile driver’s license does not define a web API to allow presentement via user agent. | ||
| This is a proposal for a new web API that allows websites to request a mobile document as defined in ISO/IEC 18013-5 using structures defined in the same ISO standard in order to achieve an online presentment. The API protects the mobile document credential data, supports selective disclosure, and allows the user to control the release of credential data. | ||
|
|
||
| The mechanisms defined by ISO/IEC 18013-5 are designed to support any type of mobile document, called mdoc. Besides the mDL, this API can therefore be used to request and transmit any mobile document that implements the ISO mdoc specification. | ||
| The ISO/IEC 18013-5:2021 standard specifies how a mobile driver's license (mDL) is represented on a mobile device and how it is presented to a physical reader. Users who choose to have their mDL on device can present it to compatible readers instead of the physical driver's license. The ISO standard defines the protocols and the exchanges between the mDL and the mDL reader for different physical uses case (e.g. TSA, hotels, stores, …). The ISO standard provides building blocks to allow remote presentment of the the mobile driver’s license over the Web such as data structures and operational phases, however it does not define a web API to allow presentement via user agent. | ||
|
|
||
| The mechanisms defined by ISO/IEC 18013-5 are designed to support any type of mobile document, generically called “mdocs”. The API defined in this document can therefore be used to request and transmit any mobile document that implements the ISO mdoc specification. | ||
|
|
||
|
|
||
| ## Goals | ||
|
|
||
| - Allow websites to request the presentment of a mobile document in mdoc format such as driver’s license. | ||
| - Enable the user to have a consent based control of what data is released to the website. | ||
| - Allow websites to request the presentment of a mobile document in mdoc format, such as driver’s license. | ||
| - Enable the user to have control of what data is released to the website. | ||
| - Protect the released data using encryption to ensure only the website the data is intended for can access the data. | ||
| - Don't preclude the addition of other credential types in the future, if needed. | ||
| - Integrate with other types of identity requests which websites may want to let users choose between. | ||
|
|
||
|
|
||
| ## Non-goals | ||
|
|
||
| - Support requests spanning identity and authentication mechanisms. | ||
| - Define issuance and provisioning of an mdoc. | ||
| - Define the communication between the User Agent and the website server is out of scope. | ||
| - Define the communication between the User Agent and the website server | ||
| - Define the native communication between the User Agent and the application holding the mdoc. | ||
| - Define how the response to the request is used by the server is out of scope. | ||
| - Requesting multiple mdocs in one API call. | ||
|
|
||
| - Define how the response to the request is used by the server. | ||
| - Support requesting multiple mdocs in one API call. | ||
|
|
||
| ## Proposed Solution | ||
|
|
||
| The API request should contain all the information needed to build up and encrypt the response. The response data from the mdoc should be a CBOR-encoded blob encrypted end-to-end for the intended relying party using Hybrid Public Key Encryption (HPKE) defined in RFC 9180. Only the targeted relying party, holder of the private part corresponding to the public key used for the response encryption, should be able to decrypt the response (with the assumption that the server always holds and protects the private key). The API should allow the server to pass as a parameter a requester identity object that allows the mdoc device to extract the public key material needed for the encryption. The passed object can be anything that allows the mdoc to determine which public key to encrypt the response to, like a certificate, a key or a key identifier. | ||
| This API would be a new identity scheme within [IdentityCredential](https://github.com/agl/identity-credential) using the scheme identifier `mdoc`. | ||
|
|
||
| ### Requests | ||
|
|
||
| ### Request | ||
| ```webidl | ||
| partial dictionary IdentityProviderConfig { | ||
| optional MdocIdentityProviderConfig mdoc; | ||
| } | ||
|
|
||
| The website would need to provide a document type and desired data elements, as well as a requester identity object that allows the device to extract the encryption public key (and the mdoc to optionally verify the eligibility of the website to request the mdoc presentment). | ||
| dictionary MdocIdentityProviderConfig { | ||
| required DOMString nonce; | ||
|
|
||
| // The mdoc document type requested. See ISO 18013-5 section 7.1. | ||
| required DOMString documentType; | ||
|
|
||
| // The elements of the mdoc requested. | ||
| required sequence<MdocElement> requestedElements; | ||
|
|
||
| // The number of days that the requester will keep the data for. | ||
| // Not providing this is equivalent to 0, meaning not asking to store. | ||
| // Infinity means forever. | ||
| double retentionDays; | ||
|
|
||
| // A set of reader identities. Each value is a base64-encoded sequence of one | ||
| // or more X.509 certificates in ASN.1 DER encoding (a “chain” of | ||
| // certificates). At least one value must be provided. The first element of | ||
| // each X.509 chain MUST be the end-entity certificate. Subsequent X.509 | ||
| // certificates in a chain are intermediate certificates as may help the wallet | ||
| // verify the end-entity certificate. | ||
| // | ||
| // If the requester has no applicable X.509 chain then it may use a | ||
| // single, self-signed certificate. | ||
| // | ||
| // The underlying wallet will evaluate these certificate chains | ||
| // and pick one, at its discretion, to identify the requesting entity. The | ||
| // SubjectPublicKeyInfo of the end-entity certificate of the selected chain | ||
| // is used to encrypt the response. | ||
| required sequence<DOMString> readerAuthentication; | ||
| }; | ||
|
|
||
| dictionary MdocElement { | ||
| required DOMString namespace; // As defined in ISO 18013-5 section 7. | ||
| required DOMString name; | ||
| }; | ||
| ``` | ||
|
|
||
| An example request: | ||
|
|
||
| ```js | ||
| let request = { | ||
| identity: { | ||
| providers: [{ | ||
| mdoc: { | ||
| nonce: "gf69kepV+m5tGxMyMF0cnn9NCnRHez/LUIsFtLi6pwg=", | ||
| documentType: "org.iso.18013.5.1.mDL", | ||
| retentionDays: 90, | ||
| readerPublicKey: ["ftl+VEHPB17r2oi6it3ENaqhOOB0AZbAkb5f4VlCPakpdNioc9QZ7X/6w..."], | ||
| requestedElements: [ | ||
| { namespace: "org.iso.18013.5.1", name: "document_number" }, | ||
| { namespace: "org.iso.18013.5.1", name: "portrait" }, | ||
| { namespace: "org.iso.18013.5.1", name: "driving_privileges" }, | ||
| { namespace: "org.iso.18013.5.1.aamva", name: "organ_donor" }, | ||
| { namespace: "org.iso.18013.5.1.aamva", name: "hazmat_endorsement_expiration_date" }, | ||
| ], | ||
| }, | ||
| }], | ||
| } | ||
| }; | ||
| navigator.credentials.get(request).then(() => { | ||
| }); | ||
| ``` | ||
|
|
||
| Once mdoc application verifies the server identity object to make sure it is a legitimate request (if needed), it would build up the response according to ISO/IEC 18013-5, including the credential data itself, the authentication by the issuer, and the authentication by the device, encrypting everything with the key derived from the requester identity object using HKPE so that only the server can decrypt the binary blob (assuming the server keeps and protects the private key). | ||
| ### Processing | ||
|
|
||
| After sending the encrypted data to the server, it would be decrypted to verify the presented mdoc issuer signature and device signature according to ISO/IEC 18013-5. | ||
| If the user rejects the request, or if no applicable mdocs are available, or if the identity in `readerPublicKey` is not authorized to request the applicable mdoc, then a "[NotAllowedError](https://heycam.github.io/webidl/#notallowederror)" [DOMException](https://heycam.github.io/webidl/#idl-DOMException) is raised. | ||
|
|
||
| Otherwise the application holding the responsive mdoc builds a response according to ISO/IEC 18013-5, including the credential data itself, the authentication by the issuer, and the authentication by the device, encrypting everything with the key taken from the selected `readerPublicKey` value. | ||
|
|
||
| ### Response | ||
|
|
||
| The response from the server would be the `DeviceResponse` object as defined in ISO/IEC 18013-5 clause 8.3.2.1.2.2 encoded with CBOR according to ISO/IEC 18013-5, encrypted using HPKE with the following settings: | ||
| A positive result from an mdoc request will be an [IdentityCredential](https://github.com/agl/identity-credential) where the `scheme` will be `mdoc` and the `result` with be the base64-encoding of the `DeviceResponse` object as defined in ISO/IEC 18013-5 clause 8.3.2.1.2.2 encoded with CBOR according to ISO/IEC 18013-5, encrypted using HPKE with the following settings: | ||
|
|
||
| ``` | ||
| mode: mode_base | ||
| KEM: DHKEM(P-256, HKDF-SHA256) | ||
|
|
@@ -64,7 +133,8 @@ AEAD: AES-128-GCM | |
| ``` | ||
|
|
||
| Part of the signature generated for `DeviceAuth` is done using the `SessionTranscript` structure as defined in ISO/IEC 18103-5 section 9.1.5.1. The `DeviceEngagementBytes` and the `EReaderKeyBytes` are both not present, and therefore have a value of `null`. The `Handover` element shall be as defined below: | ||
| ``` | ||
|
|
||
| ```cddl | ||
| BrowserHandover = [ | ||
| "BrowserHandoverv1", | ||
| Nonce, | ||
|
|
@@ -73,10 +143,12 @@ BrowserHandover = [ | |
| pkEm | ||
| ] | ||
| ``` | ||
| where `Nonce` is the nonce provided by the request, `OriginInfoBytes` contains the origin of the request and is defined in ISO/IEC 18013-7, and `RequesterIdentity` is the requester identity object from the request. | ||
|
|
||
| where `Nonce` is the nonce provided by the request, `OriginInfoBytes` contains the origin of the request and is defined in ISO/IEC 18013-7, and `RequesterIdentity` is the requester identity object from the request. (**TODO**: tighen the definition of `RequesterIdentity`, should it be the SubjectPublicKeyInfo?) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AFAICT |
||
|
|
||
| This is all included inside a CBOR encoded `CredentialDocument` with the following structure: | ||
| ``` | ||
|
|
||
| ```cddl | ||
| CredentialDocument = { | ||
| "version": tstr, | ||
| "encryptionParamaters": EncryptionParamaters, | ||
|
|
@@ -91,88 +163,60 @@ EncryptionParamaters = { | |
| ``` | ||
|
|
||
|
|
||
| ### API | ||
|
|
||
| One idea a new `CredentialRequest` (et al) | ||
| ``` | ||
| dictionary CredentialElement { | ||
| required DOMString namespace; // As defined in ISO 18013-5 clause 8. | ||
| required DOMString name; | ||
| }; | ||
|
|
||
| dictionary CredentialStorageDuration { | ||
| // At least one of these is required. | ||
|
|
||
| boolean forever; // Cannot be used with any other properties. | ||
|
|
||
| long days; // Cannot (currently) be used with any other properties. | ||
| }; | ||
|
|
||
| dictionary CredentialDocumentDescriptor { | ||
| required DOMString documentType; // As defined in ISO 18013-5 clause 8. | ||
|
|
||
| required sequence<CredentialElement> requestedElements; | ||
|
|
||
| CredentialStorageDuration desiredStorageDuration; // Not providing this is equivalent to not asking to store. | ||
| }; | ||
|
|
||
| dictionary CredentialDocument { | ||
| object data; // The CBOR encoded `CredentialDocument` defined above. | ||
| }; | ||
|
|
||
| dictionary RequestConfiguration { | ||
| required DOMString nonce; | ||
| }; | ||
|
|
||
| [ | ||
| SecureContext, | ||
| Exposed=Window, | ||
| ] interface CredentialRequest { | ||
| constructor(DOMString requesterIdentity, CredentialDocumentDescriptor documentDescriptor); // This throws if anything in the `documentDescriptor` is not recognized (e.g. an invalid `documentType`). | ||
|
|
||
| Promise<CredentialDocument> requestDocument(RequestConfiguration configuration); | ||
|
|
||
| Promise<undefined> abort(); | ||
| }; | ||
| ``` | ||
|
|
||
|
|
||
| ## Examples | ||
|
|
||
| Requesting specific attributes from a driver’s license: | ||
|
|
||
| ```js | ||
| // Driver's License | ||
| let mDLCredentialRequest = new CredentialRequest(certificate, { | ||
| documentType: "org.iso.18013.5.1.mDL", | ||
| requestedElements: [ | ||
| { namespace: "org.iso.18013.5.1", name: "document_number" }, | ||
| { namespace: "org.iso.18013.5.1", name: "portrait" }, | ||
| { namespace: "org.iso.18013.5.1", name: "driving_privileges" }, | ||
| { namespace: "org.iso.18013.5.1.aamva", name: "organ_donor" }, | ||
| { namespace: "org.iso.18013.5.1.aamva", name: "hazmat_endorsement_expiration_date" }, | ||
| ], | ||
| desiredStorageDuration: { | ||
| days: 7, | ||
| }, | ||
| let request = { | ||
| identity: { | ||
| providers: [{ | ||
| mdoc: { | ||
| nonce: "gf69kepV+m5tGxMyMF0cnn9NCnRHez/LUIsFtLi6pwg=", | ||
| readerPublicKey: ["ftl+VEHPB17r2oi6it3ENaqhOOB0AZbAkb5f4VlCPakpdNioc9QZ7X…"], | ||
| retentionDays: 90, | ||
| documentType: "org.iso.18013.5.1.mDL", | ||
| requestedElements: [ | ||
| { namespace: "org.iso.18013.5.1", name: "document_number" }, | ||
| { namespace: "org.iso.18013.5.1", name: "portrait" }, | ||
| { namespace: "org.iso.18013.5.1", name: "driving_privileges" }, | ||
| { namespace: "org.iso.18013.5.1.aamva", name: "organ_donor" }, | ||
| { namespace: "org.iso.18013.5.1.aamva", name: "hazmat_endorsement_expiration_date" }, | ||
| ], | ||
| } | ||
| }] | ||
| } | ||
| }; | ||
| navigator.credentials.get(request).then(() => { | ||
| }); | ||
| mDLCredentialRequest.request({ nonce }).then((credentialDocument) => { ... }); | ||
| ``` | ||
|
|
||
| Requesting specific mDL attributes from a COVID card: | ||
|
|
||
| ```js | ||
| // Vaccination Card | ||
| let micovCredentialRequest = new CredentialRequest(certificate, { | ||
| documentType: "org.micov.1", | ||
| requestedElements: [ | ||
| { namespace: "org.micov.attestation.1", name: "PersonId_dl" }, | ||
| { namespace: "org.micov.attestation.1", name: "portrait" }, | ||
| ], | ||
| }); | ||
| micovCredentialRequest.request({ nonce }).then((credentialDocument) => { ... }); | ||
| let request = { | ||
| identity: { | ||
| providers: [{ | ||
| mdoc: { | ||
| nonce: "gf69kepV+m5tGxMyMF0cnn9NCnRHez/LUIsFtLi6pwg=", | ||
| readerPublicKey: ["ftl+VEHPB17r2oi6it3ENaqhOOB0AZbAkb5f4VlCPakpdNioc9QZ7X…"], | ||
| retentionDays: 90, | ||
| documentType: "org.micov.1", | ||
| requestedElements: [ | ||
| { namespace: "org.micov.attestation.1", name: "PersonId_dl" }, | ||
| { namespace: "org.micov.attestation.1", name: "portrait" }, | ||
| ], | ||
| }, | ||
| }], | ||
| } | ||
| }; | ||
| ``` | ||
|
|
||
|
|
||
| ## Privacy & Security Considerations | ||
|
|
||
| This API provides the ability for websites to retrieve an ISO 18013-5 mDoc already on the device. An important part of the security and privacy mechanisms are provided by ISO 18013-5: | ||
|
|
||
| - Protection against forgery with passive data authentication defined in ISO 18013-5 based on Mobile Security Object (MSO). | ||
| - Protection against cloning using active authentication leveraging a signature over session data. The signature is produced by the device using the device private key as defined in ISO 18013-5. The Device Public key is part of the MSO signed by the issuer. | ||
| - The ability for the user to see the requested data before disclosure, in addition to being able to choose what to disclose. | ||
|
|
@@ -186,13 +230,11 @@ This API provides the ability for websites to retrieve an ISO 18013-5 mDoc alrea | |
| Many thanks for valuable feedback and advice from: | ||
|
|
||
| - [@15characterlimi](https://github.com/15characterlimi) | ||
| - [@agl](https://github.com/agl) | ||
| - [@balfanz](https://github.com/balfanz) | ||
| - [@bslassey](https://github.com/bslassey) | ||
| - [@cwilso](https://github.com/cwilso) | ||
| - [@davidz25](https://github.com/davidz25) | ||
| - [@divegeek](https://github.com/divegeek) | ||
| - [@hober](https://github.com/hober) | ||
| - [@jyasskin](https://github.com/jyasskin) | ||
| - [@samuelgoto](https://github.com/samuelgoto) | ||
| - [@sethmoo](https://github.com/sethmoo) | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks base64-encoded, but do we know any more than that? Is it a SEC 1 uncompressed EC key? Something else?