blob: b3c789f6902c2ec4aca34955e8ae43be53319f45 [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
InvalidInterrupt8e66ca62016-08-16 19:39:31 -070011import pytz
12
Paul Kehrerbfac2d12015-12-19 23:32:08 -060013from cryptography import x509
14from cryptography.hazmat.backends.interfaces import (
15 DSABackend, EllipticCurveBackend, RSABackend, X509Backend
16)
17from cryptography.hazmat.primitives import hashes
18from cryptography.hazmat.primitives.asymmetric import ec
Paul Kehrer426b48d2015-12-24 20:50:43 -060019from cryptography.x509.oid import AuthorityInformationAccessOID, NameOID
Paul Kehrerbfac2d12015-12-19 23:32:08 -060020
21from .hazmat.primitives.fixtures_dsa import DSA_KEY_2048
Paul Kehrer784e3bc2017-06-30 19:49:53 -050022from .hazmat.primitives.fixtures_ec import EC_KEY_SECP256R1
Paul Kehrerbfac2d12015-12-19 23:32:08 -060023from .hazmat.primitives.fixtures_rsa import RSA_KEY_2048, RSA_KEY_512
24from .hazmat.primitives.test_ec import _skip_curve_unsupported
25
26
27class TestCertificateRevocationListBuilder(object):
28 def test_issuer_name_invalid(self):
29 builder = x509.CertificateRevocationListBuilder()
30 with pytest.raises(TypeError):
31 builder.issuer_name("notanx509name")
32
33 def test_set_issuer_name_twice(self):
34 builder = x509.CertificateRevocationListBuilder().issuer_name(
35 x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
36 )
37 with pytest.raises(ValueError):
38 builder.issuer_name(
39 x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
40 )
41
InvalidInterrupt8e66ca62016-08-16 19:39:31 -070042 @pytest.mark.requires_backend_interface(interface=RSABackend)
43 @pytest.mark.requires_backend_interface(interface=X509Backend)
44 def test_aware_last_update(self, backend):
45 last_time = datetime.datetime(2012, 1, 16, 22, 43)
46 tz = pytz.timezone("US/Pacific")
47 last_time = tz.localize(last_time)
48 utc_last = datetime.datetime(2012, 1, 17, 6, 43)
49 next_time = datetime.datetime(2022, 1, 17, 6, 43)
50 private_key = RSA_KEY_2048.private_key(backend)
51 builder = x509.CertificateRevocationListBuilder().issuer_name(
52 x509.Name([
53 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
54 ])
55 ).last_update(last_time).next_update(next_time)
56
57 crl = builder.sign(private_key, hashes.SHA256(), backend)
58 assert crl.last_update == utc_last
59
Paul Kehrerbfac2d12015-12-19 23:32:08 -060060 def test_last_update_invalid(self):
61 builder = x509.CertificateRevocationListBuilder()
62 with pytest.raises(TypeError):
63 builder.last_update("notadatetime")
64
65 def test_last_update_before_unix_epoch(self):
66 builder = x509.CertificateRevocationListBuilder()
67 with pytest.raises(ValueError):
68 builder.last_update(datetime.datetime(1960, 8, 10))
69
70 def test_set_last_update_twice(self):
71 builder = x509.CertificateRevocationListBuilder().last_update(
72 datetime.datetime(2002, 1, 1, 12, 1)
73 )
74 with pytest.raises(ValueError):
75 builder.last_update(datetime.datetime(2002, 1, 1, 12, 1))
76
InvalidInterrupt8e66ca62016-08-16 19:39:31 -070077 @pytest.mark.requires_backend_interface(interface=RSABackend)
78 @pytest.mark.requires_backend_interface(interface=X509Backend)
79 def test_aware_next_update(self, backend):
80 next_time = datetime.datetime(2022, 1, 16, 22, 43)
81 tz = pytz.timezone("US/Pacific")
82 next_time = tz.localize(next_time)
83 utc_next = datetime.datetime(2022, 1, 17, 6, 43)
84 last_time = datetime.datetime(2012, 1, 17, 6, 43)
85 private_key = RSA_KEY_2048.private_key(backend)
86 builder = x509.CertificateRevocationListBuilder().issuer_name(
87 x509.Name([
88 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
89 ])
90 ).last_update(last_time).next_update(next_time)
91
92 crl = builder.sign(private_key, hashes.SHA256(), backend)
93 assert crl.next_update == utc_next
94
Paul Kehrerbfac2d12015-12-19 23:32:08 -060095 def test_next_update_invalid(self):
96 builder = x509.CertificateRevocationListBuilder()
97 with pytest.raises(TypeError):
98 builder.next_update("notadatetime")
99
100 def test_next_update_before_unix_epoch(self):
101 builder = x509.CertificateRevocationListBuilder()
102 with pytest.raises(ValueError):
103 builder.next_update(datetime.datetime(1960, 8, 10))
104
105 def test_set_next_update_twice(self):
106 builder = x509.CertificateRevocationListBuilder().next_update(
107 datetime.datetime(2002, 1, 1, 12, 1)
108 )
109 with pytest.raises(ValueError):
110 builder.next_update(datetime.datetime(2002, 1, 1, 12, 1))
111
112 def test_last_update_after_next_update(self):
113 builder = x509.CertificateRevocationListBuilder()
114
115 builder = builder.next_update(
116 datetime.datetime(2002, 1, 1, 12, 1)
117 )
118 with pytest.raises(ValueError):
119 builder.last_update(datetime.datetime(2003, 1, 1, 12, 1))
120
121 def test_next_update_after_last_update(self):
122 builder = x509.CertificateRevocationListBuilder()
123
124 builder = builder.last_update(
125 datetime.datetime(2002, 1, 1, 12, 1)
126 )
127 with pytest.raises(ValueError):
128 builder.next_update(datetime.datetime(2001, 1, 1, 12, 1))
129
Paul Kehrer426b48d2015-12-24 20:50:43 -0600130 def test_add_extension_checks_for_duplicates(self):
131 builder = x509.CertificateRevocationListBuilder().add_extension(
132 x509.CRLNumber(1), False
133 )
134
135 with pytest.raises(ValueError):
136 builder.add_extension(x509.CRLNumber(2), False)
137
Paul Kehrerd8359692015-12-24 22:48:38 -0600138 def test_add_invalid_extension(self):
139 builder = x509.CertificateRevocationListBuilder()
140
141 with pytest.raises(TypeError):
142 builder.add_extension(
143 object(), False
144 )
145
Paul Kehrer4c7fd5f2015-12-25 13:40:55 -0600146 def test_add_invalid_revoked_certificate(self):
147 builder = x509.CertificateRevocationListBuilder()
148
149 with pytest.raises(TypeError):
150 builder.add_revoked_certificate(object())
151
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600152 @pytest.mark.requires_backend_interface(interface=RSABackend)
153 @pytest.mark.requires_backend_interface(interface=X509Backend)
154 def test_no_issuer_name(self, backend):
155 private_key = RSA_KEY_2048.private_key(backend)
156 builder = x509.CertificateRevocationListBuilder().last_update(
157 datetime.datetime(2002, 1, 1, 12, 1)
158 ).next_update(
159 datetime.datetime(2030, 1, 1, 12, 1)
160 )
161
162 with pytest.raises(ValueError):
163 builder.sign(private_key, hashes.SHA256(), backend)
164
165 @pytest.mark.requires_backend_interface(interface=RSABackend)
166 @pytest.mark.requires_backend_interface(interface=X509Backend)
167 def test_no_last_update(self, backend):
168 private_key = RSA_KEY_2048.private_key(backend)
169 builder = x509.CertificateRevocationListBuilder().issuer_name(
170 x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
171 ).next_update(
172 datetime.datetime(2030, 1, 1, 12, 1)
173 )
174
175 with pytest.raises(ValueError):
176 builder.sign(private_key, hashes.SHA256(), backend)
177
178 @pytest.mark.requires_backend_interface(interface=RSABackend)
179 @pytest.mark.requires_backend_interface(interface=X509Backend)
180 def test_no_next_update(self, backend):
181 private_key = RSA_KEY_2048.private_key(backend)
182 builder = x509.CertificateRevocationListBuilder().issuer_name(
183 x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
184 ).last_update(
185 datetime.datetime(2030, 1, 1, 12, 1)
186 )
187
188 with pytest.raises(ValueError):
189 builder.sign(private_key, hashes.SHA256(), backend)
190
191 @pytest.mark.requires_backend_interface(interface=RSABackend)
192 @pytest.mark.requires_backend_interface(interface=X509Backend)
193 def test_sign_empty_list(self, backend):
194 private_key = RSA_KEY_2048.private_key(backend)
195 last_update = datetime.datetime(2002, 1, 1, 12, 1)
196 next_update = datetime.datetime(2030, 1, 1, 12, 1)
197 builder = x509.CertificateRevocationListBuilder().issuer_name(
198 x509.Name([
199 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
200 ])
201 ).last_update(last_update).next_update(next_update)
202
203 crl = builder.sign(private_key, hashes.SHA256(), backend)
204 assert len(crl) == 0
205 assert crl.last_update == last_update
206 assert crl.next_update == next_update
207
Paul Kehrer426b48d2015-12-24 20:50:43 -0600208 @pytest.mark.parametrize(
209 "extension",
210 [
211 x509.CRLNumber(13),
212 x509.AuthorityKeyIdentifier(
213 b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08"
214 b"\xcbY",
215 None,
216 None
217 ),
218 x509.AuthorityInformationAccess([
219 x509.AccessDescription(
220 AuthorityInformationAccessOID.CA_ISSUERS,
221 x509.DNSName(u"cryptography.io")
222 )
223 ]),
224 x509.IssuerAlternativeName([
225 x509.UniformResourceIdentifier(u"https://cryptography.io"),
226 ])
227 ]
228 )
229 @pytest.mark.requires_backend_interface(interface=RSABackend)
230 @pytest.mark.requires_backend_interface(interface=X509Backend)
231 def test_sign_extensions(self, backend, extension):
232 private_key = RSA_KEY_2048.private_key(backend)
233 last_update = datetime.datetime(2002, 1, 1, 12, 1)
234 next_update = datetime.datetime(2030, 1, 1, 12, 1)
235 builder = x509.CertificateRevocationListBuilder().issuer_name(
236 x509.Name([
237 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
238 ])
239 ).last_update(
240 last_update
241 ).next_update(
242 next_update
243 ).add_extension(
244 extension, False
245 )
246
247 crl = builder.sign(private_key, hashes.SHA256(), backend)
248 assert len(crl) == 0
249 assert len(crl.extensions) == 1
Paul Kehrerbbc1ba92015-12-25 10:05:46 -0600250 ext = crl.extensions.get_extension_for_class(type(extension))
Paul Kehrer426b48d2015-12-24 20:50:43 -0600251 assert ext.critical is False
252 assert ext.value == extension
253
254 @pytest.mark.requires_backend_interface(interface=RSABackend)
255 @pytest.mark.requires_backend_interface(interface=X509Backend)
256 def test_sign_multiple_extensions_critical(self, backend):
257 private_key = RSA_KEY_2048.private_key(backend)
258 last_update = datetime.datetime(2002, 1, 1, 12, 1)
259 next_update = datetime.datetime(2030, 1, 1, 12, 1)
260 ian = x509.IssuerAlternativeName([
261 x509.UniformResourceIdentifier(u"https://cryptography.io"),
262 ])
263 crl_number = x509.CRLNumber(13)
264 builder = x509.CertificateRevocationListBuilder().issuer_name(
265 x509.Name([
266 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
267 ])
268 ).last_update(
269 last_update
270 ).next_update(
271 next_update
272 ).add_extension(
273 crl_number, False
274 ).add_extension(
275 ian, True
276 )
277
278 crl = builder.sign(private_key, hashes.SHA256(), backend)
279 assert len(crl) == 0
280 assert len(crl.extensions) == 2
281 ext1 = crl.extensions.get_extension_for_class(x509.CRLNumber)
282 assert ext1.critical is False
283 assert ext1.value == crl_number
284 ext2 = crl.extensions.get_extension_for_class(
285 x509.IssuerAlternativeName
286 )
287 assert ext2.critical is True
288 assert ext2.value == ian
289
290 @pytest.mark.requires_backend_interface(interface=RSABackend)
291 @pytest.mark.requires_backend_interface(interface=X509Backend)
292 def test_add_unsupported_extension(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 ).add_extension(
305 x509.OCSPNoCheck(), False
306 )
307 with pytest.raises(NotImplementedError):
308 builder.sign(private_key, hashes.SHA256(), backend)
309
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600310 @pytest.mark.requires_backend_interface(interface=RSABackend)
311 @pytest.mark.requires_backend_interface(interface=X509Backend)
312 def test_sign_rsa_key_too_small(self, backend):
313 private_key = RSA_KEY_512.private_key(backend)
314 last_update = datetime.datetime(2002, 1, 1, 12, 1)
315 next_update = datetime.datetime(2030, 1, 1, 12, 1)
316 builder = x509.CertificateRevocationListBuilder().issuer_name(
317 x509.Name([
318 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
319 ])
320 ).last_update(
321 last_update
322 ).next_update(
323 next_update
324 )
325
326 with pytest.raises(ValueError):
327 builder.sign(private_key, hashes.SHA512(), backend)
328
329 @pytest.mark.requires_backend_interface(interface=RSABackend)
330 @pytest.mark.requires_backend_interface(interface=X509Backend)
331 def test_sign_with_invalid_hash(self, backend):
332 private_key = RSA_KEY_2048.private_key(backend)
333 last_update = datetime.datetime(2002, 1, 1, 12, 1)
334 next_update = datetime.datetime(2030, 1, 1, 12, 1)
335 builder = x509.CertificateRevocationListBuilder().issuer_name(
336 x509.Name([
337 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
338 ])
339 ).last_update(
340 last_update
341 ).next_update(
342 next_update
343 )
344
345 with pytest.raises(TypeError):
346 builder.sign(private_key, object(), backend)
347
348 @pytest.mark.requires_backend_interface(interface=DSABackend)
349 @pytest.mark.requires_backend_interface(interface=X509Backend)
Paul Kehrer9d345312015-12-26 18:09:52 -0600350 def test_sign_dsa_key(self, backend):
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600351 private_key = DSA_KEY_2048.private_key(backend)
Paul Kehrer9d345312015-12-26 18:09:52 -0600352 invalidity_date = x509.InvalidityDate(
353 datetime.datetime(2002, 1, 1, 0, 0)
354 )
355 ian = x509.IssuerAlternativeName([
356 x509.UniformResourceIdentifier(u"https://cryptography.io"),
357 ])
358 revoked_cert0 = x509.RevokedCertificateBuilder().serial_number(
359 2
360 ).revocation_date(
361 datetime.datetime(2012, 1, 1, 1, 1)
362 ).add_extension(
363 invalidity_date, False
364 ).build(backend)
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600365 last_update = datetime.datetime(2002, 1, 1, 12, 1)
366 next_update = datetime.datetime(2030, 1, 1, 12, 1)
367 builder = x509.CertificateRevocationListBuilder().issuer_name(
368 x509.Name([
369 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
370 ])
371 ).last_update(
372 last_update
373 ).next_update(
374 next_update
Paul Kehrer9d345312015-12-26 18:09:52 -0600375 ).add_revoked_certificate(
376 revoked_cert0
377 ).add_extension(
378 ian, False
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600379 )
380
Paul Kehrer9d345312015-12-26 18:09:52 -0600381 crl = builder.sign(private_key, hashes.SHA256(), backend)
382 assert crl.extensions.get_extension_for_class(
383 x509.IssuerAlternativeName
384 ).value == ian
385 assert crl[0].serial_number == revoked_cert0.serial_number
386 assert crl[0].revocation_date == revoked_cert0.revocation_date
387 assert len(crl[0].extensions) == 1
388 ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
389 assert ext.critical is False
390 assert ext.value == invalidity_date
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600391
392 @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
393 @pytest.mark.requires_backend_interface(interface=X509Backend)
Paul Kehrer784e3bc2017-06-30 19:49:53 -0500394 def test_sign_ec_key(self, backend):
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600395 _skip_curve_unsupported(backend, ec.SECP256R1())
396 private_key = ec.generate_private_key(ec.SECP256R1(), backend)
Paul Kehrer9d345312015-12-26 18:09:52 -0600397 invalidity_date = x509.InvalidityDate(
398 datetime.datetime(2002, 1, 1, 0, 0)
399 )
400 ian = x509.IssuerAlternativeName([
401 x509.UniformResourceIdentifier(u"https://cryptography.io"),
402 ])
403 revoked_cert0 = x509.RevokedCertificateBuilder().serial_number(
404 2
405 ).revocation_date(
406 datetime.datetime(2012, 1, 1, 1, 1)
407 ).add_extension(
408 invalidity_date, False
409 ).build(backend)
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600410 last_update = datetime.datetime(2002, 1, 1, 12, 1)
411 next_update = datetime.datetime(2030, 1, 1, 12, 1)
412 builder = x509.CertificateRevocationListBuilder().issuer_name(
413 x509.Name([
414 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
415 ])
416 ).last_update(
417 last_update
418 ).next_update(
419 next_update
Paul Kehrer9d345312015-12-26 18:09:52 -0600420 ).add_revoked_certificate(
421 revoked_cert0
422 ).add_extension(
423 ian, False
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600424 )
425
Paul Kehrer9d345312015-12-26 18:09:52 -0600426 crl = builder.sign(private_key, hashes.SHA256(), backend)
427 assert crl.extensions.get_extension_for_class(
428 x509.IssuerAlternativeName
429 ).value == ian
430 assert crl[0].serial_number == revoked_cert0.serial_number
431 assert crl[0].revocation_date == revoked_cert0.revocation_date
432 assert len(crl[0].extensions) == 1
433 ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
434 assert ext.critical is False
435 assert ext.value == invalidity_date
Paul Kehrer4c7fd5f2015-12-25 13:40:55 -0600436
Paul Kehrer784e3bc2017-06-30 19:49:53 -0500437 @pytest.mark.requires_backend_interface(interface=DSABackend)
438 @pytest.mark.requires_backend_interface(interface=X509Backend)
439 def test_dsa_key_sign_md5(self, backend):
440 private_key = DSA_KEY_2048.private_key(backend)
441 last_time = datetime.datetime(2012, 1, 16, 22, 43)
442 next_time = datetime.datetime(2022, 1, 17, 6, 43)
443 builder = x509.CertificateRevocationListBuilder().issuer_name(
444 x509.Name([
445 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
446 ])
447 ).last_update(last_time).next_update(next_time)
448
449 with pytest.raises(ValueError):
450 builder.sign(private_key, hashes.MD5(), backend)
451
452 @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
453 @pytest.mark.requires_backend_interface(interface=X509Backend)
454 def test_ec_key_sign_md5(self, backend):
455 _skip_curve_unsupported(backend, ec.SECP256R1())
456 private_key = EC_KEY_SECP256R1.private_key(backend)
457 last_time = datetime.datetime(2012, 1, 16, 22, 43)
458 next_time = datetime.datetime(2022, 1, 17, 6, 43)
459 builder = x509.CertificateRevocationListBuilder().issuer_name(
460 x509.Name([
461 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
462 ])
463 ).last_update(last_time).next_update(next_time)
464
465 with pytest.raises(ValueError):
466 builder.sign(private_key, hashes.MD5(), backend)
467
Paul Kehrer4c7fd5f2015-12-25 13:40:55 -0600468 @pytest.mark.requires_backend_interface(interface=RSABackend)
469 @pytest.mark.requires_backend_interface(interface=X509Backend)
470 def test_sign_with_revoked_certificates(self, backend):
471 private_key = RSA_KEY_2048.private_key(backend)
472 last_update = datetime.datetime(2002, 1, 1, 12, 1)
473 next_update = datetime.datetime(2030, 1, 1, 12, 1)
Paul Kehrere5f152b2015-12-25 23:55:47 -0600474 invalidity_date = x509.InvalidityDate(
475 datetime.datetime(2002, 1, 1, 0, 0)
476 )
Paul Kehrer4c7fd5f2015-12-25 13:40:55 -0600477 revoked_cert0 = x509.RevokedCertificateBuilder().serial_number(
478 38
479 ).revocation_date(
480 datetime.datetime(2011, 1, 1, 1, 1)
481 ).build(backend)
482 revoked_cert1 = x509.RevokedCertificateBuilder().serial_number(
483 2
484 ).revocation_date(
485 datetime.datetime(2012, 1, 1, 1, 1)
Paul Kehrere5f152b2015-12-25 23:55:47 -0600486 ).add_extension(
487 invalidity_date, False
Paul Kehrer4c7fd5f2015-12-25 13:40:55 -0600488 ).build(backend)
489 builder = x509.CertificateRevocationListBuilder().issuer_name(
490 x509.Name([
491 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
492 ])
493 ).last_update(
494 last_update
495 ).next_update(
496 next_update
497 ).add_revoked_certificate(
498 revoked_cert0
499 ).add_revoked_certificate(
500 revoked_cert1
501 )
502
503 crl = builder.sign(private_key, hashes.SHA256(), backend)
504 assert len(crl) == 2
505 assert crl.last_update == last_update
506 assert crl.next_update == next_update
507 assert crl[0].serial_number == revoked_cert0.serial_number
508 assert crl[0].revocation_date == revoked_cert0.revocation_date
509 assert len(crl[0].extensions) == 0
510 assert crl[1].serial_number == revoked_cert1.serial_number
511 assert crl[1].revocation_date == revoked_cert1.revocation_date
Paul Kehrere5f152b2015-12-25 23:55:47 -0600512 assert len(crl[1].extensions) == 1
513 ext = crl[1].extensions.get_extension_for_class(x509.InvalidityDate)
514 assert ext.critical is False
515 assert ext.value == invalidity_date