Skip to content

feat(oid4vc): add mDoc credential processor with isomdl-uniffi#11

Merged
burdettadam merged 171 commits intomainfrom
feat/mdoc-support
Mar 12, 2026
Merged

feat(oid4vc): add mDoc credential processor with isomdl-uniffi#11
burdettadam merged 171 commits intomainfrom
feat/mdoc-support

Conversation

@burdettadam
Copy link
Collaborator

Summary

Refactor mso_mdoc to use isomdl-uniffi for crypto operations.

Changes

  • Refactor mso_mdoc to use isomdl-uniffi for crypto operations
  • Add key generation and key management routes
  • Add storage module for keys, certificates, and trust anchors
  • Add comprehensive unit tests for mDoc functionality
  • Add isomdl-uniffi dependency (git reference to main branch)
  • Add Rust toolchain and cache to CI for isomdl-uniffi compilation

Dependencies

@burdettadam burdettadam force-pushed the feat/mdoc-support branch 3 times, most recently from ccbfb41 to 7c1c0fd Compare February 19, 2026 21:08
@burdettadam burdettadam force-pushed the feat/mdoc-support branch 4 times, most recently from cdf34a6 to b287657 Compare February 26, 2026 06:30
- Refactor mso_mdoc to use isomdl-uniffi for crypto operations
- Add key generation and key management routes
- Add storage module for keys, certificates, and trust anchors
- Add comprehensive unit tests for mDoc functionality
- Add isomdl-uniffi dependency (git reference to main branch)
- Add Rust toolchain and cache to CI for isomdl-uniffi compilation

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
- Mock context.inject_or to handle new status_handler code
- Update patch from SDJWTIssuer to sd_jwt_sign after implementation change

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
- Mock profile.session() as proper async context manager
- Use patch decorator for jwt_sign and retrieve_or_create_did_jwk
- Fix indentation of assertions inside with block

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
- Fix error class typos: PresVerifeirError -> PresVerifierError, CredVerifeirError -> CredVerifierError
- Update storage modules to catch general Exception instead of just InjectionError for graceful error handling
- Preserve error messages in credential parsing failures for better debugging
- Update GitHub workflow to install uniffi-bindgen for building isomdl-uniffi
- Update Docker images to include Rust toolchain for building isomdl-uniffi
- Set default ISOMDL_BRANCH to fix/python-build-system in integration tests

All 123 mso_mdoc unit tests now passing ✅

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
…for isomdl-uniffi

Updated all ISOMDL_BRANCH args in docker-compose.yml from 'main' to
'fix/python-build-system' to ensure integration tests use the fixed
build system that works properly in Docker containers.

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Added a new integration-tests job that runs after linting-and-unit-tests
job completes successfully. The integration tests:
- Only run for plugins with an integration/ directory
- Use Docker Compose to run end-to-end tests
- Build and run test-river service for each changed plugin
- Provide detailed logging if tests fail
- Clean up containers after each plugin test

This ensures that both unit tests and integration tests pass before
PRs can be merged.

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
- Add support for credential_identifier parameter (OID4VCI 1.0)
- Enforce mutual exclusivity between credential_identifier and format per § 7.2
- Maintain backward compatibility with draft spec format parameter
- Return clear error messages for invalid request combinations

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
- Add token_endpoint to credential issuer metadata for draft spec clients
- Fix credentials field in offer to use format (vc+sd-jwt) instead of identifier
- Relax JWT proof typ header validation to accept common variants
- Maintain full OID4VCI 1.0 compliance while supporting legacy clients

Accepts typ values: openid4vci-proof+jwt (1.0), JWT, jwt, openid4vci-jwt (draft)

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
- test_oid4vci_10_metadata: verify credential_configuration_ids in metadata
- test_oid4vci_10_credential_request_with_identifier: validate credential_identifier usage
- test_oid4vci_10_mutual_exclusion: enforce field exclusivity per § 7.2
- test_oid4vci_10_proof_of_possession: validate JWT proof handling

All tests verify compliance with OID4VCI 1.0 final specification

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
- Add openid_configuration to public routes exports
- Register /.well-known/openid-configuration route
- Enables OAuth 2.0 Authorization Server discovery per RFC 8414
- Required for OID4VCI 1.0 token endpoint discovery

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
- Register P256 key type for ES256 signature support
- Add comprehensive logging to setup and lifecycle events
- Reorganize credential processor registration
- Move supported_cred_is_unique to utils module for better code organization
- Remove circular dependency between oid4vc and jwt_vc_json

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
- Change Credo agent port to avoid conflicts
- Update all test fixtures and URLs to use new port
- Update docker-compose port mappings
- Ensure consistent port configuration across integration tests

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
- Specify linux/amd64 platform for consistent builds across architectures
- Update base image Dockerfile target and build context
- Use isomdl-uniffi main branch instead of fix/python-build-system
- Improve build reproducibility and cross-platform compatibility

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
- Remove isomdl-uniffi from poetry dependencies (causes build issues)
- Install via platform-specific pre-built wheels from GitHub releases
- Add wheels for macOS (ARM/x86), Linux, and Windows
- Resolves Rust compilation requirements and improves install reliability
- Update lock files to reflect dependency changes

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
- Use lazy % formatting in LOGGER calls per pylint rules
- Fix unused kwargs parameter with underscore prefix
- Replace broad Exception catch with specific TypeError/ValueError
- Ensures CI linting checks pass

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
- Make isomdl_uniffi imports conditional in mdoc issuer and verifier modules
- Add ISOMDL_AVAILABLE flag to check library availability at runtime
- Add IsomdlNotAvailableError for clear error messaging when library is missing
- Remove Rust toolchain and uniffi-bindgen setup from CI workflow
  (The uniffi-bindgen crate name was wrong and isomdl-uniffi wheels aren't
  available on the release yet)
- Tests using isomdl_uniffi will skip gracefully when library is not installed

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
… Rust setup"

This reverts commit 7c0ef5c.

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Replace broken Rust toolchain setup with direct wheel installation from
the isomdl-uniffi GitHub release. The wheel is only installed when oid4vc
plugin is in the changed plugins list.

- Removes rust-toolchain setup (no Cargo.toml in repo)
- Removes uniffi-bindgen cargo install (wrong package name)
- Uses prebuilt manylinux wheel from v0.1.0-test release

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Resolve conflicts:
- nonce.py: keep string-based 'used' field handling from this branch
- __init__.py: include run_migrations() startup call from main
- cred_processor.py: keep full verify_credential/verify_presentation impl
  and add format_data_is_top_level + transform_issuer_metadata from main

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
…ned_b64()

The isomdl-uniffi Dockerfile clones fix/python-build-system which now
expects JSON strings (not CBOR bytes) for namespace element values, and
provides issuer_signed_b64() for ISO 18013-5 §8.3 compliant output.

- Replace cbor2.dumps(v) with json.dumps(v) in all namespace helpers
- Replace _patch_mdoc_keys workaround with mdoc.issuer_signed_b64()
- Remove unused cbor2 and base64 imports

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Trust anchors are now exclusively stored in and retrieved from the Askar
wallet, making the trust registry per-wallet scoped. Sub-wallets maintain
their own trust registry with their own root authority certificates.

- Remove FileTrustStore (filesystem PEM directory) entirely
- Remove OID4VC_MDOC_TRUST_STORE_TYPE env var and create_trust_store()
- verify_credential / verify_presentation always build a fresh
  WalletTrustStore(profile) from the calling profile per-request,
  ensuring each tenant's Askar partition is queried correctly
- Simplify plugin __init__.py / on_startup (no trust store init at startup)
- Update test_pki.py: namespace element values use json.dumps() not cbor2
- Remove TestFileTrustStore unit tests (class no longer exists)
- Rewrite test_wallet_trust_store_per_request.py for always-wallet design
- Remove FileTrustStore import from test_review_issues.py / test_verifier.py

Signed-off-by: Adam Burdett <adam@indicio.tech>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
test10 wheel had stale Python bindings where create_and_sign still
expected bytes. test11 includes regenerated bindings where:
- create_and_sign accepts dict[str, dict[str, str]] (JSON strings)
- issuer_signed_b64() is now available in Python bindings

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
…test11)

Replace the Rust build stage (Stage 1 via git clone + cargo build) with a
direct pip install from a pinned GitHub release wheel URL. Benefits:

- Eliminates Docker layer caching issues (old git clone was cached)
- Removes ~5-minute Rust compilation from Docker build time
- Removes OOM risk on resource-constrained CI runners (CARGO_BUILD_JOBS=2)
- Updating ISOMDL_WHEEL_URL ARG invalidates cache deterministically
- Keeps unit tests and integration tests on identical wheel version

Wheel: isomdl_uniffi-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Release: v0.1.0-test11 (includes create_and_sign str API + issuer_signed_b64)
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Update pyproject.toml and regenerate uv.lock so the test-river container
also installs the wheel with the corrected Python bindings (create_and_sign
accepts JSON strings; issuer_signed_b64 available).

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Bring in the modularization work from feat/mso-mdoc-new (now on main):
- Split verifier.py into cred_verifier.py, pres_verifier.py, trust_store.py,
  mdoc_item.py, mdoc_verify.py
- Extract signing_key.py and payload.py from cred_processor.py
- Move trust anchor routes to trust_anchor_routes.py

Preserve feat/mdoc-support improvements:
- Auto-generate default signing keys on startup (from __init__.py)
- Use pre-built isomdl-uniffi wheel in Dockerfile (no Rust build stage needed)

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
ISO 18013-5 requires portrait, driving_privileges, and
un_distinguishing_sign in all mDL credentials. Add MDL_MANDATORY_FIELDS
constant and spread it into all integration test credential subjects.

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Fix syntax error (missing comma after credential_subject dict) and
re-sort import blocks in test_example_mdoc.py, test_credo_mdoc_interop.py,
and test_interop/test_credo_mdoc.py.

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
…ey setup

Add missing mandatory ISO 18013-5 fields (issue_date, expiry_date, issuing_country,
issuing_authority, document_number) to MDL_MANDATORY_FIELDS constant. These are
required by the OrgIso1801351 Rust struct and were causing MdocInitError.GeneralConstructionError.

Also add setup_issuer_certs fixture to mdoc_offer_did_based, test_mdoc_issuance_did_based,
and test_sphereon_accept_mdoc_credential_offer to ensure signing keys are explicitly
registered before credential issuance tests run.

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Per OID4VP Final spec Section 6.5.6, mso_mdoc DCQL claims use
path: [namespace, claim_name] notation, not namespace/claim_name
key-value pairs. The conformance suite (master branch) validates
this strictly and rejects namespace/claim_name entries as invalid.

Also adds verbose logging for FAILURE/WARNING log entries on failed
modules to aid future debugging.

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Signed-off-by: Adam Burdett <burdettadam@gmail.com>
…tance check)

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
…ockerfile

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Replace the pre-built wheel download with a multi-stage Rust/maturin
build. The new 'isomdl-builder' stage clones the isomdl-uniffi repo at
the branch specified by ISOMDL_BRANCH (default: main) and builds a wheel
with maturin, which is then installed in the ACA-Py base stage.

Integration docker-compose and demo docker-compose already pass
ISOMDL_BRANCH=fix/python-build-system via build args.

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
…heel

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Remove duplicate _retrieve_default_did, _create_default_did, and
retrieve_or_create_did_jwk from public_routes/verification.py.
verification.py and public_routes/__init__.py now import from the
canonical did_utils module.

Signed-off-by: Adam Burdett <burdettadam@gmail.com>
Copy link

@Eldersonar Eldersonar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@burdettadam burdettadam merged commit 545048a into main Mar 12, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants