Wallet and Key Attestation
During issuance, EUDIPLO can check two statements signed by the wallet provider: a wallet attestation, which proves that the wallet app is a genuine instance of a trusted wallet, and a key attestation, which describes how the holder keys are protected. Both are trusted through wallet-provider trust lists.
| Wallet attestation | Key attestation | |
|---|---|---|
| Proves | The wallet, as OAuth client, is an app of a trusted wallet provider | The holder keys and their storage and user-authentication level |
| Checked at | PAR and token endpoints of EUDIPLO-managed authorization servers (built-in, chained, oid4vp) | Credential endpoint, including deferred issuance |
| Required by | walletAttestationRequired of the authorization server, else of the issuance configuration | Proof types allowed by the credential configuration (config.proofTypesSupported) |
| Trusted through | walletProviderTrustLists of the authorization server, else of the issuance configuration | walletProviderTrustLists of the issuance configuration only |
1. Provide wallet-provider trust lists
Wallet-provider trust lists are LoTE JWTs whose entities offer the service types http://uri.etsi.org/19602/SvcType/WalletSolution, .../WalletSolution/Issuance or .../WalletSolution/Revocation. Reference them like any trust list:
- External list, for example the wallet provider list published for your ecosystem:
{ "url": "https://...", "verifierX509Der": "MIIB..." }(orverifierKey). Obtain the verification certificate through a trusted channel; it authenticates the list, not the providers in it. - Managed list of this tenant:
{ "trustListId": "wallet-providers" }. Create it under Trust Lists and set Provider type → Wallet provider on each entity ("providerType": "wallet-provider"). EUDIPLO then publishesWalletSolution/IssuanceandWalletSolution/Revocationservices; a list with only wallet-provider entities uses the wallet-provider scheme of ETSI TS 119 602 Annex E. If wallet and key attestations are signed by different provider CAs, list both.
Put the lists into the issuance configuration so that both checks can use them:
{
"walletProviderTrustLists": [{ "trustListId": "wallet-providers" }],
"authorizationServers": [
{ "type": "built-in", "id": "issuer-built-in", "walletAttestationRequired": true }
]
}
Merge these fields into your issuance configuration (Issuance Configuration). A presented wallet or key attestation without a configured trust list is always rejected; plain holder proofs without key attestation need no trust list.
2. Require wallet attestation
When wallet attestation is used, the wallet sends two headers to the PAR and token endpoints, following OpenID4VCI Appendix E:
OAuth-Client-Attestation: the attestation JWT signed by the wallet provider, with its certificate chain inx5cand the wallet instance key incnf,OAuth-Client-Attestation-PoP: a proof of possession signed with that instance key.
EUDIPLO verifies both signatures, builds a certificate path from x5c to a wallet provider in the trust lists and, if the attestation has a status claim, rejects revoked or suspended attestations. If the status list cannot be fetched, the error is logged and the attestation is accepted.
Each EUDIPLO-managed authorization server resolves two settings independently:
| Setting | Value used |
|---|---|
walletAttestationRequired | The authorization server's value, else the issuance configuration's, else false |
walletProviderTrustLists | The authorization server's list, else the issuance configuration's, else none |
With true, requests without attestation are rejected; with false, a wallet may omit it, but an attestation it sends must still be valid and trusted. An empty list on the authorization server disables inheritance and rejects every presented attestation. The authorization server metadata advertises attest_jwt_client_auth only when attestation is required. In the Web Client, the authorization server settings offer Use issuer default and Use shared wallet provider trust lists. An external authorization server checks wallets according to its own configuration.
3. Require key attestation
Key attestations are configured per credential type, in the credential configuration's config:
{
"config": {
"proofTypesSupported": ["attestation"],
"keyAttestationsRequired": {
"key_storage": ["iso_18045_high"],
"user_authentication": ["iso_18045_high"]
}
}
}
-
proofTypesSupportedlimits the accepted proof types,jwtandattestation(default: both). A proof of another type is rejected withinvalid_proof. -
keyAttestationsRequiredis published askey_attestations_requiredfor every supported proof type in the issuer metadata and enforced at the credential endpoint:- Every proof must carry a key attestation: an
attestationproof or ajwtproof withkey_attestation. - Every key the proof proves must be listed in the attestation's
attested_keys. - For a non-empty
key_storageoruser_authenticationlist, the attestation must state at least one of the listed values in the claim of the same name.
An empty object requires a key attestation without level constraints; empty lists add no constraint and are not published. A proof that fails is rejected with
invalid_proof. WithoutkeyAttestationsRequired, a key attestation is optional. - Every proof must carry a key attestation: an
Wallets send key attestations in two ways:
attestationproof (proofs.attestation): the key attestation JWT itself. EUDIPLO issues one credential per key in itsattested_keys, at most the issuancebatchSize.jwtproof withkey_attestationheader: a holder proof whose signing key must be one of the attested keys.
Every presented key attestation must be signed by a wallet provider in the issuance-level walletProviderTrustLists, whether it is required or not; lists on an authorization server are not used for keys.
Troubleshooting
| Symptom | Cause and fix |
|---|---|
Wallet attestation is required but not provided | The wallet sends no attestation headers. Use a wallet that supports wallet attestation, or set walletAttestationRequired: false. |
No wallet provider trust lists configured ... | Neither the authorization server nor the issuance configuration has walletProviderTrustLists (for key attestations: the issuance configuration). |
... signer is not trusted by configured wallet provider trust lists | The provider's certificate is not in the lists, or listed without a WalletSolution service type. |
The credential configuration requires a key attestation ... | The wallet sent a jwt proof without key_attestation. Use a wallet that sends key attestations, or remove keyAttestationsRequired. |
The key attestation does not state an accepted key_storage value ... (or user_authentication) | The attested level is not in the configured list. Add the level your wallets attest, if it meets your requirements. |
The proof contains a key that is not listed in attested_keys ... | The jwt proof is signed with a key the attestation does not cover. |
Wallet attestation verification failed: ... or Attestation proof x5c chain could not be validated | Often a trust list problem: the list cannot be fetched or its signature does not match verifierX509Der/verifierKey. Check the server log for the reason. |