diff options
Diffstat (limited to 'tests/x509')
-rw-r--r-- | tests/x509/test_ocsp.py | 78 | ||||
-rw-r--r-- | tests/x509/test_x509.py | 225 | ||||
-rw-r--r-- | tests/x509/test_x509_crlbuilder.py | 152 | ||||
-rw-r--r-- | tests/x509/test_x509_ext.py | 40 |
4 files changed, 488 insertions, 7 deletions
diff --git a/tests/x509/test_ocsp.py b/tests/x509/test_ocsp.py index 3abaff50..ab3752a2 100644 --- a/tests/x509/test_ocsp.py +++ b/tests/x509/test_ocsp.py @@ -13,7 +13,7 @@ import pytest from cryptography import x509 from cryptography.exceptions import UnsupportedAlgorithm from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.asymmetric import ec, ed25519, ed448 from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15 from cryptography.x509 import ocsp @@ -45,10 +45,12 @@ def _cert_and_issuer(): return cert, issuer -def _generate_root(): +def _generate_root(private_key=None, algorithm=hashes.SHA256()): from cryptography.hazmat.backends.openssl.backend import backend - private_key = EC_KEY_SECP256R1.private_key(backend) + if private_key is None: + private_key = EC_KEY_SECP256R1.private_key(backend) + subject = x509.Name([ x509.NameAttribute(x509.NameOID.COUNTRY_NAME, u'US'), x509.NameAttribute(x509.NameOID.COMMON_NAME, u'Cryptography CA'), @@ -68,7 +70,7 @@ def _generate_root(): datetime.datetime.now() + datetime.timedelta(days=3650) ) - cert = builder.sign(private_key, hashes.SHA256(), backend) + cert = builder.sign(private_key, algorithm, backend) return cert, private_key @@ -753,3 +755,71 @@ class TestOCSPResponse(object): resp.public_bytes("invalid") with pytest.raises(ValueError): resp.public_bytes(serialization.Encoding.PEM) + + +class TestOCSPEdDSA(object): + @pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support / OCSP" + ) + def test_sign_ed25519(self, backend): + builder = ocsp.OCSPResponseBuilder() + cert, issuer = _cert_and_issuer() + private_key = ed25519.Ed25519PrivateKey.generate() + root_cert, private_key = _generate_root(private_key, None) + current_time = datetime.datetime.utcnow().replace(microsecond=0) + this_update = current_time - datetime.timedelta(days=1) + next_update = this_update + datetime.timedelta(days=7) + revoked_date = this_update - datetime.timedelta(days=300) + builder = builder.responder_id( + ocsp.OCSPResponderEncoding.NAME, root_cert + ).add_response( + cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.REVOKED, + this_update, next_update, revoked_date, + x509.ReasonFlags.key_compromise + ) + resp = builder.sign(private_key, None) + assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED + assert resp.revocation_time == revoked_date + assert resp.revocation_reason is x509.ReasonFlags.key_compromise + assert resp.this_update == this_update + assert resp.next_update == next_update + assert resp.signature_hash_algorithm is None + assert (resp.signature_algorithm_oid == + x509.SignatureAlgorithmOID.ED25519) + private_key.public_key().verify( + resp.signature, resp.tbs_response_bytes + ) + + @pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support / OCSP" + ) + def test_sign_ed448(self, backend): + builder = ocsp.OCSPResponseBuilder() + cert, issuer = _cert_and_issuer() + private_key = ed448.Ed448PrivateKey.generate() + root_cert = _generate_root(private_key, None)[0] + current_time = datetime.datetime.utcnow().replace(microsecond=0) + this_update = current_time - datetime.timedelta(days=1) + next_update = this_update + datetime.timedelta(days=7) + revoked_date = this_update - datetime.timedelta(days=300) + builder = builder.responder_id( + ocsp.OCSPResponderEncoding.NAME, root_cert + ).add_response( + cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.REVOKED, + this_update, next_update, revoked_date, + x509.ReasonFlags.key_compromise + ) + resp = builder.sign(private_key, None) + assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED + assert resp.revocation_time == revoked_date + assert resp.revocation_reason is x509.ReasonFlags.key_compromise + assert resp.this_update == this_update + assert resp.next_update == next_update + assert resp.signature_hash_algorithm is None + assert (resp.signature_algorithm_oid == + x509.SignatureAlgorithmOID.ED448) + private_key.public_key().verify( + resp.signature, resp.tbs_response_bytes + ) diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 540a814a..8a8507bd 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -28,7 +28,7 @@ from cryptography.hazmat.backends.interfaces import ( ) from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ( - dsa, ec, ed25519, padding, rsa + dsa, ec, ed25519, ed448, padding, rsa ) from cryptography.hazmat.primitives.asymmetric.utils import ( decode_dss_signature @@ -2234,6 +2234,58 @@ class TestCertificateBuilder(object): with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) + @pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support" + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_request_with_unsupported_hash_ed25519(self, backend): + private_key = ed25519.Ed25519PrivateKey.generate() + builder = x509.CertificateSigningRequestBuilder().subject_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) + ) + + with pytest.raises(ValueError): + builder.sign(private_key, hashes.SHA256(), backend) + + @pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support" + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_sign_with_unsupported_hash_ed448(self, backend): + private_key = ed448.Ed448PrivateKey.generate() + builder = x509.CertificateBuilder().subject_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) + ).issuer_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) + ).serial_number( + 1 + ).public_key( + private_key.public_key() + ).not_valid_before( + datetime.datetime(2002, 1, 1, 12, 1) + ).not_valid_after( + datetime.datetime(2032, 1, 1, 12, 1) + ) + + with pytest.raises(ValueError): + builder.sign(private_key, hashes.SHA256(), backend) + + @pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support" + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_request_with_unsupported_hash_ed448(self, backend): + private_key = ed448.Ed448PrivateKey.generate() + builder = x509.CertificateSigningRequestBuilder().subject_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) + ) + + with pytest.raises(ValueError): + builder.sign(private_key, hashes.SHA256(), backend) + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) @pytest.mark.supported( @@ -2492,6 +2544,97 @@ class TestCertificateBuilder(object): assert isinstance(cert.signature_hash_algorithm, hashes.SHA256) assert isinstance(cert.public_key(), ed25519.Ed25519PublicKey) + @pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support" + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_build_cert_with_ed448(self, backend): + issuer_private_key = ed448.Ed448PrivateKey.generate() + subject_private_key = ed448.Ed448PrivateKey.generate() + + 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(NameOID.COUNTRY_NAME, u'US'), + ])).subject_name(x509.Name([ + x509.NameAttribute(NameOID.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(issuer_private_key, None, backend) + issuer_private_key.public_key().verify( + cert.signature, cert.tbs_certificate_bytes + ) + assert cert.signature_algorithm_oid == SignatureAlgorithmOID.ED448 + assert cert.signature_hash_algorithm is None + assert isinstance(cert.public_key(), ed448.Ed448PublicKey) + 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( + ExtensionOID.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( + ExtensionOID.SUBJECT_ALTERNATIVE_NAME + ) + assert list(subject_alternative_name.value) == [ + x509.DNSName(u"cryptography.io"), + ] + + @pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support" + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + @pytest.mark.requires_backend_interface(interface=RSABackend) + def test_build_cert_with_public_ed448_rsa_sig(self, backend): + issuer_private_key = RSA_KEY_2048.private_key(backend) + subject_private_key = ed448.Ed448PrivateKey.generate() + + 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(NameOID.COUNTRY_NAME, u'US'), + ])).subject_name(x509.Name([ + x509.NameAttribute(NameOID.COUNTRY_NAME, u'US'), + ])).public_key( + subject_private_key.public_key() + ).not_valid_before( + not_valid_before + ).not_valid_after( + not_valid_after + ) + + cert = builder.sign(issuer_private_key, hashes.SHA256(), backend) + issuer_private_key.public_key().verify( + cert.signature, cert.tbs_certificate_bytes, padding.PKCS1v15(), + cert.signature_hash_algorithm + ) + assert cert.signature_algorithm_oid == ( + SignatureAlgorithmOID.RSA_WITH_SHA256 + ) + assert isinstance(cert.signature_hash_algorithm, hashes.SHA256) + assert isinstance(cert.public_key(), ed448.Ed448PublicKey) + @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): @@ -3175,6 +3318,66 @@ class TestCertificateSigningRequestBuilder(object): assert basic_constraints.value.ca is True assert basic_constraints.value.path_length == 2 + @pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support" + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_build_ca_request_with_ed25519(self, backend): + private_key = ed25519.Ed25519PrivateKey.generate() + + request = x509.CertificateSigningRequestBuilder().subject_name( + x509.Name([ + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u'Texas'), + ]) + ).add_extension( + x509.BasicConstraints(ca=True, path_length=2), critical=True + ).sign(private_key, None, backend) + + assert request.signature_hash_algorithm is None + public_key = request.public_key() + assert isinstance(public_key, ed25519.Ed25519PublicKey) + subject = request.subject + assert isinstance(subject, x509.Name) + assert list(subject) == [ + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u'Texas'), + ] + basic_constraints = request.extensions.get_extension_for_oid( + ExtensionOID.BASIC_CONSTRAINTS + ) + assert basic_constraints.value.ca is True + assert basic_constraints.value.path_length == 2 + + @pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support" + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_build_ca_request_with_ed448(self, backend): + private_key = ed448.Ed448PrivateKey.generate() + + request = x509.CertificateSigningRequestBuilder().subject_name( + x509.Name([ + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u'Texas'), + ]) + ).add_extension( + x509.BasicConstraints(ca=True, path_length=2), critical=True + ).sign(private_key, None, backend) + + assert request.signature_hash_algorithm is None + public_key = request.public_key() + assert isinstance(public_key, ed448.Ed448PublicKey) + subject = request.subject + assert isinstance(subject, x509.Name) + assert list(subject) == [ + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u'Texas'), + ] + basic_constraints = request.extensions.get_extension_for_oid( + ExtensionOID.BASIC_CONSTRAINTS + ) + assert basic_constraints.value.ca is True + assert basic_constraints.value.path_length == 2 + @pytest.mark.requires_backend_interface(interface=DSABackend) def test_build_ca_request_with_dsa(self, backend): private_key = DSA_KEY_2048.private_key(backend) @@ -4420,6 +4623,26 @@ class TestEd25519Certificate(object): assert cert.signature_algorithm_oid == SignatureAlgorithmOID.ED25519 +@pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support" +) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestEd448Certificate(object): + def test_load_pem_cert(self, backend): + cert = _load_cert( + os.path.join("x509", "ed448", "root-ed448.pem"), + x509.load_pem_x509_certificate, + backend + ) + # self-signed, so this will work + cert.public_key().verify(cert.signature, cert.tbs_certificate_bytes) + assert isinstance(cert, x509.Certificate) + assert cert.serial_number == 448 + assert cert.signature_hash_algorithm is None + assert cert.signature_algorithm_oid == SignatureAlgorithmOID.ED448 + + def test_random_serial_number(monkeypatch): sample_data = os.urandom(20) diff --git a/tests/x509/test_x509_crlbuilder.py b/tests/x509/test_x509_crlbuilder.py index b9afa702..04244c1b 100644 --- a/tests/x509/test_x509_crlbuilder.py +++ b/tests/x509/test_x509_crlbuilder.py @@ -15,8 +15,10 @@ from cryptography.hazmat.backends.interfaces import ( DSABackend, EllipticCurveBackend, RSABackend, X509Backend ) from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.asymmetric import ec -from cryptography.x509.oid import AuthorityInformationAccessOID, NameOID +from cryptography.hazmat.primitives.asymmetric import ec, ed25519, ed448 +from cryptography.x509.oid import ( + AuthorityInformationAccessOID, NameOID, SignatureAlgorithmOID +) from ..hazmat.primitives.fixtures_dsa import DSA_KEY_2048 from ..hazmat.primitives.fixtures_ec import EC_KEY_SECP256R1 @@ -379,6 +381,54 @@ class TestCertificateRevocationListBuilder(object): with pytest.raises(TypeError): builder.sign(private_key, object(), backend) + @pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support" + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_sign_with_invalid_hash_ed25519(self, backend): + private_key = ed25519.Ed25519PrivateKey.generate() + last_update = datetime.datetime(2002, 1, 1, 12, 1) + next_update = datetime.datetime(2030, 1, 1, 12, 1) + builder = x509.CertificateRevocationListBuilder().issuer_name( + x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") + ]) + ).last_update( + last_update + ).next_update( + next_update + ) + + with pytest.raises(ValueError): + builder.sign(private_key, object(), backend) + with pytest.raises(ValueError): + builder.sign(private_key, hashes.SHA256(), backend) + + @pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support" + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_sign_with_invalid_hash_ed448(self, backend): + private_key = ed448.Ed448PrivateKey.generate() + last_update = datetime.datetime(2002, 1, 1, 12, 1) + next_update = datetime.datetime(2030, 1, 1, 12, 1) + builder = x509.CertificateRevocationListBuilder().issuer_name( + x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") + ]) + ).last_update( + last_update + ).next_update( + next_update + ) + + with pytest.raises(ValueError): + builder.sign(private_key, object(), backend) + with pytest.raises(ValueError): + builder.sign(private_key, hashes.SHA256(), backend) + @pytest.mark.requires_backend_interface(interface=DSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_dsa_key(self, backend): @@ -468,6 +518,104 @@ class TestCertificateRevocationListBuilder(object): assert ext.critical is False assert ext.value == invalidity_date + @pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support" + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_sign_ed25519_key(self, backend): + private_key = ed25519.Ed25519PrivateKey.generate() + invalidity_date = x509.InvalidityDate( + datetime.datetime(2002, 1, 1, 0, 0) + ) + ian = x509.IssuerAlternativeName([ + x509.UniformResourceIdentifier(u"https://cryptography.io"), + ]) + revoked_cert0 = x509.RevokedCertificateBuilder().serial_number( + 2 + ).revocation_date( + datetime.datetime(2012, 1, 1, 1, 1) + ).add_extension( + invalidity_date, False + ).build(backend) + last_update = datetime.datetime(2002, 1, 1, 12, 1) + next_update = datetime.datetime(2030, 1, 1, 12, 1) + builder = x509.CertificateRevocationListBuilder().issuer_name( + x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") + ]) + ).last_update( + last_update + ).next_update( + next_update + ).add_revoked_certificate( + revoked_cert0 + ).add_extension( + ian, False + ) + + crl = builder.sign(private_key, None, backend) + assert crl.signature_hash_algorithm is None + assert crl.signature_algorithm_oid == SignatureAlgorithmOID.ED25519 + assert crl.extensions.get_extension_for_class( + x509.IssuerAlternativeName + ).value == ian + assert crl[0].serial_number == revoked_cert0.serial_number + assert crl[0].revocation_date == revoked_cert0.revocation_date + assert len(crl[0].extensions) == 1 + ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate) + assert ext.critical is False + assert ext.value == invalidity_date + + @pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support" + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_sign_ed448_key(self, backend): + private_key = ed448.Ed448PrivateKey.generate() + invalidity_date = x509.InvalidityDate( + datetime.datetime(2002, 1, 1, 0, 0) + ) + ian = x509.IssuerAlternativeName([ + x509.UniformResourceIdentifier(u"https://cryptography.io"), + ]) + revoked_cert0 = x509.RevokedCertificateBuilder().serial_number( + 2 + ).revocation_date( + datetime.datetime(2012, 1, 1, 1, 1) + ).add_extension( + invalidity_date, False + ).build(backend) + last_update = datetime.datetime(2002, 1, 1, 12, 1) + next_update = datetime.datetime(2030, 1, 1, 12, 1) + builder = x509.CertificateRevocationListBuilder().issuer_name( + x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") + ]) + ).last_update( + last_update + ).next_update( + next_update + ).add_revoked_certificate( + revoked_cert0 + ).add_extension( + ian, False + ) + + crl = builder.sign(private_key, None, backend) + assert crl.signature_hash_algorithm is None + assert crl.signature_algorithm_oid == SignatureAlgorithmOID.ED448 + assert crl.extensions.get_extension_for_class( + x509.IssuerAlternativeName + ).value == ian + assert crl[0].serial_number == revoked_cert0.serial_number + assert crl[0].revocation_date == revoked_cert0.revocation_date + assert len(crl[0].extensions) == 1 + ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate) + assert ext.critical is False + assert ext.value == invalidity_date + @pytest.mark.requires_backend_interface(interface=DSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_dsa_key_sign_md5(self, backend): diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index cf757abd..10d217ab 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -1641,6 +1641,46 @@ class TestSubjectKeyIdentifierExtension(object): ) assert ext.value == ski + @pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support" + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_from_ed25519_public_key(self, backend): + cert = _load_cert( + os.path.join("x509", "ed25519", "root-ed25519.pem"), + x509.load_pem_x509_certificate, + backend + ) + + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_KEY_IDENTIFIER + ) + ski = x509.SubjectKeyIdentifier.from_public_key( + cert.public_key() + ) + assert ext.value == ski + + @pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support" + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_from_ed448_public_key(self, backend): + cert = _load_cert( + os.path.join("x509", "ed448", "root-ed448.pem"), + x509.load_pem_x509_certificate, + backend + ) + + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_KEY_IDENTIFIER + ) + ski = x509.SubjectKeyIdentifier.from_public_key( + cert.public_key() + ) + assert ext.value == ski + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) |