1from cryptography import x509
2from cryptography.hazmat.primitives import hashes, serialization
3from cryptography.hazmat.primitives.asymmetric import ec
4from cryptography.x509.oid import NameOID
5
6key = ec.generate_private_key(ec.SECP256R1()) # P-256
7
8csr = (
9 x509.CertificateSigningRequestBuilder()
10 .subject_name(x509.Name([
11 x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),
12 x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Example Corp"),
13 x509.NameAttribute(NameOID.COMMON_NAME, "api.example.com"),
14 ]))
15 # The SAN extension is what browsers and CAs match host names against
16 .add_extension(
17 x509.SubjectAlternativeName([x509.DNSName("api.example.com"), x509.DNSName("www.example.com")]),
18 critical=False,
19 )
20 .sign(key, hashes.SHA256()) # ecdsa-with-SHA256, signed with the request's own key
21)
22
23with open("key.pem", "wb") as f:
24 f.write(key.private_bytes(
25 serialization.Encoding.PEM,
26 serialization.PrivateFormat.PKCS8,
27 serialization.NoEncryption(), # use BestAvailableEncryption(b"…") to protect it
28 ))
29with open("csr.pem", "wb") as f:
30 f.write(csr.public_bytes(serialization.Encoding.PEM))
31
32print("signature valid:", csr.is_signature_valid)