From 15e9f2a56a58dd490bb6079146a57fd85a3b5c1b Mon Sep 17 00:00:00 2001 From: Flavius Bindea Date: Fri, 30 Jan 2026 17:25:02 +0100 Subject: [PATCH 1/2] refactor: move nested imports to top of files and improve docs - Move hashlib and datetime imports to top of mso/verifier.py - Move cbor2 import to top of test_09_errors_field.py - Rename certificate_chain_verification.md to CERTIFICATE-CHAIN-VERIFICATION.md - Add certificate verification section to README with reference to detailed docs --- README.md | 24 +++++++++++++++++++ ...n.md => CERTIFICATE-CHAIN-VERIFICATION.md} | 0 pymdoccbor/mso/verifier.py | 5 ++-- pymdoccbor/tests/test_09_errors_field.py | 4 ++-- 4 files changed, 28 insertions(+), 5 deletions(-) rename docs/{certificate_chain_verification.md => CERTIFICATE-CHAIN-VERIFICATION.md} (100%) diff --git a/README.md b/README.md index 5a6a3ec..1185771 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,30 @@ mdoc.disclosure_map >> ... dictionary containing all the disclosed attributes ... ```` +### Verify with Certificate Chain and Element Hashes + +For production use, verify both the X.509 certificate chain and element hashes: + +````python +from pymdoccbor.mdoc.verifier import MdocCbor +from cryptography import x509 +from cryptography.hazmat.backends import default_backend + +# Load trusted root certificates +with open('iaca_cert.pem', 'rb') as f: + iaca_cert = x509.load_pem_x509_certificate(f.read(), default_backend()) + +mdoc = MdocCbor() +mdoc.loads(device_response_bytes) +is_valid = mdoc.verify(trusted_root_certs=[iaca_cert], verify_hashes=True) +```` + +For complete documentation on certificate chain verification and hash verification, see [docs/CERTIFICATE-CHAIN-VERIFICATION.md](docs/CERTIFICATE-CHAIN-VERIFICATION.md). + +### Verify the Mobile Security Object + +```` + ### Verify the Mobile Security Object ```` diff --git a/docs/certificate_chain_verification.md b/docs/CERTIFICATE-CHAIN-VERIFICATION.md similarity index 100% rename from docs/certificate_chain_verification.md rename to docs/CERTIFICATE-CHAIN-VERIFICATION.md diff --git a/pymdoccbor/mso/verifier.py b/pymdoccbor/mso/verifier.py index d3ce90e..8fb4f7c 100644 --- a/pymdoccbor/mso/verifier.py +++ b/pymdoccbor/mso/verifier.py @@ -1,4 +1,6 @@ +import hashlib import logging +from datetime import datetime, timezone from typing import Union import cbor2 @@ -156,7 +158,6 @@ def attest_public_key(self, trusted_root_certs: list = None): raise ValueError("DS certificate not signed by any trusted root") # Verify certificate validity dates - from datetime import datetime, timezone now = datetime.now(timezone.utc) if ds_cert.not_valid_before_utc > now: @@ -221,8 +222,6 @@ def verify_element_hashes(self, namespaces: dict) -> dict: Returns: dict: Results with 'valid' (bool), 'total' (int), 'verified' (int), 'failed' (list) """ - import hashlib - mso_data = self.payload_as_dict value_digests = mso_data.get('valueDigests', {}) diff --git a/pymdoccbor/tests/test_09_errors_field.py b/pymdoccbor/tests/test_09_errors_field.py index 8d35bfe..e906ab6 100644 --- a/pymdoccbor/tests/test_09_errors_field.py +++ b/pymdoccbor/tests/test_09_errors_field.py @@ -5,6 +5,8 @@ an 'errors' field describing which elements were not available. """ +import cbor2 + from pymdoccbor.mdoc.issuer import MdocCborIssuer from pymdoccbor.mdoc.verifier import MobileDocument from pymdoccbor.tests.cert_data import CERT_DATA @@ -103,7 +105,6 @@ def test_mobile_document_dump_with_errors(): assert isinstance(dump, bytes) # Decode and verify errors field is present - import cbor2 decoded = cbor2.loads(dump) # The dump is wrapped in a CBORTag, so we need to access .value if hasattr(decoded, 'value'): @@ -138,7 +139,6 @@ def test_mobile_document_dump_without_errors(): assert isinstance(dump, bytes) # Decode and verify errors field is NOT present - import cbor2 decoded = cbor2.loads(dump) if hasattr(decoded, 'value'): decoded = decoded.value From b2ef8a86bf5be249b7c6e1437d5bb866a2a85c17 Mon Sep 17 00:00:00 2001 From: Flavius Bindea Date: Fri, 30 Jan 2026 17:52:17 +0100 Subject: [PATCH 2/2] docs: fix certificate verification example in README - Add skip comment to prevent CI failures - Use generic cert filename --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1185771..bb586ce 100644 --- a/README.md +++ b/README.md @@ -194,12 +194,13 @@ mdoc.disclosure_map For production use, verify both the X.509 certificate chain and element hashes: ````python +# skip in doc examples (requires your_ca_cert.pem and device_response_bytes) from pymdoccbor.mdoc.verifier import MdocCbor from cryptography import x509 from cryptography.hazmat.backends import default_backend # Load trusted root certificates -with open('iaca_cert.pem', 'rb') as f: +with open('your_ca_cert.pem', 'rb') as f: iaca_cert = x509.load_pem_x509_certificate(f.read(), default_backend()) mdoc = MdocCbor() @@ -211,10 +212,6 @@ For complete documentation on certificate chain verification and hash verificati ### Verify the Mobile Security Object -```` - -### Verify the Mobile Security Object - ```` from pymdoccbor.mso.verifier import MsoVerifier