diff options
| -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-----  | 
