6.2 MDVM Flows¶
Design Decision¶
- stateful MDVM endpoint because:
- plausibility checks
- using iOS DeviceCheck attestation for every MDVM check likely are affected into rate limits imposed by Apple
- using iOS DeviceCheck assertion is the only way to use attested hardware-backed keys to re-identify the wallet instance, but is inherently stateful
- using iOS DeviceCheck assertion allows us to validate the usage counter
- encapsulate Android/iOS-specific mechanisms to the MDVM endpoints, WB and RWSCA should have the same code path for Android/iOS
- state-less design does not match with iOS device check attestation/assertion strategy
- issuing short-lived tokens to avoid backend-to-backend calls that may impact scalability and performance
- not using Android device-specific attestation key ("parent key" or "intermediate key") to associate all keys to a particular device, as it may not be sufficiently well supported across the Android ecosystem
- we may re-consider this if we have better insight and resources to test this
Flows¶
The sequence diagrams for registering and issuance/renewal of an MDVM token is divided by WI operating system:
6.2.3 Revoke Account¶
In the Revoke Account operation, the MDVM marks the account of a Wallet Instance as revoked and triggers the WI to self-lock. When the MDVM itself initiates a revocation, it marks the affected accounts directly, see wallet revocation by the MDVM.
The following table describes the steps of the sequence diagram in more detail:
| No | Description |
|---|---|
| 001 | The MDVM continuously fetches revocation events from the revocation queue. Each event contains the JWK thumbprint of a wi_mdvm_auth_pubk, which identifies the Wallet Instance across all backends, and triggers the Revoke Account operation. |
| 002 | The MDVM looks up the corresponding mdvm_wi_id in the MDVM account database using the JWK thumbprint of wi_mdvm_auth_pubk as the indexed lookup key. If no matching account is found, the MDVM ignores the event. |
| 003 | The MDVM marks the mdvm_wi_state for the mdvm_wi_id as REVOKED. A revoked account can no longer renew its MDVM token, see the renewal flows for Android and iOS. The account record is retained for traceability, see the MDVM account database. |
| 004 | The MDVM publishes a push notification event containing the JWK thumbprint of wi_mdvm_auth_pubk to the push notification queue. The Send Push Notification operation of the Push Notification Service consumes the event and delivers a push notification via the MPP to trigger the WI to confirm the revocation through a mdvm_token renewal attempt and self-lock, see Wallet Instance self-locking for details. The self-lock confirmation is decoupled from the processing of the revocation event: the account is already revoked in step (003), regardless of whether or when the WI confirms. |
| 005 | The MDVM acknowledges the revocation event only after the account has been successfully revoked. Events that are not acknowledged are redelivered by the revocation queue and reprocessing them is idempotent, see revocation propagation between backends. |
6.2.4 Purge Account¶
In the Purge Account operation, the MDVM deletes the account record of a Wallet Instance and all related data. The operation is not exposed as an endpoint towards the WI; it is triggered by purge events that the MDVM continuously fetches from the purge queue. The MDVM itself is the producer of these events, as it identifies the Wallet Instances that exceeded the data retention period, see backend deletion.
The following table describes the steps of the sequence diagram in more detail:
| No | Description |
|---|---|
| 001 | The MDVM continuously fetches purge events from the purge queue. Each event contains the JWK thumbprint of a wi_mdvm_auth_pubk, which identifies the Wallet Instance across all backends, and triggers the Purge Account operation. |
| 002 | The MDVM looks up the corresponding mdvm_wi_id in the MDVM account database using the JWK thumbprint of wi_mdvm_auth_pubk as the indexed lookup key. If no matching account is found, e.g. because the account has already been deleted, the MDVM ignores the event. |
| 003 | The MDVM deletes all data from the MDVM account database corresponding to the mdvm_wi_id, including the platform-specific attestation key material, the wi_device_class and the last-seen timestamp. |
| 004 | The MDVM acknowledges the purge event only after the account has been successfully deleted. Events that are not acknowledged are redelivered by the purge queue and reprocessing them is idempotent, as the deletion of an already deleted account has no further effect. |
MDVM Account Database¶
The MDVM account database stores the necessary information for each Wallet Instance's account:
- mdvm_wi_id
- mdvm_wi_state (VALID, REVOKED) & timestamp of revocation event
- last-seen timestamp (the most recent activity, e.g. renewal of the mdvm_token)
- wi_mdvm_auth_pubk
- JWK Thumbprint of wi_mdvm_auth_pubk
- platform-specific attestation key material:
- iOS: wi_devicecheck_pubk
- Android: no additional key is persisted
- platform-specific wi_device_class:
- Android: attestationIdModel, attestationIdProduct, attestationIdDevice, osVersion, osPatchLevel, app versionCode
- iOS: device model, operating system version
Access to the database is secured by mutual TLS to encrypt and authenticate communication to the MDVM.
The last-seen timestamp is updated during the MDVM registration and on every successful renewal of the mdvm_token and is the basis for the retention-based deletion of the account records, see backend deletion.
Account records are deleted by the Purge Account operation once the Wallet Instance exceeded the data retention period, see backend deletion; on a revocation event the record is retained for traceability.
MDVM Token¶
The mdvm_token is an assertion by the MDVM about the security posture of the device. It is bound to a wi_mdvm_auth_prvk / wi_mdvm_auth_pubk key pair and attests to an expiry time. WB and RWSCA must fetch the valid mdvm_attestation_pubk out-of-band.
The mdvm_token contains:
- JOSE Header
typas recommended by JWT BCP - JOSE Header
algindicating ECDSA NIST P-256 - JOSE Header
x5c: The X.509 Certificate chain of the MDVM service which authenticates mdvm_attestation_pubk - JWT Claim
isscontaining a URN to represent the current deployment environment, e.g. dev/staging/prod - JWT Claim
iatcontaining the issue time of the MDVM token - JWT Claim
expcontaining the expiry time of the MDVM token - JWT Claim
cnfcontaining the serialized wi_mdvm_auth_pubk - JWT Claim
mdvm_wi_idcontaining the WI's account identifier at the MDVM, letting other backends re-use it instead of generating separate identifiers
Below is a non-normative example of a mdvm_token:
Protected headers:
Payload:{
"iss": "german-national-wallet:mdvm:prod",
"iat": 1726126250,
"exp": 1726214250,
"cnf": {
"kty": "EC",
"crv": "P-256",
"x": "TCAER19Zvu3OHF4j4W4vfSVoHIP1ILilDls7vCeGemc",
"y": "ZxjiWWbZMQGHVWKVQ4hbSIirsVfuecCE6t4jT9F2HZQ"
},
"mdvm_wi_id": "018f1a7e-9f3b-7c2a-8b3e-3a6c2e1f9d4b"
}
Signed by mdvm_attestation_prvk
Challenge JWT¶
Defined in Wallet Registration.
Proof of possessions¶
The wi_mdvm_auth_pop is a proof of possession encoded as an HTTP Message Signature. The signature includes the HTTP path and all assets mentioned in the sequence diagrams (e.g. mdvm_auth_challenge, mdvm_wi_id, ...), signed as either a JSON structure in the HTTP body or in HTTP header. The signed HTTP path component serves as an identifier for either MDVM registration or renewal.
The proof of possession also serves to assert the possession factor using the wi_mdvm_auth_prvk.
Additional details on proof of possessions using HTTP Message signatures, will be added in a dedicated section.