Skip to content

Generator

provide.foundation.crypto.certificates.generator

TODO: Add module docstring.

Classes

Functions

generate_certificate

generate_certificate(
    common_name: str,
    organization_name: str,
    validity_days: int,
    key_type: str = DEFAULT_CERTIFICATE_KEY_TYPE,
    key_size: int = DEFAULT_RSA_KEY_SIZE,
    ecdsa_curve: str = DEFAULT_CERTIFICATE_CURVE,
    alt_names: list[str] | None = None,
    is_ca: bool = False,
    is_client_cert: bool = False,
) -> tuple[
    CertificateBase, x509.Certificate, KeyPair, str, str
]

Generate a new certificate with a keypair.

Returns:

Type Description
tuple[CertificateBase, Certificate, KeyPair, str, str]

Tuple of (CertificateBase, X509Certificate, private_key, cert_pem, key_pem)

Source code in provide/foundation/crypto/certificates/generator.py
def generate_certificate(
    common_name: str,
    organization_name: str,
    validity_days: int,
    key_type: str = DEFAULT_CERTIFICATE_KEY_TYPE,
    key_size: int = DEFAULT_RSA_KEY_SIZE,
    ecdsa_curve: str = DEFAULT_CERTIFICATE_CURVE,
    alt_names: list[str] | None = None,
    is_ca: bool = False,
    is_client_cert: bool = False,
) -> tuple[
    CertificateBase,
    x509.Certificate,
    KeyPair,
    str,
    str,
]:
    """Generate a new certificate with a keypair.

    Returns:
        Tuple of (CertificateBase, X509Certificate, private_key, cert_pem, key_pem)

    """
    try:
        logger.debug("πŸ“œπŸ”‘πŸš€ Generating new keypair")

        # Calculate validity period
        now = datetime.now(UTC)
        not_valid_before = now - timedelta(days=1)
        not_valid_after = now + timedelta(days=validity_days)

        # Parse and validate key type parameters
        gen_key_type, gen_key_size, gen_curve = _parse_key_type_and_params(key_type, key_size, ecdsa_curve)

        # Build certificate configuration
        conf = _build_certificate_config(
            common_name=common_name,
            organization_name=organization_name,
            not_valid_before=not_valid_before,
            not_valid_after=not_valid_after,
            alt_names=alt_names,
            gen_key_type=gen_key_type,
            gen_key_size=gen_key_size,
            gen_curve=gen_curve,
        )
        logger.debug(f"πŸ“œπŸ”‘πŸš€ Generation config: {conf}")

        # Generate base certificate and private key
        base, private_key = CertificateBase.create(conf)

        # Create X.509 certificate
        x509_cert = create_x509_certificate(
            base=base,
            private_key=private_key,
            alt_names=alt_names or ["localhost"],
            is_ca=is_ca,
            is_client_cert=is_client_cert,
        )

        if x509_cert is None:
            raise CertificateError("Certificate object (_cert) is None after creation")

        # Serialize to PEM format
        cert_pem, key_pem = _serialize_to_pem(x509_cert, private_key)

        return base, x509_cert, private_key, cert_pem, key_pem

    except Exception as e:
        logger.error(
            f"πŸ“œβŒ Failed to generate certificate. Error: {type(e).__name__}: {e}",
            extra={"error": str(e), "trace": traceback.format_exc()},
        )
        raise CertificateError(
            f"Failed to initialize certificate. Original error: {type(e).__name__}: {e}"
        ) from e