1 | """Utilities for generating TLS certificates.""" |
---|
2 | |
---|
3 | import datetime |
---|
4 | |
---|
5 | from cryptography import x509 |
---|
6 | from cryptography.x509.oid import NameOID |
---|
7 | from cryptography.hazmat.primitives.asymmetric import rsa |
---|
8 | from cryptography.hazmat.primitives import serialization, hashes |
---|
9 | |
---|
10 | from twisted.python.filepath import FilePath |
---|
11 | |
---|
12 | |
---|
13 | def cert_to_file(path: FilePath, cert) -> FilePath: |
---|
14 | """ |
---|
15 | Write the given certificate to a file on disk. Returns the path. |
---|
16 | """ |
---|
17 | path.setContent(cert.public_bytes(serialization.Encoding.PEM)) |
---|
18 | return path |
---|
19 | |
---|
20 | |
---|
21 | def private_key_to_file(path: FilePath, private_key) -> FilePath: |
---|
22 | """ |
---|
23 | Write the given key to a file on disk. Returns the path. |
---|
24 | """ |
---|
25 | path.setContent( |
---|
26 | private_key.private_bytes( |
---|
27 | encoding=serialization.Encoding.PEM, |
---|
28 | format=serialization.PrivateFormat.TraditionalOpenSSL, |
---|
29 | encryption_algorithm=serialization.NoEncryption(), |
---|
30 | ) |
---|
31 | ) |
---|
32 | return path |
---|
33 | |
---|
34 | |
---|
35 | def generate_private_key(): |
---|
36 | """Create a RSA private key.""" |
---|
37 | return rsa.generate_private_key(public_exponent=65537, key_size=2048) |
---|
38 | |
---|
39 | |
---|
40 | def generate_certificate( |
---|
41 | private_key, |
---|
42 | expires_days: int = 10, |
---|
43 | valid_in_days: int = 0, |
---|
44 | org_name: str = "Yoyodyne", |
---|
45 | ): |
---|
46 | """Generate a certificate from a RSA private key.""" |
---|
47 | subject = issuer = x509.Name( |
---|
48 | [x509.NameAttribute(NameOID.ORGANIZATION_NAME, org_name)] |
---|
49 | ) |
---|
50 | starts = datetime.datetime.utcnow() + datetime.timedelta(days=valid_in_days) |
---|
51 | expires = datetime.datetime.utcnow() + datetime.timedelta(days=expires_days) |
---|
52 | return ( |
---|
53 | x509.CertificateBuilder() |
---|
54 | .subject_name(subject) |
---|
55 | .issuer_name(issuer) |
---|
56 | .public_key(private_key.public_key()) |
---|
57 | .serial_number(x509.random_serial_number()) |
---|
58 | .not_valid_before(min(starts, expires)) |
---|
59 | .not_valid_after(expires) |
---|
60 | .add_extension( |
---|
61 | x509.SubjectAlternativeName([x509.DNSName("localhost")]), |
---|
62 | critical=False, |
---|
63 | # Sign our certificate with our private key |
---|
64 | ) |
---|
65 | .sign(private_key, hashes.SHA256()) |
---|
66 | ) |
---|