blob: f0306ef09c0b1524d0daa33d4f85263e50a6e17c [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
22from .hazmat.primitives.fixtures_rsa import RSA_KEY_2048, RSA_KEY_512
23from .hazmat.primitives.test_ec import _skip_curve_unsupported
24
25
26class TestCertificateRevocationListBuilder(object):
27 def test_issuer_name_invalid(self):
28 builder = x509.CertificateRevocationListBuilder()
29 with pytest.raises(TypeError):
30 builder.issuer_name("notanx509name")
31
32 def test_set_issuer_name_twice(self):
33 builder = x509.CertificateRevocationListBuilder().issuer_name(
34 x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
35 )
36 with pytest.raises(ValueError):
37 builder.issuer_name(
38 x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
39 )
40
InvalidInterrupt8e66ca62016-08-16 19:39:31 -070041 @pytest.mark.requires_backend_interface(interface=RSABackend)
42 @pytest.mark.requires_backend_interface(interface=X509Backend)
43 def test_aware_last_update(self, backend):
44 last_time = datetime.datetime(2012, 1, 16, 22, 43)
45 tz = pytz.timezone("US/Pacific")
46 last_time = tz.localize(last_time)
47 utc_last = datetime.datetime(2012, 1, 17, 6, 43)
48 next_time = datetime.datetime(2022, 1, 17, 6, 43)
49 private_key = RSA_KEY_2048.private_key(backend)
50 builder = x509.CertificateRevocationListBuilder().issuer_name(
51 x509.Name([
52 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
53 ])
54 ).last_update(last_time).next_update(next_time)
55
56 crl = builder.sign(private_key, hashes.SHA256(), backend)
57 assert crl.last_update == utc_last
58
Paul Kehrerbfac2d12015-12-19 23:32:08 -060059 def test_last_update_invalid(self):
60 builder = x509.CertificateRevocationListBuilder()
61 with pytest.raises(TypeError):
62 builder.last_update("notadatetime")
63
64 def test_last_update_before_unix_epoch(self):
65 builder = x509.CertificateRevocationListBuilder()
66 with pytest.raises(ValueError):
67 builder.last_update(datetime.datetime(1960, 8, 10))
68
69 def test_set_last_update_twice(self):
70 builder = x509.CertificateRevocationListBuilder().last_update(
71 datetime.datetime(2002, 1, 1, 12, 1)
72 )
73 with pytest.raises(ValueError):
74 builder.last_update(datetime.datetime(2002, 1, 1, 12, 1))
75
InvalidInterrupt8e66ca62016-08-16 19:39:31 -070076 @pytest.mark.requires_backend_interface(interface=RSABackend)
77 @pytest.mark.requires_backend_interface(interface=X509Backend)
78 def test_aware_next_update(self, backend):
79 next_time = datetime.datetime(2022, 1, 16, 22, 43)
80 tz = pytz.timezone("US/Pacific")
81 next_time = tz.localize(next_time)
82 utc_next = datetime.datetime(2022, 1, 17, 6, 43)
83 last_time = datetime.datetime(2012, 1, 17, 6, 43)
84 private_key = RSA_KEY_2048.private_key(backend)
85 builder = x509.CertificateRevocationListBuilder().issuer_name(
86 x509.Name([
87 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
88 ])
89 ).last_update(last_time).next_update(next_time)
90
91 crl = builder.sign(private_key, hashes.SHA256(), backend)
92 assert crl.next_update == utc_next
93
Paul Kehrerbfac2d12015-12-19 23:32:08 -060094 def test_next_update_invalid(self):
95 builder = x509.CertificateRevocationListBuilder()
96 with pytest.raises(TypeError):
97 builder.next_update("notadatetime")
98
99 def test_next_update_before_unix_epoch(self):
100 builder = x509.CertificateRevocationListBuilder()
101 with pytest.raises(ValueError):
102 builder.next_update(datetime.datetime(1960, 8, 10))
103
104 def test_set_next_update_twice(self):
105 builder = x509.CertificateRevocationListBuilder().next_update(
106 datetime.datetime(2002, 1, 1, 12, 1)
107 )
108 with pytest.raises(ValueError):
109 builder.next_update(datetime.datetime(2002, 1, 1, 12, 1))
110
111 def test_last_update_after_next_update(self):
112 builder = x509.CertificateRevocationListBuilder()
113
114 builder = builder.next_update(
115 datetime.datetime(2002, 1, 1, 12, 1)
116 )
117 with pytest.raises(ValueError):
118 builder.last_update(datetime.datetime(2003, 1, 1, 12, 1))
119
120 def test_next_update_after_last_update(self):
121 builder = x509.CertificateRevocationListBuilder()
122
123 builder = builder.last_update(
124 datetime.datetime(2002, 1, 1, 12, 1)
125 )
126 with pytest.raises(ValueError):
127 builder.next_update(datetime.datetime(2001, 1, 1, 12, 1))
128
Paul Kehrer426b48d2015-12-24 20:50:43 -0600129 def test_add_extension_checks_for_duplicates(self):
130 builder = x509.CertificateRevocationListBuilder().add_extension(
131 x509.CRLNumber(1), False
132 )
133
134 with pytest.raises(ValueError):
135 builder.add_extension(x509.CRLNumber(2), False)
136
Paul Kehrerd8359692015-12-24 22:48:38 -0600137 def test_add_invalid_extension(self):
138 builder = x509.CertificateRevocationListBuilder()
139
140 with pytest.raises(TypeError):
141 builder.add_extension(
142 object(), False
143 )
144
Paul Kehrer4c7fd5f2015-12-25 13:40:55 -0600145 def test_add_invalid_revoked_certificate(self):
146 builder = x509.CertificateRevocationListBuilder()
147
148 with pytest.raises(TypeError):
149 builder.add_revoked_certificate(object())
150
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600151 @pytest.mark.requires_backend_interface(interface=RSABackend)
152 @pytest.mark.requires_backend_interface(interface=X509Backend)
153 def test_no_issuer_name(self, backend):
154 private_key = RSA_KEY_2048.private_key(backend)
155 builder = x509.CertificateRevocationListBuilder().last_update(
156 datetime.datetime(2002, 1, 1, 12, 1)
157 ).next_update(
158 datetime.datetime(2030, 1, 1, 12, 1)
159 )
160
161 with pytest.raises(ValueError):
162 builder.sign(private_key, hashes.SHA256(), backend)
163
164 @pytest.mark.requires_backend_interface(interface=RSABackend)
165 @pytest.mark.requires_backend_interface(interface=X509Backend)
166 def test_no_last_update(self, backend):
167 private_key = RSA_KEY_2048.private_key(backend)
168 builder = x509.CertificateRevocationListBuilder().issuer_name(
169 x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
170 ).next_update(
171 datetime.datetime(2030, 1, 1, 12, 1)
172 )
173
174 with pytest.raises(ValueError):
175 builder.sign(private_key, hashes.SHA256(), backend)
176
177 @pytest.mark.requires_backend_interface(interface=RSABackend)
178 @pytest.mark.requires_backend_interface(interface=X509Backend)
179 def test_no_next_update(self, backend):
180 private_key = RSA_KEY_2048.private_key(backend)
181 builder = x509.CertificateRevocationListBuilder().issuer_name(
182 x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
183 ).last_update(
184 datetime.datetime(2030, 1, 1, 12, 1)
185 )
186
187 with pytest.raises(ValueError):
188 builder.sign(private_key, hashes.SHA256(), backend)
189
190 @pytest.mark.requires_backend_interface(interface=RSABackend)
191 @pytest.mark.requires_backend_interface(interface=X509Backend)
192 def test_sign_empty_list(self, backend):
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(last_update).next_update(next_update)
201
202 crl = builder.sign(private_key, hashes.SHA256(), backend)
203 assert len(crl) == 0
204 assert crl.last_update == last_update
205 assert crl.next_update == next_update
206
Paul Kehrer426b48d2015-12-24 20:50:43 -0600207 @pytest.mark.parametrize(
208 "extension",
209 [
210 x509.CRLNumber(13),
211 x509.AuthorityKeyIdentifier(
212 b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08"
213 b"\xcbY",
214 None,
215 None
216 ),
217 x509.AuthorityInformationAccess([
218 x509.AccessDescription(
219 AuthorityInformationAccessOID.CA_ISSUERS,
220 x509.DNSName(u"cryptography.io")
221 )
222 ]),
223 x509.IssuerAlternativeName([
224 x509.UniformResourceIdentifier(u"https://cryptography.io"),
225 ])
226 ]
227 )
228 @pytest.mark.requires_backend_interface(interface=RSABackend)
229 @pytest.mark.requires_backend_interface(interface=X509Backend)
230 def test_sign_extensions(self, backend, extension):
231 private_key = RSA_KEY_2048.private_key(backend)
232 last_update = datetime.datetime(2002, 1, 1, 12, 1)
233 next_update = datetime.datetime(2030, 1, 1, 12, 1)
234 builder = x509.CertificateRevocationListBuilder().issuer_name(
235 x509.Name([
236 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
237 ])
238 ).last_update(
239 last_update
240 ).next_update(
241 next_update
242 ).add_extension(
243 extension, False
244 )
245
246 crl = builder.sign(private_key, hashes.SHA256(), backend)
247 assert len(crl) == 0
248 assert len(crl.extensions) == 1
Paul Kehrerbbc1ba92015-12-25 10:05:46 -0600249 ext = crl.extensions.get_extension_for_class(type(extension))
Paul Kehrer426b48d2015-12-24 20:50:43 -0600250 assert ext.critical is False
251 assert ext.value == extension
252
253 @pytest.mark.requires_backend_interface(interface=RSABackend)
254 @pytest.mark.requires_backend_interface(interface=X509Backend)
255 def test_sign_multiple_extensions_critical(self, backend):
256 private_key = RSA_KEY_2048.private_key(backend)
257 last_update = datetime.datetime(2002, 1, 1, 12, 1)
258 next_update = datetime.datetime(2030, 1, 1, 12, 1)
259 ian = x509.IssuerAlternativeName([
260 x509.UniformResourceIdentifier(u"https://cryptography.io"),
261 ])
262 crl_number = x509.CRLNumber(13)
263 builder = x509.CertificateRevocationListBuilder().issuer_name(
264 x509.Name([
265 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
266 ])
267 ).last_update(
268 last_update
269 ).next_update(
270 next_update
271 ).add_extension(
272 crl_number, False
273 ).add_extension(
274 ian, True
275 )
276
277 crl = builder.sign(private_key, hashes.SHA256(), backend)
278 assert len(crl) == 0
279 assert len(crl.extensions) == 2
280 ext1 = crl.extensions.get_extension_for_class(x509.CRLNumber)
281 assert ext1.critical is False
282 assert ext1.value == crl_number
283 ext2 = crl.extensions.get_extension_for_class(
284 x509.IssuerAlternativeName
285 )
286 assert ext2.critical is True
287 assert ext2.value == ian
288
289 @pytest.mark.requires_backend_interface(interface=RSABackend)
290 @pytest.mark.requires_backend_interface(interface=X509Backend)
291 def test_add_unsupported_extension(self, backend):
292 private_key = RSA_KEY_2048.private_key(backend)
293 last_update = datetime.datetime(2002, 1, 1, 12, 1)
294 next_update = datetime.datetime(2030, 1, 1, 12, 1)
295 builder = x509.CertificateRevocationListBuilder().issuer_name(
296 x509.Name([
297 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
298 ])
299 ).last_update(
300 last_update
301 ).next_update(
302 next_update
303 ).add_extension(
304 x509.OCSPNoCheck(), False
305 )
306 with pytest.raises(NotImplementedError):
307 builder.sign(private_key, hashes.SHA256(), backend)
308
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600309 @pytest.mark.requires_backend_interface(interface=RSABackend)
310 @pytest.mark.requires_backend_interface(interface=X509Backend)
311 def test_sign_rsa_key_too_small(self, backend):
312 private_key = RSA_KEY_512.private_key(backend)
313 last_update = datetime.datetime(2002, 1, 1, 12, 1)
314 next_update = datetime.datetime(2030, 1, 1, 12, 1)
315 builder = x509.CertificateRevocationListBuilder().issuer_name(
316 x509.Name([
317 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
318 ])
319 ).last_update(
320 last_update
321 ).next_update(
322 next_update
323 )
324
325 with pytest.raises(ValueError):
326 builder.sign(private_key, hashes.SHA512(), backend)
327
328 @pytest.mark.requires_backend_interface(interface=RSABackend)
329 @pytest.mark.requires_backend_interface(interface=X509Backend)
330 def test_sign_with_invalid_hash(self, backend):
331 private_key = RSA_KEY_2048.private_key(backend)
332 last_update = datetime.datetime(2002, 1, 1, 12, 1)
333 next_update = datetime.datetime(2030, 1, 1, 12, 1)
334 builder = x509.CertificateRevocationListBuilder().issuer_name(
335 x509.Name([
336 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
337 ])
338 ).last_update(
339 last_update
340 ).next_update(
341 next_update
342 )
343
344 with pytest.raises(TypeError):
345 builder.sign(private_key, object(), backend)
346
347 @pytest.mark.requires_backend_interface(interface=DSABackend)
348 @pytest.mark.requires_backend_interface(interface=X509Backend)
Paul Kehrer9d345312015-12-26 18:09:52 -0600349 def test_sign_dsa_key(self, backend):
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600350 private_key = DSA_KEY_2048.private_key(backend)
Paul Kehrer9d345312015-12-26 18:09:52 -0600351 invalidity_date = x509.InvalidityDate(
352 datetime.datetime(2002, 1, 1, 0, 0)
353 )
354 ian = x509.IssuerAlternativeName([
355 x509.UniformResourceIdentifier(u"https://cryptography.io"),
356 ])
357 revoked_cert0 = x509.RevokedCertificateBuilder().serial_number(
358 2
359 ).revocation_date(
360 datetime.datetime(2012, 1, 1, 1, 1)
361 ).add_extension(
362 invalidity_date, False
363 ).build(backend)
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600364 last_update = datetime.datetime(2002, 1, 1, 12, 1)
365 next_update = datetime.datetime(2030, 1, 1, 12, 1)
366 builder = x509.CertificateRevocationListBuilder().issuer_name(
367 x509.Name([
368 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
369 ])
370 ).last_update(
371 last_update
372 ).next_update(
373 next_update
Paul Kehrer9d345312015-12-26 18:09:52 -0600374 ).add_revoked_certificate(
375 revoked_cert0
376 ).add_extension(
377 ian, False
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600378 )
379
Paul Kehrer9d345312015-12-26 18:09:52 -0600380 crl = builder.sign(private_key, hashes.SHA256(), backend)
381 assert crl.extensions.get_extension_for_class(
382 x509.IssuerAlternativeName
383 ).value == ian
384 assert crl[0].serial_number == revoked_cert0.serial_number
385 assert crl[0].revocation_date == revoked_cert0.revocation_date
386 assert len(crl[0].extensions) == 1
387 ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
388 assert ext.critical is False
389 assert ext.value == invalidity_date
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600390
391 @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
392 @pytest.mark.requires_backend_interface(interface=X509Backend)
393 def test_sign_ec_key_unsupported(self, backend):
394 _skip_curve_unsupported(backend, ec.SECP256R1())
395 private_key = ec.generate_private_key(ec.SECP256R1(), backend)
Paul Kehrer9d345312015-12-26 18:09:52 -0600396 invalidity_date = x509.InvalidityDate(
397 datetime.datetime(2002, 1, 1, 0, 0)
398 )
399 ian = x509.IssuerAlternativeName([
400 x509.UniformResourceIdentifier(u"https://cryptography.io"),
401 ])
402 revoked_cert0 = x509.RevokedCertificateBuilder().serial_number(
403 2
404 ).revocation_date(
405 datetime.datetime(2012, 1, 1, 1, 1)
406 ).add_extension(
407 invalidity_date, False
408 ).build(backend)
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600409 last_update = datetime.datetime(2002, 1, 1, 12, 1)
410 next_update = datetime.datetime(2030, 1, 1, 12, 1)
411 builder = x509.CertificateRevocationListBuilder().issuer_name(
412 x509.Name([
413 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
414 ])
415 ).last_update(
416 last_update
417 ).next_update(
418 next_update
Paul Kehrer9d345312015-12-26 18:09:52 -0600419 ).add_revoked_certificate(
420 revoked_cert0
421 ).add_extension(
422 ian, False
Paul Kehrerbfac2d12015-12-19 23:32:08 -0600423 )
424
Paul Kehrer9d345312015-12-26 18:09:52 -0600425 crl = builder.sign(private_key, hashes.SHA256(), backend)
426 assert crl.extensions.get_extension_for_class(
427 x509.IssuerAlternativeName
428 ).value == ian
429 assert crl[0].serial_number == revoked_cert0.serial_number
430 assert crl[0].revocation_date == revoked_cert0.revocation_date
431 assert len(crl[0].extensions) == 1
432 ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
433 assert ext.critical is False
434 assert ext.value == invalidity_date
Paul Kehrer4c7fd5f2015-12-25 13:40:55 -0600435
436 @pytest.mark.requires_backend_interface(interface=RSABackend)
437 @pytest.mark.requires_backend_interface(interface=X509Backend)
438 def test_sign_with_revoked_certificates(self, backend):
439 private_key = RSA_KEY_2048.private_key(backend)
440 last_update = datetime.datetime(2002, 1, 1, 12, 1)
441 next_update = datetime.datetime(2030, 1, 1, 12, 1)
Paul Kehrere5f152b2015-12-25 23:55:47 -0600442 invalidity_date = x509.InvalidityDate(
443 datetime.datetime(2002, 1, 1, 0, 0)
444 )
Paul Kehrer4c7fd5f2015-12-25 13:40:55 -0600445 revoked_cert0 = x509.RevokedCertificateBuilder().serial_number(
446 38
447 ).revocation_date(
448 datetime.datetime(2011, 1, 1, 1, 1)
449 ).build(backend)
450 revoked_cert1 = x509.RevokedCertificateBuilder().serial_number(
451 2
452 ).revocation_date(
453 datetime.datetime(2012, 1, 1, 1, 1)
Paul Kehrere5f152b2015-12-25 23:55:47 -0600454 ).add_extension(
455 invalidity_date, False
Paul Kehrer4c7fd5f2015-12-25 13:40:55 -0600456 ).build(backend)
457 builder = x509.CertificateRevocationListBuilder().issuer_name(
458 x509.Name([
459 x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
460 ])
461 ).last_update(
462 last_update
463 ).next_update(
464 next_update
465 ).add_revoked_certificate(
466 revoked_cert0
467 ).add_revoked_certificate(
468 revoked_cert1
469 )
470
471 crl = builder.sign(private_key, hashes.SHA256(), backend)
472 assert len(crl) == 2
473 assert crl.last_update == last_update
474 assert crl.next_update == next_update
475 assert crl[0].serial_number == revoked_cert0.serial_number
476 assert crl[0].revocation_date == revoked_cert0.revocation_date
477 assert len(crl[0].extensions) == 0
478 assert crl[1].serial_number == revoked_cert1.serial_number
479 assert crl[1].revocation_date == revoked_cert1.revocation_date
Paul Kehrere5f152b2015-12-25 23:55:47 -0600480 assert len(crl[1].extensions) == 1
481 ext = crl[1].extensions.get_extension_for_class(x509.InvalidityDate)
482 assert ext.critical is False
483 assert ext.value == invalidity_date