aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rst7
-rw-r--r--docs/development/test-vectors.rst6
-rw-r--r--docs/x509/ocsp.rst22
-rw-r--r--docs/x509/reference.rst103
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py46
-rw-r--r--src/cryptography/x509/base.py10
-rw-r--r--src/cryptography/x509/ocsp.py9
-rw-r--r--src/cryptography/x509/oid.py3
-rw-r--r--tests/x509/test_ocsp.py78
-rw-r--r--tests/x509/test_x509.py225
-rw-r--r--tests/x509/test_x509_crlbuilder.py152
-rw-r--r--tests/x509/test_x509_ext.py40
-rw-r--r--vectors/cryptography_vectors/x509/ed448/root-ed448.pem11
-rw-r--r--vectors/cryptography_vectors/x509/ed448/server-ed448-cert.pem14
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-----