| #!/usr/bin/env python3 |
| import datetime |
| import ipaddress |
| import os |
| |
| from cryptography import x509 |
| from cryptography.hazmat.primitives import hashes, serialization |
| from cryptography.hazmat.primitives.asymmetric import rsa |
| from cryptography.x509.oid import NameOID |
| |
| # All state is placed in this directory |
| STATE_DIR = os.environ.get("STATE_DIR", "./state") |
| HYPERCORN_SECRETS_DIR = os.path.join(STATE_DIR, "hypercorn", "secrets") |
| CERT_PATH = os.path.join(HYPERCORN_SECRETS_DIR, "cert.pem") |
| KEY_PATH = os.path.join(HYPERCORN_SECRETS_DIR, "key.pem") |
| |
| |
| def generate_self_signed_cert() -> None: |
| # Ensure that the Hypercorn secrets directory exists |
| os.makedirs(HYPERCORN_SECRETS_DIR, exist_ok=True) |
| |
| # Generate a private RSA key |
| key = rsa.generate_private_key( |
| public_exponent=65537, |
| key_size=2048, |
| ) |
| |
| subject = issuer = x509.Name( |
| [ |
| x509.NameAttribute(NameOID.COMMON_NAME, "127.0.0.1"), |
| ] |
| ) |
| |
| # Use timezone-aware datetime objects for UTC |
| now = datetime.datetime.now(datetime.UTC) |
| |
| # Build a certificate with a SAN for 127.0.0.1 |
| cert = ( |
| x509.CertificateBuilder() |
| .subject_name(subject) |
| .issuer_name(issuer) |
| .public_key(key.public_key()) |
| .serial_number(x509.random_serial_number()) |
| .not_valid_before(now - datetime.timedelta(minutes=1)) |
| .not_valid_after(now + datetime.timedelta(days=365)) |
| .add_extension( |
| x509.SubjectAlternativeName([x509.IPAddress(ipaddress.IPv4Address("127.0.0.1"))]), |
| critical=False, |
| ) |
| .sign(key, hashes.SHA256()) |
| ) |
| |
| # Write out the private key with 400 permissions |
| os.umask(0o277) |
| with open(KEY_PATH, "wb") as f: |
| f.write( |
| key.private_bytes( |
| encoding=serialization.Encoding.PEM, |
| format=serialization.PrivateFormat.TraditionalOpenSSL, |
| encryption_algorithm=serialization.NoEncryption(), |
| ) |
| ) |
| |
| # Write out the certificate |
| with open(CERT_PATH, "wb") as f: |
| f.write(cert.public_bytes(serialization.Encoding.PEM)) |
| |
| # codeql[py/clear-text-logging-sensitive-data] |
| print(f"Certificate generated:\n Cert: {CERT_PATH}\n Key: {KEY_PATH}") |
| |
| |
| if __name__ == "__main__": |
| generate_self_signed_cert() |