blob: 96311ee6ef4a07377a4d9e6ad1a26fec384f2854 [file] [log] [blame]
Paul Kehrerbfac2d12015-12-19 23:32:08 -06001# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4
5from __future__ import absolute_import, division, print_function
6
7import datetime
8
9import pytest
10
11from cryptography import x509
12from cryptography.hazmat.backends.interfaces import (
13 DSABackend, EllipticCurveBackend, RSABackend, X509Backend
14)
15from cryptography.hazmat.primitives import hashes
16from cryptography.hazmat.primitives.asymmetric import ec
Paul Kehrer426b48d2015-12-24 20:50:43 -060017from cryptography.x509.oid import AuthorityInformationAccessOID, NameOID
Paul Kehrerbfac2d12015-12-19 23:32:08 -060018
19from .hazmat.primitives.fixtures_dsa import DSA_KEY_2048
20from .hazmat.primitives.fixtures_rsa import RSA_KEY_2048, RSA_KEY_512
21from .hazmat.primitives.test_ec import _skip_curve_unsupported
22
23
24class TestCertificateRevocationListBuilder(object):
25 def test_issuer_name_invalid(self):
26 builder = x509.CertificateRevocationListBuilder()
27 with pytest.raises(TypeError):
28 builder.issuer_name("notanx509name")
29
30 def test_set_issuer_name_twice(self):
31 builder = x509.CertificateRevocationListBuilder().issuer_name(
32 x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
33 )
34 with pytest.raises(ValueError):
35 builder.issuer_name(
36 x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
37 )
38
39 def test_last_update_invalid(self):
40 builder = x509.CertificateRevocationListBuilder()
41 with pytest.raises(TypeError):
42 builder.last_update("notadatetime")
43
44 def test_last_update_before_unix_epoch(self):
45 builder = x509.CertificateRevocationListBuilder()
46 with pytest.raises(ValueError):
47 builder.last_update(datetime.datetime(1960, 8, 10))
48
49 def test_set_last_update_twice(self):
50 builder = x509.CertificateRevocationListBuilder().last_update(
51 datetime.datetime(2002, 1, 1, 12, 1)
52 )
53 with pytest.raises(ValueError):
54 builder.last_update(datetime.datetime(2002, 1, 1, 12, 1))
55
56 def test_next_update_invalid(self):
57 builder = x509.CertificateRevocationListBuilder()
58 with pytest.raises(TypeError):
59 builder.next_update("notadatetime")
60
61 def test_next_update_before_unix_epoch(self):
62 builder = x509.CertificateRevocationListBuilder()
63 with pytest.raises(ValueError):
64 builder.next_update(datetime.datetime(1960, 8, 10))
65
66 def test_set_next_update_twice(self):
67 builder = x509.CertificateRevocationListBuilder().next_update(
68 datetime.datetime(2002, 1, 1, 12, 1)
69 )
70 with pytest.raises(ValueError):
71 builder.next_update(datetime.datetime(2002, 1, 1, 12, 1))
72
73 def test_last_update_after_next_update(self):
74 builder = x509.CertificateRevocationListBuilder()
75
76 builder = builder.next_update(
77 datetime.datetime(2002, 1, 1, 12, 1)
78 )
79 with pytest.raises(ValueError):
80 builder.last_update(datetime.datetime(2003, 1, 1, 12, 1))
81
82 def test_next_update_after_last_update(self):
83 builder = x509.CertificateRevocationListBuilder()
84
85 builder = builder.last_update(
86 datetime.datetime(2002, 1, 1, 12, 1)
87 )
88 with pytest.raises(ValueError):
89 builder.next_update(datetime.datetime(2001, 1, 1, 12, 1))
90
Paul Kehrer426b48d2015-12-24 20:50:43 -060091 def test_add_extension_checks_for_duplicates(self):
92 builder = x509.CertificateRevocationListBuilder().add_extension(
93 x509.CRLNumber(1), False
94 )
95
96 with pytest.raises(ValueError):
97 builder.add_extension(x509.CRLNumber(2), False)
98
Paul Kehrerd8359692015-12-24 22:48:38 -060099 def test_add_invalid_extension(self):
100 builder = x509.CertificateRevocationListBuilder()
101
102 with pytest.raises(TypeError):
103 builder.add_extension(
104 object(), False
105 )
106
Paul Kehrer4c7fd5f2015-12-25 13:40:55 -0600107 def test_add_invalid_revoked_certificate(self):
108 builder = x509.CertificateRevocationListBuilder()
109
110 with pytest.raises(TypeError):
111 builder.add_revoked_certificate(object())
112
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600113 @pytest.mark.requires_backend_interface(interface=RSABackend)
114 @pytest.mark.requires_backend_interface(interface=X509Backend)
115 def test_no_issuer_name(self, backend):
116 private_key = RSA_KEY_2048.private_key(backend)
117 builder = x509.CertificateRevocationListBuilder().last_update(
118 datetime.datetime(2002, 1, 1, 12, 1)
119 ).next_update(
120 datetime.datetime(2030, 1, 1, 12, 1)
121 )
122
123 with pytest.raises(ValueError):
124 builder.sign(private_key, hashes.SHA256(), backend)
125
126 @pytest.mark.requires_backend_interface(interface=RSABackend)
127 @pytest.mark.requires_backend_interface(interface=X509Backend)
128 def test_no_last_update(self, backend):
129 private_key = RSA_KEY_2048.private_key(backend)
130 builder = x509.CertificateRevocationListBuilder().issuer_name(
131 x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
132 ).next_update(
133 datetime.datetime(2030, 1, 1, 12, 1)
134 )
135
136 with pytest.raises(ValueError):
137 builder.sign(private_key, hashes.SHA256(), backend)
138
139 @pytest.mark.requires_backend_interface(interface=RSABackend)
140 @pytest.mark.requires_backend_interface(interface=X509Backend)
141 def test_no_next_update(self, backend):
142 private_key = RSA_KEY_2048.private_key(backend)
143 builder = x509.CertificateRevocationListBuilder().issuer_name(
144 x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
145 ).last_update(
146 datetime.datetime(2030, 1, 1, 12, 1)
147 )
148
149 with pytest.raises(ValueError):
150 builder.sign(private_key, hashes.SHA256(), backend)
151
152 @pytest.mark.requires_backend_interface(interface=RSABackend)
153 @pytest.mark.requires_backend_interface(interface=X509Backend)
154 def test_sign_empty_list(self, backend):
155 private_key = RSA_KEY_2048.private_key(backend)
156 last_update = datetime.datetime(2002, 1, 1, 12, 1)
157 next_update = datetime.datetime(2030, 1, 1, 12, 1)
158 builder = x509.CertificateRevocationListBuilder().issuer_name(
159 x509.Name([
160 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
161 ])
162 ).last_update(last_update).next_update(next_update)
163
164 crl = builder.sign(private_key, hashes.SHA256(), backend)
165 assert len(crl) == 0
166 assert crl.last_update == last_update
167 assert crl.next_update == next_update
168
Paul Kehrer426b48d2015-12-24 20:50:43 -0600169 @pytest.mark.parametrize(
170 "extension",
171 [
172 x509.CRLNumber(13),
173 x509.AuthorityKeyIdentifier(
174 b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08"
175 b"\xcbY",
176 None,
177 None
178 ),
179 x509.AuthorityInformationAccess([
180 x509.AccessDescription(
181 AuthorityInformationAccessOID.CA_ISSUERS,
182 x509.DNSName(u"cryptography.io")
183 )
184 ]),
185 x509.IssuerAlternativeName([
186 x509.UniformResourceIdentifier(u"https://cryptography.io"),
187 ])
188 ]
189 )
190 @pytest.mark.requires_backend_interface(interface=RSABackend)
191 @pytest.mark.requires_backend_interface(interface=X509Backend)
192 def test_sign_extensions(self, backend, extension):
193 private_key = RSA_KEY_2048.private_key(backend)
194 last_update = datetime.datetime(2002, 1, 1, 12, 1)
195 next_update = datetime.datetime(2030, 1, 1, 12, 1)
196 builder = x509.CertificateRevocationListBuilder().issuer_name(
197 x509.Name([
198 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
199 ])
200 ).last_update(
201 last_update
202 ).next_update(
203 next_update
204 ).add_extension(
205 extension, False
206 )
207
208 crl = builder.sign(private_key, hashes.SHA256(), backend)
209 assert len(crl) == 0
210 assert len(crl.extensions) == 1
Paul Kehrerbbc1ba92015-12-25 10:05:46 -0600211 ext = crl.extensions.get_extension_for_class(type(extension))
Paul Kehrer426b48d2015-12-24 20:50:43 -0600212 assert ext.critical is False
213 assert ext.value == extension
214
215 @pytest.mark.requires_backend_interface(interface=RSABackend)
216 @pytest.mark.requires_backend_interface(interface=X509Backend)
217 def test_sign_multiple_extensions_critical(self, backend):
218 private_key = RSA_KEY_2048.private_key(backend)
219 last_update = datetime.datetime(2002, 1, 1, 12, 1)
220 next_update = datetime.datetime(2030, 1, 1, 12, 1)
221 ian = x509.IssuerAlternativeName([
222 x509.UniformResourceIdentifier(u"https://cryptography.io"),
223 ])
224 crl_number = x509.CRLNumber(13)
225 builder = x509.CertificateRevocationListBuilder().issuer_name(
226 x509.Name([
227 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
228 ])
229 ).last_update(
230 last_update
231 ).next_update(
232 next_update
233 ).add_extension(
234 crl_number, False
235 ).add_extension(
236 ian, True
237 )
238
239 crl = builder.sign(private_key, hashes.SHA256(), backend)
240 assert len(crl) == 0
241 assert len(crl.extensions) == 2
242 ext1 = crl.extensions.get_extension_for_class(x509.CRLNumber)
243 assert ext1.critical is False
244 assert ext1.value == crl_number
245 ext2 = crl.extensions.get_extension_for_class(
246 x509.IssuerAlternativeName
247 )
248 assert ext2.critical is True
249 assert ext2.value == ian
250
251 @pytest.mark.requires_backend_interface(interface=RSABackend)
252 @pytest.mark.requires_backend_interface(interface=X509Backend)
253 def test_add_unsupported_extension(self, backend):
254 private_key = RSA_KEY_2048.private_key(backend)
255 last_update = datetime.datetime(2002, 1, 1, 12, 1)
256 next_update = datetime.datetime(2030, 1, 1, 12, 1)
257 builder = x509.CertificateRevocationListBuilder().issuer_name(
258 x509.Name([
259 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
260 ])
261 ).last_update(
262 last_update
263 ).next_update(
264 next_update
265 ).add_extension(
266 x509.OCSPNoCheck(), False
267 )
268 with pytest.raises(NotImplementedError):
269 builder.sign(private_key, hashes.SHA256(), backend)
270
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600271 @pytest.mark.requires_backend_interface(interface=RSABackend)
272 @pytest.mark.requires_backend_interface(interface=X509Backend)
273 def test_sign_rsa_key_too_small(self, backend):
274 private_key = RSA_KEY_512.private_key(backend)
275 last_update = datetime.datetime(2002, 1, 1, 12, 1)
276 next_update = datetime.datetime(2030, 1, 1, 12, 1)
277 builder = x509.CertificateRevocationListBuilder().issuer_name(
278 x509.Name([
279 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
280 ])
281 ).last_update(
282 last_update
283 ).next_update(
284 next_update
285 )
286
287 with pytest.raises(ValueError):
288 builder.sign(private_key, hashes.SHA512(), backend)
289
290 @pytest.mark.requires_backend_interface(interface=RSABackend)
291 @pytest.mark.requires_backend_interface(interface=X509Backend)
292 def test_sign_with_invalid_hash(self, backend):
293 private_key = RSA_KEY_2048.private_key(backend)
294 last_update = datetime.datetime(2002, 1, 1, 12, 1)
295 next_update = datetime.datetime(2030, 1, 1, 12, 1)
296 builder = x509.CertificateRevocationListBuilder().issuer_name(
297 x509.Name([
298 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
299 ])
300 ).last_update(
301 last_update
302 ).next_update(
303 next_update
304 )
305
306 with pytest.raises(TypeError):
307 builder.sign(private_key, object(), backend)
308
309 @pytest.mark.requires_backend_interface(interface=DSABackend)
310 @pytest.mark.requires_backend_interface(interface=X509Backend)
Paul Kehrer9d345312015-12-26 18:09:52 -0600311 def test_sign_dsa_key(self, backend):
Alex Gaynor3e3444f2016-07-11 17:03:13 -0400312 if backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_101:
Paul Kehrer9d345312015-12-26 18:09:52 -0600313 pytest.skip("Requires a newer OpenSSL. Must be >= 1.0.1")
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600314 private_key = DSA_KEY_2048.private_key(backend)
Paul Kehrer9d345312015-12-26 18:09:52 -0600315 invalidity_date = x509.InvalidityDate(
316 datetime.datetime(2002, 1, 1, 0, 0)
317 )
318 ian = x509.IssuerAlternativeName([
319 x509.UniformResourceIdentifier(u"https://cryptography.io"),
320 ])
321 revoked_cert0 = x509.RevokedCertificateBuilder().serial_number(
322 2
323 ).revocation_date(
324 datetime.datetime(2012, 1, 1, 1, 1)
325 ).add_extension(
326 invalidity_date, False
327 ).build(backend)
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600328 last_update = datetime.datetime(2002, 1, 1, 12, 1)
329 next_update = datetime.datetime(2030, 1, 1, 12, 1)
330 builder = x509.CertificateRevocationListBuilder().issuer_name(
331 x509.Name([
332 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
333 ])
334 ).last_update(
335 last_update
336 ).next_update(
337 next_update
Paul Kehrer9d345312015-12-26 18:09:52 -0600338 ).add_revoked_certificate(
339 revoked_cert0
340 ).add_extension(
341 ian, False
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600342 )
343
Paul Kehrer9d345312015-12-26 18:09:52 -0600344 crl = builder.sign(private_key, hashes.SHA256(), backend)
345 assert crl.extensions.get_extension_for_class(
346 x509.IssuerAlternativeName
347 ).value == ian
348 assert crl[0].serial_number == revoked_cert0.serial_number
349 assert crl[0].revocation_date == revoked_cert0.revocation_date
350 assert len(crl[0].extensions) == 1
351 ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
352 assert ext.critical is False
353 assert ext.value == invalidity_date
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600354
355 @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
356 @pytest.mark.requires_backend_interface(interface=X509Backend)
357 def test_sign_ec_key_unsupported(self, backend):
Alex Gaynor3e3444f2016-07-11 17:03:13 -0400358 if backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_101:
Paul Kehrer9d345312015-12-26 18:09:52 -0600359 pytest.skip("Requires a newer OpenSSL. Must be >= 1.0.1")
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600360 _skip_curve_unsupported(backend, ec.SECP256R1())
361 private_key = ec.generate_private_key(ec.SECP256R1(), backend)
Paul Kehrer9d345312015-12-26 18:09:52 -0600362 invalidity_date = x509.InvalidityDate(
363 datetime.datetime(2002, 1, 1, 0, 0)
364 )
365 ian = x509.IssuerAlternativeName([
366 x509.UniformResourceIdentifier(u"https://cryptography.io"),
367 ])
368 revoked_cert0 = x509.RevokedCertificateBuilder().serial_number(
369 2
370 ).revocation_date(
371 datetime.datetime(2012, 1, 1, 1, 1)
372 ).add_extension(
373 invalidity_date, False
374 ).build(backend)
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600375 last_update = datetime.datetime(2002, 1, 1, 12, 1)
376 next_update = datetime.datetime(2030, 1, 1, 12, 1)
377 builder = x509.CertificateRevocationListBuilder().issuer_name(
378 x509.Name([
379 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
380 ])
381 ).last_update(
382 last_update
383 ).next_update(
384 next_update
Paul Kehrer9d345312015-12-26 18:09:52 -0600385 ).add_revoked_certificate(
386 revoked_cert0
387 ).add_extension(
388 ian, False
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600389 )
390
Paul Kehrer9d345312015-12-26 18:09:52 -0600391 crl = builder.sign(private_key, hashes.SHA256(), backend)
392 assert crl.extensions.get_extension_for_class(
393 x509.IssuerAlternativeName
394 ).value == ian
395 assert crl[0].serial_number == revoked_cert0.serial_number
396 assert crl[0].revocation_date == revoked_cert0.revocation_date
397 assert len(crl[0].extensions) == 1
398 ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
399 assert ext.critical is False
400 assert ext.value == invalidity_date
Paul Kehrer4c7fd5f2015-12-25 13:40:55 -0600401
402 @pytest.mark.requires_backend_interface(interface=RSABackend)
403 @pytest.mark.requires_backend_interface(interface=X509Backend)
404 def test_sign_with_revoked_certificates(self, backend):
405 private_key = RSA_KEY_2048.private_key(backend)
406 last_update = datetime.datetime(2002, 1, 1, 12, 1)
407 next_update = datetime.datetime(2030, 1, 1, 12, 1)
Paul Kehrere5f152b2015-12-25 23:55:47 -0600408 invalidity_date = x509.InvalidityDate(
409 datetime.datetime(2002, 1, 1, 0, 0)
410 )
Paul Kehrer4c7fd5f2015-12-25 13:40:55 -0600411 revoked_cert0 = x509.RevokedCertificateBuilder().serial_number(
412 38
413 ).revocation_date(
414 datetime.datetime(2011, 1, 1, 1, 1)
415 ).build(backend)
416 revoked_cert1 = x509.RevokedCertificateBuilder().serial_number(
417 2
418 ).revocation_date(
419 datetime.datetime(2012, 1, 1, 1, 1)
Paul Kehrere5f152b2015-12-25 23:55:47 -0600420 ).add_extension(
421 invalidity_date, False
Paul Kehrer4c7fd5f2015-12-25 13:40:55 -0600422 ).build(backend)
423 builder = x509.CertificateRevocationListBuilder().issuer_name(
424 x509.Name([
425 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
426 ])
427 ).last_update(
428 last_update
429 ).next_update(
430 next_update
431 ).add_revoked_certificate(
432 revoked_cert0
433 ).add_revoked_certificate(
434 revoked_cert1
435 )
436
437 crl = builder.sign(private_key, hashes.SHA256(), backend)
438 assert len(crl) == 2
439 assert crl.last_update == last_update
440 assert crl.next_update == next_update
441 assert crl[0].serial_number == revoked_cert0.serial_number
442 assert crl[0].revocation_date == revoked_cert0.revocation_date
443 assert len(crl[0].extensions) == 0
444 assert crl[1].serial_number == revoked_cert1.serial_number
445 assert crl[1].revocation_date == revoked_cert1.revocation_date
Paul Kehrere5f152b2015-12-25 23:55:47 -0600446 assert len(crl[1].extensions) == 1
447 ext = crl[1].extensions.get_extension_for_class(x509.InvalidityDate)
448 assert ext.critical is False
449 assert ext.value == invalidity_date