1import datetime
2import ipaddress
3
4from cryptography import x509
5from cryptography.hazmat.primitives import hashes, serialization
6from cryptography.hazmat.primitives.asymmetric import ec
7from cryptography.x509.oid import ExtendedKeyUsageOID, NameOID
8
9key = ec.generate_private_key(ec.SECP256R1())
10name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "localhost")])
11now = datetime.datetime.now(datetime.timezone.utc) # timezone-aware: naive datetimes are taken as UTC
12
13cert = (
14 x509.CertificateBuilder()
15 .subject_name(name)
16 .issuer_name(name) # self-signed: issuer = subject
17 .public_key(key.public_key())
18 .serial_number(x509.random_serial_number())
19 .not_valid_before(now)
20 .not_valid_after(now + datetime.timedelta(days=365))
21 .add_extension(x509.SubjectAlternativeName([
22 x509.DNSName("localhost"),
23 x509.IPAddress(ipaddress.ip_address("127.0.0.1")),
24 ]), critical=False)
25 .add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=True)
26 .add_extension(x509.KeyUsage(
27 digital_signature=True, content_commitment=False, key_encipherment=False, data_encipherment=False,
28 key_agreement=False, key_cert_sign=False, crl_sign=False, encipher_only=False, decipher_only=False,
29 ), critical=True)
30 .add_extension(x509.ExtendedKeyUsage([ExtendedKeyUsageOID.SERVER_AUTH]), critical=False)
31 .sign(key, hashes.SHA256())
32)
33
34with open("key.pem", "wb") as f:
35 f.write(key.private_bytes(serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, serialization.NoEncryption()))
36with open("cert.pem", "wb") as f:
37 f.write(cert.public_bytes(serialization.Encoding.PEM))