• 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 X509Backend
15
16
17class TestRevokedCertificateBuilder(object):
18    def test_serial_number_must_be_integer(self):
19        with pytest.raises(TypeError):
20            x509.RevokedCertificateBuilder().serial_number("notanx509name")
21
22    def test_serial_number_must_be_non_negative(self):
23        with pytest.raises(ValueError):
24            x509.RevokedCertificateBuilder().serial_number(-1)
25
26    def test_serial_number_must_be_positive(self):
27        with pytest.raises(ValueError):
28            x509.RevokedCertificateBuilder().serial_number(0)
29
30    @pytest.mark.requires_backend_interface(interface=X509Backend)
31    def test_minimal_serial_number(self, backend):
32        revocation_date = datetime.datetime(2002, 1, 1, 12, 1)
33        builder = (
34            x509.RevokedCertificateBuilder()
35            .serial_number(1)
36            .revocation_date(revocation_date)
37        )
38
39        revoked_certificate = builder.build(backend)
40        assert revoked_certificate.serial_number == 1
41
42    @pytest.mark.requires_backend_interface(interface=X509Backend)
43    def test_biggest_serial_number(self, backend):
44        revocation_date = datetime.datetime(2002, 1, 1, 12, 1)
45        builder = (
46            x509.RevokedCertificateBuilder()
47            .serial_number((1 << 159) - 1)
48            .revocation_date(revocation_date)
49        )
50
51        revoked_certificate = builder.build(backend)
52        assert revoked_certificate.serial_number == (1 << 159) - 1
53
54    def test_serial_number_must_be_less_than_160_bits_long(self):
55        with pytest.raises(ValueError):
56            x509.RevokedCertificateBuilder().serial_number(1 << 159)
57
58    def test_set_serial_number_twice(self):
59        builder = x509.RevokedCertificateBuilder().serial_number(3)
60        with pytest.raises(ValueError):
61            builder.serial_number(4)
62
63    @pytest.mark.requires_backend_interface(interface=X509Backend)
64    def test_aware_revocation_date(self, backend):
65        time = datetime.datetime(2012, 1, 16, 22, 43)
66        tz = pytz.timezone("US/Pacific")
67        time = tz.localize(time)
68        utc_time = datetime.datetime(2012, 1, 17, 6, 43)
69        serial_number = 333
70        builder = (
71            x509.RevokedCertificateBuilder()
72            .serial_number(serial_number)
73            .revocation_date(time)
74        )
75
76        revoked_certificate = builder.build(backend)
77        assert revoked_certificate.revocation_date == utc_time
78
79    def test_revocation_date_invalid(self):
80        with pytest.raises(TypeError):
81            x509.RevokedCertificateBuilder().revocation_date("notadatetime")
82
83    def test_revocation_date_before_1950(self):
84        with pytest.raises(ValueError):
85            x509.RevokedCertificateBuilder().revocation_date(
86                datetime.datetime(1940, 8, 10)
87            )
88
89    def test_set_revocation_date_twice(self):
90        builder = x509.RevokedCertificateBuilder().revocation_date(
91            datetime.datetime(2002, 1, 1, 12, 1)
92        )
93        with pytest.raises(ValueError):
94            builder.revocation_date(datetime.datetime(2002, 1, 1, 12, 1))
95
96    def test_add_extension_checks_for_duplicates(self):
97        builder = x509.RevokedCertificateBuilder().add_extension(
98            x509.CRLReason(x509.ReasonFlags.ca_compromise), False
99        )
100
101        with pytest.raises(ValueError):
102            builder.add_extension(
103                x509.CRLReason(x509.ReasonFlags.ca_compromise), False
104            )
105
106    def test_add_invalid_extension(self):
107        with pytest.raises(TypeError):
108            x509.RevokedCertificateBuilder().add_extension(
109                "notanextension", False
110            )
111
112    @pytest.mark.requires_backend_interface(interface=X509Backend)
113    def test_no_serial_number(self, backend):
114        builder = x509.RevokedCertificateBuilder().revocation_date(
115            datetime.datetime(2002, 1, 1, 12, 1)
116        )
117
118        with pytest.raises(ValueError):
119            builder.build(backend)
120
121    @pytest.mark.requires_backend_interface(interface=X509Backend)
122    def test_no_revocation_date(self, backend):
123        builder = x509.RevokedCertificateBuilder().serial_number(3)
124
125        with pytest.raises(ValueError):
126            builder.build(backend)
127
128    @pytest.mark.requires_backend_interface(interface=X509Backend)
129    def test_create_revoked(self, backend):
130        serial_number = 333
131        revocation_date = datetime.datetime(2002, 1, 1, 12, 1)
132        builder = (
133            x509.RevokedCertificateBuilder()
134            .serial_number(serial_number)
135            .revocation_date(revocation_date)
136        )
137
138        revoked_certificate = builder.build(backend)
139        assert revoked_certificate.serial_number == serial_number
140        assert revoked_certificate.revocation_date == revocation_date
141        assert len(revoked_certificate.extensions) == 0
142
143    @pytest.mark.parametrize(
144        "extension",
145        [
146            x509.InvalidityDate(datetime.datetime(2015, 1, 1, 0, 0)),
147            x509.CRLReason(x509.ReasonFlags.ca_compromise),
148            x509.CertificateIssuer([x509.DNSName(u"cryptography.io")]),
149        ],
150    )
151    @pytest.mark.requires_backend_interface(interface=X509Backend)
152    def test_add_extensions(self, backend, extension):
153        serial_number = 333
154        revocation_date = datetime.datetime(2002, 1, 1, 12, 1)
155        builder = (
156            x509.RevokedCertificateBuilder()
157            .serial_number(serial_number)
158            .revocation_date(revocation_date)
159            .add_extension(extension, False)
160        )
161
162        revoked_certificate = builder.build(backend)
163        assert revoked_certificate.serial_number == serial_number
164        assert revoked_certificate.revocation_date == revocation_date
165        assert len(revoked_certificate.extensions) == 1
166        ext = revoked_certificate.extensions.get_extension_for_class(
167            type(extension)
168        )
169        assert ext.critical is False
170        assert ext.value == extension
171
172    @pytest.mark.requires_backend_interface(interface=X509Backend)
173    def test_add_multiple_extensions(self, backend):
174        serial_number = 333
175        revocation_date = datetime.datetime(2002, 1, 1, 12, 1)
176        invalidity_date = x509.InvalidityDate(
177            datetime.datetime(2015, 1, 1, 0, 0)
178        )
179        certificate_issuer = x509.CertificateIssuer(
180            [x509.DNSName(u"cryptography.io")]
181        )
182        crl_reason = x509.CRLReason(x509.ReasonFlags.aa_compromise)
183        builder = (
184            x509.RevokedCertificateBuilder()
185            .serial_number(serial_number)
186            .revocation_date(revocation_date)
187            .add_extension(invalidity_date, True)
188            .add_extension(crl_reason, True)
189            .add_extension(certificate_issuer, True)
190        )
191
192        revoked_certificate = builder.build(backend)
193        assert len(revoked_certificate.extensions) == 3
194        for ext_data in [invalidity_date, certificate_issuer, crl_reason]:
195            ext = revoked_certificate.extensions.get_extension_for_class(
196                type(ext_data)
197            )
198            assert ext.critical is True
199            assert ext.value == ext_data
200