Skip to content

PID Option C'': Signed Credential with eID Card

Basic Idea

In this design, PID credentials are issued on-demand in ISO mdoc / SD-JWT VC format using the OpenID4VCI protocol and directly presented using the OpenID4VP protocol. While this Option is similar to Option B, the PID credentials are signed by the PID Provider for the specific transaction. The user is authenticated by utilizing the eID card towards the PID Provider in every presentation.

In this design, the device key for signing the presentation is generated by the PID Provider in order to achieve a high level of assurance and perform critical key management outside the Wallet. To ensure that the PID Provider does not get to know where a PID credential is used and which claims are provided, the payload of the presentation part (deviceAuth for mdoc or KB-JWT for SD-JWT) is created by the Wallet and only its hash is sent to the PID Provider for signing. This design therefore results in the following properties:

  • The complexity of implementation is lower for the Wallet, as it does not need to handle and secure the device key.
  • The PID Provider can enforce that there is exactly one presentation for the PID credential, ensuring a tight binding between the eID Card process and the PID presentation.
  • It is expected that certification for LoA High is easier for this design, as the PID Provider has full control over all keys and a secure authentication is guaranteed each time via the usage of the eID.

Note that this design assumes that the signing algorithm performs a hashing step on the data first; this step is happening at the Wallet, while the rest of the signing is done at the PID Provider. In particular, this works well with ECDSA.

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
    • an ephemeral key in deviceKeyInfo
    • signed hashes in the valueDigests
  • deviceSignature as mdoc authentication method, a COSE_Sign1 signature over the deviceAuthentication data (see ISO 18013-5 9.1.3.6); 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
    • an ephemeral key in cnf
    • the signed hashes in _sd arrays
  • KB-JWT signed by the PID Provider with the Hash; containing
    • nonce and audience of the Relying Party
    • a hash of the SD-JWT and the selected disclosures
  • Disclosures containing the PID data

Cryptographic Formats

(to be defined)

Issuance

Long-Term keys:

Transaction-specific keys:

Artifacts:

Presentation

Long-Term keys:

Transaction-specific keys:

Artifacts:

Dependencies

Sequence Diagram

Issuance

PID presentation over OpenID4VP and On-the-fly PID Issuance over OpenID4VCI with SD-JWTPID presentation over OpenID4VP and On-the-fly PID Issuance over OpenID4VCI with SD-JWTUserOpenID 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)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)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 existence 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_credentialPID provisioningPID Issuer and EUDI Wallet have inherenttrust relationship, metadata may bepre-configured or retrieved(014)Wallet fetches fresh walletattestation from backend(015)[TLS] HTTP POST</session_endpoint> walletattestation nonce(016)generate and store nonce(017)[TLS] HTTP 200 <walletattestation nonce>(018)sign wallet attestation PoPJWT (incl. wallet attestationnonce)(019)[TLS] HTTP POST PAR (PKCEcode_challenge, walletattestation JWT, walletattestation PoP JWT,redirect_uri,authorization_details=PIDwith requested attributes)(020)verify wallet attestation & PoPcheck Wallet Provider solutionstatus on trust list(021)[TLS] HTTP 200 request_uriAttestation guarantees with high certaintythat Wallet is trustworthy and notmanipulated(022)[TLS] HTTP GET <OpenID4VCIAuthorizationRequest(request_uri)>Screen: eid_startRead eID or Smart eID acc. to BSI TR-03130(023)[TLS] HTTP 200 starting theeID Process(024)eID Process(025)<eID-PIN>Screen: eid_pin(026)eID Process(027)[TLS] HTTP GET finishing theeID process with refreshUrlScreen: eid_nfc_data(028)[TLS] HTTP 302 AuthorizationResponse (code)(029)[TLS] HTTP POST TokenRequest(code, code_verifier,DPoP key)(030)match code and verifycode_verifier(031)[TLS] HTTP 200 TokenResponse(access_token,c_nonce)alt[C'': ISO mdoc](032)HTTP POST <CredentialRequest(DPoP-bound accesstoken)>(033)lookup access token(034)generate ephemeral devicekey pair (device_pub,device_priv)(035)create mdoc with all eID dataattributes and device_pub,signed by pp_priv, andmatching NameSpaceBytes(036)[TLS] HTTP 200 CredentialResponse(issuerSigned)issuerSigned contains issuerAuth (the signedpart, also known as MSO) and nameSpaces(the data elements)(037)calculate SessionTranscript(mDocGeneratedNonce,clientId, responseUri, nonce)(038)calculate hash of deviceAuthusing SessionTranscript andincluding only selected dataelements in nameSpaces(039)[TLS] HTTP POST PresentationSigning Request (deviceAuthhash, DPoP-bound accesstoken)(040)create signature overdeviceAuth hash usingdevice_priv(041)[TLS] HTTP 200 PresentationSigning Response(deviceAuthsignature)(042)assemble mdoc usingdeviceAuth and its signaturemdoc is ISO18013-5 Document containingissuerAuth and deviceAuth[C'': SD-JWT VC](043)[TLS] HTTP POST <CredentialRequest(DPoP-bound accesstoken)>(044)lookup access token(045)generate ephemeral devicekey pair (device_pub,device_priv)(046)create SD-JWT with eID dataand device_pub, signed bypp_priv and matchingDisclosures(047)[TLS] HTTP 200 CredentialResponse(SD-JWT)(048)calculate hash of KB-JWTusing nonce, audience, andsd_hashthe SD-JWT+Disclosures are required by theWallet to calculate sd_hash(049)[TLS] HTTP POST PresentationSigning Request (kb_hash,DPoP-bound access token)Issuer ensures that each device key is onlyused once and deletes it afterwards(050)create KB-JWT signature overkb_hash with device_priv(051)[TLS] HTTP 200 PresentationSigning Response(KB-JWTsignature)(052)assemble KB-JWT using thepayload and its signature(053)create vp_token andpresentation_submission(054)add mDL presentationaccording to<presentation_definition>with <nonce> to vp_tokenand presentation_submissionWallet may add presentations with keysunder its own control as thecommunication channel between Relying Partand PID Provider is not E2EE(055)[TLS] HTTP POST encrypted<AuthorizationResponse(presentation_submission,vp_token, state)>(056)look up state in existingsessionscreate & store response_codefor session(057)[TLS] HTTP 200 <redirect_uriincl. response_code>(058)launch browser with<redirect_uri withresponse_code>Screen: success_redirect(059)[TLS] HTTP GET <redirect_uriwith response_code>Cookie: sid=session_id(060)look up session withsession_id and matchresponse_codealt[B.1.1: ISO mdoc](061)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](062)verify contents of<vp_token>:- verify SD-JWT PID- verify KB-JWT withdevice_priv from SD-JWT- validate nonce and audiencefrom KB-JWT(063)[TLS] HTTP 200 <HTML withcontinued UX flow>Screen: same_device_relying_party_identified

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.

  1. 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 response encryption
  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 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 an 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
  18. Was the signature valid and the key bound to the RP's metadata?
  19. 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.
  20. The Wallet displays information about the identity of the Relying Party and the purpose, the user gives consent to present the PID.
  21. The Wallet fetches fresh wallet attestation from the Wallet Provider backend.
  22. The Wallet requests a fresh nonce for the wallet attestation nonce from the PID Provider (wallet attestation nonce).
  23. The PID Provider generates a fresh nonce linked to the issuance session.
  24. The PID Provider returns the wallet attestation nonce to the Wallet.
  25. The Wallet generates a Wallet Attestation PoP and signs it with dev_priv; containing
    • audience
    • expiration time
    • wallet attestation nonce
  26. The wallet sends the Pushed Authorization Request to the PID Provider; containing
    • PKCE code_challenge
    • wallet attestation + PoP
    • redirect_uri
    • an authorization_details object requesting a PID with a list of claims
  27. 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.
  28. The PID Provider returns a request_uri that is bound to the Pushed Authorization Request.
  29. The Wallet sends the Authorization Request; containing
    • the PAR request_uri
  30. 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.
  31. Further communication is exchanged to perform the eID process
  32. The user provides the eID PIN to the wallet app.
  33. Further communication is exchanged to perform the eID process
  34. 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.
  35. The PID Provider responds to the Wallet with an Authorization Response; containing
    • the auth code
  36. 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
    • a DPoP key
  37. The PID Provider matches the code and verifies the PKCE code_verifier to the previously received code_challenge. It then generates an access token bound to the DPoP key.
  38. The PID Provider sends a Token Response; containing
    • DPoP-bound access token
    • a c_nonce
  39. (mdoc) The Wallet send a Credential Request; containing
    • DPoP-bound access token
    • sessionTranscript
    • it does not contain a "proof"
  40. (mdoc) The PID Provider looks up and validates the access token.
  41. (mdoc) The PID Provider generate an ephemeral DeviceKey pair (device_pub,device_priv).
  42. (mdoc) The PID Provider creates the mdoc issuerSigned; containing
    • issuerAuth (MSO) with the public part of DeviceKey and the hashes of the data elements and signs it with pp_priv
    • nameSpaces with the data elements
  43. (mdoc) The PID Provider returns the issuerSigned to the Wallet.
  44. (mdoc) The Wallet calculates the SessionTranscript according to ISO-18013-7 Annex B.4.4 from mDocGeneratedNonce, client_id, responseUri, nonce. The final result is a SHA-256 hash, thus not revealing the client_id and ResponseUri to the PID Provider.
  45. (mdoc) The Wallet generates the deviceAuth utilizing the SessionTranscript and the requested data elements for nameSpaces and calculates the hash of it
  46. (mdoc) The Wallet sends the hash of the deviceAuth to the Presentation Signing Endpoint of the PID Provider; the request is protected by a DPoP-bound access token.
  47. (mdoc) The PID Provider creates the signature for the deviceAuth hash.
  48. (mdoc) The PID Provider returns the signature to the Wallet.
  49. (mdoc) The Wallet creates the mdoc using the issuerAuth, the deviceAuth payload and the deviceAuth signature returned by the PID Provider.
  50. (SD-JWT) The Wallet send a Credential Request; containing - DPoP-bound access token - it does not contain a "proof"
  51. (SD-JWT) The PID Provider looks up and validates the access token.
  52. (SD-JWT) The PID Provider generate an ephemeral DeviceKey pair (device_pub,device_priv).
  53. (SD-JWT) The PID Provider creates the issuer-signed part of the SD-JWT and signs it with pp_priv; containing
    • eID as the user claims
    • device_pub as cnf claim
  54. (SD-JWT) The PID Provider sends the Credential Response; containing:
    • SD-JWT VC PID with Disclosures
  55. (SD-JWT) The Wallet creates the header and payload for the KB-JWT from audience, nonce, and the hash of SD-JWT and selected disclosures and hashes it. The Wallet appends the KB-JWT to the SD-JWT. Note that this step can only happen after the SD-JWT has been issued and received by the Wallet, as the KB-JWT payload includes the sd_hash parameter, that is a hash over issuerSigned JWT and the Disclosures.
  56. (SD-JWT) The Wallet sends a Request to the Presentation Signing Endpoint transmitting the hash of the KB-JWT. The request is protected by a DPoP-bound access token.
  57. (SD-JWT) The PID Provider recognizes the device key from the provided public key reference and uses device_priv to create the signature of the KB-JWT using the hash of the KB-JWT. Afterwards, it must ensure that the device key pair is deleted and not used again.
  58. (SD-JWT) The PID Provider sends the response containing the signature of KB-JWT.
  59. (SD-JWT) The Wallet assembles the PID presentation from SD-JWT and KB-JWT payload/signature.
  60. The wallet app creates a VP token and a presentation submission from the received SD-JWT PID.
  61. Optional: The wallet app can add further presentations with keys under its own control as the communication channel between Relying Part and PID Provider is not E2EE
  62. The wallet app sends the VP token and presentation submission to the RP (encrypted to the RP's public key rp_eph_pub).
  63. The RP finds a session with the state and generates a response_code for this session.
  64. The RP returns the redirect_uri with the response_code to the wallet app.
  65. The wallet app launches the browser with the redirect_uri and response_code.
  66. The browser sends the redirect_uri and response code to the RP, attaching the browser session id as a cookie.
  67. The RP looks up whether there exists a session with the session id from the cookie and a matching response_code
  68. (mdoc) The RP verifies the PID in the VP token with the MAC key and verifies the SessionTranscript calculated from nonce, mDocGeneratedNonce, clientID, response_uri.
  69. (SD-JWT) The RP verifies the SD-JWT PID in the VP token with the MAC key, verifies the KB-JWT using the kb_eph_pub in the SD-JWT, and verifies the nonce and audience in the KB-JWT
  70. The RP considers the user to be identified in the session context and continues the UX flow.

Extensions to the Protocols

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"
}

Presentation Signing Endpoint

This endpoint is used by the Wallet to obtain a signature over the KB-JWT or deviceAuth structure. Support for this endpoint is REQUIRED.

Communication with this endpoint MUST use TLS and this endpoint MUST be protected using the DPoP-bound access token, similar to the Credential Endpoint.

To fetch the bytes of the signature, the Wallet MUST send an HTTP request using the POST method and the application/json media type. The request contains a JSON-encoded object with the following parameters:

  • hash_bytes: REQUIRED. base64url-encoded bytes of the hash over the bytes of the deviceAuth structure or the KB-JWT structure, respectively. Note that the hash algorithm MUST be matched to the signing algorithm used by the PID Provider for signing the deviceAuth or KB-JWT structure.

The PID Provider MUST return the HTTP Status Code 200 and a signature_bytes parameter defined below.

  • signature_bytes: REQUIRED. base64url-encoded bytes of the signature over the deviceAuth or KB-JWT, respectively.

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.
  • presentation_signing_endpoint: REQUIRED: URL of the Presentation Signing Endpoint, as defined above. This URL MUST use the https scheme and MAY contain port, path, and query parameter components.

Usability Considerations

Privacy Considerations

Security Considerations

Open Topics