aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/hazmat/primitives/asymmetric/ec.rst27
-rw-r--r--src/cryptography/hazmat/backends/interfaces.py2
-rw-r--r--src/cryptography/hazmat/backends/multibackend.py4
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py25
-rw-r--r--src/cryptography/hazmat/backends/openssl/ec.py25
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/ec.py22
-rw-r--r--tests/hazmat/backends/test_multibackend.py27
-rw-r--r--tests/hazmat/backends/test_openssl.py14
-rw-r--r--tests/hazmat/primitives/test_ec.py94
9 files changed, 98 insertions, 142 deletions
diff --git a/docs/hazmat/primitives/asymmetric/ec.rst b/docs/hazmat/primitives/asymmetric/ec.rst
index 910ce5d8..9b2e61fb 100644
--- a/docs/hazmat/primitives/asymmetric/ec.rst
+++ b/docs/hazmat/primitives/asymmetric/ec.rst
@@ -125,14 +125,12 @@ Elliptic Curve Signature Algorithms
Elliptic Curve Key Exchange algorithm
-------------------------------------
-.. class:: ECDH(private_key)
+.. class:: ECDH()
.. versionadded:: 1.1
- The ECDH Key Exchange algorithm first standardized in NIST publication
- `800-56A`_, and later in `800-56Ar2`_.
-
- :param private_key: An instance of :class:`EllipticCurvePrivateKey`.
+ The Elliptic Curve Diffie-Hellman Key Exchange algorithm first standardized
+ in NIST publication `800-56A`_, and later in `800-56Ar2`_.
.. doctest::
@@ -144,24 +142,7 @@ Elliptic Curve Key Exchange algorithm
>>> peer_public_key = ec.generate_private_key(
... ec.SECP384R1(), default_backend()
... ).public_key()
- >>> ecdh = ec.ECDH(private_key)
- >>> sharedkey = ecdh.compute_key(peer_public_key)
-
- .. attribute:: private_key
-
- :type: :class:`EllipticCurvePrivateKey`
-
- The private key associated to this object
-
- .. method:: public_key()
-
- The public key associated to the object's private key.
-
- .. method:: compute_key(peer_public_key)
-
- :param peer_public_key: A :class:`EllipticCurvePublicKey` object.
-
- :returns: A ``bytes`` object containing the computed key.
+ >>> shared_key = private_key.exchange(ec.ECDH(), peer_public_key)
Elliptic Curves
diff --git a/src/cryptography/hazmat/backends/interfaces.py b/src/cryptography/hazmat/backends/interfaces.py
index faa0b313..dbebc883 100644
--- a/src/cryptography/hazmat/backends/interfaces.py
+++ b/src/cryptography/hazmat/backends/interfaces.py
@@ -216,7 +216,7 @@ class EllipticCurveBackend(object):
"""
@abc.abstractmethod
- def elliptic_curve_exchange_algorithm_supported(self):
+ def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve):
"""
Returns whether the exchange algorithm is supported by this backend.
"""
diff --git a/src/cryptography/hazmat/backends/multibackend.py b/src/cryptography/hazmat/backends/multibackend.py
index 77a45ccd..c4d2c133 100644
--- a/src/cryptography/hazmat/backends/multibackend.py
+++ b/src/cryptography/hazmat/backends/multibackend.py
@@ -271,9 +271,9 @@ class MultiBackend(object):
_Reasons.UNSUPPORTED_ELLIPTIC_CURVE
)
- def elliptic_curve_exchange_algorithm_supported(self):
+ def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve):
return any(
- b.elliptic_curve_exchange_algorithm_supported()
+ b.elliptic_curve_exchange_algorithm_supported(algorithm, curve)
for b in self._filtered_backends(EllipticCurveBackend)
)
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index d82f3834..f86c3aa1 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -1671,25 +1671,12 @@ class Backend(object):
return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey)
- def elliptic_curve_exchange_algorithm_supported(self):
- return (self._lib.Cryptography_HAS_EC == 1 and
- self._lib.Cryptography_HAS_ECDH == 1)
-
- def ecdh_compute_key(self, private_key, peer_public_key):
- pri_key = private_key._ec_key
- pub_key = peer_public_key._ec_key
-
- group = self._lib.EC_KEY_get0_group(pri_key)
- z_len = (self._lib.EC_GROUP_get_degree(group) + 7) // 8
- self.openssl_assert(z_len > 0)
- z_buf = self._ffi.new("uint8_t[]", z_len)
- peer_key = self._lib.EC_KEY_get0_public_key(pub_key)
-
- r = self._lib.ECDH_compute_key(z_buf, z_len,
- peer_key, pri_key,
- self._ffi.NULL)
- self.openssl_assert(r > 0)
- return self._ffi.buffer(z_buf)[:z_len]
+ def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve):
+ return (
+ self.elliptic_curve_supported(curve) and
+ self._lib.Cryptography_HAS_ECDH == 1 and
+ isinstance(algorithm, ec.ECDH)
+ )
def _ec_cdata_to_evp_pkey(self, ec_cdata):
evp_pkey = self._lib.EVP_PKEY_new()
diff --git a/src/cryptography/hazmat/backends/openssl/ec.py b/src/cryptography/hazmat/backends/openssl/ec.py
index 939a3f90..cfd559ae 100644
--- a/src/cryptography/hazmat/backends/openssl/ec.py
+++ b/src/cryptography/hazmat/backends/openssl/ec.py
@@ -171,6 +171,31 @@ class _EllipticCurvePrivateKey(object):
"Unsupported elliptic curve signature algorithm.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+ def exchange(self, algorithm, peer_public_key):
+ if not (
+ self._backend.elliptic_curve_exchange_algorithm_supported(
+ algorithm, self.curve
+ )
+ ):
+ raise UnsupportedAlgorithm(
+ "This backend does not support the ECDH algorithm.",
+ _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
+ )
+
+ group = self._backend._lib.EC_KEY_get0_group(self._ec_key)
+ z_len = (self._backend._lib.EC_GROUP_get_degree(group) + 7) // 8
+ self._backend.openssl_assert(z_len > 0)
+ z_buf = self._backend._ffi.new("uint8_t[]", z_len)
+ peer_key = self._backend._lib.EC_KEY_get0_public_key(
+ peer_public_key._ec_key
+ )
+
+ r = self._backend._lib.ECDH_compute_key(
+ z_buf, z_len, peer_key, self._ec_key, self._backend._ffi.NULL
+ )
+ self._backend.openssl_assert(r > 0)
+ return self._backend._ffi.buffer(z_buf)[:z_len]
+
def public_key(self):
group = self._backend._lib.EC_KEY_get0_group(self._ec_key)
self._backend.openssl_assert(group != self._backend._ffi.NULL)
diff --git a/src/cryptography/hazmat/primitives/asymmetric/ec.py b/src/cryptography/hazmat/primitives/asymmetric/ec.py
index 978a7c41..544894a9 100644
--- a/src/cryptography/hazmat/primitives/asymmetric/ec.py
+++ b/src/cryptography/hazmat/primitives/asymmetric/ec.py
@@ -306,24 +306,4 @@ class EllipticCurvePrivateNumbers(object):
class ECDH(object):
- def __init__(self, private_key):
- if not isinstance(private_key, EllipticCurvePrivateKey):
- raise TypeError("Private Key must be a EllipticCurvePrivateKey")
- self._private_key = private_key
- self._backend = private_key._backend
- if not self._backend.elliptic_curve_exchange_algorithm_supported():
- raise exceptions.UnsupportedAlgorithm(
- "This backend does not support the ECDH algorithm.",
- exceptions._Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
- )
-
- private_key = utils.read_only_property("_private_key")
-
- def public_key(self):
- return self._private_key.public_key()
-
- def compute_key(self, peer_public_key):
- if not isinstance(peer_public_key, EllipticCurvePublicKey):
- raise TypeError("Peer Public Key must be a EllipticCurvePublicKey")
- return self._backend.ecdh_compute_key(self._private_key,
- peer_public_key)
+ pass
diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py
index 57aa7f44..2a533750 100644
--- a/tests/hazmat/backends/test_multibackend.py
+++ b/tests/hazmat/backends/test_multibackend.py
@@ -138,9 +138,8 @@ class DummyCMACBackend(object):
@utils.register_interface(EllipticCurveBackend)
class DummyEllipticCurveBackend(object):
- def __init__(self, supported_curves, exchange_supported):
+ def __init__(self, supported_curves):
self._curves = supported_curves
- self.exchange_supported = exchange_supported
def elliptic_curve_supported(self, curve):
return any(
@@ -153,10 +152,7 @@ class DummyEllipticCurveBackend(object):
):
return (
isinstance(signature_algorithm, ec.ECDSA) and
- any(
- isinstance(curve, curve_type)
- for curve_type in self._curves
- )
+ self.elliptic_curve_supported(curve)
)
def generate_elliptic_curve_private_key(self, curve):
@@ -171,8 +167,11 @@ class DummyEllipticCurveBackend(object):
if not self.elliptic_curve_supported(numbers.curve):
raise UnsupportedAlgorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE)
- def elliptic_curve_exchange_algorithm_supported(self):
- return self.exchange_supported
+ def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve):
+ return (
+ isinstance(algorithm, ec.ECDH) and
+ self.elliptic_curve_supported(curve)
+ )
@utils.register_interface(PEMSerializationBackend)
@@ -404,7 +403,7 @@ class TestMultiBackend(object):
backend = MultiBackend([
DummyEllipticCurveBackend([
ec.SECT283K1
- ], True)
+ ])
])
assert backend.elliptic_curve_supported(ec.SECT283K1()) is True
@@ -466,9 +465,13 @@ class TestMultiBackend(object):
)
)
- assert backend.elliptic_curve_exchange_algorithm_supported() is True
- backend2 = MultiBackend([DummyEllipticCurveBackend([], False)])
- assert backend2.elliptic_curve_exchange_algorithm_supported() is False
+ assert backend.elliptic_curve_exchange_algorithm_supported(
+ ec.ECDH(), ec.SECT283K1()
+ )
+ backend2 = MultiBackend([DummyEllipticCurveBackend([])])
+ assert not backend2.elliptic_curve_exchange_algorithm_supported(
+ ec.ECDH(), ec.SECT163K1()
+ )
def test_pem_serialization_backend(self):
backend = MultiBackend([DummyPEMSerializationBackend()])
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index 13162046..85331595 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -534,11 +534,6 @@ class DummyLibrary(object):
Cryptography_HAS_EC = 0
-class DummyLibraryECDH(object):
- Cryptography_HAS_EC = 1
- Cryptography_HAS_ECDH = 0
-
-
class TestOpenSSLEllipticCurve(object):
def test_elliptic_curve_supported(self, monkeypatch):
monkeypatch.setattr(backend, "_lib", DummyLibrary())
@@ -558,12 +553,9 @@ class TestOpenSSLEllipticCurve(object):
def test_elliptic_curve_exchange_algorithm_supported(self, monkeypatch):
monkeypatch.setattr(backend, "_lib", DummyLibrary())
-
- assert backend.elliptic_curve_exchange_algorithm_supported() is False
-
- monkeypatch.setattr(backend, "_lib", DummyLibraryECDH())
-
- assert backend.elliptic_curve_exchange_algorithm_supported() is False
+ assert not backend.elliptic_curve_exchange_algorithm_supported(
+ ec.ECDH(), ec.SECP256R1()
+ )
@pytest.mark.requires_backend_interface(interface=RSABackend)
diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py
index c3a99e5d..2594d5db 100644
--- a/tests/hazmat/primitives/test_ec.py
+++ b/tests/hazmat/primitives/test_ec.py
@@ -57,8 +57,10 @@ def _skip_curve_unsupported(backend, curve):
)
-def _skip_exchange_algorithm_unsupported(backend):
- if not backend.elliptic_curve_exchange_algorithm_supported():
+def _skip_exchange_algorithm_unsupported(backend, algorithm, curve):
+ if not backend.elliptic_curve_exchange_algorithm_supported(
+ algorithm, curve
+ ):
pytest.skip(
"Exchange algorithm is not supported by this backend {0}".format(
backend
@@ -771,50 +773,6 @@ class DummyECDHBackend(object):
@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
class TestECDHVectors(object):
-
- def test_unsupported_ecdh_arguments(self, backend):
- with pytest.raises(TypeError):
- ec.ECDH(None)
- curve = ec.SECP521R1
- _skip_curve_unsupported(backend, curve)
- prikey = ec.generate_private_key(curve, backend)
- ecdh = ec.ECDH(prikey)
- ecdh.compute_key(ecdh.public_key())
- with pytest.raises(TypeError):
- ecdh.compute_key(None)
- with pytest.raises(exceptions.UnsupportedAlgorithm):
- prikey._backend = DummyECDHBackend()
- ecdh = ec.ECDH(prikey)
- _skip_exchange_algorithm_unsupported(DummyECDHBackend())
-
- def key_exchange(self, backend, vector):
- key_numbers = vector['IUT']
- peer_numbers = vector['CAVS']
-
- prikey = ec.EllipticCurvePrivateNumbers(
- key_numbers['d'],
- ec.EllipticCurvePublicNumbers(
- key_numbers['x'],
- key_numbers['y'],
- ec._CURVE_TYPES[vector['curve']]()
- )
- ).private_key(backend)
-
- peerkey = ec.EllipticCurvePrivateNumbers(
- peer_numbers['d'],
- ec.EllipticCurvePublicNumbers(
- peer_numbers['x'],
- peer_numbers['y'],
- ec._CURVE_TYPES[vector['curve']]()
- )
- ).private_key(backend)
- peerpubkey = peerkey.public_key()
-
- ecdh = ec.ECDH(prikey)
- z = ecdh.compute_key(peerpubkey)
-
- return int(hexlify(z).decode('ascii'), 16)
-
@pytest.mark.parametrize(
"vector",
load_vectors_from_file(
@@ -825,19 +783,49 @@ class TestECDHVectors(object):
)
)
def test_key_exchange_with_vectors(self, backend, vector):
- _skip_curve_unsupported(backend, ec._CURVE_TYPES[vector['curve']])
- _skip_exchange_algorithm_unsupported(backend)
+ _skip_exchange_algorithm_unsupported(
+ backend, ec.ECDH(), ec._CURVE_TYPES[vector['curve']]
+ )
+ key_numbers = vector['IUT']
try:
- z = self.key_exchange(backend, vector)
+ private_key = ec.EllipticCurvePrivateNumbers(
+ key_numbers['d'],
+ ec.EllipticCurvePublicNumbers(
+ key_numbers['x'],
+ key_numbers['y'],
+ ec._CURVE_TYPES[vector['curve']]()
+ )
+ ).private_key(backend)
except ValueError:
- assert vector['fail'] is True
+ # Errno 5 and 6 indicates a bad public key, this doesn't test the
+ # ECDH code at all
+ assert vector['fail'] and vector['errno'] in [5, 6]
+ return
- if vector['fail']:
+ peer_numbers = vector['CAVS']
+ try:
+ peer_pubkey = ec.EllipticCurvePublicNumbers(
+ peer_numbers['x'],
+ peer_numbers['y'],
+ ec._CURVE_TYPES[vector['curve']]()
+ ).public_key(backend)
+ except ValueError:
+ # Errno 1 and 2 indicates a bad public key, this doesn't test the
+ # ECDH code at all
+ assert vector['fail'] and vector['errno'] in [1, 2]
+ return
+
+ if vector['fail'] and vector['errno'] not in [7, 8]:
+ with pytest.raises(ValueError):
+ private_key.exchange(ec.ECDH(), peer_pubkey)
+ else:
+ z = private_key.exchange(ec.ECDH(), peer_pubkey)
+ z = int(hexlify(z).decode('ascii'), 16)
# Errno 7 denotes a changed private key. Errno 8 denotes a changed
# shared key. Both these errors will not cause a failure in the
# exchange but should lead to a non-matching derived shared key.
if vector['errno'] in [7, 8]:
assert z != vector['Z']
- else:
- assert z == vector['Z']
+ else:
+ assert z == vector['Z']