• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 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
11import pytz
12
13from cryptography import x509
14from cryptography.hazmat.backends.interfaces import (
15    DSABackend,
16    EllipticCurveBackend,
17    RSABackend,
18    X509Backend,
19)
20from cryptography.hazmat.primitives import hashes
21from cryptography.hazmat.primitives.asymmetric import ec, ed25519, ed448
22from cryptography.x509.oid import (
23    AuthorityInformationAccessOID,
24    NameOID,
25    SignatureAlgorithmOID,
26)
27
28from ..hazmat.primitives.fixtures_dsa import DSA_KEY_2048
29from ..hazmat.primitives.fixtures_ec import EC_KEY_SECP256R1
30from ..hazmat.primitives.fixtures_rsa import RSA_KEY_2048, RSA_KEY_512
31from ..hazmat.primitives.test_ec import _skip_curve_unsupported
32
33
34class TestCertificateRevocationListBuilder(object):
35    def test_issuer_name_invalid(self):
36        builder = x509.CertificateRevocationListBuilder()
37        with pytest.raises(TypeError):
38            builder.issuer_name("notanx509name")
39
40    def test_set_issuer_name_twice(self):
41        builder = x509.CertificateRevocationListBuilder().issuer_name(
42            x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u"US")])
43        )
44        with pytest.raises(ValueError):
45            builder.issuer_name(
46                x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u"US")])
47            )
48
49    @pytest.mark.requires_backend_interface(interface=RSABackend)
50    @pytest.mark.requires_backend_interface(interface=X509Backend)
51    def test_aware_last_update(self, backend):
52        last_time = datetime.datetime(2012, 1, 16, 22, 43)
53        tz = pytz.timezone("US/Pacific")
54        last_time = tz.localize(last_time)
55        utc_last = datetime.datetime(2012, 1, 17, 6, 43)
56        next_time = datetime.datetime(2022, 1, 17, 6, 43)
57        private_key = RSA_KEY_2048.private_key(backend)
58        builder = (
59            x509.CertificateRevocationListBuilder()
60            .issuer_name(
61                x509.Name(
62                    [
63                        x509.NameAttribute(
64                            NameOID.COMMON_NAME, u"cryptography.io CA"
65                        )
66                    ]
67                )
68            )
69            .last_update(last_time)
70            .next_update(next_time)
71        )
72
73        crl = builder.sign(private_key, hashes.SHA256(), backend)
74        assert crl.last_update == utc_last
75
76    def test_last_update_invalid(self):
77        builder = x509.CertificateRevocationListBuilder()
78        with pytest.raises(TypeError):
79            builder.last_update("notadatetime")
80
81    def test_last_update_before_1950(self):
82        builder = x509.CertificateRevocationListBuilder()
83        with pytest.raises(ValueError):
84            builder.last_update(datetime.datetime(1940, 8, 10))
85
86    def test_set_last_update_twice(self):
87        builder = x509.CertificateRevocationListBuilder().last_update(
88            datetime.datetime(2002, 1, 1, 12, 1)
89        )
90        with pytest.raises(ValueError):
91            builder.last_update(datetime.datetime(2002, 1, 1, 12, 1))
92
93    @pytest.mark.requires_backend_interface(interface=RSABackend)
94    @pytest.mark.requires_backend_interface(interface=X509Backend)
95    def test_aware_next_update(self, backend):
96        next_time = datetime.datetime(2022, 1, 16, 22, 43)
97        tz = pytz.timezone("US/Pacific")
98        next_time = tz.localize(next_time)
99        utc_next = datetime.datetime(2022, 1, 17, 6, 43)
100        last_time = datetime.datetime(2012, 1, 17, 6, 43)
101        private_key = RSA_KEY_2048.private_key(backend)
102        builder = (
103            x509.CertificateRevocationListBuilder()
104            .issuer_name(
105                x509.Name(
106                    [
107                        x509.NameAttribute(
108                            NameOID.COMMON_NAME, u"cryptography.io CA"
109                        )
110                    ]
111                )
112            )
113            .last_update(last_time)
114            .next_update(next_time)
115        )
116
117        crl = builder.sign(private_key, hashes.SHA256(), backend)
118        assert crl.next_update == utc_next
119
120    def test_next_update_invalid(self):
121        builder = x509.CertificateRevocationListBuilder()
122        with pytest.raises(TypeError):
123            builder.next_update("notadatetime")
124
125    def test_next_update_before_1950(self):
126        builder = x509.CertificateRevocationListBuilder()
127        with pytest.raises(ValueError):
128            builder.next_update(datetime.datetime(1940, 8, 10))
129
130    def test_set_next_update_twice(self):
131        builder = x509.CertificateRevocationListBuilder().next_update(
132            datetime.datetime(2002, 1, 1, 12, 1)
133        )
134        with pytest.raises(ValueError):
135            builder.next_update(datetime.datetime(2002, 1, 1, 12, 1))
136
137    def test_last_update_after_next_update(self):
138        builder = x509.CertificateRevocationListBuilder()
139
140        builder = builder.next_update(datetime.datetime(2002, 1, 1, 12, 1))
141        with pytest.raises(ValueError):
142            builder.last_update(datetime.datetime(2003, 1, 1, 12, 1))
143
144    def test_next_update_after_last_update(self):
145        builder = x509.CertificateRevocationListBuilder()
146
147        builder = builder.last_update(datetime.datetime(2002, 1, 1, 12, 1))
148        with pytest.raises(ValueError):
149            builder.next_update(datetime.datetime(2001, 1, 1, 12, 1))
150
151    def test_add_extension_checks_for_duplicates(self):
152        builder = x509.CertificateRevocationListBuilder().add_extension(
153            x509.CRLNumber(1), False
154        )
155
156        with pytest.raises(ValueError):
157            builder.add_extension(x509.CRLNumber(2), False)
158
159    def test_add_invalid_extension(self):
160        builder = x509.CertificateRevocationListBuilder()
161
162        with pytest.raises(TypeError):
163            builder.add_extension(object(), False)
164
165    def test_add_invalid_revoked_certificate(self):
166        builder = x509.CertificateRevocationListBuilder()
167
168        with pytest.raises(TypeError):
169            builder.add_revoked_certificate(object())
170
171    @pytest.mark.requires_backend_interface(interface=RSABackend)
172    @pytest.mark.requires_backend_interface(interface=X509Backend)
173    def test_no_issuer_name(self, backend):
174        private_key = RSA_KEY_2048.private_key(backend)
175        builder = (
176            x509.CertificateRevocationListBuilder()
177            .last_update(datetime.datetime(2002, 1, 1, 12, 1))
178            .next_update(datetime.datetime(2030, 1, 1, 12, 1))
179        )
180
181        with pytest.raises(ValueError):
182            builder.sign(private_key, hashes.SHA256(), backend)
183
184    @pytest.mark.requires_backend_interface(interface=RSABackend)
185    @pytest.mark.requires_backend_interface(interface=X509Backend)
186    def test_no_last_update(self, backend):
187        private_key = RSA_KEY_2048.private_key(backend)
188        builder = (
189            x509.CertificateRevocationListBuilder()
190            .issuer_name(
191                x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u"US")])
192            )
193            .next_update(datetime.datetime(2030, 1, 1, 12, 1))
194        )
195
196        with pytest.raises(ValueError):
197            builder.sign(private_key, hashes.SHA256(), backend)
198
199    @pytest.mark.requires_backend_interface(interface=RSABackend)
200    @pytest.mark.requires_backend_interface(interface=X509Backend)
201    def test_no_next_update(self, backend):
202        private_key = RSA_KEY_2048.private_key(backend)
203        builder = (
204            x509.CertificateRevocationListBuilder()
205            .issuer_name(
206                x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u"US")])
207            )
208            .last_update(datetime.datetime(2030, 1, 1, 12, 1))
209        )
210
211        with pytest.raises(ValueError):
212            builder.sign(private_key, hashes.SHA256(), backend)
213
214    @pytest.mark.requires_backend_interface(interface=RSABackend)
215    @pytest.mark.requires_backend_interface(interface=X509Backend)
216    def test_sign_empty_list(self, backend):
217        private_key = RSA_KEY_2048.private_key(backend)
218        last_update = datetime.datetime(2002, 1, 1, 12, 1)
219        next_update = datetime.datetime(2030, 1, 1, 12, 1)
220        builder = (
221            x509.CertificateRevocationListBuilder()
222            .issuer_name(
223                x509.Name(
224                    [
225                        x509.NameAttribute(
226                            NameOID.COMMON_NAME, u"cryptography.io CA"
227                        )
228                    ]
229                )
230            )
231            .last_update(last_update)
232            .next_update(next_update)
233        )
234
235        crl = builder.sign(private_key, hashes.SHA256(), backend)
236        assert len(crl) == 0
237        assert crl.last_update == last_update
238        assert crl.next_update == next_update
239
240    @pytest.mark.parametrize(
241        "extension",
242        [
243            x509.CRLNumber(13),
244            x509.DeltaCRLIndicator(12345678901234567890),
245            x509.AuthorityKeyIdentifier(
246                b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08"
247                b"\xcbY",
248                None,
249                None,
250            ),
251            x509.AuthorityInformationAccess(
252                [
253                    x509.AccessDescription(
254                        AuthorityInformationAccessOID.CA_ISSUERS,
255                        x509.DNSName(u"cryptography.io"),
256                    )
257                ]
258            ),
259            x509.IssuerAlternativeName(
260                [x509.UniformResourceIdentifier(u"https://cryptography.io")]
261            ),
262        ],
263    )
264    @pytest.mark.requires_backend_interface(interface=RSABackend)
265    @pytest.mark.requires_backend_interface(interface=X509Backend)
266    def test_sign_extensions(self, backend, extension):
267        private_key = RSA_KEY_2048.private_key(backend)
268        last_update = datetime.datetime(2002, 1, 1, 12, 1)
269        next_update = datetime.datetime(2030, 1, 1, 12, 1)
270        builder = (
271            x509.CertificateRevocationListBuilder()
272            .issuer_name(
273                x509.Name(
274                    [
275                        x509.NameAttribute(
276                            NameOID.COMMON_NAME, u"cryptography.io CA"
277                        )
278                    ]
279                )
280            )
281            .last_update(last_update)
282            .next_update(next_update)
283            .add_extension(extension, False)
284        )
285
286        crl = builder.sign(private_key, hashes.SHA256(), backend)
287        assert len(crl) == 0
288        assert len(crl.extensions) == 1
289        ext = crl.extensions.get_extension_for_class(type(extension))
290        assert ext.critical is False
291        assert ext.value == extension
292
293    @pytest.mark.requires_backend_interface(interface=RSABackend)
294    @pytest.mark.requires_backend_interface(interface=X509Backend)
295    def test_sign_multiple_extensions_critical(self, backend):
296        private_key = RSA_KEY_2048.private_key(backend)
297        last_update = datetime.datetime(2002, 1, 1, 12, 1)
298        next_update = datetime.datetime(2030, 1, 1, 12, 1)
299        ian = x509.IssuerAlternativeName(
300            [x509.UniformResourceIdentifier(u"https://cryptography.io")]
301        )
302        crl_number = x509.CRLNumber(13)
303        builder = (
304            x509.CertificateRevocationListBuilder()
305            .issuer_name(
306                x509.Name(
307                    [
308                        x509.NameAttribute(
309                            NameOID.COMMON_NAME, u"cryptography.io CA"
310                        )
311                    ]
312                )
313            )
314            .last_update(last_update)
315            .next_update(next_update)
316            .add_extension(crl_number, False)
317            .add_extension(ian, True)
318        )
319
320        crl = builder.sign(private_key, hashes.SHA256(), backend)
321        assert len(crl) == 0
322        assert len(crl.extensions) == 2
323        ext1 = crl.extensions.get_extension_for_class(x509.CRLNumber)
324        assert ext1.critical is False
325        assert ext1.value == crl_number
326        ext2 = crl.extensions.get_extension_for_class(
327            x509.IssuerAlternativeName
328        )
329        assert ext2.critical is True
330        assert ext2.value == ian
331
332    @pytest.mark.requires_backend_interface(interface=RSABackend)
333    @pytest.mark.requires_backend_interface(interface=X509Backend)
334    def test_freshestcrl_extension(self, backend):
335        private_key = RSA_KEY_2048.private_key(backend)
336        last_update = datetime.datetime(2002, 1, 1, 12, 1)
337        next_update = datetime.datetime(2030, 1, 1, 12, 1)
338        freshest = x509.FreshestCRL(
339            [
340                x509.DistributionPoint(
341                    [x509.UniformResourceIdentifier(u"http://d.om/delta")],
342                    None,
343                    None,
344                    None,
345                )
346            ]
347        )
348        builder = (
349            x509.CertificateRevocationListBuilder()
350            .issuer_name(
351                x509.Name(
352                    [
353                        x509.NameAttribute(
354                            NameOID.COMMON_NAME, u"cryptography.io CA"
355                        )
356                    ]
357                )
358            )
359            .last_update(last_update)
360            .next_update(next_update)
361            .add_extension(freshest, False)
362        )
363
364        crl = builder.sign(private_key, hashes.SHA256(), backend)
365        assert len(crl) == 0
366        assert len(crl.extensions) == 1
367        ext1 = crl.extensions.get_extension_for_class(x509.FreshestCRL)
368        assert ext1.critical is False
369        assert isinstance(ext1.value[0], x509.DistributionPoint)
370        uri = ext1.value[0].full_name[0]
371        assert isinstance(uri, x509.UniformResourceIdentifier)
372        assert uri.value == u"http://d.om/delta"
373
374    @pytest.mark.requires_backend_interface(interface=RSABackend)
375    @pytest.mark.requires_backend_interface(interface=X509Backend)
376    def test_add_unsupported_extension(self, backend):
377        private_key = RSA_KEY_2048.private_key(backend)
378        last_update = datetime.datetime(2002, 1, 1, 12, 1)
379        next_update = datetime.datetime(2030, 1, 1, 12, 1)
380        builder = (
381            x509.CertificateRevocationListBuilder()
382            .issuer_name(
383                x509.Name(
384                    [
385                        x509.NameAttribute(
386                            NameOID.COMMON_NAME, u"cryptography.io CA"
387                        )
388                    ]
389                )
390            )
391            .last_update(last_update)
392            .next_update(next_update)
393            .add_extension(x509.OCSPNoCheck(), False)
394        )
395        with pytest.raises(NotImplementedError):
396            builder.sign(private_key, hashes.SHA256(), backend)
397
398    @pytest.mark.requires_backend_interface(interface=RSABackend)
399    @pytest.mark.requires_backend_interface(interface=X509Backend)
400    def test_sign_rsa_key_too_small(self, backend):
401        private_key = RSA_KEY_512.private_key(backend)
402        last_update = datetime.datetime(2002, 1, 1, 12, 1)
403        next_update = datetime.datetime(2030, 1, 1, 12, 1)
404        builder = (
405            x509.CertificateRevocationListBuilder()
406            .issuer_name(
407                x509.Name(
408                    [
409                        x509.NameAttribute(
410                            NameOID.COMMON_NAME, u"cryptography.io CA"
411                        )
412                    ]
413                )
414            )
415            .last_update(last_update)
416            .next_update(next_update)
417        )
418
419        with pytest.raises(ValueError):
420            builder.sign(private_key, hashes.SHA512(), backend)
421
422    @pytest.mark.requires_backend_interface(interface=RSABackend)
423    @pytest.mark.requires_backend_interface(interface=X509Backend)
424    def test_sign_with_invalid_hash(self, backend):
425        private_key = RSA_KEY_2048.private_key(backend)
426        last_update = datetime.datetime(2002, 1, 1, 12, 1)
427        next_update = datetime.datetime(2030, 1, 1, 12, 1)
428        builder = (
429            x509.CertificateRevocationListBuilder()
430            .issuer_name(
431                x509.Name(
432                    [
433                        x509.NameAttribute(
434                            NameOID.COMMON_NAME, u"cryptography.io CA"
435                        )
436                    ]
437                )
438            )
439            .last_update(last_update)
440            .next_update(next_update)
441        )
442
443        with pytest.raises(TypeError):
444            builder.sign(private_key, object(), backend)
445
446    @pytest.mark.supported(
447        only_if=lambda backend: backend.ed25519_supported(),
448        skip_message="Requires OpenSSL with Ed25519 support",
449    )
450    @pytest.mark.requires_backend_interface(interface=X509Backend)
451    def test_sign_with_invalid_hash_ed25519(self, backend):
452        private_key = ed25519.Ed25519PrivateKey.generate()
453        last_update = datetime.datetime(2002, 1, 1, 12, 1)
454        next_update = datetime.datetime(2030, 1, 1, 12, 1)
455        builder = (
456            x509.CertificateRevocationListBuilder()
457            .issuer_name(
458                x509.Name(
459                    [
460                        x509.NameAttribute(
461                            NameOID.COMMON_NAME, u"cryptography.io CA"
462                        )
463                    ]
464                )
465            )
466            .last_update(last_update)
467            .next_update(next_update)
468        )
469
470        with pytest.raises(ValueError):
471            builder.sign(private_key, object(), backend)
472        with pytest.raises(ValueError):
473            builder.sign(private_key, hashes.SHA256(), backend)
474
475    @pytest.mark.supported(
476        only_if=lambda backend: backend.ed448_supported(),
477        skip_message="Requires OpenSSL with Ed448 support",
478    )
479    @pytest.mark.requires_backend_interface(interface=X509Backend)
480    def test_sign_with_invalid_hash_ed448(self, backend):
481        private_key = ed448.Ed448PrivateKey.generate()
482        last_update = datetime.datetime(2002, 1, 1, 12, 1)
483        next_update = datetime.datetime(2030, 1, 1, 12, 1)
484        builder = (
485            x509.CertificateRevocationListBuilder()
486            .issuer_name(
487                x509.Name(
488                    [
489                        x509.NameAttribute(
490                            NameOID.COMMON_NAME, u"cryptography.io CA"
491                        )
492                    ]
493                )
494            )
495            .last_update(last_update)
496            .next_update(next_update)
497        )
498
499        with pytest.raises(ValueError):
500            builder.sign(private_key, object(), backend)
501        with pytest.raises(ValueError):
502            builder.sign(private_key, hashes.SHA256(), backend)
503
504    @pytest.mark.requires_backend_interface(interface=DSABackend)
505    @pytest.mark.requires_backend_interface(interface=X509Backend)
506    def test_sign_dsa_key(self, backend):
507        private_key = DSA_KEY_2048.private_key(backend)
508        invalidity_date = x509.InvalidityDate(
509            datetime.datetime(2002, 1, 1, 0, 0)
510        )
511        ian = x509.IssuerAlternativeName(
512            [x509.UniformResourceIdentifier(u"https://cryptography.io")]
513        )
514        revoked_cert0 = (
515            x509.RevokedCertificateBuilder()
516            .serial_number(2)
517            .revocation_date(datetime.datetime(2012, 1, 1, 1, 1))
518            .add_extension(invalidity_date, False)
519            .build(backend)
520        )
521        last_update = datetime.datetime(2002, 1, 1, 12, 1)
522        next_update = datetime.datetime(2030, 1, 1, 12, 1)
523        builder = (
524            x509.CertificateRevocationListBuilder()
525            .issuer_name(
526                x509.Name(
527                    [
528                        x509.NameAttribute(
529                            NameOID.COMMON_NAME, u"cryptography.io CA"
530                        )
531                    ]
532                )
533            )
534            .last_update(last_update)
535            .next_update(next_update)
536            .add_revoked_certificate(revoked_cert0)
537            .add_extension(ian, False)
538        )
539
540        crl = builder.sign(private_key, hashes.SHA256(), backend)
541        assert (
542            crl.extensions.get_extension_for_class(
543                x509.IssuerAlternativeName
544            ).value
545            == ian
546        )
547        assert crl[0].serial_number == revoked_cert0.serial_number
548        assert crl[0].revocation_date == revoked_cert0.revocation_date
549        assert len(crl[0].extensions) == 1
550        ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
551        assert ext.critical is False
552        assert ext.value == invalidity_date
553
554    @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
555    @pytest.mark.requires_backend_interface(interface=X509Backend)
556    def test_sign_ec_key(self, backend):
557        _skip_curve_unsupported(backend, ec.SECP256R1())
558        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
559        invalidity_date = x509.InvalidityDate(
560            datetime.datetime(2002, 1, 1, 0, 0)
561        )
562        ian = x509.IssuerAlternativeName(
563            [x509.UniformResourceIdentifier(u"https://cryptography.io")]
564        )
565        revoked_cert0 = (
566            x509.RevokedCertificateBuilder()
567            .serial_number(2)
568            .revocation_date(datetime.datetime(2012, 1, 1, 1, 1))
569            .add_extension(invalidity_date, False)
570            .build(backend)
571        )
572        last_update = datetime.datetime(2002, 1, 1, 12, 1)
573        next_update = datetime.datetime(2030, 1, 1, 12, 1)
574        builder = (
575            x509.CertificateRevocationListBuilder()
576            .issuer_name(
577                x509.Name(
578                    [
579                        x509.NameAttribute(
580                            NameOID.COMMON_NAME, u"cryptography.io CA"
581                        )
582                    ]
583                )
584            )
585            .last_update(last_update)
586            .next_update(next_update)
587            .add_revoked_certificate(revoked_cert0)
588            .add_extension(ian, False)
589        )
590
591        crl = builder.sign(private_key, hashes.SHA256(), backend)
592        assert (
593            crl.extensions.get_extension_for_class(
594                x509.IssuerAlternativeName
595            ).value
596            == ian
597        )
598        assert crl[0].serial_number == revoked_cert0.serial_number
599        assert crl[0].revocation_date == revoked_cert0.revocation_date
600        assert len(crl[0].extensions) == 1
601        ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
602        assert ext.critical is False
603        assert ext.value == invalidity_date
604
605    @pytest.mark.supported(
606        only_if=lambda backend: backend.ed25519_supported(),
607        skip_message="Requires OpenSSL with Ed25519 support",
608    )
609    @pytest.mark.requires_backend_interface(interface=X509Backend)
610    def test_sign_ed25519_key(self, backend):
611        private_key = ed25519.Ed25519PrivateKey.generate()
612        invalidity_date = x509.InvalidityDate(
613            datetime.datetime(2002, 1, 1, 0, 0)
614        )
615        ian = x509.IssuerAlternativeName(
616            [x509.UniformResourceIdentifier(u"https://cryptography.io")]
617        )
618        revoked_cert0 = (
619            x509.RevokedCertificateBuilder()
620            .serial_number(2)
621            .revocation_date(datetime.datetime(2012, 1, 1, 1, 1))
622            .add_extension(invalidity_date, False)
623            .build(backend)
624        )
625        last_update = datetime.datetime(2002, 1, 1, 12, 1)
626        next_update = datetime.datetime(2030, 1, 1, 12, 1)
627        builder = (
628            x509.CertificateRevocationListBuilder()
629            .issuer_name(
630                x509.Name(
631                    [
632                        x509.NameAttribute(
633                            NameOID.COMMON_NAME, u"cryptography.io CA"
634                        )
635                    ]
636                )
637            )
638            .last_update(last_update)
639            .next_update(next_update)
640            .add_revoked_certificate(revoked_cert0)
641            .add_extension(ian, False)
642        )
643
644        crl = builder.sign(private_key, None, backend)
645        assert crl.signature_hash_algorithm is None
646        assert crl.signature_algorithm_oid == SignatureAlgorithmOID.ED25519
647        assert (
648            crl.extensions.get_extension_for_class(
649                x509.IssuerAlternativeName
650            ).value
651            == ian
652        )
653        assert crl[0].serial_number == revoked_cert0.serial_number
654        assert crl[0].revocation_date == revoked_cert0.revocation_date
655        assert len(crl[0].extensions) == 1
656        ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
657        assert ext.critical is False
658        assert ext.value == invalidity_date
659
660    @pytest.mark.supported(
661        only_if=lambda backend: backend.ed448_supported(),
662        skip_message="Requires OpenSSL with Ed448 support",
663    )
664    @pytest.mark.requires_backend_interface(interface=X509Backend)
665    def test_sign_ed448_key(self, backend):
666        private_key = ed448.Ed448PrivateKey.generate()
667        invalidity_date = x509.InvalidityDate(
668            datetime.datetime(2002, 1, 1, 0, 0)
669        )
670        ian = x509.IssuerAlternativeName(
671            [x509.UniformResourceIdentifier(u"https://cryptography.io")]
672        )
673        revoked_cert0 = (
674            x509.RevokedCertificateBuilder()
675            .serial_number(2)
676            .revocation_date(datetime.datetime(2012, 1, 1, 1, 1))
677            .add_extension(invalidity_date, False)
678            .build(backend)
679        )
680        last_update = datetime.datetime(2002, 1, 1, 12, 1)
681        next_update = datetime.datetime(2030, 1, 1, 12, 1)
682        builder = (
683            x509.CertificateRevocationListBuilder()
684            .issuer_name(
685                x509.Name(
686                    [
687                        x509.NameAttribute(
688                            NameOID.COMMON_NAME, u"cryptography.io CA"
689                        )
690                    ]
691                )
692            )
693            .last_update(last_update)
694            .next_update(next_update)
695            .add_revoked_certificate(revoked_cert0)
696            .add_extension(ian, False)
697        )
698
699        crl = builder.sign(private_key, None, backend)
700        assert crl.signature_hash_algorithm is None
701        assert crl.signature_algorithm_oid == SignatureAlgorithmOID.ED448
702        assert (
703            crl.extensions.get_extension_for_class(
704                x509.IssuerAlternativeName
705            ).value
706            == ian
707        )
708        assert crl[0].serial_number == revoked_cert0.serial_number
709        assert crl[0].revocation_date == revoked_cert0.revocation_date
710        assert len(crl[0].extensions) == 1
711        ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
712        assert ext.critical is False
713        assert ext.value == invalidity_date
714
715    @pytest.mark.requires_backend_interface(interface=DSABackend)
716    @pytest.mark.requires_backend_interface(interface=X509Backend)
717    def test_dsa_key_sign_md5(self, backend):
718        private_key = DSA_KEY_2048.private_key(backend)
719        last_time = datetime.datetime(2012, 1, 16, 22, 43)
720        next_time = datetime.datetime(2022, 1, 17, 6, 43)
721        builder = (
722            x509.CertificateRevocationListBuilder()
723            .issuer_name(
724                x509.Name(
725                    [
726                        x509.NameAttribute(
727                            NameOID.COMMON_NAME, u"cryptography.io CA"
728                        )
729                    ]
730                )
731            )
732            .last_update(last_time)
733            .next_update(next_time)
734        )
735
736        with pytest.raises(ValueError):
737            builder.sign(private_key, hashes.MD5(), backend)
738
739    @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
740    @pytest.mark.requires_backend_interface(interface=X509Backend)
741    def test_ec_key_sign_md5(self, backend):
742        _skip_curve_unsupported(backend, ec.SECP256R1())
743        private_key = EC_KEY_SECP256R1.private_key(backend)
744        last_time = datetime.datetime(2012, 1, 16, 22, 43)
745        next_time = datetime.datetime(2022, 1, 17, 6, 43)
746        builder = (
747            x509.CertificateRevocationListBuilder()
748            .issuer_name(
749                x509.Name(
750                    [
751                        x509.NameAttribute(
752                            NameOID.COMMON_NAME, u"cryptography.io CA"
753                        )
754                    ]
755                )
756            )
757            .last_update(last_time)
758            .next_update(next_time)
759        )
760
761        with pytest.raises(ValueError):
762            builder.sign(private_key, hashes.MD5(), backend)
763
764    @pytest.mark.requires_backend_interface(interface=RSABackend)
765    @pytest.mark.requires_backend_interface(interface=X509Backend)
766    def test_sign_with_revoked_certificates(self, backend):
767        private_key = RSA_KEY_2048.private_key(backend)
768        last_update = datetime.datetime(2002, 1, 1, 12, 1)
769        next_update = datetime.datetime(2030, 1, 1, 12, 1)
770        invalidity_date = x509.InvalidityDate(
771            datetime.datetime(2002, 1, 1, 0, 0)
772        )
773        revoked_cert0 = (
774            x509.RevokedCertificateBuilder()
775            .serial_number(38)
776            .revocation_date(datetime.datetime(2011, 1, 1, 1, 1))
777            .build(backend)
778        )
779        revoked_cert1 = (
780            x509.RevokedCertificateBuilder()
781            .serial_number(2)
782            .revocation_date(datetime.datetime(2012, 1, 1, 1, 1))
783            .add_extension(invalidity_date, False)
784            .build(backend)
785        )
786        builder = (
787            x509.CertificateRevocationListBuilder()
788            .issuer_name(
789                x509.Name(
790                    [
791                        x509.NameAttribute(
792                            NameOID.COMMON_NAME, u"cryptography.io CA"
793                        )
794                    ]
795                )
796            )
797            .last_update(last_update)
798            .next_update(next_update)
799            .add_revoked_certificate(revoked_cert0)
800            .add_revoked_certificate(revoked_cert1)
801        )
802
803        crl = builder.sign(private_key, hashes.SHA256(), backend)
804        assert len(crl) == 2
805        assert crl.last_update == last_update
806        assert crl.next_update == next_update
807        assert crl[0].serial_number == revoked_cert0.serial_number
808        assert crl[0].revocation_date == revoked_cert0.revocation_date
809        assert len(crl[0].extensions) == 0
810        assert crl[1].serial_number == revoked_cert1.serial_number
811        assert crl[1].revocation_date == revoked_cert1.revocation_date
812        assert len(crl[1].extensions) == 1
813        ext = crl[1].extensions.get_extension_for_class(x509.InvalidityDate)
814        assert ext.critical is False
815        assert ext.value == invalidity_date
816