(Q)EAA Presentation with OpenID4VC¶
Basic Idea¶
The Q(EAA) Provider issues signed credentials to the Wallet, which are stored for a longer period. The Wallet can then present the credentials (including a proof of possession by signing over a wallet-held key) to the Relying Party.
Cryptographic Formats¶
Long-Term keys:
- (Q)EAA Provider has long-term key pair \((ep\_pub, ep\_priv)\) that is used to sign SD-JWT
- RP has long-term key pair \((rp\_pub, rp\_priv)\) that is used to sign OpenID4VP Authorization Request
- Wallet app has device key pair \((device\_pub, device\_priv)\) that is attested by the EAA Provider are used to sign KB-JWT
Transaction-specific keys:
- RP has ephemeral key pair \((rp\_eph\_pub, rp\_eph\_priv)\) that is used to encrypt the response
Artifacts:
- \(kb\_jwt := \text{sign}(nonce, audience, \text{hash}(sd\_jwt, disclosures))_{device\_priv}\)
- \(device\_Auth\) for mdoc
Dependencies¶
TODO: May want to expand to include metadata.
Note: Wallet attestation not shown in this chart.
Sequence Diagram for Same Device Flow¶
User Journey: (Q)EAA Presentation - Same Device
Step-by-Step Description¶
Note: While certain assumptions about session management of the Relaying Party are made here, the concrete implementation is considered out of scope for this document. The usual security considerations for web session management apply.
- User browses to Relying Party (RP) website
- Browser app on the user's device opens the RP website
- The RP generates a new browser session, depicted
session_id
- RP generates a key pair to be used for ECDH key agreement for response encryption
- RP generates an OpenID4VP Authorization Request, binding it internally to the
session_id
and stores it under arequest_uri
(e.g.,https://rp.example.com/oidc/request/1234
); - The request is bound to the user's browser session
- It is signed using a key bound to the RP's metadata that can be retrieved using the RP's client_id
- It contains the presentation_definition containing the information about the requested (Q)EAAs
- It contains RP's nonce and state
- It contains the purpose given by the RP
- RP returns a HTML page to the browser containing a link to the wallet app (e.g.,
openid4vp://authorize?client_id=..&request_uri=https://rp.example.com/oidc/request/1234
). It also sets a Cookie with thesession_id
. - The user clicks on the link
- The wallet app is launched with the custom URI scheme
- The user unlocks the wallet app (see notes below)
- The wallet app retrieves the Authorization Request from the RP website (e.g.,
https://rp.example.com/oidc/request/1234
) - The wallet app receives the Authorization Request
- The wallet app validates the Authorization Request using the RP's public key
- Was the signature valid and the key bound to the RP's metadata?
- Security: This ensures that the Authorization Request was not tampered with; it does not ensure that the party that sent the Authorization Request is the RP.
- The Wallet displays information about the identity of the Relying Party and the purpose, the user gives consent to present the (Q)EAA.
- (SD-JWT (Q)EAA) The Wallet generates a KB-JWT by signing over nonce and audience with device_priv
- (SD-JWT (Q)EAA) The Wallet creates the presentation according to presentation_definition by cutting out the unnecessary Disclosures and appending the KB-JWT
- (mdoc (Q)EAA) The Wallet generates an mdoc deviceAuth by signing over SessionTranscript with device_priv
- (mdoc (Q)EAA) The Wallet creates the presentation according to presentation_definition by cutting out the unnecessary Releases assembling the issuerAuth with deviceAuth
- The wallet app creates a VP token and a presentation submission
- The wallet app sends the VP token and presentation submission to the RP (encrypted to the RP's public key rp_eph_pub).
- The RP optionally decrypts the Authorization Response with rp_eph_pub received in the Authorization Request.
- The RP finds a session with the state, generates a response_code and stores the received vp_token
- The RP responds with a redirect inluding the generated response_code.
- The wallet launches the browser with the redirect_uri and response_code.
- The browser receives the redirect_uri and response_code and sends an HTTP GET request to the RP frontend, this request contains the Cookie set in the beginning of the protocol.
- The RP matches the session_id from the Cookie and matches the response_code to find the received vp_token.
- (SD-JWT (Q)EAA) The RP verifies the content of the vp_token. In case of SD-JWT it validates the Issuer signature from the (Q)EAA Provider, verifies the KB-JWT matching to the cnf claim and validates that the KB-JWT is fresh and matches to its own client_id and nonce.
- (mdoc (Q)EAA) The RP verifies the content of the vp_token. In case of mdoc it validates the Issuer signature from the (Q)EAA Provider, verifies the deviceAuth matching to the deviceKey and validates that the SessionTranscript is fresh and matches to its own client_id and nonce.
- The RP considers the user to be identified in the session context and continues the UX flow.
Sequence Diagram for Cross Device Flow¶
User Journey: (Q)EAA Presentation - Cross Device
Step-by-Step Description¶
Note: While certain assumptions about session management of the Relaying Party are made here, the concrete implementation is considered out of scope for this document. The usual security considerations for web session management apply.
- User browses to Relying Party (RP) website
- Browser app on the user's device opens the RP website
- The RP generates a new browser session, depicted
session_id
- RP generates a key pair to be used for ECDH key agreement for response encryption
- RP generates an OpenID4VP Authorization Request, binding it internally to the
session_id
and stores it under arequest_uri
(e.g.,https://rp.example.com/oidc/request/1234
); - The request is bound to the user's browser session
- It is signed using a key bound to the RP's metadata that can be retrieved using the RP's client_id
- It contains the presentation_definition containing the information about the requested (Q)EAAs
- It contains RP's nonce and state
- It contains the purpose given by the RP
- RP returns a HTML page to the browser containing a QR-Code to the wallet app (e.g.,
openid4vp://authorize?client_id=..&request_uri=https://rp.example.com/oidc/request/1234
). It also sets a Cookie with thesession_id
. - The user launches his wallet and hits a button to scan QR-Code from the RP's website.
- The wallet decodes the Authorization Request from the QR-Code and starts the OpenID4VP Flow.
- The user unlocks the wallet app (see notes below)
- The wallet app retrieves the Authorization Request from the RP website (e.g.,
https://rp.example.com/oidc/request/1234
) - The wallet app receives the Authorization Request
- The wallet app validates the Authorization Request using the RP's public key
- Was the signature valid and the key bound to the RP's metadata?
- Security: This ensures that the Authorization Request was not tampered with; it does not ensure that the party that sent the Authorization Request is the RP.
- The Wallet displays information about the identity of the Relying Party and the purpose, the user gives consent to present the (Q)EAA.
- (SD-JWT (Q)EAA) The Wallet generates a KB-JWT by signing over nonce, audience, and hash of SD-JWT and selected disclosures with device_priv
- (SD-JWT (Q)EAA) The Wallet creates the presentation according to presentation_definition by cutting out the unnecessary Disclosures and appending the KB-JWT
- (mdoc (Q)EAA) The Wallet generates an mdoc deviceAuth by signing over SessionTranscript with device_priv
- (mdoc (Q)EAA) The Wallet creates the presentation according to presentation_definition by cutting out the unnecessary Releases assembling the issuerAuth with deviceAuth
- The wallet app creates a VP token and a presentation submission
- The wallet app sends the VP token and presentation submission to the RP (encrypted to the RP's public key rp_eph_pub).
- The RP optionally decrypts the Authorization Response with rp_eph_pub received in the Authorization Request.
- The RP matches the browser session with the state parameter.
- (SD-JWT (Q)EAA) The RP verifies the content of the vp_token. In case of SD-JWT it validates the Issuer signature from the (Q)EAA Provider, verifies the KB-JWT matching to the cnf claim and validates that the KB-JWT is fresh and matches to its own client_id and nonce.
- (mdoc (Q)EAA) The RP verifies the content of the vp_token. In case of mdoc it validates the Issuer signature from the (Q)EAA Provider, verifies the deviceAuth matching to the deviceKey and validates that the SessionTranscript is fresh and matches to its own client_id and nonce.
- The RP responds with HTTP 200 and acknowledges the received vp_token.
- The browser refreshes the RP's website, either by polling regularly or by receiving a signal from the RP, e.g. through websockets. It sends a HTTP GET request using the Cookie set in the beginning of the protocol.
- The RP matches the session_id from the Cookie and matches this with the verification result.
- The RP considers the user to be identified in the session context and continues the UX flow.
Usability Considerations¶
Common Considerations¶
- Relying Party should inform users in advance of what is required for the process to be completed successfully and what steps to follow
- For reasons of transparency and to increase trust, Relying Parties should provide sufficient information (metadata) for the consent screen. This allows users to learn everything relevant e.g. about the relying party itself, privacy and data retention
- The user's data values for the requested attributes can be displayed on the consent screen
- The user only needs to confirm the (Q)EAA presentation with the Device Authenticator
Same Device Considerations¶
- It needs to be clarified whether the wallet app needs to be unlocked in this flow, as the device authenticator is requested again directly after the consent screen. This might create friction and feel redundant to users
- It must be ensured that users are returned to the correct tab in the correct browser in order to continue the process or users know how to get there manually, if necessary (especially for iOS devices, if the process was not started in the default browser)
Cross Device Considerations¶
- It needs to be clarified whether the wallet app needs to be unlocked in this flow and how this should be implemented.
- User can then continue with the process on the RP page on the second device (page must be updated accordingly by the RP)
Privacy Considerations¶
- Selective Disclosure is achieved by ensuring that the presentation contains only those data items (claims) that are requested by the RP. The selective disclosure features of SD-JWT are used to this end.
- Unlinkability has to be achieved with batch issuance
- In Presentation Step 5, a malicious app may spoof the wallet app; an attacker may
- on his own device: Capture the request and replay it to a victim on another device, thus having the victim identify itself in a context of the attacker (Relaying Attack breaking Identification Context); or
- on the victim's device: Capture the request and spoof the whole identification process or parts of it (Wallet App Spoofing).
- In Presentation Step 5: An attacker acting as an RP can forward a request from a different RP.
- As long as the request remains unchanged, we're in the Relaying Attack breaking Identification Context
- If the attacker changes anything in the request, this will break the signature. The attacker could otherwise attempt to
- insert his own ephemeral key, leading to an SD-JWT artifact that could be used in a different flow between the attacker and some other RP.
- modify state or nonce or other data. Q: Any useful attacks resulting from this?
- In Presentation Step 14: The RP must not consider the user identified at this point; it is important to have the browser redirect in the later steps.
Security Considerations¶
TBD