Skip to content

Ecosystem Architecture

Person Identification Data (PID)

Runtime Views

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 OpenID4VCI 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 using Wallet Backend to manage keys on behalf of the Wallet Instance, under the assumption that keys managed on the mobile device cannot be secured in a way that is appropriate for Level of Assurance High (unlike Option C).

To improve user experience and prevent the users from tapping an eID card every time a batch of Credentials needs to be refreshed and tapping an eID card as many times as there are Credentials in a batch, a concept of Seed Credential is introduced. A Seed Credential is used to acquire a set of single-use Batch Credentials from the Provider. The Wallet can then present these Batch Credentials to the Relying Parties. The user only needs to present the physical ID card once - to acquire the Seed Credential - instead of every presentation.

Such Seed Credential is issued by a PID Provider to the Wallet as a signed DPoP-bound refresh token and can be stored for a longer period. The key from the wallet backend, that the refresh token is bound to, is stored and managed by an HSM in the wallet backend (WSCD) instead of the wallet device itself.

Wallet Attestation PoP and DPoP Proof are bound to the keys managed by a wallet backend, but since they contain session specific information (audience and a nonce/session id) that should be known only to the wallet instance from a privacy perspective, to generate a signature, the wallet instance sends only a ready-to-be-signed hash to the wallet backend. Wallet Attestation PoP and DPoP Proof require key attestation for the keys that they are bound to.

Cryptographic Keys

Prefixes
Prefix Meaning
wb_ Wallet Backend
pp_ PID Provider
Prefix Meaning
rp_ Relying Party
device_ Wallet Instance
Long-Term keys
Key Meaning
\(device\_pub, device\_priv\) Wallet Instance generates locally managed key pair which is used to bind the PIN proof to the device.
\(pin\_salt\) Wallet Instance generates AES key which is used to derive the pin_derived_eph_priv used as PoP of Wallet PIN.
\(wb\_attestation\_pub_wa, wb\_attestation\_priv_wa\)
\(wb\_attestation\_pub_kbp, wb\_attestation\_priv_kbp\)
\(wb\_attestation\_pub_ks, wb\_attestation\_priv_ks\)
\(wb\_attestation\_pub_kd, wb\_attestation\_priv_kd\)
Wallet Backend has key pairs with postfixes which are each used:
- to sign wallet instance's wallet attestations: _wa
- to sign key attestation for the key that a PID is bound to: _kbp
- to sign key attestation for the key that a seed credential is bound to: _ks
- to sign key attestation for the key that a DPoP Proof is bound to: _kd.
\(wb\_device\_pub, wb\_device\_priv\) Wallet Backend generates the key pair which is used to sign proof of possession of wallet attestation.
\(wb\_dpop\_pub, wb\_dpop\_priv\) Wallet Backend generates the HSM bound key pair which is used to generate DPoP proof (a key to which refresh token used as a seed credential is bound to).
\(pp\_pub, pp\_priv\) PID Provider has the HSM bound long-term key pair to sign over the issued Credential and to sign over the Refresh Token JWT.
\(pp\_data\) PID Provider has this symmetric long-term key which is used to encrypt eID data inside the refresh token.
\(rp\_pub, rp\_priv\) Relying Party has this long-term key pair which is used to sign over the authorization request, authenticating its contents.

Note (not normative for Wallet implementations)

The following sequence diagrams include, among other things, user interactions with the Wallet. These interactions are not normative; only the depicted data flows are normative.

Issuance of a Refresh Token used as a Seed Credential

Sequence Diagram

-> Visual Example of the User Journey: PID Issuance - Issuer Signed - Cloud

..PID Holder....User.s EUDI Wallet Backend....User.s EUDI Wallet Instance.....PID Provider..PID HolderPIN: (user_pin)PID HolderPIN: (user_pin)User's EUDI Wallet BackendLong-term Key: (wb_device_pub,wb_device_priv)User's EUDI Wallet BackendLong-term Key: (wb_device_pub,wb_device_priv)User's EUDI Wallet Instance\(eID-Client)Device Key: (device_pub,device_priv)Wallet Attestation bound towb_device_pubPIN Salt:pin_saltUser's EUDI Wallet Instance\(eID-Client)Device Key: (device_pub,device_priv)Wallet Attestation bound towb_device_pubPIN Salt:pin_saltPID Provider(eService+eID Server)Long-term Key: (pp_pub,pp_priv)eID data encryption Key: (pp_data)PID Provider(eService+eID Server)Long-term Key: (pp_pub,pp_priv)eID data encryption Key: (pp_data)(001)open wallet, unlock walletScreen: launch_walletScreen: unlock_wallet(002)request issuance of PIDScreen: credential_catalogPID Issuer and EUDI Wallet have inherenttrust relationship, metadata may bepre-configured or retrieved(003)[TLS] HTTP POST</session_endpoint>pid_issuer_session_id(004)generate and storepid_issuer_session_id(005)[TLS] HTTP 200<pid_issuer_session_id>Screen: consent_add_credentialcheck pin(006)[TLS] HTTP POST</session_endpoint>wallet_backend_session_id(007)generate and storewallet_backend_session_id(008)[TLS] HTTP 200<wallet_backend_session_id>(009)enter Wallet PINScreen: wallet_pin(010)derive key pair(pin_derived_eph_pub,pin_derived_eph_priv) fromKDF(Wallet PIN,encrypt_AES(pin_salt, WalletPIN))(011)generate PoP for pin derivedephemeral key -sign(wallet_backend_session_id| device_pub)pin_derived_eph_priv(012)generate PoP for wallet app'skey -sign(wallet_backend_session_id|pin_derived_eph_pub)device_privproof must be built from both the device keyand the key derived from the user PIN, mightrequire new proof typeRemote HSM(013)prepare wallet attestation POPwith audience, expiration timeand pid_issuer_session_id(014)hash wallet attestation PoP(015)[TLS] HTTP POST <UUID,issuer_ID, PoP for pin derivedephemeral key, PoP for walletapp's key, hash of walletattestation PoP>(016)load instance information forUUIDInstance Information: retry counter,pin_derived_eph_pub, device_pub, securityrelevant device attributes(017)check user pin retryrequest would be refused in case of lockedpin(018)check security of deviceagainst VulnerabilityManagement informationPIN will not be validated if device is known tobe insecure(019)check signaturesuser pin retry counter would be increased incase of failed pin signature check, user pinwould be locked after threshold is exeeded(020)sign hash of wallet attestationPoP with wb_device_priv(021)[TLS] HTTP 200 <send signedhash of wallet attestation PoP,wallet_backend_session_id>(022)assemble wallet attestationPoP(023)[TLS] HTTP POST PAR (PKCEcode_challenge, WalletAttestation + PoP, client_id)(024)verify wallet attestation & PoPcheck Wallet Provider solutionstatus on trust list(025)[TLS] HTTP 200 request_uriAttestation guarantees with high certaintythat Wallet is trustworthy and notmanipulated(026)[TLS] HTTP GET <OpenID4VCIAuthorizationRequest(request_uri)>Screen: eid_startRead eID or Smart eID acc. to BSI TR-03130(027)[TLS] HTTP 200 starting theeID Process(028)eID Process(029)<eID-PIN>Screen: eid_pin(030)eID Process(031)[TLS] HTTP GET finishing theeID process with refreshUrlScreen: eid_nfc_data(032)[TLS] HTTP 302 <OpenID4VCIAuthorizationResponse(authorizationcode)>Generate initial DPoP nonce(033)generate placeholder DPoPproof with generic (notHSM-bound) key pair(034)[TLS] HTTP POST <TokenRequest(DPoP Header withplaceholder proof,authorization code, PKCEcode_verifier)>(035)generate and storedpop_nonce(036)[TLS] HTTP 400 <Bad Request(DPoP nonce Header withdpop_nonce, error:"use_dpop_nonce")>The Wallet should check at this point,whether the Token Endpoint delivered theexpected error and nonce. If not, this needsto be handled (retry or abort gracefully).(037)store dpop_nonceRemote HSM(038)prepare DPoP-proof JWT forHSM bound key incl.dpop_nonce(039)hash(DPoP-proof JWT for HSMbound key)(040)[TLS] HTTP POST <hash ofPoP,wallet_backend_session_id>(041)checkwallet_backend_session_id(042)sign hash of PoP withwb_dpop_priv (associated withUUID & Issuer_ID)(043)[TLS] HTTP 200 <signed hashof proof>(044)assemble DPoP-proof JWT forHSM bound key with signature(045)[TLS] HTTP POST <TokenRequest(DPoP Header withproof JWT incl. wb_dpop_puband key attestation,authorization code, PKCEcode_verifier)>(046)lookup authorization code verify PKCE challenge verify DPoP proof verify key attestation forDPoP proof(047)create refresh token bound towb_dpop_priv in JWT formatwith eID data symmetricallyencrypted with pp_data andits expiration date and sign the refresh tokenJWT with pp_priv(048)generate and storedpop_nonce(049)generate Token Responsewith access and refresh tokenDPoP bound to wb_dpop_privand fresh dpop_nonce(050)[TLS] HTTP 200 <TokenResponse(DPoP nonce headerwith dpop_nonce, DPoP-boundaccess_token, DPoP-boundrefresh_token)>The access token and the refresh token areboth bound to the same key.(051)store DPoP bound access andrefresh token(052)store dpop_nonceScreen: successScreen: home         Legend  Visual Example of the User Journey reference TLS (Transport Layer Security)
Step-by-Step Description
No Description
001 The user opens and unlocks the Wallet.
002 The user browses through the pre-configured credential catalog and chooses to request a PID.
003 The Wallet requests a fresh pid_issuer_session_id from the PID Provider.
004 The PID Provider generates a fresh pid_issuer_session_id linked to the issuance session.
005 The PID Provider returns the pid_issuer_session_id to the Wallet.
006 The Wallet obtains fresh wallet_backend_session_id from the Wallet Backend's session endpoint.
007 Part of the above-mentioned module.
008 Part of the above-mentioned module.
009 The User enters the Wallet PIN.
010 The Wallet proves possession of the Wallet PIN {See "Wallet proving possession of the PIN" module for a detailed description of the steps).
011 Part of the above-mentioned module.
012 Part of the above-mentioned module.
013 The Wallet prepares a Wallet Attestation PoP containing audience, expiration time and pid_issuer_session_id
014 The Wallet hashes the prepared Wallet Attestation PoP.
015 The Wallet sends a request to the Wallet Backend containing UUID & Issuer_ID, PoP for pin_derived_eph_priv, PoP for device_priv and hash of the Wallet Attestation PoP
016 The Wallet Backend checks Wallet Instance.
017 Part of the above-mentioned module.
018 Part of the above-mentioned module.
019 The Wallet Backend validates the PoP for pin_derived_eph_pub and device_pub.
020 The Wallet Backend signs the hash of Wallet Attestation PoP with wb_device_priv.
021 The Wallet Backend returns the request to the Wallet containing signed hash of Wallet Attestation PoP.
022 The Wallet assembles the Wallet Attestation PoP using the signature received in a previous step.
023 The Wallet sends the Pushed Authorization Request to the PID Provider, containing the Wallet Provider's client_id, authorization_details for PID, a PKCE code_challenge and a wallet attestation and proof of possession.
024 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.
025 The PID Provider returns a request_uri that is bound to the Pushed Authorization Request.
026 The Wallet sends the Authorization Request; containing the PAR request_uri.
027 The PID Provider responds with the first step to start the eID process with the Wallet, e.g. the tcToken, to authenticate the user.
028 Further communication is exchanged to perform the eID process.
029 The user provides the eID PIN to the Wallet.
030 Further communication is exchanged to perform the eID process.
031 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.
032 The PID Provider responds to the Wallet with an Authorization Response containing the authorization code.
033 The Wallet generates (and stores) a placeholder DPoP proof with a generic (not HSM-bound) keypair to trigger an error response from the Token endpoint necessary to retrieve the dpop_nonce.
034 The Wallet sends a Token Request to the PID Provider; containing the placeholder DPoP proof.
035 The PID Provider generates and stores a dpop_nonce.
036 The PID Provider responds with the expected error "use_dpop_nonce" containing the dpop_nonce to be used from now in the DPoP nonce header.
037 The Wallet extracts and stores the dpop_nonce.
038 The Wallet now prepares the actual DPoP-proof JWT for the HSM-bound wb_dpop_pub including the dpop_nonce and iat.
039 The Wallet hashes the DPoP proof.
040 The Wallet sends a request to the Wallet Backend to sign the hash of the DPoP-proof for the HSM bound key containing the hash of the PoP for the HSM bound key and the wallet_backend_session_id.
041 The Wallet Backend validates the wallet_backend_session_id and loads session context.
042 The Wallet Backend signs the hash of the PoP for the HSM bound key with wb_dpop_priv (associated with UUID & Issuer_ID) from the HSM.
043 The Wallet Backend returns the signed hash of the PoP for the HSM bound key to the Wallet.
044 The Wallet assembles the DPoP-proof for the HSM bound key using the signature received in a previous step.
045 The Wallet sends a Token Request to the PID Provider containing a DPoP Header with the DPoP-proof JWT incl. wb_dpop_pub, the authorization code from Authorization Response, the PKCE code_verifier matching the code_challenge from Authorization Request and the.key attestation for wb_dpop_pub.
046 The PID Provider matches the code, verifies the PKCE code_verifier to the previously received code_challenge and verifies the DPoP proof.
047 The PID Provider then generates an access token and a refresh token bound to the DPoP key wb_dpop_priv in JWT format, signed with pp_priv containing the eID data encrypted with pp_data and the expiration date of the refresh token.
048 The PID Provider generates and stores a fresh dpop_nonce.
049 The PID Provider generates a Token Response containing the DPoP-bound access token (bound to wb_dpop_priv), the DPoP-bound refresh token (bound to wb_dpop_priv), a c_nonce and a fresh dpop_nonce in the DPoP nonce header.
050 The PID Provider sends the Token Response to the Wallet.
051 The Wallet stores the access and the refresh token.
052 The wallet stores the dpop_nonce.

Issuance of a Batch of PIDs

Sequence Diagram
..PID Holder....User.s EUDI Wallet Backend....User.s EUDI Wallet Instance .eID-Client.....PID Provider .eService.eID Server...PID HolderPIN: (user_pin)PID HolderPIN: (user_pin)User's EUDI Wallet BackendLong-term Key: (wb_attestation_pub,wb_attestation_priv)Long-term Key: (wb_device_pub,wb_device_priv)User's EUDI Wallet BackendLong-term Key: (wb_attestation_pub,wb_attestation_priv)Long-term Key: (wb_device_pub,wb_device_priv)User's EUDI Wallet Instance (eID-Client)Device Key: (device_pub,device_priv)Wallet Attestation bound towb_device_pubPIN Salt:pin_saltUser's EUDI Wallet Instance (eID-Client)Device Key: (device_pub,device_priv)Wallet Attestation bound towb_device_pubPIN Salt:pin_saltPID Provider (eService+eID Server)Long-term Key: (pp_pub,pp_priv)eID data encryption Key: (pp_data)PID Provider (eService+eID Server)Long-term Key: (pp_pub,pp_priv)eID data encryption Key: (pp_data)(001)open wallet, unlock wallet(002)request issuance of PID BatchCredentialscheck pin and generate batch keys(003)[TLS] HTTP POST</session_endpoint>pid_issuer_session_id(004)generate and storepid_issuer_session_id(005)[TLS] HTTP 200<pid_issuer_session_id>(006)[TLS] HTTP POST</session_endpoint>wallet_backend_session_id(007)generate and storewallet_backend_session_id(008)[TLS] HTTP 200<wallet_backend_session_id>(009)enter Wallet PIN(010)derive key pair(pin_derived_eph_pub,pin_derived_eph_priv) fromKDF(Wallet PIN,encrypt_AES(pin_salt, WalletPIN))(011)generate PoP for pin derivedephemeral key -sign(wallet_backend_session_id| device_pub)pin_derived_eph_priv(012)generate PoP for wallet app'skey -sign(wallet_backend_session_id|pin_derived_eph_pub)device_privproof must be built from both the device keyand the key derived from the user PIN, mightrequire new proof type(013)[TLS] HTTP POST<CredentialRequest(UUID,issuer_ID, PoP for pin derivedephemeral key, PoP for walletapp's key)>(014)load instance information forUUIDInstance Information: retry counter,pin_derived_eph_pub, device_pub, securityrelevant device attributes(015)check user pin retryrequest would be refused in case of lockedpin(016)check security of deviceagainst VulnerabilityManagement informationPIN will not be validated if device is known tobe insecure(017)check signaturesuser pin retry counter would be increased incase of failed pin signature check, user pinwould be locked after threshold is exeeded(018)generate cryptographic seed(c_seed) for batch credentialsand associate with issuer_ID(019)derive X key pairs (incl. keyIDs) (keyIDx,(batch_kb_X_pub,batch_kb_X_priv))deterministically from c_seed(020)assembleCloudWalletBatchKey claimwith X tuples (keyIDx,batch_kb_X_pub) and signwith wb_attestation_priv(021)[TLS] HTTP 200 <signedCloudWalletBatchKey,wallet_backend_session_id>Remote HSM(022)generate wallet attestationPOP with audience, expirationtime, CloudWalletBatchKeyand pid_issuer_session_id(023)hash wallet attestation PoP(024)[TLS] HTTP POST <hash ofwallet attestation PoP,wallet_backend_session_id>(025)validatewallet_backend_session_idand load session context(026)sign hash of wallet attestationPoP with wb_device_priv(027)[TLS] HTTP 200 <signature forhash of wallet attestationPoP>(028)assemble wallet attestationPoP with signaturePID batch issuancealt[Noorstale DPoP nonce](029)generate placeholder DPoPproof with generic (notHSM-bound) keypair(030)[TLS] HTTP POST <TokenRequest(DPoP Header withplaceholder proof,authorization code, PKCEcode_verifier)>(031)generate and storedpop_nonce(032)[TLS] HTTP 400 <Bad Request(DPoP nonce Header withdpop_nonce, error:"use_dpop_nonce")>(033)store dpop_nonceRemote HSM(034)prepare DPoP-proof JWT forHSM bound key incl.dpop_nonce(035)hash(DPoP-proof JWT for HSMbound key)(036)[TLS] HTTP POST <hash ofPoP,wallet_backend_session_id>(037)checkwallet_backend_session_id(038)sign hash of PoP withwb_dpop_priv (associated withUUID & Issuer_ID)(039)[TLS] HTTP 200 <signed hashof proof>(040)assemble DPoP-proof JWT forHSM bound key with signature(041)[TLS] HTTP POST <TokenRequest(wallet attestationand wallet attestation PoP, DPoP-proof JWT overwb_dpop_pub, grant_type=refresh_token,DPoP bound refresh token)>wallet attestation Header includes Walletattestation and PoP. DPoP Header includesDPoP proof JWT. refresh_token contains theeID data encrypted with pp_pub(042)verify wallet attestation & PoPcheck Wallet Provider solutionstatus on trust list(043)verify the validity of therefresh token (incl.DPoP-binding)(044)decrypt refresh tokencontents with pp_data andstore user data in session(045)generate and storedpop_nonce(046)generate Token Responsewith DPoP-boundaccess_token(047)[TLS] HTTP 200 <TokenResponse(DPoP nonce headerwith dpop_nonce, DPop boundaccess_token, c_nonce)>(048)prepare X batch credentialkey PoPs (incl. audience,batch_kb_X_pub, c_nonce)and hash them(049)[TLS] HTTP POST<BatchSigningRequest(Xhashed PoPs,wallet_backend_session_id)>(050)validatewallet_backend_session_idand load session context(051)sign hashed PoPs X withbatch_kb_X_priv(052)[TLS] HTTP 200 <X signedhashed PoPs>(053)assemble XCredentialRequests withsigned batch credential keyPoPsRemote HSM(054)prepare DPoP-proof JWT forHSM bound key incl.dpop_nonce(055)hash(DPoP-proof JWT for HSMbound key)(056)[TLS] HTTP POST <hash ofPoP,wallet_backend_session_id>(057)checkwallet_backend_session_id(058)sign hash of PoP withwb_device_priv (associatedwith UUID & Issuer_ID)(059)[TLS] HTTP 200 <signed hashof proof>(060)assemble DPoP-proof JWT forHSM bound key with signature(061)generate credential responseencryption key pair(cre_eph_pub, cre_eph_priv)(062)createcredential_response_encryptionobject with jwk containingcre_eph_pub(063)[TLS] HTTP POST <BatchCredential Request (DPoPHeader with proof, XCredentialRequests,credential_response_encryptionobject, DPoP-boundaccess_token)>(064)validate DPoP-boundaccess_token and checksignatures of theCredentialRequest proofsensure that the batch_kb_X_pub from theCredentialRequests match to the public keysin the CloudWalletBatchKey claim from thewallet attestation PoPalt[ISO mdoc](065)create mdoc with eID dataand batch_kb_X_pub, signedby pp_priv, and matchingNameSpaceBytes(066)generate encrypted credentialresponse JWT using the valuesreceived in thecredential_response_encryptionobject(067)generate and storedpop_nonce(068)[TLS] HTTP 200 <BatchCredential Response(DPoPnonce Header withdpop_nonce, JWT(mdoc))>[SD-JWT VC](069)create SD-JWT VC with eIDdata and batch_kb_X_pub,signed by pp_priv, andmatching Disclosures(070)generate encrypted credentialresponse JWT using the valuesreceived in thecredential_response_encryptionobject(071)generate and storedpop_nonce(072)[TLS] HTTP 200 <BatchCredential Response(DPoPnonce Header withdpop_nonce, JWT(SD-JWT VC,Disclosures))>(073)decrypt batch credentialresponse JWT and retrieve PID(074)match keyIDx fromCloudWalletBatchKey claim toSD-JWT/mdoc Credentials bytheir respective public key(batch_kb_X_pub) and storeas tuple inBatchCredentialStore withissuer_ID(075)store dpop_nonce
Step-by-Step Description
No Description
001 The user opens and unlocks the Wallet.
002 The Wallet requests issuance of PID Batch Credentials.
003 The Wallet requests fresh wallet_backend_session_id.
004 The Wallet Backend generates and links it to the session.
005 The Wallet Backend returns the wallet_backend_session_id to the Wallet.
006 The Wallet requests a fresh pid_issuer_session_id from the Wallet Backend
007 The Wallet Backend generates a fresh wallet_backend_session_id linked to the session.
008 The Wallet Backend returns the pid_issuer_session_id to the Wallet.
009 The user enters the Wallet PIN.
010 The Wallet proves possession of the Wallet PIN. See "Wallet proving possession of the PIN" module for a detailed description of the steps.
011 Part of the above-mentioned module.
012 Part of the above-mentioned module.
013 The Wallet sends a Credential Request to the Wallet Backend containing the UUID & the Issuer_ID, the PoP for pin_derived_eph_priv and the PoP for device_priv.
014 The Wallet Backend checks Wallet Instance. See Issuance of Wallet Instance Attestation (WIA)¶ for a detailed description of the steps.
015 Part of the above-mentioned module.
016 Part of the above-mentioned module.
017 The Wallet Backend validates the PoP for pin_derived_eph_pub and device_pub.
018 The Wallet Backend generates a cryptographic seed (c_seed) for the batch credential keys and associates it with Issuer_ID. Each batch of credentials uses it's own c_seed, previous c_seeds are discarded when a new batch of credentials for a specific Issuer are requested.
019 The Wallet Backend deterministically derives the required number of key pairs incl. key IDs from c_seed. A mechanism for key derivation will be defined later.
020 The Wallet Backend assembles a claim called CloudWalletBatchKey containing the public part of the just generated key pairs and the respective key IDs and signs the claim with wb_attestation_priv.
021 The Wallet Backend returns the request to the Wallet; containing the signed CloudWalletBatchKey.
022 The Wallet prepares a Wallet Attestation PoP containing the audience, the signed CloudWalletBatchKey claim and the pid_issuer_session_id.
023 The Wallet hashes the Wallet Attestation PoP.
024 The Wallet sends a signing request to the Wallet Backend containing the hash of the Wallet Attestation PoP and the wallet_backend_session_id.
025 The Wallet Backend validates the wallet_backend_session_id and loads the session context.
026 The Wallet Backend signs the hash of the Wallet Attestation PoP with the respective wb_device_priv.
027 The Wallet Backend returns the request to the Wallet incl. the signed hash of the Wallet Attestation PoP.
028 The Wallet assembles the Wallet Attestation PoP using the signature received in a previous step.
029 The Wallet generates (and stores) a placeholder DPoP proof with a generic (not HSM-bound) keypair to trigger an error response from the Token endpoint necessary to retrieve the dpop_nonce.
030 The Wallet sends a Token Request to the PID Provider; containing the placeholder DPoP proof.
031 The PID Provider generates and stores a dpop_nonce.
032 The PID Provider responds with the expected error "use_dpop_nonce" containing the dpop_nonce to be used from now in the DPoP nonce header.
033 The Wallet extracts and stores the dpop_nonce.
034 The Wallet prepares the DPoP-proof JWT for the HSM-bound wb_attestation_pub including the dpop_nonce and iat.
035 The Wallet hashes the DPoP proof.
036 The Wallet sends a request to the Wallet Backend to sign the hash of the DPoP-proof for the HSM bound key containing a hash of the PoP for the HSM bound key.
037 The Wallet Backend validates the wallet_backend_session_id and loads the session context.
038 The Wallet Backend signs the hash of the PoP for the HSM bound key with wb_device_priv (associated with UUID & Issuer_ID) from the HSM.
039 The Wallet Backend returns the signed hash of the PoP for the HSM bound key to the Wallet.
040 The Wallet assembles the DPoP-proof for the HSM bound key using the signature received in a previous step.
041 The Wallet sends a Token Request to the PID Provider containing the Wallet Attestation + PoP in the wallet attestation Header, the DPoP-proof JWT over wb_attestation_pub, the grant_type "refresh_token" and the DPoP-bound refresh token.
042 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.
043 The PID Provider verifies the validity of the refresh token (incl. DPoP-binding).
044 The PID Provider decrypts the refresh token contents with //pp_data// and stores the users identity attributes in the session.
045 The PID Provider generates and stores a dpop_nonce.
046 The PID Provider generates a Token Response with a DPop bound access token.
047 The PID Provider returns a Token Response to the Wallet containing the DPoP bound access_token, the c_nonce and a fresh dpop_nonce in the DPoP nonce header.
048 The Wallet prepares the required number of PoP (incl. audience and respective public key) for the batch credential keys and hashes them.
049 The Wallet sends a BatchSigningRequest to the Wallet Backend containing the required number of hashed batch credential key PoPs and the wallet_backend_session_id.
050 The Wallet Backend validates the wallet_backend_session_id and loads the session context.
051 The Wallet Backend signs the hashed batch credential key PoPs with the respective batch_kb_X_priv.
052 The Wallet Backend returns the request to the Wallet incl. the signed hashes of the batch credential key PoPs.
053 The Wallet assembles the required amount of CredentialRequests containing the signed batch credential key PoPs.
054 The Wallet prepares the DPoP-proof JWT for the HSM-bound //dev// key including the dpop_nonce and iat.
055 The Wallet hashes the DPoP proof.
056 The Wallet sends a request to the Wallet Backend to sign the hash of the DPoP-proof for the HSM bound key containing a hash of the PoP for the HSM bound key and the wallet_backend_session_id.
057 The Wallet Backend validates the wallet_backend_session_id and loads the session context.
058 The Wallet Backend signs the hash of the PoP for the HSM bound key with wb_dpop_priv (associated with UUID & Issuer_ID) from the HSM.
059 The Wallet Backend returns the signed hash of the PoP for the HSM bound key to the Wallet.
060 The Wallet assembles the DPoP-proof for the HSM bound key using the signature received in a previous step.
061 The Wallet generates a new ephemeral keypair (cre_eph_pub, cre_eph_priv).
062 The Wallet creates the credential_response_encryption JSON object containing a jwk containing the cre_eph_pub, the JWE alg parameter and the JWE enc parameter.
063 The Wallet sends a BatchCredentialRequest to the PID Provider containing the DPoP proof JWT, the required amount of CredentialRequests, the credential_response_encryption object and the DPoP bound access_token.
064 The PID Provider validates the DPoP bound access_token and checks the signatures of the CredentialRequests. The PID Provider has to ensure that the batch_kb_X_pub from the CredentialRequests match to the public keys in the CloudWalletBatchKey claim from the Wallet Attestation PoP.
065 (mdoc) The PID Provider creates the mdoc containing the issuerAuth with the batch_kb_X_pub as deviceKey and hashes of the eID data, the eID data as NameSpaceBytes and the status management information.
066 (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 credential to the payload.
067 The PID Provider generates and stores a fresh dpop_nonce.
068 (mdoc) The PID Provider sends the Credential Response JWT containing the required amount of PID credentials as mdoc.
069 (SD-JWT) The PID Provider creates SD-JWT VC containing the SD-JWT with the batch_kb_X_pub as confirmation claim and hashes of the eID data, the eID data as Disclosures and the status management information.
070 (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 credential to the payload.
071 The PID Provider generates and stores a fresh dpop_nonce.
072 (SD-JWT) The PID Provider sends the Credential Response JWT containing the required amount of PID credentials as SD-JWT VC.
073 The Wallet decrypts the Credential Response JWT using the cre_eph_priv.
074 The Wallet matches the key IDs (from the CloudWalletBatchKey claim) to the public keys in the Credential Response by their respective public keys and stores them as tuple in a BatchCredentialStore with the issuer_ID.
075 The Wallet extracts and stores the dpop_nonce.

Credential Presentation

Sequence Diagram

-> Visual Example of the User Journey: PID Presentation - Issuer Signed - Cloud

..PID Holder....Browser App....Relying Party....User.s EUDI Wallet Instance .eID-Client.....User.s EUDI Wallet Backend..PID HolderPIN: (user_pin)PID HolderPIN: (user_pin)Browser 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 Key: (device_pub,device_priv)Wallet Attestation bound towb_device_pubPIN Salt:pin_saltUser's EUDI Wallet Instance (eID-Client)Device Key: (device_pub,device_priv)Wallet Attestation bound towb_device_pubPIN Salt:pin_saltUser's EUDI Wallet BackendLong-term Key: (wb_attestation_pub,wb_attestation_priv)Long-term Key: (wb_device_pub,wb_device_priv)User's EUDI Wallet BackendLong-term Key: (wb_attestation_pub,wb_attestation_priv)Long-term Key: (wb_device_pub,wb_device_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 sessionsessionId and bind theauthorization request to it(006)[TLS] HTTP 200 HTMLcontaining wallet-linkopenid4vp://authorize?")client_id=..&request_uri=<request_uri>Set-Cookie: sid=sessionId(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_credential(014)pick batch credential tuple(Credential, keyIDx) frombatch credential storealt[ISO mdoc](015)prepare mdoc presentationaccording to<presentation_definition> byremoving unnecessaryNameSpaceBytes(016)calculate SessionTranscript(mDocGeneratedNonce,client_id, responseUri, nonce)and generate deviceAuthpayload and hash[SD-JWT VC](017)prepare SD-JWT presentationaccording to<presentation_definition> byremoving unnecessaryDisclosures(018)generate KB-JWT payload(nonce, audience, hash ofSD-JWT and disclosures) andhashcheck pin & sign in remote HSM(019)[TLS] HTTP POST</session_endpoint>wallet_backend_session_id(020)generate and storewallet_backend_session_id(021)[TLS] HTTP 200<wallet_backend_session_id>(022)input Wallet PINScreen: wallet_pin(023)generate key pair(pin_derived_eph_pub,pin_derived_eph_priv) fromKDF(Wallet PIN,encrypt_AES(pin_salt, WalletPIN))(024)generate PoP for pin derivedephemeral key -sign(wallet_backend_session_id| device_pub)pin_derived_eph_priv(025)generate PoP for wallet app'skey -sign(wallet_backend_session_id|pin_derived_eph_pub)device_priv(026)[TLS] HTTP POST <UUID,issuer_ID, PoP for pin derivedephemeral key, PoP for walletapp's key, hash ofKB-JWT/deviceAuth , keyIDx>(027)load instance information forUUIDInstance Information: retry counter,pin_derived_eph_pub, device_pub, securityrelevant device attributes(028)check user pin retryrequest would be refused in case of lockedpin(029)check security of deviceagainst VulnerabilityManagement informationPIN will not be validated if device is known tobe insecure(030)check signaturesuser pin retry counter would be increased incase of failed pin signature check, user pinwould be locked after threshold is exeeded(031)identify c_seed with issuer_IDand load(032)deterministically regenerate(batch_kb_X_pub,batch_kb_X_priv) from c_seedand keyIDx(033)sign hash ofKB-JWT/deviceAuth hash withbatch_kb_X_priv(034)[TLS] HTTP 200 <signedKB-JWT/deviceAuth hash>alt[ISO mdoc](035)assemble deviceAuth andbuild presentation withissuerSigned anddeviceSigned(deviceAuth)[SD-JWT VC](036)assemble KB-JWT and buildpresentation with SD-JWT,selected Disclosures andKB-JWT(037)create vp_token andpresentation_definition(038)add optionally otherpresentations according tothe presentation_definition(039)delete used batch credentialand matching keyIDx(040)[TLS] HTTP POST<AuthorizationResponse(presentation_submission,vp_token, state)>(041)look up state in existingsessionscreate & store response_codefor session(042)[TLS] HTTP 200 <redirect_uriincl. response_code>(043)launch browser with<redirect_uri withresponse_code>Screen: success_redirect(044)[TLS] HTTP GET <redirect_uriwith response_code>Cookie: sid=sessionId(045)look up session with sessionIdand match response_codealt[ISO mdoc](046)verify contents of<vp_token>:- verify mdoc issuerAuth PID- verify deviceAuth withbatch_kb_X_pub fromissuerAuth- calculate and validatecorrect SessionTranscript[SD-JWT VC](047)verify contents of<vp_token>:- verify SD-JWT PID- verify KB-JWT withbatch_kb_X_pub from SD-JWT- validate nonce and audiencefrom KB-JWT(048)[TLS] HTTP 200 <HTML withcontinued UX flow>Screen: same_device_relying_party_identified         Legend  Visual Example of the User Journey reference TLS (Transport Layer Security)
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.

No Description
001 The user browses to Relying Party (RP) website.
002 Browser app on the user's device opens the RP website.
003 RP generates an ephemeral key pair (e.g., rp_eph_pub, rp_eph_priv).
004 RP generates an OpenID4VP Authorization Request and stores it under a request_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 ephemeral key for response encryption. It contains RP's nonce and state. It contains the RP's response_uri endpoint for sending the Authorization Response over POST.
005 RP generates a new browser session and binds the generated Authorization Request to it.
006 RP returns a HTML page to the browser containing a link to the Wallet (e.g., openid4vp://authorize?client_id=..&request_uri=https://rp.example.com/oidc/request/1234) and a cookie with the browser sessionId is set.
007 The user clicks on the link.
008 The RP website navigates to the custom scheme link to launch the Wallet.
009 The user unlocks the Wallet (see notes below).
010 The Wallet sends a GET request to the RP's Authorization Request endpoint (e.g., https://rp.example.com/oidc/request/1234).
011 The Wallet retrieves the Authorization Request from the RP website.
012 The Wallet 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.
013 The Wallet displays information about the identity of the Relying Party and the purpose, the user gives consent to present the PID.
014 The Wallet picks a batch credential tuple (Credential incl. possible disclosures, keyID) from the batch credential store.
015 (mdoc) The Wallet prepares an mdoc presentation according to the presentation_definition by removing NameSpaceBytes of not disclosed attributes.
016 (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 and hashes the deviceAuthentication structure.
017 (SD-JWT) The Wallet generates an SD-JWT VC presentation according to the presentation_definition by removing Disclosures of not disclosed attributes.
018 (SD-JWT) The Wallet creates the header and payload for the KB-JWT from audience, nonce, hash of issuer-signed JWT and Disclosures for signing and hashes the payload.
019 The Wallet requests a fresh wallet_backend_session_id from the Wallet Backend.
020 The Wallet Backend generates a fresh wallet_backend_session_id linked to the session.
021 The Wallet Backend returns the wallet_backend_session_id to the Wallet.
022 The User enters the Wallet PIN.
023 The Wallet proves possession of the Wallet PIN. See "Wallet proving possession of the PIN" module for a detailed description of the steps.
024 The Wallet signs over the wallet_backend_session_id and the device-bound public key device_pub using the key pin_derived_eph_priv.
025 The Wallet signs over the wallet_backend_session_id and the Wallet PIN derived public key pin_derived_eph_pub using the key device_priv.
026 The Wallet sends a signing request to the Wallet Backend containing UUID & issuer_ID, PoP for pin_derived_eph_priv, PoP for device_priv, the hash of KB-JWT/deviceAuth and keyID (of the respective key that should be used to sign).
027 The Wallet Backend checks Wallet Instance. See Issuance of Wallet Instance Attestation (WIA) for a detailed description of the steps.
028 Part of the above-mentioned module.
029 Part of the above-mentioned module.
030 The Wallet Backend validates the PoP for pin_derived_eph_pub and device_pub.
031 The Wallet Backend loads the c_seed associated with the issuer_ID.
032 The Wallet Backend deterministically regenerates (batch_kb_X_pub, batch_kb_X_priv) from c_seed and keyIDx - A mechanism for key derivation will be defined later.
033 The Wallet Backend signs the hash of KB-JWT/deviceAuth with the respective batch_kb_X_priv.
034 The Wallet Backend returns the signed hashes of KB-JWT/deviceAuth to the Wallet.
035 (mdoc) The Wallet assembles the deviceAuth from header, payload and signature and builds the presentation from deviceAuth and issuerSigned.
036 (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.
037 The Wallet creates a VP token and a presentation submission from the received credential.
038 Optional: The Wallet can add further presentations.
039 The Wallet deletes the used batch credential tuple (credential, keyID).
040 The Wallet sends the VP token and presentation submission to the RP (encrypted to the RP's public key rp_eph_pub).
041 The RP finds a session with the state and generates a response_code for this session.
042 The RP returns the redirect_uri with the response_code to the Wallet.
043 The Wallet launches the browser with the redirect_uri and response_code.
044 The browser sends the redirect_uri and response code to the RP, attaching the browser sessionId as a cookie.
045 The RP looks up whether there exists a session with the sessionId from the cookie and a matching response_code.
046 (mdoc) The RP verifies the PID in the VP token and verifies the SessionTranscript calculated from nonce, mDocGeneratedNonce, client_id, response_uri.
047 (SD-JWT) The RP verifies the SD-JWT PID in the VP token, verifies the KB-JWT using the batch_kb_X_pub in the SD-JWT, and verifies the nonce and audience in the KB-JWT.
048 The RP considers the user to be identified in the session context and continues the UX flow.

Wallet proving possession of the PIN

Generation of a Proof of Knowledge of the Wallet PIN

A PIN-derived ephemeral public key that is needed to validate the signature on this JWT must be included in the jwk header parameter. There must be a JWT header parameter typ with the value being pin_derived_eph_pub_pop. The JWT payload must contain an aud claim whose value is equal to the Wallet backend's Identifier. wallet_backend_session_id must be included in a wallet_backend_session_id parameter.

Below is a non-normative example of a JWT generated as a PoP for pin derived ephemeral key:

{
  "alg": "...",
  "typ": "pin_derived_eph_key_pop",
  "jwk": {
    "kty": "EC",
    "crv": "P-256",
    "x": "bPP7f...gW_ao",
    "y": "38_Lg...VUCfW"
  }
}.
{
  "wallet_backend_session_id": "123456",
  "aud": "https://pid-issuer.example.com",
  "device_key": {
    "jwk": {
      "kty": "EC",
      "crv": "P-256",
      "x": "...",
      "y": "..."
    }
  }
}.[signature by the pin derived ephemeral pub key]

The jwk claim contains the public key of a PIN-derived ephemeral key pair.