diff --git a/README.md b/README.md index 5a6a3ec..bb586ce 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,27 @@ 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 +# 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('your_ca_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 ```` 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