blob: 34d0d7d353882f145597da54d81da680e7ba08d7 [file] [log] [blame]
Michael Johnson0a0f9b32019-01-02 16:58:21 -08001# Copyright 2018 Rackspace US Inc. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15import datetime
16
17from cryptography.hazmat.backends import default_backend
18from cryptography.hazmat.primitives.asymmetric import rsa
19from cryptography.hazmat.primitives import hashes
Gregory Thiemongea66952e2022-07-21 12:21:40 +020020from cryptography.hazmat.primitives.serialization import NoEncryption
21from cryptography.hazmat.primitives.serialization import pkcs12
Michael Johnson0a0f9b32019-01-02 16:58:21 -080022from cryptography import x509
23from cryptography.x509.oid import NameOID
Michael Johnson0a0f9b32019-01-02 16:58:21 -080024
25
26def generate_ca_cert_and_key():
27 """Creates a CA cert and key for testing.
28
29 :returns: The cryptography CA cert and CA key objects.
30 """
31
32 ca_key = rsa.generate_private_key(
33 public_exponent=65537, key_size=2048, backend=default_backend())
34
35 subject = issuer = x509.Name([
36 x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"),
37 x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"Denial"),
38 x509.NameAttribute(NameOID.LOCALITY_NAME, u"Corvallis"),
39 x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"OpenStack"),
40 x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, u"Octavia"),
41 x509.NameAttribute(NameOID.COMMON_NAME, u"ca_cert.example.com"),
42 ])
43
44 ca_cert = x509.CertificateBuilder().subject_name(
45 subject
46 ).issuer_name(
47 issuer
48 ).public_key(
49 ca_key.public_key()
50 ).serial_number(
51 x509.random_serial_number()
52 ).not_valid_before(
53 datetime.datetime.utcnow()
54 ).not_valid_after(
55 datetime.datetime.utcnow() + datetime.timedelta(days=10)
56 ).add_extension(
57 x509.SubjectAlternativeName([x509.DNSName(u"ca_cert.example.com")]),
58 critical=False,
59 ).add_extension(
60 x509.BasicConstraints(ca=True, path_length=None),
61 critical=True,
Michael Johnson63786632019-11-08 23:22:13 -080062 ).add_extension(
63 # KeyUsage(digital_signature, content_commitment, key_encipherment,
64 # data_encipherment, key_agreement, key_cert_sign, crl_sign,
65 # encipher_only, decipher_only)
66 x509.KeyUsage(True, False, False, False, False,
67 True, True, False, False),
68 critical=True,
Michael Johnson0a0f9b32019-01-02 16:58:21 -080069 ).sign(ca_key, hashes.SHA256(), default_backend())
70
71 return ca_cert, ca_key
72
73
74def generate_server_cert_and_key(ca_cert, ca_key, server_uuid):
75 """Creates a server cert and key for testing.
76
77 :param ca_cert: A cryptography CA certificate (x509) object.
78 :param ca_key: A cryptography CA key (x509) object.
79 :param server_uuid: A UUID identifying the server.
80 :returns: The cryptography server cert and key objects.
81 """
82
83 server_key = rsa.generate_private_key(
84 public_exponent=65537, key_size=2048, backend=default_backend())
85
86 subject = x509.Name([
87 x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"),
88 x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"Denial"),
89 x509.NameAttribute(NameOID.LOCALITY_NAME, u"Corvallis"),
90 x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"OpenStack"),
91 x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, u"Octavia"),
92 x509.NameAttribute(NameOID.COMMON_NAME, u"{}.example.com".format(
93 server_uuid)),
94 ])
95
96 server_cert = x509.CertificateBuilder().subject_name(
97 subject
98 ).issuer_name(
99 ca_cert.subject
100 ).public_key(
101 server_key.public_key()
102 ).serial_number(
103 x509.random_serial_number()
104 ).not_valid_before(
105 datetime.datetime.utcnow()
106 ).not_valid_after(
107 datetime.datetime.utcnow() + datetime.timedelta(days=10)
108 ).add_extension(
109 x509.SubjectAlternativeName(
110 [x509.DNSName(u"{}.example.com".format(server_uuid))]),
111 critical=False,
112 ).add_extension(
113 x509.BasicConstraints(ca=False, path_length=None),
114 critical=True,
Michael Johnson63786632019-11-08 23:22:13 -0800115 ).add_extension(
116 # KeyUsage(digital_signature, content_commitment, key_encipherment,
117 # data_encipherment, key_agreement, key_cert_sign, crl_sign,
118 # encipher_only, decipher_only)
119 x509.KeyUsage(True, False, True, False, False,
120 False, False, False, False),
121 critical=True,
Michael Johnson0a0f9b32019-01-02 16:58:21 -0800122 ).sign(ca_key, hashes.SHA256(), default_backend())
123
124 return server_cert, server_key
125
126
Michael Johnson63786632019-11-08 23:22:13 -0800127def generate_client_cert_and_key(ca_cert, ca_key, client_uuid):
128 """Creates a client cert and key for testing.
129
130 :param ca_cert: A cryptography CA certificate (x509) object.
131 :param ca_key: A cryptography CA key (x509) object.
132 :param client_uuid: A UUID identifying the client.
133 :returns: The cryptography server cert and key objects.
134 """
135
136 client_key = rsa.generate_private_key(
137 public_exponent=65537, key_size=2048, backend=default_backend())
138
139 subject = x509.Name([
140 x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"),
141 x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"Denial"),
142 x509.NameAttribute(NameOID.LOCALITY_NAME, u"Corvallis"),
143 x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"OpenStack"),
144 x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, u"Octavia"),
145 x509.NameAttribute(NameOID.COMMON_NAME, u"{}".format(client_uuid)),
146 ])
147
148 client_cert = x509.CertificateBuilder().subject_name(
149 subject
150 ).issuer_name(
151 ca_cert.subject
152 ).public_key(
153 client_key.public_key()
154 ).serial_number(
155 x509.random_serial_number()
156 ).not_valid_before(
157 datetime.datetime.utcnow()
158 ).not_valid_after(
159 datetime.datetime.utcnow() + datetime.timedelta(days=10)
160 ).add_extension(
161 x509.BasicConstraints(ca=False, path_length=None),
162 critical=True,
163 ).add_extension(
164 # KeyUsage(digital_signature, content_commitment, key_encipherment,
165 # data_encipherment, key_agreement, key_cert_sign, crl_sign,
166 # encipher_only, decipher_only)
167 x509.KeyUsage(True, True, True, False, False, False,
168 False, False, False),
169 critical=True,
170 ).sign(ca_key, hashes.SHA256(), default_backend())
171
172 return client_cert, client_key
173
174
Michael Johnson0a0f9b32019-01-02 16:58:21 -0800175def generate_pkcs12_bundle(server_cert, server_key):
176 """Creates a pkcs12 formated bundle.
177
Michael Johnson0a0f9b32019-01-02 16:58:21 -0800178 :param server_cert: A cryptography certificate (x509) object.
179 :param server_key: A cryptography key (x509) object.
180 :returns: A pkcs12 bundle.
181 """
Takashi Kajinami25872b32023-11-06 22:03:14 +0900182 p12 = pkcs12.serialize_key_and_certificates(
183 b'', server_key, server_cert,
184 cas=None, encryption_algorithm=NoEncryption())
Gregory Thiemongea66952e2022-07-21 12:21:40 +0200185 return p12
Michael Johnson63786632019-11-08 23:22:13 -0800186
187
188def generate_certificate_revocation_list(ca_cert, ca_key, cert_to_revoke):
189 """Create a certificate revocation list with a revoked certificate.
190
191 :param ca_cert: A cryptography CA certificate (x509) object.
192 :param ca_key: A cryptography CA key (x509) object.
193 :param cert_to_revoke: A cryptography CA certificate (x509) object.
194 :returns: A signed certificate revocation list.
195 """
196 crl_builder = x509.CertificateRevocationListBuilder()
197 crl_builder = crl_builder.issuer_name(ca_cert.subject)
Gregory Thiemongee474c3e2019-12-10 19:24:10 +0100198 crl_builder = crl_builder.last_update(datetime.datetime.utcnow())
199 crl_builder = crl_builder.next_update(datetime.datetime.utcnow() +
Michael Johnson63786632019-11-08 23:22:13 -0800200 datetime.timedelta(1, 0, 0))
201
202 revoked_cert = x509.RevokedCertificateBuilder().serial_number(
203 cert_to_revoke.serial_number
204 ).revocation_date(
Gregory Thiemongee474c3e2019-12-10 19:24:10 +0100205 datetime.datetime.utcnow()
Michael Johnson63786632019-11-08 23:22:13 -0800206 ).build(default_backend())
207
208 crl_builder = crl_builder.add_revoked_certificate(revoked_cert)
209 return crl_builder.sign(private_key=ca_key, algorithm=hashes.SHA256(),
210 backend=default_backend())