Skip to content

Issuance of Wallet Instance Attestation (WIA)

This flow describes the process of issuing a wallet attestation (WIA) as introduced here in the blueprint.

Design Decisions

In the wallet attestation process, the WI establishes a long-term authentication key pair for a particular Credential Issuer. This key pair is attested by the WB within the Wallet Instance Attestation (WIA), that attests to the security posture of the WI. The WIA contains a Status List entry, that the Credential Issuer may use to verify the security posture of the Wallet Instance in the future. The WIA may be revoked if:

The Wallet Instance generates a hardware-bound key pair on the mobile device and transmits the public key to the Wallet Backend. The key generation must utilize the most secure key store available on the mobile device, such as a Secure Element, StrongBox, SecureEnclave or TEE. A proof of possession for the private key is done by signing the challenge.

The Wallet Provider Backend (WB) verifies the provided MDVM Token (see MDVM flows for details) and that performs additional checks on vulnerability management and user-initiated revocation (see wallet revocation for details). In return, the WB issues a Wallet Instance Attestation (wb_wia), that attests the integrity and authenticity of the Wallet Instance, bound to the public key (wi_wia_pubk). The wb_wia is a JWT as defined in attestation-based client authentication, using x509 certificate as trust mechanism to sign the WIA.

Data Flow

This section described the data flow of the Wallet Registration in a sequence diagram and a more detailed table. Artifacts in italics are further explained in the data register chapter

Sequence Diagram

The sequence diagram contains two flows marked as alternatives when they diverge:

1) In the initial WIA issuance operation, the WI requests a Wallet Instance Attestation for the very first interaction with a new Credential Issuer. The green section describes steps that are only relevant for this flow. 2) In the WIA renewal operation, the WI requests to get an updated WIA for a Credential Issuer that it already interacted with in the past. The pink section describes steps that are only relevant for this flow.

Issuance of Wallet Instance Attestation (WIA)Issuance of Wallet Instance Attestation (WIA)Wallet Instance . AppWallet BackendWSCA account databaseHardware Security ModuleMobile DeviceWallet Instance / App(WI)Wallet Instance / App(WI)Wallet Backend(WB)Wallet Backend(WB)WSCA account databaseWSCA account databaseHardware Security Module(HSM)Hardware Security Module(HSM)Mobile DeviceVulnerability Management(MDVM)Mobile DeviceVulnerability Management(MDVM)(001)renewal of mdvm_token(002)[TLS] </challengeEndpoint>()(003)generate wb_auth_challenge:sign(nonce, timestamp)wb_mac_symk(004)[TLS] <wb_auth_challenge>(005)generate client attestation key pair(wi_wia_prvk, wi_wia_pubk)(006)look-up mapping of Credential Issueridentifier to wb_wia_statusalt[WIA renewal](007)set wb_wia_status aswi_wb_operation_params(008)generate wi_wb_auth_pop:sign(wb_wi_id, wb_auth_challenge,mdvm_token, wi_wia_pubk,wi_wb_operation_params)wi_mdvm_auth_prvk,wi_wia_prvk(009)[TLS] </wiaEndpoint>(wi_wb_auth_pop)(010)verify wb_auth_challenge fromwi_wb_auth_pop using wb_mac_symk(011)verify mdvm_token withmdvm_attestation_pubk to ensuredevice authenticity and integrity ofthe WI(012)lookup wi_mdvm_auth_pubk from thedatabase using wb_wi_id(013)match wi_mdvm_auth_pubkcontained in mdvm_token withdatabase(014)verify wi_wb_auth_pop usingwi_mdvm_auth_pubk(015)verify wi_wb_auth_pop usingwi_wia_pubk(016)check wb_wi_state if the walletinstance is revoked by the useralt[initial WIA issuance](017)generate a new statuslist entrywb_wia_status(018)store wb_wia_status for wb_wi_id[WIA renewal](019)validate wb_wia_status matches towb_wi_id(020)call PKCS#11 C_SignInit and C_Signto request signature for generatingwb_wia: sign(wi_wia_pubk,wb_wia_status)wb_wia_auth_prvk(021)[TLS] wb_wiaalt[initial WIA issuance](022)store mapping of wb_wia_status forCredential Issuer identifier

Detailed Description

No Description
001 The WI determines if its most recent mdvm_token is still valid. If the mdvm_token is not up-to-date, the WI may fetch a fresh one from the MDVM endpoint using the renewal flow for either Android or iOS.
002 - 004 The WI requests a challenge from the WB challenge endpoint using an HTTP POST request, the request is unauthenticated. The WB generates a JSON structure containing a random nonce and a timestamp of the current time and MACs it using a symmetric key (wb_mac_symk) as a JSON Web Token (JWT), the resulting structure is the wb_auth_challenge. The WB responds to the WI with the wb_auth_challenge in the HTTP payload. The WI uses the challenge as a transparent string and does not evaluate the JWT claims. The WB does not store the challenge after creation, thus the operation is stateless.
005 The WI generates a a new hardware-bound key pair (wi_wia_prvk,wi_wia_pubk) which is used as the client attestation key for the wallet attestation (WIA). The WI must leverage the most secure, local key storage available, i.e. a Secure Element, StrongBox, SecureEnclave or TEE. The key must have sufficient security, information on algorithms and key lengths can be found in the cryptography chapter.
006 The WI performs a look-up in its internal mapping of Credential Issuer identifier to WIA Status List entry wb_wia_status (consisting of uri and idx). If the WI had a previous interaction with this Credential Issuer it would have stored such a mapping in Step 022.
007 Step 007 only occurs in the WIA renewal operation
If a WIA has been used with the Credential Issuer before the WI finds an entry in the mapping and sets the corresponding Status List entry wb_wia_status as an additional input wi_wb_operation_params for the request wi_wb_auth_pop.
008 The WI computes a proof of possession by signing the payload of wb_wi_id for identification, wb_auth_challenge for freshness and to enable replay protection, the mdvm_token to ensure authenticity and integrity of the WI, the client attestation public key wi_wia_pubk and potentially additional wi_wb_operation_params containing the wb_wia_status with
  • the possession factor wi_mdvm_auth_prvk
  • client attestation private key wi_wia_prvk
. The resulting structure is called wi_wb_auth_pop.
009 The WI requests the WB to issue a WIA by sending the proof of possession (wi_wb_auth_pop) to the WIA endpoint. The request is authenticated.
010 The WB verifies the self-contained wb_auth_challenge included in the wi_wb_auth_pop using its symmetric key (wb_mac_symk) and validating that the timestamp is within a valid time interval of 0 minute to +5 minutes. This step ensures replay protection beyond the valid time interval of the challenge.
011 - 014 The WB validates the security posture of the WI by verifying the mdvm_token with mdvm_attestation_pubk and checks that it is still valid. The WB has a trusted, out-of-band mechanism towards the MDVM to fetch the valid mdvm_attestation_pubk. The WB fetches the public key for the possession factor wi_wb_auth_pubk from the database using the provided account identifier wb_wi_id included in wi_wb_auth_pop. The WB verifies the signature of the received proof of possession (wi_wb_auth_pop) for the WI's possession factor using wi_mdvm_auth_pubk from the mdvm_token. Lastly, the WB verifies that the used key wi_mdvm_auth_pubk is the same in mdvm_token and in the database. The database lookup is not subject to prevention of distributed denial of service attacks, as these attacks need to be mitigated further up in the infrastructure layer.
015 The WB verifies the second signature of proof of possession wi_wb_auth_pop using using the included wi_wia_pubk.
016 The WB queries the revocation state wb_wi_state from its database to validate that the user did not revoke its WI. If the state is not "VALID", the request is aborted. This step ensures that a revoked WI cannot receive new WIAs to prevent further issuances.
017 - 018 Steps 017 - 018 only occur in the initial WIA issuance operation
The WB chooses a new, un-used Status List entry wb_wia_status for the WIA to be created. The WB then stores the new wb_wia_status for this particular WI account in the database.
019 Step 019 only occurs in the WIA renewal operation
020 The WB generates a Wallet Instance Attestation wb_wia by signing the provided public key wi_wia_pubk and the status entry wb_wia_status using its wb_wia_auth_prvk using PKCS#11 function C_SignInit and C_Sign. As the rwscd_wte_auth_prvk is a long-term key stored in the HSM, it does not need to be imported or destroyed. The resulting wb_wia assures the Issuer that the corresponding Wallet Instance is a valid client of the wallet solution, the particular WI's security posture is attested by the WB and that the user did not revoke its WI. The Issuer later fetches the wb_wia_auth_pubk from a trust list to verify the wb_wia.
021 The WB returns the Wallet Instance Attestations wb_wia to the WI.
022 Step 021 only occurs in the initial WIA issuance operation

WB setup

The WB uses a Hardware Security Module (HSM) for the following use cases:

  • wb_wia_auth_prvk (used to sign the Wallet Instance Attestations)

The WB and the HSM uses mutual TLS to encrypt and authenticate their communication. Additionally, the PKCS#11 C_Login operation is used to authenticate to a specific HSM partition. The WB uses PKCS#11 as the API to send requests to the HSM.

WB Account database

The WB account database stores the necessary information for each Wallet Instance's account:

  • wb_wi_id
  • wi_mdvm_auth_pubk
  • Hash(wb_wi_revocation_secret)
  • wb_wi_state (VALID, PENDING_WIA_REVOCATION, PENDING_APP_REVOCATION, REVOKED)
  • list of wb_wia_status

Access to the database is secured by mutual TLS to encrypt and authenticate communication to the WB.

Wallet Challenge JWT

Defined in Wallet Registration

Proof of Possession JWT for Authentication

The wi_wb_auth_pop is a possession-based authentication factor of the Wallet App, that creates a proof of the wi_mdvm_auth_prvk over the wb_auth_challenge.

The wi_wb_auth_pop contains:

  • JOSE Header typ as recommended by JWT BCP
  • JOSE Header alg indicating ECDSA NIST P-256
  • JWT Claim wb_wi_id containing the serialized wb_wi_id
  • JWT Claim wb_auth_challenge containing the serialized wb_auth_challenge
  • JWT Claim mdvm_token containing the serialized mdvm_token
  • JWT Claim wi_wia_pubk containing the serialized wi_wia_pubk
  • JWT Claim aud referencing the URL of the Wallet Provider Backend

Note: There is no jti parameter for potential enhanced replay protection, as we can reuse the wb_auth_challenge for this purpose. There is also no iat or exp parameter, because the wb_auth_challenge already includes a trusted timestamp. There is also no iat or exp parameter, which is added by the WI, because the wb_auth_challenge already includes a trusted timestamp.

Below is a non-normative example of a wi_wb_auth_pop:

Protected headers:

{
  "typ": "wi-wb-auth-pop+jwt",
  "alg": "ES256"
}
Payload:
{
  "wb_wi_id": "3e8ba9be-78d9-4ed3-996a-a9d4d72ce414",
  "wb_auth_challenge": "eyJ0eXAiOiJ3Yi1hdXRoLWNoYWxsZW5nZStqd3QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MzgzMTQ4NzQsIm5vbmNlIjoiZmEwYTMxMGUtOTFkMi00NjFjLWJhMDAtY2MzNWE5OTVmMTY2IiwiaWF0IjoxNzM4MzExMjc0fQ.7QpBVKvwuukioYhLX402ay-DwTv5H3x-hhovev72i58",
  "mdvm_token": "...",
  "wi_wia_pubk": {
      "kty": "EC",
      "crv": "P-256",
      "x": "32jtyqhBGxKxqeihaRsmW449oB9hcMUSgNCxDjHfADo",
      "y": "3ARvwMghvfz7zAcGEdwQj2h5DQU64BezdaSthn7qJzk"
    }
  "aud": "https://wallet-provider-backend.eudi-wallet.de"
}

Signed by wi_mdvm_auth_prvk

Wallet Instance Attestation (WIA)

The wb_wia is a signed attestation of the Wallet Provider backend, attesting to the validity of the Wallet Instance towards Issuers and Relying Parties. The format is described in Section 5.1 of attestation-based client authentication.

In accordance to the rules defined in the draft, the wb_wia contains:

  • JOSE Header typ as recommended by JWT BCP
  • JOSE Header alg indicating ECDSA NIST P-256
  • JOSE Header x5c containing the x509 certificate chain of the Wallet Provider
  • JWT Claim sub: referencing the client_id of the Wallet Provider Backend
  • JWT Claim exp: current time + expiration time interval, indicating the expiration data of the WIA
  • JWT Claim cnf: containing the serialized wi_wia_pubk
  • JWT Claim iat: current time, indicating the issuance date of the WIA (optional)
  • JWT Claim status: status information about the authenticity and integrity of the Wallet Instance
    • JWT Claim status_list: status information as a Status List
      • JWT Claim uri: URI that links to the Status List Token
      • JWT Claim idx: index within the Status List Token that represents the status of the WI

Below is a non-normative example of a wb_wia:

Protected headers:

{
  "typ": "oauth-client-attestation+jwt",
  "alg": "ES256",
  "x5c": [
    "MIIBETCBuQIJAM6k5TM9MgHEMAkGByqGSM49BAEwEjEQMA4GA1UEAwwHdGVzdC5kZTAeFw0yNDExMTExMjMwMTRaFw0yNTExMTExMjMwMTRaMBIxEDAOBgNVBAMMB3Rlc3QuZGUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATQivHxcyv56XIfjt6EeyekabQ44oXSvplQXwE42c5SKheiZyhKfjhATMdpNQKV+2WnNX28Dwlv/mBQkA2pPe98MAkGByqGSM49BAEDSAAwRQIgcn7PP74vJ82nUxVQA4nt++IzWK+xYX2jGe9oh/5R9CICIQCsCjry+BL5biHKY6Pp8hUSsGqpMCV2uza/lhq4C4RoWg=="
  ]
}
Payload:
{
  "sub": "de.bmi.eudi-wallet.wallet-provider-backend",
  "cnf": {
    "jwk": {
      "kty": "EC",
      "crv": "P-256",
      "x": "32jtyqhBGxKxqeihaRsmW449oB9hcMUSgNCxDjHfADo",
      "y": "3ARvwMghvfz7zAcGEdwQj2h5DQU64BezdaSthn7qJzk"
    }
  },
  "iat": 1750742508,
  "exp": 1750828908,
  "status" : {
    "status_list" : {
      "uri" : "https://wallet-provider-backend.eudi-wallet.de/status/0953e816-c84e-4ae4-a955-d2190552f21b",
      "idx" : 5217
    }
  }
}

Signed by wb_wia_auth_prvk

Proof of Possession JWT for Wallet Instance Attestation (WIA)

The wi_wia_pop is a proof of possession signed by the Wallet Instance, attesting to the possession and usage of the WIA towards the Wallet Provider Backend. The format is aligned with Section 5.2 of attestation-based client authentication, but contains slight differences.

In accordance to the rules defined in the draft, the wi_wia_pop contains:

  • JOSE Header typ as recommended by JWT BCP
  • JOSE Header alg indicating ECDSA NIST P-256
  • JOSE Header jwk containing the serialized wi_wia_pubk
  • JWT Claim aud referencing the URL of the Wallet Provider Backend
  • JWT Claim jti containing a UUID
  • JWT Claim iat: current time, indicating the issuance date of the PoP
  • JWT Claim wb_auth_challenge containing the serialized wb_auth_challenge

Note: The Wallet Backend is using the challenge for replay protection instead of jti, but the draft of attestation-based client authentication requires jti to be present in any case.

Below is a non-normative example of a wi_wia_pop:

Protected headers:

{
  "typ": "oauth-client-attestation-pop+jwt",
  "alg": "ES256",
  "jwk": {
    "kty": "EC",
    "crv": "P-256",
    "x": "32jtyqhBGxKxqeihaRsmW449oB9hcMUSgNCxDjHfADo",
    "y": "3ARvwMghvfz7zAcGEdwQj2h5DQU64BezdaSthn7qJzk"
  }
}
Payload:
{
  "aud": "https://wallet-provider-backend.eudi-wallet.de",
  "jti": "d25d00ab-552b-46fc-ae19-98f440f25064",
  "iat": 1750742508,
  "wb_auth_challenge": "eyJ0eXAiOiJ3Yi1hdXRoLWNoYWxsZW5nZStqd3QiLCJhbGciOiJIUzI1NiJ9.eyJub25jZSI6IjhjM2YyODM4LTU1Y2QtNGE0MC1iOTg5LWEzMzYyNDhkOGNlOCIsImlhdCI6MTc1MDc0MjUwOH0.VD0P5y2EZbut0_JxCd_nwo0RNDZhndzO7M2xWzZ7xyA"
}

Signed by wi_wia_pop_prvk