Skip to content

PID Option C: Signed Credential

Basic Idea

In this flow, long-lived, digitally signed PID credentials in ISO mdoc and IETF SD-JWT VC formats are issued to the Wallet Instance utilizing the OpenID4VP protocol. During the issuance, the user is authenticated using the eID card, so when these PID credentials are presented to the Relying Parties over OpenID4VP protocol, there is no need for the user to use physical eID card. This flow trusts Wallet Instance to manage the keys on the device without Wallet Backend's involvement (unlike Option C').

This section describes the commonalities of the Issuer-Signed options. Details to the type of Wallet Security Cryptographic Device (WSCD), the user binding and the lifecycle of the credentials is further specified in the sub-options.

Credential formats

Two solutions are described:

  • ISO mdoc The ISO mdoc credential format is used with
  • issuerAuth as issuer data authentication, a COSE_Sign1 signature over the MobileSecurityObject (see ISO 23220-4 7.1.3.4.2.1); containing
    • the Wallets long-lived key in deviceKeyInfo
    • signed hashes in the valueDigests
  • deviceSignature as mdoc authentication method, a COSE_Sign1 MAC over the deviceAuthentication data (see ISO 18013-5 9.1.3.5)
    • containing the PID data
  • SD-JWT VC The SD-JWT VC credential format is used with
  • SD-JWT signed with JWS by the PID Provider; containing
    • the Wallets long-lived key in cnf
    • the signed hashes in _sd arrays
  • the Disclosures containing the PID data

Cryptographic Formats

Issuance

Long-Term keys:

  • PID Provider has long-term key pair \((pp\_pub, pp\_priv)\) which is used
  • to sign the Credential
  • RP has long-term key pair \((rp\_pub, rp\_priv)\) which is used
  • to sign over the authorization request, authenticating its contents
  • Wallet app has device key pair \((device\_pub, device\_priv)\) which is used
  • to generate proof of possession of a Credential

Artifacts

Issuance

  • PID Provider issues SD-JWT (plus Disclosures): \(sd\_jwt := \text{sign}(\mathit{hashed\_eID\_data}, device\_pub)_{pp\_priv}\)

Presentation

  • \(kb\_jwt := \text{sign}(nonce, audience, \text{hash}(sd\_jwt, disclosures))_{device\_priv}\)

Dependencies

TODO: May want to expand to include metadata.

G cluster_pid_provider PID Provider cluster_wallet Wallet pp 🗝 (pp_priv, pp_pub) user_data eID data pp->user_data sign (SD-JWT) dev 🗝 (device_pub, device_priv) pp->dev sign (SD-JWT) nonce_audience nonce, audience dev->nonce_audience sign (KB-JWT)

Note: Wallet attestation not shown in this chart.

Sequence Diagram

Wallet Activation

To initialize the wallet, the Wallet obtains wallet attestation as defined in Wallet Attestation.

Issuance

User Journey: PID Issuance - Issuer Signed

PID Issuance over OpenID4VCI using Issuer-Signed Credentials (generic)PID Issuance over OpenID4VCI using Issuer-Signed Credentials (generic)UserOpenID HolderUserOpenID HolderWallet Secure Cryptographic Device(WSCD)Long-term Key: (device_pub,device_priv)Wallet Secure Cryptographic Device(WSCD)Long-term Key: (device_pub,device_priv)User's EUDI Wallet Instance(eID-Client)User's EUDI Wallet Instance(eID-Client)PID Provider(eService+eID Server)Long-term Key: (pp_pub,pp_priv)PID Provider(eService+eID Server)Long-term Key: (pp_pub,pp_priv)(001)open wallet, unlock walletScreen: launch_walletScreen: unlock_wallet(002)request issuance of PIDScreen: credential_catalogPID Issuer and EUDI Wallet have inherent trust relationship, metadata maybe pre-configured or retrieved(003)[TLS] HTTP POST</session_endpoint> walletattestation nonce(004)generate and store nonce(005)[TLS] HTTP 200 <walletattestation nonce>(006)get proof of possession forwallet attestation (walletattestation nonce)Attestation guarantees with high certainty that Wallet is trustworthy andnot manipulated(007)[TLS] HTTP POST PAR(client_id, code_challenge,wallet attestation+PoP)(008)verify wallet attestation andcheck Wallet Provider solutionstatus on trust list(009)[TLS] HTTP 200 request_uri(010)[TLS] HTTP GET <OpenID4VCIAuthorizationRequest(request_uri)>Screen: consent_add_credentialScreen: eid_startRead eID or Smart eID acc. to BSI TR-03130(011)[TLS] HTTP 200 starting theeID Process(012)eID Process(013)<eID-PIN>Screen: eid_pin(014)eID Process(015)[TLS] HTTP GET finishing theeID process with refreshUrlScreen: eid_nfc_data(016)[TLS] HTTP 302 <OpenID4VCIAuthorizationResponse(authorizationcode)>(017)[TLS] HTTP POST <TokenRequest(authorization code,PKCE code_verifier, walletattestation, DPoP Header)>(018)lookup authorization codegenerate TokenResponse withDPoP access tokenverify PKCE challenge(019)[TLS] HTTP 200 <TokenResponse(DPoP-boundaccess_token, c_nonce)>(020)generate device binding keypair (device_pub, device_priv)and proof of possession withc_nonceScreen: device_authenticator(021)generate credential responseencryption key pair(cre_eph_pub, cre_eph_priv)(022)createcredential_response_encryptionobject with jwk containingcre_eph_pub(023)[TLS] HTTP POST <CredentialRequest(DPoP-bound accesstoken, device_pub,credential_response_encryptionobject)>(024)lookup access token andvalidate key proofalt[C: ISO mdoc](025)create mdoc with eID dataand device_pub, signed bypp_priv, and matchingNameSpaceBytes(026)generate encrypted credentialresponse JWT using the valuesreceived in thecredential_response_encryptionobject(027)[TLS] HTTP 200<JWT(CredentialResponse(mdoc))>[C: SD-JWT VC](028)create SD-JWT VC with eIDdata and device_pub, signedby pp_priv, and matchingDisclosures(029)generate encrypted credentialresponse JWT using the valuesreceived in thecredential_response_encryptionobject(030)[TLS] HTTP 200<JWT(CredentialResponse(SD-JWT VC,Disclosures))>(031)decrypt credential responseJWT(032)store PID credentialPID is signed dataScreen: successScreen: home

Presentation

User Journey: PID Presentation - Issuer Signed

PID presentation over OpenID4VPPID presentation over OpenID4VPUserOpenID HolderUserOpenID HolderBrowser App(same device)Browser App(same device)Relying PartyLong-term Key: (rp_pub,rp_priv)Relying PartyLong-term Key: (rp_pub,rp_priv)User's EUDI Wallet Instance(eID-Client)Device binding Key: (device_pub,device_priv)User's EUDI Wallet Instance(eID-Client)Device binding Key: (device_pub,device_priv)Wallet Secure Cryptographic Device(WSCD)Wallet Secure Cryptographic Device(WSCD)(001)browse to applicationScreen: same_device_relying_party_start(002)[TLS] HTTP GET <rp-website>(003)generate ephemeral key pair(rp_eph_pub, rp_eph_priv)(004)create OpenID4VPAuthorization Request, sign with rp_priv, store under <request_uri>Authorization Request includes:- presentation_definition- purpose- state- nonce- rp_eph_pub- response_uri(005)generate new browser sessionsession_id and bind theauthorization request to it(006)[TLS] HTTP 200 HTMLcontaining wallet-linkopenid4vp://authorize?")client_id=..&request_uri=<request_uri>Set-Cookie: sid=session_id(007)action to start flow/launchwallet(008)launch with wallet-linkopenid4vp://Potential security risk: Wallet app may bespoofed by malicious appScreen: launch_wallet(009)unlock walletmay be moved to later point in flow orremoved, see notes.Screen: unlock_wallet(010)[TLS] HTTP GET<request_uri>Potential privacy risk: RP learns existance ofwallet app and potentially identifyinginformation (e.g., headers)(011)[TLS] HTTP 200 <JWT-SecuredAuthorization Request>(012)validate AuthorizationRequest JWT using rp_pub(013)user consent to present PID toRelying Party for givenpurposeScreen: consent_present_credentialScreen: device_authenticatoralt[B.1.1: ISO mdoc](014)prepare mdoc presentationaccording to<presentation_definition> byremoving unnecessaryNameSpaceBytes(015)calculate SessionTranscript(mDocGeneratedNonce,clientId, responseUri, nonce)and generate deviceAuthpayload[B.1.2: SD-JWT VC](016)prepare SD-JWT presentationaccording to<presentation_definition> byremoving unnecessaryDisclosures(017)generate KB-JWT payload(nonce, audience and hash ofSD-JWT and disclosures)(018)sign payload with device_privalt[C: ISO mdoc](019)assemble deviceAuth andbuild presentation withissuerSigned anddeviceSigned(deviceAuth)[C: SD-JWT VC](020)assemble KB-JWT and buildpresentation with SD-JWT,selected Disclosures andKB-JWT(021)create vp_token andpresentation_submission(022)add optionally otherpresentations according tothe presentation_definition(023)[TLS] HTTP POST encrypted<AuthorizationResponse(presentation_submission,vp_token, state)>(024)look up state in existingsessionscreate & store response_codefor session(025)[TLS] HTTP 200 <redirect_uriincl. response_code>(026)launch browser with<redirect_uri withresponse_code>Screen: success_redirect(027)[TLS] HTTP GET <redirect_uriwith response_code>Cookie: sid=session_id(028)look up session withsession_id and matchresponse_codealt[B.1.1: ISO mdoc](029)verify contents of<vp_token>:- verify mdoc issuerAuth PID- verify deviceAuth withdevice_priv from issuerAuth- calculate and validatecorrect SessionTranscript[B.1.2: SD-JWT VC](030)verify contents of<vp_token>:- verify SD-JWT PID- verify KB-JWT withdevice_priv from SD-JWT- validate nonce and audiencefrom KB-JWT(031)[TLS] HTTP 200 <HTML withcontinued UX flow>Screen: same_device_relying_party_identified

Step-by-Step Description

Issuance

  1. The user opens and unlocks the Wallet.
  2. The user browses through the pre-configured credential catalog and chooses to request a PID.
  3. The Wallet requests a fresh nonce for the wallet attestation nonce (wallet attestation).
  4. The PID Provider generates a fresh nonce linked to the issuance session.
  5. The PID Provider returns the wallet attestation nonce to the Wallet.
  6. The Wallet performs a wallet attestation.
  7. Optionally it fetches a new wallet attestation from the Wallet Provider if none exists yet.
  8. It generates a proof of possession (PoP) for the public key of the wallet attestation using its WSCD.
  9. The Wallet sends the Pushed Authorization Request to the PID Provider containing
  10. the Wallet Provider's client_id,
  11. the authorization_details for PID,
  12. a PKCE code_challenge,
  13. a wallet attestation and proof of possession.
  14. The PID Provider verifies the wallet attestation and its proof of possession and validates the certification status of the Wallet Solution on a trust list.
  15. The PID Provider returns a request_uri that is bound to the Pushed Authorization Request.
  16. The Wallet sends the Authorization Request containing
    • the PAR request_uri.
  17. The PID Provider responds with the first step to start the eID process with the wallet app, e.g. the tcToken. Note that this is the direct HTTP Response to Step 14.
  18. Further communication is exchanged to perform the eID process.
  19. The user provides the eID PIN to the wallet app.
  20. Further communication is exchanged to perform the eID process.
  21. The eID process is finished and as a final step the Wallet sends a request to the PID Provider calling the refreshURL. From now on Wallet and PID Provider are using the TLS-PSK channel generated by the eID flow.
  22. The PID Provider responds to the Wallet with an Authorization Response containing
    • the auth code.
  23. The Wallet sends a Token Request to the PID Provider containing
    • the auth code from Authorization Response,
    • the PKCE code_verifier matching the code_challenge from Authorization Request,
    • the wallet attestation and proof of possession and
    • a DPoP key.
  24. The PID Provider matches the code, verifies the PKCE code_verifier to the previously received code_challenge and verifies the wallet attestation. It then generates an access token bound to the DPoP key.
  25. The PID Provider sends a Token Response containing
    • DPoP-bound access token and
    • a c_nonce.
  26. The Wallet generates a new key pair for device binding (device_pub, device_priv) and signs the c_nonce using its WSCD.
  27. The Wallet generates a new ephemeral keypair (cre_eph_pub, cre_eph_priv).
  28. The Wallet creates the credential_response_encryption JSON object containing the following information:
    • a jwk containing the cre_eph_pub
    • the JWE alg parameter
    • the JWE enc parameter
  29. The Wallet sends a Credential Request to the PID Provider containing
    • the DpoP-bound access token,
    • the device binding key device_pub and the proof of possession and
    • the credential_response_encryption object.
  30. The Issuer validates the access token and the proof of possession.
  31. (mdoc) The PID Provider creates the mdoc by signing with pp_priv containing
    • the issuerAuth with the device_pub as deviceKey and hashes of the eID data and
    • the eID data as NameSpaceBytes.
  32. (mdoc) The PID Provider creates an encrypted JWT (JWE) using the values received in the credential_response_encryption object and adds (among others) the PID as mdoc to the payload.
  33. (mdoc) The PID Provider sends the Credential Response JWT containing
    • the PID as mdoc.
  34. (SD-JWT) The PID Provider creates SD-JWT VC by signing with pp_priv containing
    • the SD-JWT with the device_pub as confirmation claim and hashes of the eID data and
    • the eID data as Disclosures.
  35. (SD-JWT) The PID Provider creates an encrypted JWT (JWE) using the values received in the credential_response_encryption object and adds (among others) the PID as SD-JWT VC to the payload.
  36. (SD-JWT) The PID Provider sends the Credential Response JWT containing
    • the PID as SD-JWT VC.
  37. The Wallet decrypts the Credential Response JWT using the cre_eph_priv and retrieves the PID.
  38. The Wallet stores the PID credential.

Presentation

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.

  1. The user browses to Relying Party (RP) website
  2. Browser app on the user's device opens the RP website
  3. RP generates a key pair to be used for ECDH key agreement for SD-JWT HMAC'ing
  4. RP generates an OpenID4VP Authorization Request and stores it under a request_uri (e.g., https://rp.example.com/oidc/request/1234);
  5. The request is bound to the user's browser session
  6. It is signed using a key bound to the RP's metadata that can be retrieved using the RP's client_id
  7. It contains the ephemeral key for response encryption
  8. It contains RP's nonce and state
  9. It contains the RP's response_uri endpoint for sending the Authorization Response over POST
  10. RP generates a new browser session and binds the generated Authorization Request to it
  11. 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); a cookie with the browser session id is set
  12. The user clicks on the link
  13. The RP website navigates to the custom scheme link to launch the wallet app
  14. The user unlocks the wallet app (see notes below)
  15. The wallet app retrieves the Authorization Request from the RP website (e.g., https://rp.example.com/oidc/request/1234)
  16. The wallet app receives the Authorization Request
  17. 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.
  18. The Wallet displays information about the identity of the Relying Party and the purpose, the user gives consent to present the PID.
  19. (mdoc) The Wallet prepares an mdoc presentation according to the presentation_definition by removing NameSpaceBytes of not disclosed attributes.
  20. (mdoc) The Wallet calculates the SessionTranscript according to ISO-18013-7 Annex B.4.4 from mDocGeneratedNonce, client_id, responseUri, nonce and generates the deviceAuthentication structure from SessionTranscript and NameSpaceBytes for signing.
  21. (SD-JWT) The Wallet generates an SD-JWT VC presentation according to the presentation_definition by removing Disclosures of not disclosed attributes.
  22. (SD-JWT) The Wallet creates the header and payload for the KB-JWT from audience, nonce, hash of issuer-signed JWT+Disclosures for signing.
  23. The Wallet signs the payload with device_priv.
  24. (mdoc) The Wallet assembles the deviceAuth from header, payload and signature and builds the presentation from deviceAuth and issuerSigned
  25. (SD-JWT) The Wallet assembles the KB-JWT from header, payload and signature and builds the SD-JWT VC presentation from issuer-signed JWT, Disclosures and KB-JWT
  26. The wallet app creates a VP token and a presentation submission from the received SD-JWT PID.
  27. Optional: The wallet app can add further presentations
  28. The wallet app sends the VP token and presentation submission to the RP (encrypted to the RP's public key rp_eph_pub).
  29. The RP finds a session with the state and generates a response_code for this session
  30. The RP returns the redirect_uri with the response_code to the wallet app
  31. The wallet app launches the browser with the redirect_uri and response_code.
  32. The browser sends the redirect_uri and response code to the RP, attaching the browser session id as a cookie.
  33. The RP looks up whether there exists a session with the session id from the cookie and a matching response_code
  34. (mdoc) The RP verifies the PID in the VP token and verifies the SessionTranscript calculated from nonce, mDocGeneratedNonce, clientID, response_uri.
  35. (SD-JWT) The RP verifies the SD-JWT PID in the VP token, verifies the KB-JWT using the device_priv in the SD-JWT, and verifies the nonce and audience in the KB-JWT
  36. The RP considers the user to be identified in the session context and continues the UX flow.

Extensions to the Protocols

This section defines extensions to the protocols required to implement this flow (Option C).

Issuer Session Endpoint (at the PID Provider)

Note that this extension is the same across multiple flows.

This endpoint is used by the Wallet to obtain session_id from the PID Provider that is used to bind PoPs to the session and prove their freshness. Support for this endpoint is REQUIRED.

To fetch the session_id, the Wallet MUST send an HTTP request using the POST method and the application/json media type. The PID Provider MUST return the HTTP Status Code 200 and a session_id parameter defined below.

  • session_id: REQUIRED. String that is a unique session identifier, chosen as a cryptographically random nonce with at least 128 bits of entropy.

Communication with the Session Endpoint MUST utilize TLS.

Below is a non-normative example of a request to a Session Endpoint:

POST /session_endpoint HTTP/1.1
Host: server.example.com
Content-Type: application/json

Below is a non-normative example of a response from a Session Endpoint:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{
  "session_id": "iOiJSUzI1NiIsInR"
}

OpenID4VCI Credential Issuer Metadata

Note that this extension is the same across multiple flows.

This document defines the following additional Credential Issuer Metadata parameters:

  • session_endpoint: REQUIRED. URL of the Credential Issuer's Session Endpoint, as defined in a previous section. This URL MUST use the https scheme and MAY contain port, path, and query parameter components.

Usability Considerations

Issuance

  • Credential catalogue should inform users in advance of what is required for the successful issuance of the PID and what steps follow
  • For reasons of transparency and to increase trust, PID Provider should provide sufficient information (metadata) for the consent screen. This allows users to learn everything relevant e.g. about the PID Provider itself, privacy and data retention
  • eID process is integrated in Wallet. No context switch to the AusweisApp is required
  • Physical ID card is required for issuing the PID credential
  • Online-Ausweisfunktion must be activated
  • eID PIN must be set by the user (replacement of the Transport PIN) and be known to them so that they can successfully confirm the process
  • User must confirm the process with the eID PIN and the device authenticator
  • User can have a PID credential derived from the eID on several end devices at the same time

Presentation

  • Offline support for PID representation
  • Relying Party should inform users in advance of what is required for the process to be completed successfully and what steps follow
  • 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
  • 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 PID presentation with the Device Authenticator
  • Physical ID card is not required for PID presentation
  • It must be ensured that users return to the correct tab in the correct browser in order to continue the process or know how to get there manually if necessary (especially for iOS devices, if the process was not started in the default browser)

Privacy Considerations

  • Unobservability:
  • Issuer: the issuer-signed credentials are under sole control of the Wallet, the usage of credentials is not recognized by the Issuer, even when revocation is used
  • Wallet Provider: see specific sub-options
  • Unlinkability:
  • Outsider: Both OpenID4VCI and OpenID4VP are entirely encrypted using TLS, an outsider is therefore not able to link any transactions apart from the low-level network traffic itself
  • Relying Party: the same Relying Party will not be able to link transactions when batch-issued single use credentials are issued
  • Issuer: the PID Issuer will be able to link the transactions
  • Colluding Relying Parties: colluding Relying Parties will not be able to link transactions when batch-issued single use credentials are issued
  • Colluding Issuers: colluding issuers will not be able to link transactions when ephemeral or issuer-specific wallet attestations are used
  • Colluding Relying Party and Issuer: colluding PID Provider and Relying Party will be able to link transactions due to the nature of SD-JWT VC and ISO mdoc cryptography
  • Repudiation:
  • Repudiation of Data Authenticity: issuer-signed credentials are not repudiable due to the nature of signature algorithms. This may be mitigated by key publication, but is currently out of scope
  • Repudiation of User binding: in the current design presentations are not repudiable due to the use of signature algorithms for key binding. ISO mdoc has the option to use deviceMac, which is currently not in scope.
  • Selective Disclosure: both SD-JWT VC and ISO mdoc achieve selective disclosure by ensuring that the Wallet contains only those attributes (claims) that are requested by the Relying Party

Security Considerations

  • Level of Assurance:
  • Unforgeability of Credentials: unforgeability is guaranteed by the signature of the issuer-signed credential, i.e. the SD-JWT or the issuerSigned
  • Freshness of Presentations: freshness is guaranteed by the nonce provided by the Relying Party, which is integrated in the KB-JWT or deviceAuth, see replay prevention.
  • User Binding of presentations: see specific sub-options
  • Session Integrity:
  • Issuance: PID Provider and Wallet share a pre-configured trust relationship, established through certificate pinning and other mechanisms
  • Presentation: Session Integrity is supported by OpenID4VP through browser redirect, see session fixation.
  • further topics:
    • In Presentation Step 008, a malicious app may spoof the wallet app; an attacker may
    • on the attacker's 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 008: 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 the attacker's 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 024: The RP must not consider the user identified at this point; it is important to have the browser redirect in the later steps.

Open Topics

  • integrate revocation mechanisms
  • Security of PID Provider Interface in Issuance Step 3ff:
  • Are additional steps required to protect the interface to the PID Provider?
  • What exactly is the transaction binding?
  • How is the eID process tied to the process at the PID provider?