diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/hazmat/backends/test_multibackend.py | 12 | ||||
-rw-r--r-- | tests/hazmat/bindings/test_openssl.py | 4 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_keywrap.py | 116 | ||||
-rw-r--r-- | tests/test_x509.py | 355 | ||||
-rw-r--r-- | tests/test_x509_ext.py | 14 |
5 files changed, 499 insertions, 2 deletions
diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index 2a533750..81a64ce0 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -200,6 +200,12 @@ class DummyX509Backend(object): def load_der_x509_certificate(self, data): pass + def load_pem_x509_crl(self, data): + pass + + def load_der_x509_crl(self, data): + pass + def load_pem_x509_csr(self, data): pass @@ -502,6 +508,8 @@ class TestMultiBackend(object): backend.load_pem_x509_certificate(b"certdata") backend.load_der_x509_certificate(b"certdata") + backend.load_pem_x509_crl(b"crldata") + backend.load_der_x509_crl(b"crldata") backend.load_pem_x509_csr(b"reqdata") backend.load_der_x509_csr(b"reqdata") backend.create_x509_csr(object(), b"privatekey", hashes.SHA1()) @@ -513,6 +521,10 @@ class TestMultiBackend(object): with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509): backend.load_der_x509_certificate(b"certdata") with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509): + backend.load_pem_x509_crl(b"crldata") + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509): + backend.load_der_x509_crl(b"crldata") + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509): backend.load_pem_x509_csr(b"reqdata") with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509): backend.load_der_x509_csr(b"reqdata") diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py index 20171fa7..76a9218b 100644 --- a/tests/hazmat/bindings/test_openssl.py +++ b/tests/hazmat/bindings/test_openssl.py @@ -89,8 +89,8 @@ class TestOpenSSL(object): def test_add_engine_more_than_once(self): b = Binding() - with pytest.raises(RuntimeError): - b._register_osrandom_engine() + b._register_osrandom_engine() + assert b.lib.ERR_get_error() == 0 def test_ssl_ctx_options(self): # Test that we're properly handling 32-bit unsigned on all platforms. diff --git a/tests/hazmat/primitives/test_keywrap.py b/tests/hazmat/primitives/test_keywrap.py new file mode 100644 index 00000000..f1238c9a --- /dev/null +++ b/tests/hazmat/primitives/test_keywrap.py @@ -0,0 +1,116 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii +import os + +import pytest + +from cryptography.hazmat.backends.interfaces import CipherBackend +from cryptography.hazmat.primitives import keywrap +from cryptography.hazmat.primitives.ciphers import algorithms, modes + +from .utils import _load_all_params +from ...utils import load_nist_vectors + + +@pytest.mark.requires_backend_interface(interface=CipherBackend) +class TestAESKeyWrap(object): + @pytest.mark.parametrize( + "params", + _load_all_params( + os.path.join("keywrap", "kwtestvectors"), + ["KW_AE_128.txt", "KW_AE_192.txt", "KW_AE_256.txt"], + load_nist_vectors + ) + ) + @pytest.mark.supported( + only_if=lambda backend: backend.cipher_supported( + algorithms.AES("\x00" * 16), modes.ECB() + ), + skip_message="Does not support AES key wrap (RFC 3394) because AES-ECB" + " is unsupported", + ) + def test_wrap(self, backend, params): + wrapping_key = binascii.unhexlify(params["k"]) + key_to_wrap = binascii.unhexlify(params["p"]) + wrapped_key = keywrap.aes_key_wrap(wrapping_key, key_to_wrap, backend) + assert params["c"] == binascii.hexlify(wrapped_key) + + @pytest.mark.parametrize( + "params", + _load_all_params( + os.path.join("keywrap", "kwtestvectors"), + ["KW_AD_128.txt", "KW_AD_192.txt", "KW_AD_256.txt"], + load_nist_vectors + ) + ) + @pytest.mark.supported( + only_if=lambda backend: backend.cipher_supported( + algorithms.AES("\x00" * 16), modes.ECB() + ), + skip_message="Does not support AES key wrap (RFC 3394) because AES-ECB" + " is unsupported", + ) + def test_unwrap(self, backend, params): + wrapping_key = binascii.unhexlify(params["k"]) + wrapped_key = binascii.unhexlify(params["c"]) + if params.get("fail") is True: + with pytest.raises(keywrap.InvalidUnwrap): + keywrap.aes_key_unwrap(wrapping_key, wrapped_key, backend) + else: + unwrapped_key = keywrap.aes_key_unwrap( + wrapping_key, wrapped_key, backend + ) + assert params["p"] == binascii.hexlify(unwrapped_key) + + @pytest.mark.supported( + only_if=lambda backend: backend.cipher_supported( + algorithms.AES("\x00" * 16), modes.ECB() + ), + skip_message="Does not support AES key wrap (RFC 3394) because AES-ECB" + " is unsupported", + ) + def test_wrap_invalid_key_length(self, backend): + # The wrapping key must be of length [16, 24, 32] + with pytest.raises(ValueError): + keywrap.aes_key_wrap(b"badkey", b"sixteen_byte_key", backend) + + @pytest.mark.supported( + only_if=lambda backend: backend.cipher_supported( + algorithms.AES("\x00" * 16), modes.ECB() + ), + skip_message="Does not support AES key wrap (RFC 3394) because AES-ECB" + " is unsupported", + ) + def test_unwrap_invalid_key_length(self, backend): + with pytest.raises(ValueError): + keywrap.aes_key_unwrap(b"badkey", b"\x00" * 24, backend) + + @pytest.mark.supported( + only_if=lambda backend: backend.cipher_supported( + algorithms.AES("\x00" * 16), modes.ECB() + ), + skip_message="Does not support AES key wrap (RFC 3394) because AES-ECB" + " is unsupported", + ) + def test_wrap_invalid_key_to_wrap_length(self, backend): + # Keys to wrap must be at least 16 bytes long + with pytest.raises(ValueError): + keywrap.aes_key_wrap(b"sixteen_byte_key", b"\x00" * 15, backend) + + # Keys to wrap must be a multiple of 8 bytes + with pytest.raises(ValueError): + keywrap.aes_key_wrap(b"sixteen_byte_key", b"\x00" * 23, backend) + + def test_unwrap_invalid_wrapped_key_length(self, backend): + # Keys to unwrap must be at least 24 bytes + with pytest.raises(ValueError): + keywrap.aes_key_unwrap(b"sixteen_byte_key", b"\x00" * 16, backend) + + # Keys to unwrap must be a multiple of 8 bytes + with pytest.raises(ValueError): + keywrap.aes_key_unwrap(b"sixteen_byte_key", b"\x00" * 27, backend) diff --git a/tests/test_x509.py b/tests/test_x509.py index 43eca472..4072ef15 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -56,6 +56,255 @@ def _load_cert(filename, loader, backend): return cert +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestCertificateRevocationList(object): + def test_load_pem_crl(self, backend): + crl = _load_cert( + os.path.join("x509", "custom", "crl_all_reasons.pem"), + x509.load_pem_x509_crl, + backend + ) + + assert isinstance(crl, x509.CertificateRevocationList) + fingerprint = binascii.hexlify(crl.fingerprint(hashes.SHA1())) + assert fingerprint == b"3234b0cb4c0cedf6423724b736729dcfc9e441ef" + assert isinstance(crl.signature_hash_algorithm, hashes.SHA256) + + def test_load_der_crl(self, backend): + crl = _load_cert( + os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"), + x509.load_der_x509_crl, + backend + ) + + assert isinstance(crl, x509.CertificateRevocationList) + fingerprint = binascii.hexlify(crl.fingerprint(hashes.SHA1())) + assert fingerprint == b"dd3db63c50f4c4a13e090f14053227cb1011a5ad" + assert isinstance(crl.signature_hash_algorithm, hashes.SHA256) + + def test_invalid_pem(self, backend): + with pytest.raises(ValueError): + x509.load_pem_x509_crl(b"notacrl", backend) + + def test_invalid_der(self, backend): + with pytest.raises(ValueError): + x509.load_der_x509_crl(b"notacrl", backend) + + def test_unknown_signature_algorithm(self, backend): + crl = _load_cert( + os.path.join( + "x509", "custom", "crl_md2_unknown_crit_entry_ext.pem" + ), + x509.load_pem_x509_crl, + backend + ) + + with pytest.raises(UnsupportedAlgorithm): + crl.signature_hash_algorithm() + + def test_issuer(self, backend): + crl = _load_cert( + os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"), + x509.load_der_x509_crl, + backend + ) + + assert isinstance(crl.issuer, x509.Name) + assert list(crl.issuer) == [ + x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'), + x509.NameAttribute( + x509.OID_ORGANIZATION_NAME, u'Test Certificates 2011' + ), + x509.NameAttribute(x509.OID_COMMON_NAME, u'Good CA') + ] + assert crl.issuer.get_attributes_for_oid(x509.OID_COMMON_NAME) == [ + x509.NameAttribute(x509.OID_COMMON_NAME, u'Good CA') + ] + + def test_equality(self, backend): + crl1 = _load_cert( + os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"), + x509.load_der_x509_crl, + backend + ) + + crl2 = _load_cert( + os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"), + x509.load_der_x509_crl, + backend + ) + + crl3 = _load_cert( + os.path.join("x509", "custom", "crl_all_reasons.pem"), + x509.load_pem_x509_crl, + backend + ) + + assert crl1 == crl2 + assert crl1 != crl3 + assert crl1 != object() + + def test_update_dates(self, backend): + crl = _load_cert( + os.path.join("x509", "custom", "crl_all_reasons.pem"), + x509.load_pem_x509_crl, + backend + ) + + assert isinstance(crl.next_update, datetime.datetime) + assert isinstance(crl.last_update, datetime.datetime) + + assert crl.next_update.isoformat() == "2016-01-01T00:00:00" + assert crl.last_update.isoformat() == "2015-01-01T00:00:00" + + def test_revoked_cert_retrieval(self, backend): + crl = _load_cert( + os.path.join("x509", "custom", "crl_all_reasons.pem"), + x509.load_pem_x509_crl, + backend + ) + + for r in crl: + assert isinstance(r, x509.RevokedCertificate) + + # Check that len() works for CRLs. + assert len(crl) == 12 + + def test_extensions(self, backend): + crl = _load_cert( + os.path.join("x509", "custom", "crl_all_reasons.pem"), + x509.load_pem_x509_crl, + backend + ) + + # CRL extensions are currently not supported in the OpenSSL backend. + with pytest.raises(NotImplementedError): + crl.extensions + + +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestRevokedCertificate(object): + + def test_revoked_basics(self, backend): + crl = _load_cert( + os.path.join("x509", "custom", "crl_all_reasons.pem"), + x509.load_pem_x509_crl, + backend + ) + + for i, rev in enumerate(crl): + assert isinstance(rev, x509.RevokedCertificate) + assert isinstance(rev.serial_number, int) + assert isinstance(rev.revocation_date, datetime.datetime) + assert isinstance(rev.extensions, x509.Extensions) + + assert rev.serial_number == i + assert rev.revocation_date.isoformat() == "2015-01-01T00:00:00" + + def test_revoked_extensions(self, backend): + crl = _load_cert( + os.path.join("x509", "custom", "crl_all_reasons.pem"), + x509.load_pem_x509_crl, + backend + ) + + exp_issuer = x509.GeneralNames([ + x509.DirectoryName(x509.Name([ + x509.NameAttribute(x509.OID_COUNTRY_NAME, u"US"), + x509.NameAttribute(x509.OID_COMMON_NAME, u"cryptography.io"), + ])) + ]) + + # First revoked cert doesn't have extensions, test if it is handled + # correctly. + rev0 = crl[0] + # It should return an empty Extensions object. + assert isinstance(rev0.extensions, x509.Extensions) + assert len(rev0.extensions) == 0 + with pytest.raises(x509.ExtensionNotFound): + rev0.extensions.get_extension_for_oid(x509.OID_CRL_REASON) + with pytest.raises(x509.ExtensionNotFound): + rev0.extensions.get_extension_for_oid(x509.OID_CERTIFICATE_ISSUER) + with pytest.raises(x509.ExtensionNotFound): + rev0.extensions.get_extension_for_oid(x509.OID_INVALIDITY_DATE) + + # Test manual retrieval of extension values. + rev1 = crl[1] + assert isinstance(rev1.extensions, x509.Extensions) + + reason = rev1.extensions.get_extension_for_oid( + x509.OID_CRL_REASON).value + assert reason == x509.ReasonFlags.unspecified + + issuer = rev1.extensions.get_extension_for_oid( + x509.OID_CERTIFICATE_ISSUER).value + assert issuer == exp_issuer + + date = rev1.extensions.get_extension_for_oid( + x509.OID_INVALIDITY_DATE).value + assert isinstance(date, datetime.datetime) + assert date.isoformat() == "2015-01-01T00:00:00" + + # Check if all reason flags can be found in the CRL. + flags = set(x509.ReasonFlags) + for rev in crl: + try: + r = rev.extensions.get_extension_for_oid(x509.OID_CRL_REASON) + except x509.ExtensionNotFound: + # Not all revoked certs have a reason extension. + pass + else: + flags.discard(r.value) + + assert len(flags) == 0 + + def test_duplicate_entry_ext(self, backend): + crl = _load_cert( + os.path.join("x509", "custom", "crl_dup_entry_ext.pem"), + x509.load_pem_x509_crl, + backend + ) + + with pytest.raises(x509.DuplicateExtension): + crl[0].extensions + + def test_unsupported_crit_entry_ext(self, backend): + crl = _load_cert( + os.path.join( + "x509", "custom", "crl_md2_unknown_crit_entry_ext.pem" + ), + x509.load_pem_x509_crl, + backend + ) + + with pytest.raises(x509.UnsupportedExtension): + crl[0].extensions + + def test_unsupported_reason(self, backend): + crl = _load_cert( + os.path.join( + "x509", "custom", "crl_unsupported_reason.pem" + ), + x509.load_pem_x509_crl, + backend + ) + + with pytest.raises(ValueError): + crl[0].extensions + + def test_invalid_cert_issuer_ext(self, backend): + crl = _load_cert( + os.path.join( + "x509", "custom", "crl_inval_cert_issuer_entry_ext.pem" + ), + x509.load_pem_x509_crl, + backend + ) + + with pytest.raises(ValueError): + crl[0].extensions + + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) class TestRSACertificate(object): @@ -1486,6 +1735,95 @@ class TestCertificateBuilder(object): with pytest.raises(ValueError): builder.sign(issuer_private_key, hashes.SHA512(), backend) + @pytest.mark.parametrize( + "cp", + [ + x509.CertificatePolicies([ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [u"http://other.com/cps"] + ) + ]), + x509.CertificatePolicies([ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + None + ) + ]), + x509.CertificatePolicies([ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [ + u"http://example.com/cps", + u"http://other.com/cps", + x509.UserNotice( + x509.NoticeReference(u"my org", [1, 2, 3, 4]), + u"thing" + ) + ] + ) + ]), + x509.CertificatePolicies([ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [ + u"http://example.com/cps", + x509.UserNotice( + x509.NoticeReference(u"UTF8\u2122'", [1, 2, 3, 4]), + u"We heart UTF8!\u2122" + ) + ] + ) + ]), + x509.CertificatePolicies([ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [x509.UserNotice(None, u"thing")] + ) + ]), + x509.CertificatePolicies([ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [ + x509.UserNotice( + x509.NoticeReference(u"my org", [1, 2, 3, 4]), + None + ) + ] + ) + ]) + ] + ) + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_certificate_policies(self, cp, backend): + issuer_private_key = RSA_KEY_2048.private_key(backend) + subject_private_key = RSA_KEY_2048.private_key(backend) + + not_valid_before = datetime.datetime(2002, 1, 1, 12, 1) + not_valid_after = datetime.datetime(2030, 12, 31, 8, 30) + + cert = x509.CertificateBuilder().subject_name( + x509.Name([x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US')]) + ).issuer_name( + x509.Name([x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US')]) + ).not_valid_before( + not_valid_before + ).not_valid_after( + not_valid_after + ).public_key( + subject_private_key.public_key() + ).serial_number( + 123 + ).add_extension( + cp, critical=False + ).sign(issuer_private_key, hashes.SHA256(), backend) + + ext = cert.extensions.get_extension_for_oid( + x509.OID_CERTIFICATE_POLICIES + ) + assert ext.value == cp + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_issuer_alt_name(self, backend): @@ -2547,6 +2885,23 @@ class TestName(object): assert name1 != name2 assert name1 != object() + def test_hash(self): + name1 = x509.Name([ + x509.NameAttribute(x509.ObjectIdentifier('oid'), u'value1'), + x509.NameAttribute(x509.ObjectIdentifier('oid2'), u'value2'), + ]) + name2 = x509.Name([ + x509.NameAttribute(x509.ObjectIdentifier('oid'), u'value1'), + x509.NameAttribute(x509.ObjectIdentifier('oid2'), u'value2'), + ]) + name3 = x509.Name([ + x509.NameAttribute(x509.ObjectIdentifier('oid2'), u'value2'), + x509.NameAttribute(x509.ObjectIdentifier('oid'), u'value1'), + ]) + + assert hash(name1) == hash(name2) + assert hash(name1) != hash(name3) + def test_repr(self): name = x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, u'cryptography.io'), diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index 1bc14620..8f469366 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -857,6 +857,20 @@ class TestExtensions(object): assert ext is not None assert isinstance(ext.value, x509.BasicConstraints) + def test_repr(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "basic_constraints_not_critical.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + assert repr(cert.extensions) == ( + "<Extensions([<Extension(oid=<ObjectIdentifier(oid=2.5.29.19, name" + "=basicConstraints)>, critical=False, value=<BasicConstraints(ca=F" + "alse, path_length=None)>)>])>" + ) + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) |