OID4VC High Assurance Interoperability Profile (HAIP) โ Conformance Audit
Spec: openid.net/specs/openid4vc-high-assurance-interoperability-profile-sd-jwt-vc-1_0.html
Audited: 2026-05-16
Scope: verifiably-go as orchestrator (not issuer/verifier DPG); walt.id 0.18.2 as primary DPG.
Legend
| Symbol | Meaning |
|---|---|
| โ | Conformant |
| โ ๏ธ | Partial / conditional |
| โ | Gap โ action required |
| N/A | Not applicable to this component |
1. Credential Format
| Requirement | Status | Notes |
|---|---|---|
SD-JWT VC (vc+sd-jwt) MUST be supported |
โ | wired via sd_jwt_vc (IETF) in schema catalog |
mdoc (mso_mdoc) SHOULD be supported |
โ ๏ธ | format recognized, no revocation support |
W3C VCDM 2.0 (ldp_vc) is out of scope for HAIP |
N/A | still supported for non-HAIP flows |
2. Issuance (OID4VCI)
| Requirement | Status | Notes |
|---|---|---|
| Authorization Code Flow | โ | delegated to walt.id |
| Pre-authorized Code Flow | โ | used in single / bulk issuance |
credential_offer URI via QR |
โ | offerURI returned and surfaced to operator |
issuer_state binding |
โ | handled by walt.id |
| Proof-of-possession (DPoP / key-binding) | โ ๏ธ | enforced by walt.id; verifiably-go doesn't inspect proof |
Issuer metadata at /.well-known/openid-credential-issuer |
โ ๏ธ | served by walt.id; verifiably-go proxies the offer, not the metadata |
credential_identifier in offer |
โ | schema-id mapped to credential config |
Batch issuance (/batch_credential) |
โ ๏ธ | bulk.go issues N single credentials; no true batch endpoint |
| Display metadata for credentials | โ ๏ธ | SchemaName propagated; display array not surfaced |
3. Presentation (OID4VP)
| Requirement | Status | Notes |
|---|---|---|
vp_token returned via response_mode=direct_post |
โ | verified in internal/adapters/waltid/verifier.go |
response_mode=direct_post.jwt (HAIP REQUIRED) |
โ | Gap: HAIP mandates JARM-encrypted response; walt.id 0.18.2 supports direct_post only |
client_id_scheme=x509_san_dns (HAIP REQUIRED) |
โ | Gap: walt.id uses redirect_uri as client_id; x509 cert not provisioned |
client_id_scheme=did |
โ | current default in walt.id |
| Presentation exchange (DIF PE) | โ | presentation_definition wired via OID4VP template |
nonce freshness |
โ | session state enforces one-time use |
| SD-JWT selective disclosure | โ | disclosed fields extracted and stored in DisclosedFields |
vp_token as SD-JWT (not LD-Proof) |
โ | verified by regression tests in vp_token_regression_test.go |
4. Key Binding & Wallet Attestation
| Requirement | Status | Notes |
|---|---|---|
wallet_attestation JWT in token request |
โ | Gap: HAIP ยง6 requires wallets to present a wallet attestation signed by the wallet provider; not enforced in verifiably-go (would require verifier-side attestation validation) |
Holder key binding proof (cnf claim) |
โ ๏ธ | enforced by walt.id wallet-api; verifiably-go doesn't verify cnf independently |
Key binding JWT (kb-jwt) over vp_token |
โ ๏ธ | present in SD-JWT VC wire format; verifiably-go extracts claims without re-verifying kb-jwt signature |
5. Security
| Requirement | Status | Notes |
|---|---|---|
| TLS for all endpoints (HAIP ยง4.1) | โ | enforced by Caddy in subdomain mode; localhost mode exempt per spec |
| Authorization Code PKCE | โ | PendingPKCE stored in session, passed through OIDC flow |
| DPoP token binding (HAIP RECOMMENDED) | โ ๏ธ | not enforced by verifiably-go; delegated to walt.id |
iss claim validation in responses |
โ ๏ธ | verified by walt.id; verifiably-go trusts the adapter's success/error |
| Status list revocation (HAIP ยง7.2) | โ | W3C BSL 2023 + IETF Token Status List both implemented |
Credential expiry (exp claim) |
โ ๏ธ | set by walt.id; not enforced by verifiably-go on fetch |
6. Identified Gaps โ Priority Order
โ Gap 1: response_mode=direct_post.jwt (JARM)
Requirement: HAIP ยง5.5 โ response MUST be JWT-encrypted to the verifier's public key.
Current state: direct_post (plain JSON body, no encryption).
Risk: Credential claims in transit are visible to redirect intermediaries.
Fix path:
- Upgrade walt.id to a version that supports JARM (check release notes for
direct_post.jwt). - Provision the verifier's encryption key (ECDH-ES+A256KW) and register it in the verifier metadata.
- verifiably-go passes the
response_modeparameter through toRequestPresentationโ no code change needed once walt.id supports it.
Effort: M โ depends on walt.id upstream support.
โ Gap 2: client_id_scheme=x509_san_dns
Requirement: HAIP ยง4.3 โ verifiers in high-assurance flows MUST authenticate with an X.509 certificate whose SAN DNS matches the client_id.
Current state: client_id is the verifier's redirect_uri (scheme redirect_uri).
Risk: Wallet cannot distinguish a legitimate verifier from a phishing site without a certificate.
Fix path:
- Issue a TLS certificate for the verifier subdomain (already done via Caddy/Let's Encrypt in subdomain mode).
- Configure walt.id verifier-api
client_id_scheme = "x509_san_dns"and point to the cert. - verifiably-go passes
client_idthrough theOID4VPTemplate; addClientIDSchemefield to the template type.
Effort: M โ config change in walt.id + schema extension in verifiably-go.
โ Gap 3: wallet_attestation
Requirement: HAIP ยง6 โ issuer MUST validate wallet attestation JWT before issuing.
Current state: attestation not required or validated.
Risk: Any OAuth client that has the authorization code can impersonate a conformant wallet.
Fix path:
- Add
wallet_attestationvalidation to the issuance flow inAPIIssue/ walt.id adapter. - Trust anchor (wallet provider public key) must be fetched from a trusted registry or pinned.
Effort: LโXL (depends on whether a public wallet attestation registry exists for the target wallets).
7. What's Already HAIP-Compliant
- SD-JWT VC credential format end-to-end (issue โ present โ verify disclosed fields)
- OID4VCI Pre-auth + Authorization Code flows via walt.id
- OID4VP with DIF PE
presentation_definition - W3C BSL 2023 + IETF Token Status List revocation
- PKCE in OIDC authorization flows
- TLS termination via Caddy in production mode
- Nonce freshness (one-time use enforced via session state)
- Per-issuer credential scoping (
OwnerKey)
8. Recommended Closure Plan
| Priority | Item | Version target |
|---|---|---|
| P1 | Upgrade walt.id to a release with direct_post.jwt support |
Next walt.id release after 0.18.2 |
| P1 | Configure client_id_scheme=x509_san_dns in verifier-api |
Same release cycle |
| P2 | Add ClientIDScheme field to OID4VPTemplate and thread it through RequestPresentation |
verifiably-go sprint |
| P3 | Research wallet attestation registry for target wallets (EUDI, inji) | Architecture spike |
| P3 | Add kb-jwt signature verification in verifier adapter |
After trust anchor decision |