Source code for aoki.management.commands.aoki_gen_test_certs

"""Generates a testing IDevID PKI and associated Owner Certificate PKI for AOKI testing."""

from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING

from cryptography import x509
from cryptography.hazmat.primitives import hashes, serialization
from django.core.management.base import BaseCommand
from pki.util.x509 import CertificateGenerator

if TYPE_CHECKING:
    from typing import Any

    from trustpoint_core.crypto_types import PrivateKey

[docs] TEST_SERIAL_NUMBER = '4212'
[docs] CURRENT_DIR = Path(__file__).parent.resolve()
[docs] CERTS_DIR = (CURRENT_DIR / '../../tests/certs/').resolve()
CERTS_DIR.mkdir(parents=True, exist_ok=True) # ruff: noqa: T201 # use of print is fine in this simple generator script
[docs] class Command(BaseCommand): """Command to check for certificates using insufficient RSA key lengths."""
[docs] help = 'Check certificates with insufficient key lengths.'
[docs] def handle(self, *args: Any, **kwargs: Any) -> None: """Entrypoint for the command. Args: *args: Additional positional arguments. **kwargs: Additional keyword arguments. """ del args, kwargs # Unused idevid_cert = AokiTestCertGenerator.generate_idevid_pki() AokiTestCertGenerator.generate_owner_id_cert(idevid_cert) print('Certificates generated successfully.')
[docs] def write_private_key(key: PrivateKey, file: Path) -> None: """Write the private key to a PEM file.""" with file.open('wb') as key_file: key_file.write( key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption(), ) )
[docs] def write_cert_pem(cert: x509.Certificate, file: Path) -> None: """Write the certificate to a PEM file.""" with file.open('wb') as cert_file: cert_file.write(cert.public_bytes(encoding=serialization.Encoding.PEM))
[docs] class AokiTestCertGenerator: """Generates a testing IDevID PKI and associated Owner Certificate PKI for AOKI testing.""" @staticmethod
[docs] def generate_idevid_pki() -> x509.Certificate: """Generates a testing IDevID PKI.""" # Generate the IDevID test CA root_ca_cert, root_ca_key = CertificateGenerator.create_root_ca( 'IDevID_Test_Root_CA' ) # write the root CA certificate and key to files write_cert_pem(root_ca_cert, CERTS_DIR / 'idevid_ca.pem') write_private_key(root_ca_key, CERTS_DIR / 'idevid_ca_pk.pem') # Generate the IDevID test cert idevid_cert, idevid_key = CertificateGenerator.create_ee( issuer_private_key=root_ca_key, issuer_cn='IDevID_Test_Root_CA', subject_name=x509.Name( [ x509.NameAttribute(x509.NameOID.COMMON_NAME, 'IDevID_Test'), x509.NameAttribute(x509.NameOID.SERIAL_NUMBER, TEST_SERIAL_NUMBER), ] ), private_key=None, extensions=[ (x509.SubjectAlternativeName([x509.UniformResourceIdentifier('test_idevid.alt')]), False), ], validity_days=99999, ) write_cert_pem(idevid_cert, CERTS_DIR / 'idevid.pem') write_private_key(idevid_key, CERTS_DIR / 'idevid_pk.pem') return idevid_cert
@staticmethod
[docs] def generate_owner_id_cert(idevid_cert: x509.Certificate) -> None: """Generate the DeviceOwnerID certificate.""" # It is RECOMMENDED that the same CA is used as for the IDevID cert, # but here a separate CA is used to ascertain they can be different owner_ca_cert, owner_ca_key = CertificateGenerator.create_root_ca( 'Owner_Test_Root_CA' ) write_cert_pem(owner_ca_cert, CERTS_DIR / 'ownerid_ca.pem') write_private_key(owner_ca_key, CERTS_DIR / 'ownerid_ca_pk.pem') idevid_x509_sn = hex(idevid_cert.serial_number)[2:].zfill(16) idevid_sha256_fingerprint = idevid_cert.fingerprint(hashes.SHA256()).hex() # Build URI string "dev-owner:<idevid_subj_sn>.<idevid_x509_sn>.<idevid_sha256_fingerprint>" # If the IDevID Subject Serial Number is not present, '_' shall be used as a placeholder idevid_san_uri = f'dev-owner:{TEST_SERIAL_NUMBER}.{idevid_x509_sn}.{idevid_sha256_fingerprint}' print(f'DeviceOwnerID SAN URI: {idevid_san_uri}') ownerid_cert, ownerid_key = CertificateGenerator.create_ee( issuer_private_key=owner_ca_key, issuer_cn='Owner_Test_Root_CA', subject_name=x509.Name( [ x509.NameAttribute(x509.NameOID.COMMON_NAME, 'DevOwnerID_Test'), x509.NameAttribute(x509.NameOID.PSEUDONYM, 'DevOwnerID'), ] ), private_key=None, extensions=[ (x509.SubjectAlternativeName([ x509.UniformResourceIdentifier(idevid_san_uri) ]), False), # SAN should be critical for an OwnerID cert, # but then the subject name should be empty according to RFC 5280 ], validity_days=99999, ) write_cert_pem(ownerid_cert, CERTS_DIR / 'owner_id.pem') write_private_key(ownerid_key, CERTS_DIR / 'owner_id_pk.pem')