v0.6.0 (dev)
Upgrading
Issuers now require
registration_certificate: a base64url-encoded WRPRC bound to their metadata-signing WRPAC. Helm deployments require this key in each issuer’s WRPAC secret. Before updating wallets, deploy the issuers, publish their referenced status lists, and ensure the wallet trusts the WRPRC signing chains.OpenID4VP disclosure use cases now require a Wallet Relying Party Registration Certificate (WRPRC). Configure each verification server and disclosure-based issuance server use case with a
registration_certificate, configurewrprc_trust_anchors, and publish the referenced WRPRC status list before deploying wallet clients. Thestatic_serverconfiguration now also requireswrprc_publish_dir, which identifies the directory containing those status lists. The services reject missing or invalid certificates at startup, and the wallet rejects requests that are revoked or exceed the certificate’s authorization.The wallet now requires a usable Certificate Revocation List (CRL) for every Wallet Relying Party Access Certificate (WRPAC) used in signed OpenID4VP authorization requests, signed issuer metadata, and close-proximity reader authentication. Before deploying wallet clients with this change, publish a signed CRL at a stable HTTP(S) URL, rotate existing WRPACs to include that URL as a CRL Distribution Point, and verify the CRL endpoint is available. The CRL publication and certificate rotation must be deployed before CRL validation is enabled in wallet clients. For production, the WRPAC PKI operator must provide an automated CRL service; the
wallet_cautility is intended for development and is not suitable for operating a production CA. The production service must:Include a usable CRL Distribution Point in every WRPAC and supplied intermediate CA certificate. The root trust anchor is excluded.
Publish a complete, DER-encoded X.509 version 2 CRL at each distribution point over unauthenticated HTTP(S), reachable by wallet clients. Delta and indirect CRLs are not supported.
Sign CRLs using the applicable WRPAC issuing CA and ECDSA P-256 with SHA-256. Include
nextUpdateand a monotonically increasing CRL number, and retain revoked certificate serial numbers until those certificates expire.For CRLs covering WRPACs, publish a complete CRL at least every 24 hours until a final CRL is published. This cadence follows from ETSI TS 119 411-8,
REV-6.3.9-01, applying ETSI EN 319 411-1,CSS-6.3.9-05. SetnextUpdateto the next scheduled publication, automate renewal before it expires, and support immediate publication after an emergency revocation.Keep CRLs at most 5 MiB. Monitor endpoint availability, CRL integrity and freshness, and alert before
nextUpdate; the wallet rejects a WRPAC when its applicable CRL cannot be fetched or validated.
The callback URI for issuance changed from “/return-from-digid” to “/iss”. This will need to be updated in relevant applications, like rdo-max and DigiD.
The
neithervalue forsession_type_return_urlin the verification server configuration is no longer supported; usesame_device(the default) with areturn_url_templateinstead.The
pid_issuancesection of the Wallet configuration has been paired down as follows:The
pid_issuer_urlfield is now just calledurl.The value at the
digid/client_idpath has been moved toclient_id.The object contained in
digid_http_confighas been removed.
The
pid_issuerconfiguration has had itsdigid.http_configsection renamed todigid.client_settings. Within this section, thebase_urlfield has been renamed tooidc_identifier, which contains the same value.The supported client identifier prefix (in the context of OpenID4VP, so a “client” here is a relying-party, a verifier) has changed from
x509_san_dnstox509_hash. That means our wallet app expectsx509_hashclient ids. In our issuer server, theclient_idfield, which is part of ausecaseneeds to be updated (in our code that means thedemo_issuer). For example:"client_id": "x509_hash:YYIN_SgqjFj2044q1fpvpa0rxqrXEG0U1xdm2Hw_ohM",
The value of
x509_hashis the base64url-encoded value of the SHA-256 hash of the DER-encoded X.509 certificate.The
attestation_settingssections of both thepid_issuerand theissuance_serverhave undergone significant changes. These sections have been renamed tocredential_configurationsan are now configured per credential format. Each individual section directly represent a Credential Configuration as presented in the Issuer Metadata. The full changes are as follows:The section key now represents a Credential Configuration identifier, where before this was used as the Attestation Type.
The
attestation_typefield was added.The
copies_per_formatfield has been removed and replaced by aformatfield and a top-levelbatch_sizefield, that applies to all issued credentials.The
status_listsection has had agroup_namefield added, in order to decouple status lists from the Attestation Type. Normally this value would be set to the same value as the Credential Configuration identifier.
Related to the previous change, the
IssuerDocumentthe attestation server provides in the context of disclosure-based issuance has had theformatfield added.The Wallet Instance Attestation (WIA) configuration has changed, reflecting a rename from WUA (Wallet Unit Attestation) and the addition of wallet metadata fields:
In the Wallet Provider configuration, all
wua_*fields have been renamed towia_*, and the[wua_status_lists]section has been renamed to[wia_status_list]. Additionally:wua_issuer_identifierhas been replaced by four wallet metadata fields:wia_wallet_name,wia_wallet_version,wia_wallet_link(optional), andwia_wallet_solution_certification_information.A
wia_certificatefield (base64-encoded DER X.509 certificate) must now be provided. The WIA JWT is signed using a certificate chain (x5cheader) instead of a bare key.
In the PID Issuer configuration,
wua_issuer_pubkeyhas been replaced bywia_trust_anchors, a list of base64-encoded DER X.509 CA certificates used to validate WIA tokens.
The
pid_issuancesection of the wallet configuration has been replaced withpid_credential_offer, which contains a single string value. This string value contains a Credential Offer URI that should be used as the basis for PID issuance. Note that this URI can contain a Credential Offer either by value or by reference and must use the Authorization Code flow.A
type_metadata_uriis added to theCredentialConfigurationto specify a SD-JWT VC type metadata. The preview endpoint is modified to not return the type metadata but theCredentialConfigurationIdinstead ensuring type metadata fetching is independent of the preview.A new service
pacf_issuance_serverhas been added. It is a standalone issuance server that issues credentials using the Pre-Authorized Code Flow, and requires its own configuration file and database.The
demo_issuerconfiguration has two changes:A new top-level
pacf_issuance_server_urlfield must be added, pointing to the internal server port of thepacf_issuance_server.Each entry under
usecasesis now either a Pre-Authorized Code Flow usecase (containing onlydata) or a disclosure-based usecase (containingdata,client_id, anddisclosed).
The SD-JWT VC type metadata is updated to draft 13. This means they will have to be updated as follows:
The
langfield inDisplayMetadataandClaimDisplayMetadatais renamed tolocale.ClaimMetadatanow contains amandatoryfield that indicates whether the claim is mandatory. This should be set to true for all claims that are listed inschema.required.The
schemais now dropped from the metadata.
A new service
acf_demo_issuerhas been added. It is a standalone issuer server that issues credentials using the Authorization Code Flow, and requires its own configuration file and database.flutter_rust_bridge has been updated to 2.12.0, run
cargo install flutter_rust_bridge_codegen --locked --version 2.12.0to update.The new
ALLOW_RELEASE_LOGSbuild flag controls whether profile/release builds emit Flutter, Rust, and native platform-support device logs and forward Flutter/Rust logs to Sentry Logs. It defaults tofalseand is intended only for non-production release builds, such as ont/demo; production builds should leave it unset or set it tofalse.The
pid_issuerservice can now serve a custom DigiD login page, where a preconfigured BSN can be selected. For this, thepid_issueroffers adigid.mock_subjectssetting.All issuance binaries now require the
wia_trust_anchorsarray in their configuration file, instead of just the PID issuer.The enum
Attributeis now a tagged enum. Therefore, attributes configured indemo-issuer,acf-demo-issuerandpacf-issuance-servermust tag their values with the appropriate tag.The Wallet Provider settings now requires a
current_certificate_kidand optionallyprevious_certificate_kids. Thecurrent_certificate_kidis used to identify the current certificate signing key, andprevious_certificate_kidsis used to accept certificates signed with previous signing keys after key rollover.The Wallet Provider settings now requires a
current_instruction_result_kidinstead ofinstruction_result_signing_key_identifier. Thecurrent_instruction_result_kidis used to identify the current instruction result signing key.The
certificate_public_keyfield in the Wallet configuration has been renamed tocertificate_public_keysand changed to be a map from key identifier (kid) tokey, used_from. This allows multiple wallet certificate signing keys to be present in the Wallet configuration during key rollover. Theused_fromfield indicates the moment from which the Wallet Provider actually signs with that key, because a key must be added to the Wallet configuration ahead of the Wallet Provider’s own rollover.The Wallet configuration’s
account_serversection now requires acertificate_refresh_threshold_in_daysfield, specifying how long before a wallet certificate’s expiry (exp) the wallet should proactively request a new one.The
attestation_qualificationfield has been removed from credentials, which means it is also removed from thedisclosed_attributesresponse and from issuer credential configuration.The
issuer_urifield has been removed from the mdoc MSO and theissclaim has been removed from SD-JWT VC credentials and thedisclosed_attributesresponse. Issuer authentication now relies solely on certificate chain verification against trust anchors. Consequently thecertificate_sansetting has been removed from the issuer configuration.The Wallet Provider settings’
attestation_wrapping_key_identifierandpin_pubkey_encryption_key_identifierfields have been replaced by[attestation_wrapping_kid]and[pin_pubkey_encryption_kid], each with acurrentand optionalpreviouskey identifier (kid).Every credential configuration with format
mso_mdocnow requires acredential_metadatasetting that names a JSON file with the Credential Metadata for that credential, and the issuer refuses to start without it. SD-JWT VC Type Metadata documents can only be used forsd_jwtcredentials.The attributes of an issuable mdoc document now have exactly two levels of keys: a namespace and the name of a data element. Existing
IssuableDocumentsshould be updated to reflect this.The Wallet Provider Helm chart values for iOS root certificates and Android root public keys and Play Store certificate hashes are now arrays. Operators should convert their existing CSV values into proper arrays.
New features
The Wallet Provider will now block recovery codes during PIN recovery or PID renewal when the newly disclosed recovery code does not match with stored recovery code. This is suspicious because it is already checked by the NL Wallet app as well.
Users can delete non-PID cards from their wallet, via the card detail screen.
When a card is deleted, the wallet now stores this in its history.
Allow incoming BLE connection through ‘Present QR’ screen. The BLE server is now started when this screen is displayed and a remote verifier can connect to trigger navigation to the disclosure flow.
Parse the ISO 18013-5 “close proximity” DeviceRequest and present it in the disclosure screen so the user can share the specified credentials.
If the RP’s DCQL request contains a Trusted Authorities Query of type Authority Key Identifier, both the verification_server and the wallet will now respect this, allowing the RP to request attestations signed by specific issuer keys.
The verification server will now include
session_typein the hash computation of theephemeral_id, making it impossible for any intermediary to change its value.The
timefield will now only be included in theephemeral_idcomputation for sessions that do not use a return URL. As a result, same-device sessions (and cross-device sessions that use a return URL) no longer expire, fixing a UX issue that occurred when the user took too long to enter their PIN.Added an in-app FAQ, reachable from the menu’s “Need help?” entry.
Show a dedicated error screen instead of crashing when the app hits an invariant/unexpected fatal error.
Updated Flutter to 3.47.5
Added logic to filter duplicate PID cards using the prioritized list of PidAttestations from FlutterConfiguration. This results in no longer showing duplicate PID cards in the UI.
Add support for credential offer based issuance flow in wallet_app.
There is now support for Generic Issuance using the Authorization Code Flow. This is demonstrated by the new service
acf_demo_issuer, which can issue an insurance attestation including a user consent page.The wallet uses fields from the Wallet Relying Party Access Certificate when showing an organization to the user.
The
pid_issuerservice can now serve a custom styled DigiD login page, where a preconfigured BSN can be selected, or a custom BSN can be entered.A new
admin-portalservice has been added. It is a Vue 3 web GUI for administrative tasks such as (de)blocking and revocation, served by NGINX. The service ships with a Helm chart (deploy/helm-charts/admin-portal), and a Docker image built in CI (nl-wallet-admin-portal).The Wallet Provider now supports key rollover for the wallet certificate related keys (wallet certificate signing key and PIN HMAC key). This is done by updating the
current_certificate_kidandprevious_certificate_kidsfields in the Wallet Provider settings.The Wallet Provider now supports key rollover for the instruction result signing key. The Wallet Configuration’s
instruction_result_public_keysfield maps key identifiers to public keys, and the Wallet Provider’scurrent_instruction_result_kidsetting selects which key is currently used for signing.The Wallet Provider now supports key rollover for the attestation wrapping key and the PIN public key encryption key. The
currentfield of the[attestation_wrapping_kid]and[pin_pubkey_encryption_kid]settings sections selects the key used to encrypt new data, while thepreviousfield still allows already-stored data to be decrypted during a rollover.Wallet Certificates now expire and are automatically renewed by the wallet when needed, without requiring a PIN change. Validity is controlled by the Wallet Provider setting
wallet_certificate_validity_in_days, and renewal timing bycertificate_refresh_threshold_in_daysin the Wallet configuration.
Interoperability improvements
The verification server now enforces HAIP 1.0 compliance for same-device flows: a
redirect_uriis always returned to the wallet after a successful disclosure. See the Upgrading section for the required configuration change.Sections of both the wallet and issuer code have been updated to be compliant with OpenID4VCI 1.0:
The issuer now provides a nonce endpoint, which replaces the
c_noncevalue in theTokenResponse.The PID issuance flow has been changed to use the Authorization Code flow, instead of a hybrid implementation of the Authorization Code and Pre-authorized Code flow.
The issuer and wallet now support and use Pushed Authorization Requests (PAR) for the PID issuance flow.
The wallet supports retrieving a Credential Offer from a URI that is passed using the
credential_offer_uriquery parameter.The wallet includes the correct
scopevalue in the Authorization Request it sends in the Authorization Code flow, as retrieved from the Issuer Metadata. The Issuer issues credentials based on these particularscopevalues.The Issuer in turn includes the correct
authorization_detailsvalue in its Token Response, containing both the Credential Configuration Identifiers and the Credential Identifiers. These values are processed by the wallet.The separate Credential Endpoint and Batch Credential Endpoint on the
Issuerhave been replaced by a new Credential Endpoint. Instead of issuing copies of all credentials offered in the session at once, it only provides copies of a single credential, necessitating the Wallet to call this endpoint as many times as there are distinct credentials in a session.Sending a DELETE to the
IssuerCredential Endpoint in order to reject an offered credential has been removed. This is not part of the OpenID4VCI specification, the Notitication Endpoint should be used for this instead. Currently theIssuerdoes not support this endpoint.
The well-known path is now derived according to spec for Credential Issuer Metadata and Oauth 2.0 Authorization Server Metadata when a subpath is involved.
SD-JWT VC type metadata is updated to draft 13.
All issuance servers can serve signed OpenID4VCI metadata with the WRPAC certificate.
The WIA, also known as the Wallet Attestation in OpenID4VCI, is now no longer sent as part of the
CredentialRequestdata structure, but along with the PAR and Token Request as defined in the [“OAuth 2.0 Attestation-Based Client Authentication” draft specification][2], in accordance with OpenID4VCI 1.0.The wallet requires signed credential issuer metadata.
The wallet can now receive and render an ISO mDL. Labeling fields in nested objects is not supported yet.
mdocs should now be described by Credential Metadata from the Credential Issuer Metadata and are completely independent of SD-JWT VC Type Metadata.
The
type_metadata_integrityfield has been removed from the mdoc MSO, as mdocs no longer refer to SD-JWT VC Type Metadata.When an SD-JWT does not have
type_metadata_uri, the wallet will use the Credential Metadata from the Credential Issuer Metadata.The wallet can now receive and store mdocs whose MSO declares an
identifier_liststatus mechanism instead of astatus_list. Sinceidentifier_listis not yet supported, the revocation status of these mdocs is treated as undetermined.The wallet no longer rejects SD-JWT VC Type Metadata or Credential Issuer Metadata that references a logo or background image hosted externally (i.e. a
urithat does not use thedata:scheme). Such images are now silently ignored, instead of causing the credential’s metadata to be rejected.
Bug fixes
The issuance server now correctly returns a 406 when it cannot match the Accept header in content negotiation.
Wallet transfer requests are now bounded to limit peak memory usage on the wallet provider. Thanks Harsh Banshpal