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