diff options
author | Marko Kreen <markokr@gmail.com> | 2019-09-09 02:44:02 +0300 |
---|---|---|
committer | Paul Kehrer <paul.l.kehrer@gmail.com> | 2019-09-09 07:44:02 +0800 |
commit | f7c77712d6611dc72cb2ef6fb1fe72fee4ab88de (patch) | |
tree | 7ff0841b1c2e9b29737874ff76c215de50ce0ee0 | |
parent | c918fef88670fc46433d3edd91957231c654ff05 (diff) | |
download | cryptography-f7c77712d6611dc72cb2ef6fb1fe72fee4ab88de.tar.gz cryptography-f7c77712d6611dc72cb2ef6fb1fe72fee4ab88de.tar.bz2 cryptography-f7c77712d6611dc72cb2ef6fb1fe72fee4ab88de.zip |
Finish ed25519 and ed448 support in x509 module (#4972)
* Support ed25519 in csr/crl creation
* Tests for ed25519/x509
* Support ed448 in crt/csr/crl creation
* Tests for ed448/x509
* Support ed25519/ed448 in OCSPResponseBuilder
* Tests for eddsa in OCSPResponseBuilder
* Builder check missing in create_x509_csr
* Documentation update for ed25519+ed448 in x509
-rw-r--r-- | CHANGELOG.rst | 7 | ||||
-rw-r--r-- | docs/development/test-vectors.rst | 6 | ||||
-rw-r--r-- | docs/x509/ocsp.rst | 22 | ||||
-rw-r--r-- | docs/x509/reference.rst | 103 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/backend.py | 46 | ||||
-rw-r--r-- | src/cryptography/x509/base.py | 10 | ||||
-rw-r--r-- | src/cryptography/x509/ocsp.py | 9 | ||||
-rw-r--r-- | src/cryptography/x509/oid.py | 3 | ||||
-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 | ||||
-rw-r--r-- | vectors/cryptography_vectors/x509/ed448/root-ed448.pem | 11 | ||||
-rw-r--r-- | vectors/cryptography_vectors/x509/ed448/server-ed448-cert.pem | 14 |
14 files changed, 662 insertions, 64 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 56d955e1..9a4a79ba 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -19,8 +19,11 @@ Changelog ``cryptography`` 2.9. * We now ship ``manylinux2010`` wheels in addition to our ``manylinux1`` wheels. -* Added support for ``ed25519`` keys in the - :class:`~cryptography.x509.CertificateBuilder`. +* Added support for ``ed25519`` and ``ed448`` keys in the + :class:`~cryptography.x509.CertificateBuilder`, + :class:`~cryptography.x509.CertificateSigningRequestBuilder`, + :class:`~cryptography.x509.CertificateRevocationListBuilder` and + :class:`~cryptography.x509.ocsp.OCSPResponseBuilder`. * ``cryptography`` no longer depends on ``asn1crypto``. * :class:`~cryptography.x509.FreshestCRL` is now allowed as a :class:`~cryptography.x509.CertificateRevocationList` extension. diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 7584881a..9976d138 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -244,6 +244,9 @@ X.509 * ``server-ed25519-cert.pem`` - An ``ed25519`` server certificate (RSA signature with ``ed25519`` public key) from the OpenSSL test suite. (`server-ed25519-cert.pem`_) +* ``server-ed448-cert.pem`` - An ``ed448`` server certificate (RSA + signature with ``ed448`` public key) from the OpenSSL test suite. + (`server-ed448-cert.pem`_) Custom X.509 Vectors ~~~~~~~~~~~~~~~~~~~~ @@ -404,6 +407,8 @@ Custom X.509 Vectors * ``negative_serial.pem`` - A certificate with a serial number that is a negative number. * ``rsa_pss.pem`` - A certificate with an RSA PSS signature. +* ``root-ed448.pem`` - An ``ed448`` self-signed CA certificate + using ``ed448-pkcs8.pem`` as key. Custom X.509 Request Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -703,3 +708,4 @@ header format (substituting the correct information): .. _`Botan's key wrap vectors`: https://github.com/randombit/botan/blob/737f33c09a18500e044dca3e2ae13bd2c08bafdd/src/tests/data/keywrap/nist_key_wrap.vec .. _`root-ed25519.pem`: https://github.com/openssl/openssl/blob/2a1e2fe145c6eb8e75aa2e1b3a8c3a49384b2852/test/certs/root-ed25519.pem .. _`server-ed25519-cert.pem`: https://github.com/openssl/openssl/blob/2a1e2fe145c6eb8e75aa2e1b3a8c3a49384b2852/test/certs/server-ed25519-cert.pem +.. _`server-ed448-cert.pem`: https://github.com/openssl/openssl/blob/2a1e2fe145c6eb8e75aa2e1b3a8c3a49384b2852/test/certs/server-ed448-cert.pem diff --git a/docs/x509/ocsp.rst b/docs/x509/ocsp.rst index d3815d6f..e28c05a7 100644 --- a/docs/x509/ocsp.rst +++ b/docs/x509/ocsp.rst @@ -292,14 +292,23 @@ Creating Responses :attr:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL` response. :param private_key: The - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey` - or - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey` that will be used to sign the certificate. :param algorithm: The :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` that - will be used to generate the signature. + will be used to generate the signature. This must be ``None`` if + the ``private_key`` is an + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey` + or an + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey` + and an instance of a + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + otherwise. :returns: A new :class:`~cryptography.x509.ocsp.OCSPResponse`. @@ -434,7 +443,10 @@ Interfaces Returns the :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` which - was used in signing this response. + was used in signing this response. Can be ``None`` if signature + did not use separate hash + (:attr:`~cryptography.x509.oid.SignatureAlgorithmOID.ED25519`, + :attr:`~cryptography.x509.oid.SignatureAlgorithmOID.ED448`). .. attribute:: signature diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index 7156ab8c..46cc0d27 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -335,11 +335,12 @@ X.509 Certificate Object The public key associated with the certificate. - :returns: - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey` or - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey` or - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` or - :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey` + :returns: One of + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PublicKey` .. doctest:: @@ -394,7 +395,10 @@ X.509 Certificate Object Returns the :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` which - was used in signing this certificate. + was used in signing this certificate. Can be ``None`` if signature + did not use separate hash + (:attr:`~cryptography.x509.oid.SignatureAlgorithmOID.ED25519`, + :attr:`~cryptography.x509.oid.SignatureAlgorithmOID.ED448`). .. doctest:: @@ -552,7 +556,10 @@ X.509 CRL (Certificate Revocation List) Object Returns the :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` which - was used in signing this CRL. + was used in signing this CRL. Can be ``None`` if signature + did not use separate hash + (:attr:`~cryptography.x509.oid.SignatureAlgorithmOID.ED25519`, + :attr:`~cryptography.x509.oid.SignatureAlgorithmOID.ED448`). .. doctest:: @@ -729,9 +736,9 @@ X.509 Certificate Builder :param public_key: The subject's public key. This can be one of :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` - or - :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey` + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PublicKey`. .. method:: serial_number(serial_number) @@ -785,9 +792,9 @@ X.509 Certificate Builder :param private_key: The :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`, - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` - , or - :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey` + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey` that will be used to sign the certificate. :param algorithm: The @@ -795,6 +802,8 @@ X.509 Certificate Builder will be used to generate the signature. This must be ``None`` if the ``private_key`` is an :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey` + or an + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey` and an instance of a :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` otherwise. @@ -818,10 +827,12 @@ X.509 CSR (Certificate Signing Request) Object The public key associated with the request. - :returns: - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey` or - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey` or - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` + :returns: One of + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PublicKey`. .. doctest:: @@ -842,7 +853,10 @@ X.509 CSR (Certificate Signing Request) Object Returns the :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` which - was used in signing this request. + was used in signing this request. Can be ``None`` if signature + did not use separate hash + (:attr:`~cryptography.x509.oid.SignatureAlgorithmOID.ED25519`, + :attr:`~cryptography.x509.oid.SignatureAlgorithmOID.ED448`). .. doctest:: @@ -1010,13 +1024,22 @@ X.509 Certificate Revocation List Builder :param private_key: The :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey` or - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey` that will be used to sign the certificate. :param algorithm: The :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` that will be used to generate the signature. + This must be ``None`` if the ``private_key`` is an + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey` + or an + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey` + and an instance of a + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + otherwise. :param backend: Backend that will be used to build the CRL. Must support the @@ -1182,8 +1205,10 @@ X.509 CSR (Certificate Signing Request) Builder Object :param private_key: The :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey` or - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey` that will be used to sign the request. When the request is signed by a certificate authority, the private key's associated public key will be stored in the resulting certificate. @@ -1191,6 +1216,13 @@ X.509 CSR (Certificate Signing Request) Builder Object :param algorithm: The :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` that will be used to generate the request signature. + This must be ``None`` if the ``private_key`` is an + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey` + or an + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey` + and an instance of a + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + otherwise. :returns: A new :class:`~cryptography.x509.CertificateSigningRequest`. @@ -1863,11 +1895,11 @@ X.509 Extensions section 4.2.1.2. :param public_key: One of - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey` - , - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey` - , or - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`. + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PublicKey`. .. doctest:: @@ -1941,11 +1973,11 @@ X.509 Extensions recommendation in :rfc:`5280` section 4.2.1.2. :param public_key: One of - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey` - , - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey` - , or - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`. + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PublicKey`. .. doctest:: @@ -2853,6 +2885,13 @@ instances. The following common OIDs are available as constants. Corresponds to the dotted string ``"1.3.101.112"``. This is a signature using an ed25519 key. + .. attribute:: ED448 + + .. versionadded:: 2.8 + + Corresponds to the dotted string ``"1.3.101.113"``. This is a signature + using an ed448 key. + .. class:: ExtendedKeyUsageOID diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index eb6654b0..7e9fa202 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -74,7 +74,9 @@ from cryptography.hazmat.backends.openssl.x509 import ( ) from cryptography.hazmat.bindings.openssl import binding from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import dsa, ec, ed25519, rsa +from cryptography.hazmat.primitives.asymmetric import ( + dsa, ec, ed25519, ed448, rsa +) from cryptography.hazmat.primitives.asymmetric.padding import ( MGF1, OAEP, PKCS1v15, PSS ) @@ -722,10 +724,18 @@ class Backend(object): return _CMACContext(self, algorithm) def create_x509_csr(self, builder, private_key, algorithm): - if not isinstance(algorithm, hashes.HashAlgorithm): - raise TypeError('Algorithm must be a registered hash algorithm.') + if not isinstance(builder, x509.CertificateSigningRequestBuilder): + raise TypeError('Builder type mismatch.') - if ( + if isinstance(private_key, + (ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey)): + if algorithm is not None: + raise ValueError( + "algorithm must be None when signing via ed25519 or ed448" + ) + elif not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError('Algorithm must be a registered hash algorithm.') + elif ( isinstance(algorithm, hashes.MD5) and not isinstance(private_key, rsa.RSAPrivateKey) ): @@ -734,7 +744,7 @@ class Backend(object): ) # Resolve the signature algorithm. - evp_md = self._evp_md_non_null_from_algorithm(algorithm) + evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm) # Create an empty request. x509_req = self._lib.X509_REQ_new() @@ -801,10 +811,11 @@ class Backend(object): def create_x509_certificate(self, builder, private_key, algorithm): if not isinstance(builder, x509.CertificateBuilder): raise TypeError('Builder type mismatch.') - if isinstance(private_key, ed25519.Ed25519PrivateKey): + if isinstance(private_key, + (ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey)): if algorithm is not None: raise ValueError( - "algorithm must be None when signing via ed25519" + "algorithm must be None when signing via ed25519 or ed448" ) elif not isinstance(algorithm, hashes.HashAlgorithm): raise TypeError('Algorithm must be a registered hash algorithm.') @@ -818,7 +829,7 @@ class Backend(object): ) # Resolve the signature algorithm. - evp_md = self._evp_md_x509_null_if_ed25519(private_key, algorithm) + evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm) # Create an empty certificate. x509_cert = self._lib.X509_new() @@ -886,9 +897,10 @@ class Backend(object): return _Certificate(self, x509_cert) - def _evp_md_x509_null_if_ed25519(self, private_key, algorithm): - if isinstance(private_key, ed25519.Ed25519PrivateKey): - # OpenSSL requires us to pass NULL for EVP_MD for ed25519 signing + def _evp_md_x509_null_if_eddsa(self, private_key, algorithm): + if isinstance(private_key, + (ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey)): + # OpenSSL requires us to pass NULL for EVP_MD for ed25519/ed448 return self._ffi.NULL else: return self._evp_md_non_null_from_algorithm(algorithm) @@ -911,7 +923,13 @@ class Backend(object): def create_x509_crl(self, builder, private_key, algorithm): if not isinstance(builder, x509.CertificateRevocationListBuilder): raise TypeError('Builder type mismatch.') - if not isinstance(algorithm, hashes.HashAlgorithm): + if isinstance(private_key, + (ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey)): + if algorithm is not None: + raise ValueError( + "algorithm must be None when signing via ed25519 or ed448" + ) + elif not isinstance(algorithm, hashes.HashAlgorithm): raise TypeError('Algorithm must be a registered hash algorithm.') if ( @@ -922,7 +940,7 @@ class Backend(object): "MD5 is not a supported hash algorithm for EC/DSA CRLs" ) - evp_md = self._evp_md_non_null_from_algorithm(algorithm) + evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm) # Create an empty CRL. x509_crl = self._lib.X509_CRL_new() @@ -1578,7 +1596,7 @@ class Backend(object): ) self.openssl_assert(res != self._ffi.NULL) # okay, now sign the basic structure - evp_md = self._evp_md_non_null_from_algorithm(algorithm) + evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm) responder_cert, responder_encoding = builder._responder_id flags = self._lib.OCSP_NOCERTS if responder_encoding is ocsp.OCSPResponderEncoding.HASH: diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index dc7eee94..3983c9b3 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -12,7 +12,9 @@ from enum import Enum import six from cryptography import utils -from cryptography.hazmat.primitives.asymmetric import dsa, ec, ed25519, rsa +from cryptography.hazmat.primitives.asymmetric import ( + dsa, ec, ed25519, ed448, rsa +) from cryptography.x509.extensions import Extension, ExtensionType from cryptography.x509.name import Name @@ -475,9 +477,11 @@ class CertificateBuilder(object): """ if not isinstance(key, (dsa.DSAPublicKey, rsa.RSAPublicKey, ec.EllipticCurvePublicKey, - ed25519.Ed25519PublicKey)): + ed25519.Ed25519PublicKey, + ed448.Ed448PublicKey)): raise TypeError('Expecting one of DSAPublicKey, RSAPublicKey,' - ' EllipticCurvePublicKey, or Ed25519PublicKey.') + ' EllipticCurvePublicKey, Ed25519PublicKey or' + ' Ed448PublicKey.') if self._public_key is not None: raise ValueError('The public key may only be set once.') return CertificateBuilder( diff --git a/src/cryptography/x509/ocsp.py b/src/cryptography/x509/ocsp.py index aae9b626..b15063d1 100644 --- a/src/cryptography/x509/ocsp.py +++ b/src/cryptography/x509/ocsp.py @@ -12,6 +12,7 @@ import six from cryptography import x509 from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import ed25519, ed448 from cryptography.x509.base import ( _EARLIEST_UTC_TIME, _convert_to_naive_utc_time, _reject_duplicate_extension ) @@ -241,7 +242,13 @@ class OCSPResponseBuilder(object): if self._responder_id is None: raise ValueError("You must add a responder_id before signing") - if not isinstance(algorithm, hashes.HashAlgorithm): + if isinstance(private_key, + (ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey)): + if algorithm is not None: + raise ValueError( + "algorithm must be None when signing via ed25519 or ed448" + ) + elif not isinstance(algorithm, hashes.HashAlgorithm): raise TypeError("Algorithm must be a registered hash algorithm.") return backend.create_ocsp_response( diff --git a/src/cryptography/x509/oid.py b/src/cryptography/x509/oid.py index ab01d67b..c1e5dc53 100644 --- a/src/cryptography/x509/oid.py +++ b/src/cryptography/x509/oid.py @@ -97,6 +97,7 @@ class SignatureAlgorithmOID(object): DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1") DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2") ED25519 = ObjectIdentifier("1.3.101.112") + ED448 = ObjectIdentifier("1.3.101.113") _SIG_OIDS_TO_HASH = { @@ -116,6 +117,7 @@ _SIG_OIDS_TO_HASH = { SignatureAlgorithmOID.DSA_WITH_SHA224: hashes.SHA224(), SignatureAlgorithmOID.DSA_WITH_SHA256: hashes.SHA256(), SignatureAlgorithmOID.ED25519: None, + SignatureAlgorithmOID.ED448: None, } @@ -184,6 +186,7 @@ _OID_NAMES = { SignatureAlgorithmOID.DSA_WITH_SHA224: "dsa-with-sha224", SignatureAlgorithmOID.DSA_WITH_SHA256: "dsa-with-sha256", SignatureAlgorithmOID.ED25519: "ed25519", + SignatureAlgorithmOID.ED448: "ed448", ExtendedKeyUsageOID.SERVER_AUTH: "serverAuth", ExtendedKeyUsageOID.CLIENT_AUTH: "clientAuth", ExtendedKeyUsageOID.CODE_SIGNING: "codeSigning", 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) diff --git a/vectors/cryptography_vectors/x509/ed448/root-ed448.pem b/vectors/cryptography_vectors/x509/ed448/root-ed448.pem new file mode 100644 index 00000000..d1d4eaa9 --- /dev/null +++ b/vectors/cryptography_vectors/x509/ed448/root-ed448.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBgDCCAQCgAwIBAgICAcAwBQYDK2VxMBgxFjAUBgNVBAMMDUVkNDQ4IERlbW8g +Q0EwIBcNMTkwODE1MTkzNzU2WhgPMjExOTA3MjIxOTM3NTZaMBgxFjAUBgNVBAMM +DUVkNDQ4IERlbW8gQ0EwQzAFBgMrZXEDOgBf10SbWbRh/Sznh+xhatRqHaE0JIWn +Dh+KDqddgOlneO3xJHabRscGG9Z4PfHlD2zR+hq+r+glYYCjUzBRMB0GA1UdDgQW +BBRt4IpyNR7xrevKLNfx/aaRVK36TzAfBgNVHSMEGDAWgBRt4IpyNR7xrevKLNfx +/aaRVK36TzAPBgNVHRMBAf8EBTADAQH/MAUGAytlcQNzAHx1CfZgc40PRGSiZTWC +P8HQAFgAMwIh34cE4WSrb1m8fxv8/uMG0bIvIez/+PMx/ErKPMtyBC2+ACJCCL0Q +In1OC28cIlpXIcQUFXamiGdg1Pd4NqAYl1BVNGWymHxf1AM/NNBPUhYxs1Qw1ape +dJIjAA== +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/ed448/server-ed448-cert.pem b/vectors/cryptography_vectors/x509/ed448/server-ed448-cert.pem new file mode 100644 index 00000000..740f2755 --- /dev/null +++ b/vectors/cryptography_vectors/x509/ed448/server-ed448-cert.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICHTCCAQWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290 +IENBMCAXDTE4MDIyNzE1MDcxM1oYDzIxMTgwMjI4MTUwNzEzWjAQMQ4wDAYDVQQD +DAVFZDQ0ODBDMAUGAytlcQM6ABBicYlhG1s3AoG5BFmY3r50lJzjQoER4zwuieEe +QTvKxLEV06vGh79UWO6yQ5FxqmxvM1F/Xw7RAKNfMF0wHQYDVR0OBBYEFAwa1L4m +3pwA8+IEJ7K/4izrjJIHMB8GA1UdIwQYMBaAFHB/Lq6DaFmYBCMqzes+F80k3QFJ +MAkGA1UdEwQCMAAwEAYDVR0RBAkwB4IFRWQ0NDgwDQYJKoZIhvcNAQELBQADggEB +AAugH2aE6VvArnOVjKBtalqtHlx+NCC3+S65sdWc9A9sNgI1ZiN7dn76TKn5d0T7 +NqV8nY1rwQg6WPGrCD6Eh63qhotytqYIxltppb4MOUJcz/Zf0ZwhB5bUfwNB//Ih +5aZT86FpXVuyMnwUTWPcISJqpZiBv95yzZFMpniHFvecvV445ly4TFW5y6VURh40 +Tg4tMgjPTE7ADw+dX4FvnTWY3blxT1GzGxGvqWW4HgP8dOETnjmAwCzN0nUVmH9s +7ybHORcSljcpe0XH6L/K7mbI+r8mVLsAoIzUeDwUdKKJZ2uGEtdhQDmJBp4EjOXE +3qIn3wEQQ6ax4NIwkZihdLI= +-----END CERTIFICATE----- |