Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,26 @@ 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

````
Expand Down
14 changes: 8 additions & 6 deletions pymdoccbor/mso/verifier.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import cbor2
import cryptography
import hashlib
import logging
from datetime import datetime, timezone

from pycose.keys import CoseKey, EC2Key
from pycose.messages import Sign1Message
Expand All @@ -11,6 +13,11 @@
MsoX509ChainNotFound,
UnsupportedMsoDataFormat
)

from cryptography import x509
from cryptography.hazmat.primitives import hashes
from cryptography.exceptions import InvalidSignature

from pymdoccbor import settings
from pymdoccbor.tools import bytes2CoseSign1, cborlist2CoseSign1

Expand Down Expand Up @@ -132,9 +139,7 @@ def attest_public_key(self, trusted_root_certs: list = None):
return None

# Verify certificate chain
from cryptography import x509
from cryptography.hazmat.primitives import hashes
from cryptography.exceptions import InvalidSignature


# Load DS certificate (first in chain)
ds_cert = self.x509_certificates[0] if self.x509_certificates else None
Expand Down Expand Up @@ -164,7 +169,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:
Expand Down Expand Up @@ -225,8 +229,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', {})

Expand Down
4 changes: 2 additions & 2 deletions pymdoccbor/tests/test_09_errors_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
an 'errors' field describing which elements were not available.
"""

import cbor2

from pymdoccbor.mdoc.verifier import MobileDocument
from pymdoccbor.mdoc.issuer import MdocCborIssuer
from pymdoccbor.tests.micov_data import MICOV_DATA
Expand Down Expand Up @@ -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'):
Expand Down Expand Up @@ -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
Expand Down