ISO/IEC 18013-5 mdoc support + EU AV profile compliance
Tracking issue for landing the mso_mdoc credential format in irmago — issuance to the wallet via OpenID4VCI and disclosure via OpenID4VP (DCQL) — and for becoming compliant with the EU Age Verification (AV) profile, including making go-passport-issuer an AV Attestation Provider issuing proof-of-age mdocs over OpenID4VCI.
Plans (PR #570):
docs/mdoc-implementation-plan.md — mdoc in irmago (milestones M1–M7)
docs/av-profile-compliance-plan.md — cross-check against the EU AV technical specification / Annex A AV profile, irmago deltas (incl. milestone M8), and the go-passport-issuer phases (P1–P6)
Reference implementation: multipaz.
Relevant specs
- ISO/IEC 18013-5:2021 — mdoc data model, MSO, DeviceResponse, selective disclosure
- ISO/IEC TS 18013-7 — mdoc over OpenID4VP and the W3C Digital Credentials API (Annex C)
- OpenID4VCI / OpenID4VP —
mso_mdoc format, DCQL, vp_token encoding
- EU Age Verification profile (Annex A): docType/namespace
eu.europa.ec.av.1, age_over_NN boolean claims only, ES256/P-256, both OID4VCI grant types with PKCE S256, JWT proofs with batch issuance (recommended size 30), single-use attestations ≤ ~3 months, no revocation, av:// invocation scheme; presentation primarily via the W3C Digital Credentials API (org-iso-mdoc, HPKE-encrypted responses per RFC 9180), with unsigned-request OpenID4VP (direct_post, client-id scheme redirect_uri) as fallback
- RFC 9052/9053 (COSE), RFC 8949 (CBOR), RFC 9180 (HPKE), RFC 7636 (PKCE)
Scope
irmago (wallet/holder side):
- Receiving
mso_mdoc credentials via OpenID4VCI (pre-authorized + authorization code flows, batch issuance), verified against trust anchors before storage.
- Storing mdoc credentials and device keys alongside SD-JWT VCs.
- Answering DCQL
mso_mdoc queries with a DeviceResponse in a vp_token (direct_post and direct_post.jwt), selective disclosure, deviceSignature device auth.
- AV profile deltas: Digital Credentials API presentation (M8), unsigned OpenID4VP requests with
redirect_uri client-id scheme, MSO timestamp-precision truncation, av:// scheme handling, ETSI TS 119 612 trusted-list support.
- Enough issuer/verifier-side mdoc code to build fixtures and run hermetic end-to-end tests in-process.
go-passport-issuer (AV Attestation Provider, sub-issues P1–P6):
- Mint
eu.europa.ec.av.1 proof-of-age mdocs (only age_over_NN claims) from ICAO 9303-validated documents, reusing irmago's mdoc building blocks.
- Full OpenID4VCI issuer: metadata, token endpoint (pre-authorized code + authorization code, PKCE S256), nonce + credential endpoints with JWT-proofs batch issuance,
av:// credential offers.
- AV trust & ops: ETSI EN 319 411-1 (NCP) document signer cert / IACA, registration on the AV trusted list, privacy review (data minimisation, unlinkability).
- Interop with the AV reference implementation; the IRMA issuance path remains.
Out of scope (for now):
deviceMac device auth, proximity flows (BLE/NFC device engagement, session encryption)
- ZK presentations (longfellow-zk; SHOULD in the AV profile — tracked as a possible M9 once the profile hardens)
- mdoc revocation/status lists (explicitly not required by the AV profile)
Key design decisions
- Add
fxamacker/cbor/v2 and veraison/go-cose; COSE_Key (and later COSE_Mac0) implemented in-repo on top of cbor/v2.
- New self-contained package
eudi/credentials/mdoc/, sibling of sdjwtvc/.
- Reuse the existing holder-binding key machinery (ECDSA P-256, encrypted storage, one key per batch instance) for mdoc device keys.
- Extend
DcqlCredentialQueryHandler.PrepareDisclosure to take a DisclosureContext — the only cross-format interface change required.
- Storage follows the existing polymorphic-format TODO in
eudi/storage/db/models/credentials.go.
- Handover construction (OpenID4VPHandover / DC-API handover) isolated in one function to absorb spec-draft churn.
Milestones
Each milestone is independently mergeable, fully covered by automated tests, and must not regress existing SD-JWT VC / idemix flows. See sub-issues (irmago M1–M8, go-passport-issuer P1–P6).
irmago: M1 → M2 → M3 → M4 ─┬→ M5 (OID4VCI) ──┬→ M7 → (M8 DC API)
└→ M6 (OID4VP) ───┘
go-passport-issuer: P1 (needs M3) → P2 (needs M5 as test harness) → P3 → P5 → P6
└→ P4 (parallel with P3)
Risks / open questions
- OpenID4VP draft alignment: the handover structure changed between drafts; Annex A pins neither the OID4VCI nor OID4VP draft and AP metadata is "TBD" — keep handover construction isolated and AP metadata config-driven.
- Device-binding ambiguity in the AV profile: Annex A marks device-bound attestations out of scope yet mandates JWT proofs; if AV reference attestations carry no device key, M2/M6 must tolerate MSOs without
deviceKeyInfo — confirm early during interop.
- cbor v1/v2 coexistence: legacy v1 usage (revocation) should eventually migrate, out of scope here.
- go-cose API fit: if x5chain or raw R||S handling fights us, fall back to a minimal in-repo COSE_Sign1; decide during M1.
- Claims projection fidelity: stable JSON mapping for CBOR element values (tdate, full-date, binary); DCQL value matching must follow OpenID4VP rules for non-string values (AV uses boolean claims).
- Trusted-list operational dependency: AV trusted-list registration is a process with the Commission — start early; test lists exist for development.
- Python EUDI issuer mdoc config: enabling the mdoc PID variant needs IACA/DS certificate config in
testdata/eudi-pid-issuer-py/; budget for this in M5.
ISO/IEC 18013-5 mdoc support + EU AV profile compliance
Tracking issue for landing the
mso_mdoccredential format in irmago — issuance to the wallet via OpenID4VCI and disclosure via OpenID4VP (DCQL) — and for becoming compliant with the EU Age Verification (AV) profile, including making go-passport-issuer an AV Attestation Provider issuing proof-of-age mdocs over OpenID4VCI.Plans (PR #570):
docs/mdoc-implementation-plan.md— mdoc in irmago (milestones M1–M7)docs/av-profile-compliance-plan.md— cross-check against the EU AV technical specification / Annex A AV profile, irmago deltas (incl. milestone M8), and the go-passport-issuer phases (P1–P6)Reference implementation: multipaz.
Relevant specs
mso_mdocformat, DCQL, vp_token encodingeu.europa.ec.av.1,age_over_NNboolean claims only, ES256/P-256, both OID4VCI grant types with PKCE S256, JWT proofs with batch issuance (recommended size 30), single-use attestations ≤ ~3 months, no revocation,av://invocation scheme; presentation primarily via the W3C Digital Credentials API (org-iso-mdoc, HPKE-encrypted responses per RFC 9180), with unsigned-request OpenID4VP (direct_post, client-id schemeredirect_uri) as fallbackScope
irmago (wallet/holder side):
mso_mdoccredentials via OpenID4VCI (pre-authorized + authorization code flows, batch issuance), verified against trust anchors before storage.mso_mdocqueries with aDeviceResponsein a vp_token (direct_postanddirect_post.jwt), selective disclosure,deviceSignaturedevice auth.redirect_uriclient-id scheme, MSO timestamp-precision truncation,av://scheme handling, ETSI TS 119 612 trusted-list support.go-passport-issuer (AV Attestation Provider, sub-issues P1–P6):
eu.europa.ec.av.1proof-of-age mdocs (onlyage_over_NNclaims) from ICAO 9303-validated documents, reusing irmago's mdoc building blocks.av://credential offers.Out of scope (for now):
deviceMacdevice auth, proximity flows (BLE/NFC device engagement, session encryption)Key design decisions
fxamacker/cbor/v2andveraison/go-cose;COSE_Key(and laterCOSE_Mac0) implemented in-repo on top of cbor/v2.eudi/credentials/mdoc/, sibling ofsdjwtvc/.DcqlCredentialQueryHandler.PrepareDisclosureto take aDisclosureContext— the only cross-format interface change required.eudi/storage/db/models/credentials.go.Milestones
Each milestone is independently mergeable, fully covered by automated tests, and must not regress existing SD-JWT VC / idemix flows. See sub-issues (irmago M1–M8, go-passport-issuer P1–P6).
Risks / open questions
deviceKeyInfo— confirm early during interop.testdata/eudi-pid-issuer-py/; budget for this in M5.