blob: f99ce88ee8fcd9482812855939dbe0d51257d756 [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
20from cryptography import x509
21from cryptography.x509.oid import NameOID
22import OpenSSL
23
24
25def generate_ca_cert_and_key():
26 """Creates a CA cert and key for testing.
27
28 :returns: The cryptography CA cert and CA key objects.
29 """
30
31 ca_key = rsa.generate_private_key(
32 public_exponent=65537, key_size=2048, backend=default_backend())
33
34 subject = issuer = x509.Name([
35 x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"),
36 x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"Denial"),
37 x509.NameAttribute(NameOID.LOCALITY_NAME, u"Corvallis"),
38 x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"OpenStack"),
39 x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, u"Octavia"),
40 x509.NameAttribute(NameOID.COMMON_NAME, u"ca_cert.example.com"),
41 ])
42
43 ca_cert = x509.CertificateBuilder().subject_name(
44 subject
45 ).issuer_name(
46 issuer
47 ).public_key(
48 ca_key.public_key()
49 ).serial_number(
50 x509.random_serial_number()
51 ).not_valid_before(
52 datetime.datetime.utcnow()
53 ).not_valid_after(
54 datetime.datetime.utcnow() + datetime.timedelta(days=10)
55 ).add_extension(
56 x509.SubjectAlternativeName([x509.DNSName(u"ca_cert.example.com")]),
57 critical=False,
58 ).add_extension(
59 x509.BasicConstraints(ca=True, path_length=None),
60 critical=True,
Michael Johnson63786632019-11-08 23:22:13 -080061 ).add_extension(
62 # KeyUsage(digital_signature, content_commitment, key_encipherment,
63 # data_encipherment, key_agreement, key_cert_sign, crl_sign,
64 # encipher_only, decipher_only)
65 x509.KeyUsage(True, False, False, False, False,
66 True, True, False, False),
67 critical=True,
Michael Johnson0a0f9b32019-01-02 16:58:21 -080068 ).sign(ca_key, hashes.SHA256(), default_backend())
69
70 return ca_cert, ca_key
71
72
73def generate_server_cert_and_key(ca_cert, ca_key, server_uuid):
74 """Creates a server cert and key for testing.
75
76 :param ca_cert: A cryptography CA certificate (x509) object.
77 :param ca_key: A cryptography CA key (x509) object.
78 :param server_uuid: A UUID identifying the server.
79 :returns: The cryptography server cert and key objects.
80 """
81
82 server_key = rsa.generate_private_key(
83 public_exponent=65537, key_size=2048, backend=default_backend())
84
85 subject = x509.Name([
86 x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"),
87 x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"Denial"),
88 x509.NameAttribute(NameOID.LOCALITY_NAME, u"Corvallis"),
89 x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"OpenStack"),
90 x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, u"Octavia"),
91 x509.NameAttribute(NameOID.COMMON_NAME, u"{}.example.com".format(
92 server_uuid)),
93 ])
94
95 server_cert = x509.CertificateBuilder().subject_name(
96 subject
97 ).issuer_name(
98 ca_cert.subject
99 ).public_key(
100 server_key.public_key()
101 ).serial_number(
102 x509.random_serial_number()
103 ).not_valid_before(
104 datetime.datetime.utcnow()
105 ).not_valid_after(
106 datetime.datetime.utcnow() + datetime.timedelta(days=10)
107 ).add_extension(
108 x509.SubjectAlternativeName(
109 [x509.DNSName(u"{}.example.com".format(server_uuid))]),
110 critical=False,
111 ).add_extension(
112 x509.BasicConstraints(ca=False, path_length=None),
113 critical=True,
Michael Johnson63786632019-11-08 23:22:13 -0800114 ).add_extension(
115 # KeyUsage(digital_signature, content_commitment, key_encipherment,
116 # data_encipherment, key_agreement, key_cert_sign, crl_sign,
117 # encipher_only, decipher_only)
118 x509.KeyUsage(True, False, True, False, False,
119 False, False, False, False),
120 critical=True,
Michael Johnson0a0f9b32019-01-02 16:58:21 -0800121 ).sign(ca_key, hashes.SHA256(), default_backend())
122
123 return server_cert, server_key
124
125
Michael Johnson63786632019-11-08 23:22:13 -0800126def generate_client_cert_and_key(ca_cert, ca_key, client_uuid):
127 """Creates a client cert and key for testing.
128
129 :param ca_cert: A cryptography CA certificate (x509) object.
130 :param ca_key: A cryptography CA key (x509) object.
131 :param client_uuid: A UUID identifying the client.
132 :returns: The cryptography server cert and key objects.
133 """
134
135 client_key = rsa.generate_private_key(
136 public_exponent=65537, key_size=2048, backend=default_backend())
137
138 subject = x509.Name([
139 x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"),
140 x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"Denial"),
141 x509.NameAttribute(NameOID.LOCALITY_NAME, u"Corvallis"),
142 x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"OpenStack"),
143 x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, u"Octavia"),
144 x509.NameAttribute(NameOID.COMMON_NAME, u"{}".format(client_uuid)),
145 ])
146
147 client_cert = x509.CertificateBuilder().subject_name(
148 subject
149 ).issuer_name(
150 ca_cert.subject
151 ).public_key(
152 client_key.public_key()
153 ).serial_number(
154 x509.random_serial_number()
155 ).not_valid_before(
156 datetime.datetime.utcnow()
157 ).not_valid_after(
158 datetime.datetime.utcnow() + datetime.timedelta(days=10)
159 ).add_extension(
160 x509.BasicConstraints(ca=False, path_length=None),
161 critical=True,
162 ).add_extension(
163 # KeyUsage(digital_signature, content_commitment, key_encipherment,
164 # data_encipherment, key_agreement, key_cert_sign, crl_sign,
165 # encipher_only, decipher_only)
166 x509.KeyUsage(True, True, True, False, False, False,
167 False, False, False),
168 critical=True,
169 ).sign(ca_key, hashes.SHA256(), default_backend())
170
171 return client_cert, client_key
172
173
Michael Johnson0a0f9b32019-01-02 16:58:21 -0800174def generate_pkcs12_bundle(server_cert, server_key):
175 """Creates a pkcs12 formated bundle.
176
177 Note: This uses pyOpenSSL as the cryptography package does not yet
178 support creating pkcs12 bundles. The currently un-released
179 2.5 version of cryptography supports reading pkcs12, but not
180 creation. This method should be updated to only use
181 cryptography once it supports creating pkcs12 bundles.
182
183 :param server_cert: A cryptography certificate (x509) object.
184 :param server_key: A cryptography key (x509) object.
185 :returns: A pkcs12 bundle.
186 """
187 # TODO(johnsom) Replace with cryptography once it supports creating pkcs12
188 pkcs12 = OpenSSL.crypto.PKCS12()
189 pkcs12.set_privatekey(
190 OpenSSL.crypto.PKey.from_cryptography_key(server_key))
191 pkcs12.set_certificate(OpenSSL.crypto.X509.from_cryptography(server_cert))
192 return pkcs12.export()
Michael Johnson63786632019-11-08 23:22:13 -0800193
194
195def generate_certificate_revocation_list(ca_cert, ca_key, cert_to_revoke):
196 """Create a certificate revocation list with a revoked certificate.
197
198 :param ca_cert: A cryptography CA certificate (x509) object.
199 :param ca_key: A cryptography CA key (x509) object.
200 :param cert_to_revoke: A cryptography CA certificate (x509) object.
201 :returns: A signed certificate revocation list.
202 """
203 crl_builder = x509.CertificateRevocationListBuilder()
204 crl_builder = crl_builder.issuer_name(ca_cert.subject)
Gregory Thiemongee474c3e2019-12-10 19:24:10 +0100205 crl_builder = crl_builder.last_update(datetime.datetime.utcnow())
206 crl_builder = crl_builder.next_update(datetime.datetime.utcnow() +
Michael Johnson63786632019-11-08 23:22:13 -0800207 datetime.timedelta(1, 0, 0))
208
209 revoked_cert = x509.RevokedCertificateBuilder().serial_number(
210 cert_to_revoke.serial_number
211 ).revocation_date(
Gregory Thiemongee474c3e2019-12-10 19:24:10 +0100212 datetime.datetime.utcnow()
Michael Johnson63786632019-11-08 23:22:13 -0800213 ).build(default_backend())
214
215 crl_builder = crl_builder.add_revoked_certificate(revoked_cert)
216 return crl_builder.sign(private_key=ca_key, algorithm=hashes.SHA256(),
217 backend=default_backend())