From 8407c761735f70359b835032a8ed4681db80bfa4 Mon Sep 17 00:00:00 2001 From: Alex Guinman Date: Sat, 17 Aug 2024 09:35:39 +1000 Subject: [PATCH] Fix MICA creation --- sep2tools/cert_create.py | 48 ++++++++++++++++++++++++---------------- sep2tools/cli.py | 12 ++++++---- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/sep2tools/cert_create.py b/sep2tools/cert_create.py index 247e7c2..ca62210 100644 --- a/sep2tools/cert_create.py +++ b/sep2tools/cert_create.py @@ -200,29 +200,30 @@ def generate_serca( def generate_mica( + csr_path: Path, ca_cert_path: Path, ca_key_path: Path, - key_file: Path, cert_file: Path | None = None, org_name: str = "Example Org Name", country_name: str = "AU", + common_name: str = "IEEE 2030.5 MICA", policy_oids: list[ObjectIdentifier] = DEFAULT_MICA_POLICIES, ) -> tuple[Path, Path]: """Use a CSR and MICA key pair to generate a SEP2 Certificate""" + with open(csr_path, "rb") as fh: + csr_data = fh.read() + csr = x509.load_pem_x509_csr(csr_data) + if not cert_file: - output_dir = key_file.parent + output_dir = csr_path.parent output_dir.mkdir(exist_ok=True) - if key_file.suffix == "pem": - cert_name = f"{key_file.stem}-mica.pem" + if csr_path.suffix == "pem": + cert_name = f"{csr_path.stem}-mica.pem" else: - cert_name = f"{key_file.stem}.pem" + cert_name = f"{csr_path.stem}.pem" cert_file = output_dir / cert_name - with open(key_file, "rb") as fh: - pem_data = fh.read() - key = serialization.load_pem_private_key(pem_data, password=None) - # Load certificate authority with open(ca_cert_path, "rb") as fh: ca_pem_data = fh.read() @@ -234,20 +235,20 @@ def generate_mica( valid_from = datetime.now(tz=tz.UTC) valid_to = INDEF_EXPIRY # as per standard - policies = [x509.PolicyInformation(ANY_POLICY_OID, None)] + policies = [x509.PolicyInformation(oid, None) for oid in policy_oids] # Define the Subject Name subject = x509.Name( [ x509.NameAttribute(NameOID.COUNTRY_NAME, country_name), x509.NameAttribute(NameOID.ORGANIZATION_NAME, org_name), - x509.NameAttribute(NameOID.COMMON_NAME, "IEEE 2030.5 MICA"), + x509.NameAttribute(NameOID.COMMON_NAME, common_name), x509.NameAttribute(NameOID.SERIAL_NUMBER, "1"), ] ) # Generate a Subject Key Identifier (SKI) - ski = key.public_key().public_bytes( + ski = csr.public_key().public_bytes( encoding=serialization.Encoding.DER, format=serialization.PublicFormat.SubjectPublicKeyInfo, ) @@ -256,11 +257,14 @@ def generate_mica( ski_digest.update(ski) ski_value = ski_digest.finalize() + issuer_name = ca_cert.subject + iname = x509.Name(issuer_name) + cert = ( x509.CertificateBuilder() .subject_name(subject) - .issuer_name(subject) - .public_key(key.public_key()) + .issuer_name(iname) + .public_key(csr.public_key()) .serial_number(x509.random_serial_number()) .not_valid_before(valid_from) .not_valid_after(valid_to) @@ -321,7 +325,7 @@ def generate_device_certificate( cert_file: Path | None = None, policy_oids: list[ObjectIdentifier] = DEFAULT_DEV_POLICIES, valid_to: datetime | None = None, - subject_name: str = "", + common_name: str = "", ) -> Path: """Use a CSR and Signing Certificate key pair to generate a SEP2 Certificate""" @@ -359,16 +363,22 @@ def generate_device_certificate( encoder.leave() hw_module_name = encoder.output() - # SubjectName should be blank - if subject_name: + # Define the Subject Name + if common_name: log.warning("Specifying a SubjectName is a deviation from SEP2") - sname = x509.Name(subject_name) + subject = x509.Name( + [ + x509.NameAttribute(NameOID.COMMON_NAME, common_name), + ] + ) + else: + subject = x509.Name("") issuer_name = ca_cert.subject iname = x509.Name(issuer_name) cert = ( x509.CertificateBuilder() - .subject_name(sname) + .subject_name(subject) .issuer_name(iname) .public_key(csr.public_key()) .serial_number(x509.random_serial_number()) diff --git a/sep2tools/cli.py b/sep2tools/cli.py index 769e4bf..42aba09 100644 --- a/sep2tools/cli.py +++ b/sep2tools/cli.py @@ -60,14 +60,18 @@ def create_key(key_file: Optional[Path] = None, verbose: bool = False) -> None: @app.command() -def create_serca(verbose: bool = False, output_dir: Path = DEFAULT_DIR) -> None: +def create_serca( + org_name: str = "Smart Energy", + verbose: bool = False, + output_dir: Path = DEFAULT_DIR, +) -> None: log_level = "DEBUG" if verbose else "INFO" logging.basicConfig(level=log_level, format=LOG_FORMAT) output_dir.mkdir(exist_ok=True) key_file = output_dir / "serca.key" key, csr = generate_key(key_file, generate_csr=False) - generate_serca(key) + generate_serca(key, org_name=org_name) @app.command() @@ -83,8 +87,8 @@ def create_mica( output_dir.mkdir(exist_ok=True) key_file = output_dir / "mica.key" - key, csr = generate_key(key_file, generate_csr=False) - generate_mica(ca_cert, ca_key, key) + key, csr = generate_key(key_file, generate_csr=True) + generate_mica(csr, ca_cert, ca_key, org_name=org_name) @app.command()