feat(mso_mdoc): trust anchor registry, signing key registry, and mDOC revocation#30
Merged
burdettadam merged 23 commits intomainfrom Mar 24, 2026
Merged
Conversation
…0 excess admin endpoints, custom storage subsystem, key/trust-anchor mgmt. Align with sd_jwt_vc pattern: 2 admin routes, signing keys in vc_additional_data, trust anchors in vc_additional_data.trust_anchors Signed-off-by: Adam Burdett <burdettadam@gmail.com>
…gn-patterns # Conflicts: # oid4vc/mso_mdoc/key_generation.py # oid4vc/mso_mdoc/key_routes.py # oid4vc/mso_mdoc/storage/__init__.py
… upload - Move cryptography imports to module level in test_credo_mdoc.py and cred_processor.py (PLC0415) - Fix unsorted import block and use datetime.UTC alias in test_credo_mdoc.py (I001, UP017) - Break long lines in cred_verifier.py and pres_verifier.py (E501) - Include required fields (format, id, doctype) in PUT body when uploading trust anchors via setup_acapy.py to fix 422 from MsoMdocSupportedCredCreateReq Signed-off-by: Adam Burdett <burdettadam@gmail.com>
… UP017) Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
- Add MsoMdocSupportedCredUpdateReq with all fields optional so that partial updates (e.g. only trust_anchors, or only signing_key_pem) work without requiring format/id/doctype in the request body. - Rewrite supported_cred_update_helper to merge with existing record values instead of overwriting with None for missing fields. - Switch @request_schema on PUT route to MsoMdocSupportedCredUpdateReq. - Fix test_mdoc_issuer_key_generation to assert private_key_pem and certificate_pem (what the fixture actually returns) instead of the old key_id/verification_method fields that no longer exist. Signed-off-by: Adam Burdett <burdettadam@gmail.com>
…credential configs Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
…mDOC revocation infrastructure
- Add TrustAnchorRecord(BaseRecord) with TAG_NAMES {doctype, purpose} for
multi-tenant-safe X.509 trust anchor storage. Replaces cramming trust
anchors into SupportedCredential.vc_additional_data.
- Add MdocSigningKeyRecord(BaseRecord) with TAG_NAMES {doctype, label} for
multi-tenant-safe signing key storage. private_key_pem is stored in the
encrypted Askar wallet and is load_only in the schema (never via API).
- Add trust_anchor_routes.py with full CRUD:
POST/GET/GET/{id}/DELETE /mso-mdoc/trust-anchors
POST/GET/GET/{id}/DELETE /mso-mdoc/signing-keys
- Update cred_processor._get_trust_anchors() to query TrustAnchorRecord
first, with backward-compat fallback to SupportedCredential.vc_additional_data.
- Update cred_processor._resolve_signing_key() to check MdocSigningKeyRecord
(by signing_key_id or doctype) before falling back to vc_additional_data
and env vars.
- Add _assign_status_entry() for optional mDOC revocation: if the status_list
plugin is installed and status_list_def_id + status_list_base_uri are set on
the SupportedCredential, assigns a Token Status List entry at issuance and
embeds {status: {status_list: {idx, uri}}} in the credential payload.
- Update SupportedCredential route schemas to accept signing_key_id,
status_list_def_id, and status_list_base_uri fields.
- Update integration conftest.py:
- setup_issuer_certs: generates a proper IACA-compliant leaf DS cert
(via _generate_leaf_ds) and uploads via POST /mso-mdoc/signing-keys
with vc_additional_data fallback for older agents.
- setup_verifier_trust_anchors: uses POST /mso-mdoc/trust-anchors with
vc_additional_data fallback.
- setup_all_trust_anchors: yields issuer_key_pem (was missing, causing KeyError).
- setup_pki_chain_trust_anchor: uses POST /mso-mdoc/trust-anchors.
- Add test_trust_registry.py with 12 unit tests covering record creation,
serialisation, save/retrieve, query-by-tag, and delete.
Signed-off-by: Adam Burdett <adam@indicio.tech>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
- check_status_list_claim() in utils.py: IETF Token Status List HTTP fetch + little-endian bit decode; fail-open on network/parse errors - pres_verifier.py: revocation check after issuer signature success - cred_verifier.py: revocation check after issuer signature success - _get_trust_anchors(): fix doctype=None to include ALL anchors (not just wildcard records) - setup_credo_trust_anchors: upload root_ca_pem instead of leaf cert - tests: 15 unit tests for check_status_list_claim; expanded test_trust_registry with 9 processor method tests; fix test isolation by using fresh profiles instead of shared module-scoped profile Signed-off-by: Adam Burdett <burdettadam@gmail.com>
9cb54ed to
e14c0b2
Compare
Resolve modify/delete conflicts by keeping the refactor removal of the old mso_mdoc key-management and storage subsystem. The branch intentionally replaced that architecture, so restoring main's deleted files would reintroduce dead code and broken imports. Verified with: - poetry run pytest mso_mdoc/tests/ -v --no-cov - 97 passed Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
… registry The refactor replaced vc_additional_data trust_anchors with a proper TrustAnchorRecord Askar registry accessible via POST /mso-mdoc/trust-anchors. Update the conformance test helper to POST to the new endpoint instead of patching each SupportedCredential record individually. Signed-off-by: Adam Burdett <burdettadam@gmail.com>
…t_anchors proven-api exclusively uses the /mso-mdoc/trust-anchors registry. No deployment writes trust anchors to SupportedCredential.vc_additional_data. The fallback is dead code — remove it and its covering test. Signed-off-by: Adam Burdett <burdettadam@gmail.com>
…_signing_key proven-api exclusively uses MdocSigningKeyRecord via POST /mso-mdoc/signing-keys. Steps 3 (vc_additional_data signing_key_pem/signing_cert_pem) and 4 (env vars OID4VC_MDOC_SIGNING_KEY_PATH/OID4VC_MDOC_SIGNING_CERT_PATH) are dead code. Remove them and update tests to inject key material via MdocSigningKeyRecord.query. Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Daniel Bluhm <dbluhm@pm.me>
- POST /mso-mdoc/signing-keys now generates EC P-256 key pair server-side
and returns public_key_pem (private key never exposed via API)
- POST /mso-mdoc/signing-keys/import for pre-existing keys tied to
public registries (IACA, etc.)
- PUT /mso-mdoc/signing-keys/{id} to attach certificate and update
metadata, with public key match validation
- Removed dead signing_key_pem/signing_cert_pem from legacy mso_mdoc
routes (never read by _resolve_signing_key)
- Fixed IACA BasicConstraints path_length for direct root->leaf signing
(was 1, should be 0 when no intermediate CA)
- Updated integration test fixtures to use two-step generate+attach flow
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
- POST /mso-mdoc/signing-keys now generates EC P-256 key pair server-side
- POST /mso-mdoc/signing-keys/import for pre-existing keys (IACA registry)
- PUT /mso-mdoc/signing-keys/{id} to attach certificate after generation
- Response includes public_key_pem (derived); private_key_pem never exposed
- Remove dead signing_key_pem/signing_cert_pem from legacy mso-mdoc routes
- Fix IACA path_length for direct root->leaf cert chains in tests
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
All integration tests still referenced signing_key_pem/signing_cert_pem in vc_additional_data and setup_all_trust_anchors, even though these fields were removed from the API. Updated test_credo_mdoc.py to use the /mso-mdoc/signing-keys/import endpoint directly. Signed-off-by: Adam Burdett <burdettadam@gmail.com>
…tests Signed-off-by: Adam Burdett <burdettadam@gmail.com>
mdoc_offer_verification_method depended on mdoc_issuer_key which creates a bare cert not registered as a trust anchor on the ACA-Py verifier. During presentation tests _resolve_signing_key may pick the bare-cert record, causing the verifier to reject the mDoc. Using setup_issuer_certs ensures the signing key is the same one whose root CA is registered on both Credo and the ACA-Py verifier. Signed-off-by: Adam Burdett <burdettadam@gmail.com>
mepeltier
approved these changes
Mar 24, 2026
burdettadam
added a commit
that referenced
this pull request
Mar 25, 2026
- Merged origin/main which includes PR #30 refactor/mso-mdoc-align-patterns - Resolved conflict in oid4vc/mso_mdoc/routes.py: - Removed sign/verify endpoints (deleted upstream with key_generation, key_routes, and storage modules) - Fixed imports to use new trust_anchor_routes.register(app) pattern - Kept OID4VCI 1.0 improvements (credential_definition, credential_metadata, credential_signing_alg_values_supported, RAISE validation) - Fixed variable name mismatch in supported_cred.py to_issuer_metadata() - Fixed test mock return values (hex string for bytes.fromhex compatibility) - All 292 tests passing Signed-off-by: Adam Burdett <burdettadam@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Aligns
mso_mdocwith the established plugin patterns, adds a proper trust anchor and signing key registry backed by the ACA-Py store, and implements end-to-end mDOC credential revocation using the IETF Token Status List.Changes
Trust Anchor & Signing Key Registry
TrustAnchorRecord(BaseRecord) stores IACA/reader-auth root CAs per doctype (or wildcard); CRUD routes at/mso-mdoc/trust-anchorsMdocSigningKeyRecord(BaseRecord) stores issuer private key + certificate per doctype; CRUD routes at/mso-mdoc/signing-keys_get_trust_anchors(profile, doctype=None)queriesTrustAnchorRecordfirst, falls back toSupportedCredential.vc_additional_data_resolve_signing_key(supported, profile)queriesMdocSigningKeyRecordfirst, falls back tovc_additional_datalegacy fieldsmDOC Revocation (IETF Token Status List)
_assign_status_entry()at issuance calls thestatus_listplugin to allocate a slot and embeds{status: {status_list: {idx, uri}}}in the MSO payloadcheck_status_list_claim(claims)at verification: HTTP GET the published status list JWT, base64url-decode + zlib-decompress thelstfield, check little-endian bit at positionidx; fail-open on network/parse errorspres_verifier.py(OID4VP path) andcred_verifier.py(direct verification path)Refactor (original scope)
mso_mdocwithsd_jwt_vcregistration patternstorage/package,key_routes.py,trust_anchor_routes.py,key_generation.py,mdoc/trust_store.py, 11 obsolete test filesBug Fixes
_get_trust_anchors(doctype=None)now returns all trust anchors (previously only returned wildcard records, silently missing doctype-specific ones)setup_credo_trust_anchorsfixture now uploadsroot_ca_peminstead of the leaf DS cert (Credo validates the full chain)Tests
check_status_list_claim(valid, revoked, 2-bit entries, fail-open, edge cases)_get_trust_anchors,_resolve_signing_key,_assign_status_entry)All 97 unit tests pass.