diff options
author | Paul Kehrer <paul.l.kehrer@gmail.com> | 2015-08-03 16:04:06 +0100 |
---|---|---|
committer | Paul Kehrer <paul.l.kehrer@gmail.com> | 2015-08-03 16:04:06 +0100 |
commit | b69aa4cdacb6e85845f590e528f7e9a471d7dd36 (patch) | |
tree | 943886277c3549cc62c6f5a40d7a5d7d9a274061 /tests | |
parent | 93b5e3efab0337c51c84c27208d9034b607f09e2 (diff) | |
parent | 46479d0d21755b47e14659ecd73bb0caf4074268 (diff) | |
download | cryptography-b69aa4cdacb6e85845f590e528f7e9a471d7dd36.tar.gz cryptography-b69aa4cdacb6e85845f590e528f7e9a471d7dd36.tar.bz2 cryptography-b69aa4cdacb6e85845f590e528f7e9a471d7dd36.zip |
Merge pull request #2098 from sigmavirus24/cert-builder
Adds certificate builder.
Diffstat (limited to 'tests')
-rw-r--r-- | tests/hazmat/backends/test_multibackend.py | 8 | ||||
-rw-r--r-- | tests/hazmat/backends/test_openssl.py | 29 | ||||
-rw-r--r-- | tests/test_x509.py | 346 |
3 files changed, 382 insertions, 1 deletions
diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index 3c05cdfa..d516af16 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -206,6 +206,9 @@ class DummyX509Backend(object): def create_x509_csr(self, builder, private_key, algorithm): pass + def sign_x509_certificate(self, builder, private_key, algorithm): + pass + class TestMultiBackend(object): def test_ciphers(self): @@ -484,6 +487,7 @@ class TestMultiBackend(object): backend.load_pem_x509_csr(b"reqdata") backend.load_der_x509_csr(b"reqdata") backend.create_x509_csr(object(), b"privatekey", hashes.SHA1()) + backend.sign_x509_certificate(object(), b"privatekey", hashes.SHA1()) backend = MultiBackend([]) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509): @@ -496,3 +500,7 @@ class TestMultiBackend(object): backend.load_der_x509_csr(b"reqdata") with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509): backend.create_x509_csr(object(), b"privatekey", hashes.SHA1()) + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509): + backend.sign_x509_certificate( + object(), b"privatekey", hashes.SHA1() + ) diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 040e3677..c2a4f544 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -4,6 +4,7 @@ from __future__ import absolute_import, division, print_function +import datetime import os import subprocess import sys @@ -14,6 +15,7 @@ import pretend import pytest from cryptography import utils +from cryptography import x509 from cryptography.exceptions import InternalError, _Reasons from cryptography.hazmat.backends.interfaces import RSABackend from cryptography.hazmat.backends.openssl.backend import ( @@ -505,6 +507,33 @@ class TestOpenSSLCreateX509CSR(object): backend.create_x509_csr(object(), private_key, hashes.SHA1()) +class TestOpenSSLSignX509Certificate(object): + def test_requires_certificate_builder(self): + private_key = RSA_KEY_2048.private_key(backend) + + with pytest.raises(TypeError): + backend.sign_x509_certificate(object(), private_key, DummyHash()) + + def test_checks_for_unsupported_extensions(self): + private_key = RSA_KEY_2048.private_key(backend) + builder = x509.CertificateBuilder().subject_name(x509.Name([ + x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'), + ])).public_key( + private_key.public_key() + ).serial_number( + 777 + ).not_valid_before( + datetime.datetime(1999, 1, 1) + ).not_valid_after( + datetime.datetime(2020, 1, 1) + ).add_extension( + x509.InhibitAnyPolicy(0), False + ) + + with pytest.raises(NotImplementedError): + builder.sign(backend, private_key, hashes.SHA1()) + + class TestOpenSSLSerialisationWithOpenSSL(object): def test_pem_password_cb_buffer_too_small(self): ffi_cb, cb = backend._pem_password_cb(b"aa") diff --git a/tests/test_x509.py b/tests/test_x509.py index 98cf49be..ac20f649 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -22,7 +22,7 @@ from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa from .hazmat.primitives.fixtures_dsa import DSA_KEY_2048 -from .hazmat.primitives.fixtures_rsa import RSA_KEY_2048 +from .hazmat.primitives.fixtures_rsa import RSA_KEY_2048, RSA_KEY_512 from .hazmat.primitives.test_ec import _skip_curve_unsupported from .utils import load_vectors_from_file @@ -775,6 +775,350 @@ class TestRSACertificateRequest(object): assert hash(request1) == hash(request2) assert hash(request1) != hash(request3) + def test_build_cert(self, 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) + + builder = x509.CertificateBuilder().serial_number( + 777 + ).issuer_name(x509.Name([ + x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'), + x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, u'Texas'), + x509.NameAttribute(x509.OID_LOCALITY_NAME, u'Austin'), + x509.NameAttribute(x509.OID_ORGANIZATION_NAME, u'PyCA'), + x509.NameAttribute(x509.OID_COMMON_NAME, u'cryptography.io'), + ])).subject_name(x509.Name([ + x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'), + x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, u'Texas'), + x509.NameAttribute(x509.OID_LOCALITY_NAME, u'Austin'), + x509.NameAttribute(x509.OID_ORGANIZATION_NAME, u'PyCA'), + x509.NameAttribute(x509.OID_COMMON_NAME, u'cryptography.io'), + ])).public_key( + subject_private_key.public_key() + ).add_extension( + x509.BasicConstraints(ca=False, path_length=None), True, + ).add_extension( + x509.SubjectAlternativeName([x509.DNSName(u"cryptography.io")]), + critical=False, + ).not_valid_before( + not_valid_before + ).not_valid_after( + not_valid_after + ) + + cert = builder.sign(backend, issuer_private_key, hashes.SHA1()) + + assert cert.version is x509.Version.v3 + assert cert.not_valid_before == not_valid_before + assert cert.not_valid_after == not_valid_after + basic_constraints = cert.extensions.get_extension_for_oid( + x509.OID_BASIC_CONSTRAINTS + ) + assert basic_constraints.value.ca is False + assert basic_constraints.value.path_length is None + subject_alternative_name = cert.extensions.get_extension_for_oid( + x509.OID_SUBJECT_ALTERNATIVE_NAME + ) + assert list(subject_alternative_name.value) == [ + x509.DNSName(u"cryptography.io"), + ] + + +class TestCertificateBuilder(object): + def test_issuer_name_must_be_a_name_type(self): + builder = x509.CertificateBuilder() + + with pytest.raises(TypeError): + builder.issuer_name("subject") + + with pytest.raises(TypeError): + builder.issuer_name(object) + + def test_issuer_name_may_only_be_set_once(self): + name = x509.Name([ + x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'), + ]) + builder = x509.CertificateBuilder().issuer_name(name) + + with pytest.raises(ValueError): + builder.issuer_name(name) + + def test_subject_name_must_be_a_name_type(self): + builder = x509.CertificateBuilder() + + with pytest.raises(TypeError): + builder.subject_name("subject") + + with pytest.raises(TypeError): + builder.subject_name(object) + + def test_subject_name_may_only_be_set_once(self): + name = x509.Name([ + x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'), + ]) + builder = x509.CertificateBuilder().subject_name(name) + + with pytest.raises(ValueError): + builder.subject_name(name) + + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_public_key_must_be_public_key(self, backend): + private_key = RSA_KEY_2048.private_key(backend) + builder = x509.CertificateBuilder() + + with pytest.raises(TypeError): + builder.public_key(private_key) + + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_public_key_may_only_be_set_once(self, backend): + private_key = RSA_KEY_2048.private_key(backend) + public_key = private_key.public_key() + builder = x509.CertificateBuilder().public_key(public_key) + + with pytest.raises(ValueError): + builder.public_key(public_key) + + def test_serial_number_must_be_an_integer_type(self): + with pytest.raises(TypeError): + x509.CertificateBuilder().serial_number(10.0) + + def test_serial_number_must_be_non_negative(self): + with pytest.raises(ValueError): + x509.CertificateBuilder().serial_number(-10) + + def test_serial_number_must_be_less_than_160_bits_long(self): + with pytest.raises(ValueError): + # 2 raised to the 160th power is actually 161 bits + x509.CertificateBuilder().serial_number(2 ** 160) + + def test_serial_number_may_only_be_set_once(self): + builder = x509.CertificateBuilder().serial_number(10) + + with pytest.raises(ValueError): + builder.serial_number(20) + + def test_invalid_not_valid_after(self): + with pytest.raises(TypeError): + x509.CertificateBuilder().not_valid_after(104204304504) + + with pytest.raises(TypeError): + x509.CertificateBuilder().not_valid_after(datetime.time()) + + with pytest.raises(ValueError): + x509.CertificateBuilder().not_valid_after( + datetime.datetime(1960, 8, 10) + ) + + def test_not_valid_after_may_only_be_set_once(self): + builder = x509.CertificateBuilder().not_valid_after( + datetime.datetime.now() + ) + + with pytest.raises(ValueError): + builder.not_valid_after( + datetime.datetime.now() + ) + + def test_invalid_not_valid_before(self): + with pytest.raises(TypeError): + x509.CertificateBuilder().not_valid_before(104204304504) + + with pytest.raises(TypeError): + x509.CertificateBuilder().not_valid_before(datetime.time()) + + with pytest.raises(ValueError): + x509.CertificateBuilder().not_valid_before( + datetime.datetime(1960, 8, 10) + ) + + def test_not_valid_before_may_only_be_set_once(self): + builder = x509.CertificateBuilder().not_valid_before( + datetime.datetime.now() + ) + + with pytest.raises(ValueError): + builder.not_valid_before( + datetime.datetime.now() + ) + + def test_add_extension_checks_for_duplicates(self): + builder = x509.CertificateBuilder().add_extension( + x509.BasicConstraints(ca=False, path_length=None), True, + ) + + with pytest.raises(ValueError): + builder.add_extension( + x509.BasicConstraints(ca=False, path_length=None), True, + ) + + def test_add_unsupported_extension(self): + builder = x509.CertificateBuilder() + + with pytest.raises(NotImplementedError): + builder.add_extension(object(), False) + + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_sign_with_unsupported_hash(self, backend): + private_key = RSA_KEY_2048.private_key(backend) + builder = x509.CertificateBuilder() + + with pytest.raises(TypeError): + builder.sign(backend, private_key, object()) + + @pytest.mark.requires_backend_interface(interface=DSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_sign_with_dsa_private_key_is_unsupported(self, backend): + if backend._lib.OPENSSL_VERSION_NUMBER >= 0x10001000: + pytest.skip("Requires an older OpenSSL. Must be < 1.0.1") + + private_key = DSA_KEY_2048.private_key(backend) + builder = x509.CertificateBuilder() + + with pytest.raises(NotImplementedError): + builder.sign(backend, private_key, hashes.SHA512()) + + @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_sign_with_ec_private_key_is_unsupported(self, backend): + if backend._lib.OPENSSL_VERSION_NUMBER >= 0x10001000: + pytest.skip("Requires an older OpenSSL. Must be < 1.0.1") + + _skip_curve_unsupported(backend, ec.SECP256R1()) + private_key = ec.generate_private_key(ec.SECP256R1(), backend) + builder = x509.CertificateBuilder() + + with pytest.raises(NotImplementedError): + builder.sign(backend, private_key, hashes.SHA512()) + + @pytest.mark.requires_backend_interface(interface=DSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_build_cert_with_dsa_private_key(self, backend): + if backend._lib.OPENSSL_VERSION_NUMBER < 0x10001000: + pytest.skip("Requires a newer OpenSSL. Must be >= 1.0.1") + + issuer_private_key = DSA_KEY_2048.private_key(backend) + subject_private_key = DSA_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) + + builder = x509.CertificateBuilder().serial_number( + 777 + ).issuer_name(x509.Name([ + x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'), + ])).subject_name(x509.Name([ + x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'), + ])).public_key( + subject_private_key.public_key() + ).add_extension( + x509.BasicConstraints(ca=False, path_length=None), True, + ).add_extension( + x509.SubjectAlternativeName([x509.DNSName(u"cryptography.io")]), + critical=False, + ).not_valid_before( + not_valid_before + ).not_valid_after( + not_valid_after + ) + + cert = builder.sign(backend, issuer_private_key, hashes.SHA1()) + + assert cert.version is x509.Version.v3 + assert cert.not_valid_before == not_valid_before + assert cert.not_valid_after == not_valid_after + basic_constraints = cert.extensions.get_extension_for_oid( + x509.OID_BASIC_CONSTRAINTS + ) + assert basic_constraints.value.ca is False + assert basic_constraints.value.path_length is None + subject_alternative_name = cert.extensions.get_extension_for_oid( + x509.OID_SUBJECT_ALTERNATIVE_NAME + ) + assert list(subject_alternative_name.value) == [ + x509.DNSName(u"cryptography.io"), + ] + + @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_build_cert_with_ec_private_key(self, backend): + if backend._lib.OPENSSL_VERSION_NUMBER < 0x10001000: + pytest.skip("Requires a newer OpenSSL. Must be >= 1.0.1") + + _skip_curve_unsupported(backend, ec.SECP256R1()) + issuer_private_key = ec.generate_private_key(ec.SECP256R1(), backend) + subject_private_key = ec.generate_private_key(ec.SECP256R1(), backend) + + not_valid_before = datetime.datetime(2002, 1, 1, 12, 1) + not_valid_after = datetime.datetime(2030, 12, 31, 8, 30) + + builder = x509.CertificateBuilder().serial_number( + 777 + ).issuer_name(x509.Name([ + x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'), + ])).subject_name(x509.Name([ + x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'), + ])).public_key( + subject_private_key.public_key() + ).add_extension( + x509.BasicConstraints(ca=False, path_length=None), True, + ).add_extension( + x509.SubjectAlternativeName([x509.DNSName(u"cryptography.io")]), + critical=False, + ).not_valid_before( + not_valid_before + ).not_valid_after( + not_valid_after + ) + + cert = builder.sign(backend, issuer_private_key, hashes.SHA1()) + + assert cert.version is x509.Version.v3 + assert cert.not_valid_before == not_valid_before + assert cert.not_valid_after == not_valid_after + basic_constraints = cert.extensions.get_extension_for_oid( + x509.OID_BASIC_CONSTRAINTS + ) + assert basic_constraints.value.ca is False + assert basic_constraints.value.path_length is None + subject_alternative_name = cert.extensions.get_extension_for_oid( + x509.OID_SUBJECT_ALTERNATIVE_NAME + ) + assert list(subject_alternative_name.value) == [ + x509.DNSName(u"cryptography.io"), + ] + + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_build_cert_with_rsa_key_too_small(self, backend): + issuer_private_key = RSA_KEY_512.private_key(backend) + subject_private_key = RSA_KEY_512.private_key(backend) + + not_valid_before = datetime.datetime(2002, 1, 1, 12, 1) + not_valid_after = datetime.datetime(2030, 12, 31, 8, 30) + + builder = x509.CertificateBuilder().serial_number( + 777 + ).issuer_name(x509.Name([ + x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'), + ])).subject_name(x509.Name([ + x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'), + ])).public_key( + subject_private_key.public_key() + ).not_valid_before( + not_valid_before + ).not_valid_after( + not_valid_after + ) + + with pytest.raises(ValueError): + builder.sign(backend, issuer_private_key, hashes.SHA512()) + @pytest.mark.requires_backend_interface(interface=X509Backend) class TestCertificateSigningRequestBuilder(object): |