diff options
-rw-r--r-- | CHANGELOG.rst | 27 | ||||
-rw-r--r-- | README.rst | 4 | ||||
-rw-r--r-- | cryptography/hazmat/backends/interfaces.py | 4 | ||||
-rw-r--r-- | cryptography/hazmat/backends/multibackend.py | 38 | ||||
-rw-r--r-- | cryptography/hazmat/backends/openssl/backend.py | 126 | ||||
-rw-r--r-- | cryptography/hazmat/backends/openssl/ec.py | 73 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/asymmetric/ec.py | 10 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/interfaces.py | 18 | ||||
-rw-r--r-- | docs/hazmat/backends/interfaces.rst | 4 | ||||
-rw-r--r-- | docs/hazmat/primitives/interfaces.rst | 36 | ||||
-rw-r--r-- | tests/hazmat/backends/test_multibackend.py | 59 | ||||
-rw-r--r-- | tests/hazmat/backends/test_openssl.py | 44 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_ec.py | 57 |
13 files changed, 420 insertions, 80 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dfc6d8b0..65577498 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,11 +6,38 @@ Changelog .. note:: This version is not yet released and is under active development. +* Added + :func:`~cryptography.hazmat.primitives.serialization.load_pem_private_key` to + ease loading private keys, and + :func:`~cryptography.hazmat.primitives.serialization.load_pem_public_key` to + support loading public keys. * Removed the, deprecated in 0.4, support for the ``salt_length`` argument to the :class:`~cryptography.hazmat.primitives.asymmetric.padding.MGF1` constructor. The ``salt_length`` should be passed to :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS` instead. * Fix compilation on OS X Yosemite. +* Deprecated ``elliptic_curve_private_key_from_numbers`` and + ``elliptic_curve_public_key_from_numbers`` in favor of + ``load_elliptic_curve_private_numbers`` and + ``load_elliptic_curve_public_numbers`` on + :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`. +* Added + :class:`~cryptography.hazmat.primitives.interfaces.EllipticCurvePrivateKeyWithNumbers` + and + :class:`~cryptography.hazmat.primitives.interfaces.EllipticCurvePublicKeyWithNumbers` + support. +* Work around three GCM related bugs in CommonCrypto and OpenSSL. + + * On the CommonCrypto backend adding AAD but not subsequently calling update + would return null tag bytes. + + * One the CommonCrypto backend a call to update without an empty add AAD call + would return null ciphertext bytes. + + * On the OpenSSL backend with certain versions adding AAD only would give + invalid tag bytes. + +* Support loading EC private keys from PEM. 0.5.4 - 2014-08-20 ~~~~~~~~~~~~~~~~~~ @@ -5,6 +5,10 @@ Cryptography :target: https://pypi.python.org/pypi/cryptography/ :alt: Latest Version +.. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest + :target: https://cryptography.io + :alt: Latest Docs + .. image:: https://travis-ci.org/pyca/cryptography.svg?branch=master :target: https://travis-ci.org/pyca/cryptography diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py index dc720ad3..f471b948 100644 --- a/cryptography/hazmat/backends/interfaces.py +++ b/cryptography/hazmat/backends/interfaces.py @@ -260,13 +260,13 @@ class EllipticCurveBackend(object): """ @abc.abstractmethod - def elliptic_curve_public_key_from_numbers(self, numbers): + def load_elliptic_curve_public_numbers(self, numbers): """ Return an EllipticCurvePublicKey provider using the given numbers. """ @abc.abstractmethod - def elliptic_curve_private_key_from_numbers(self, numbers): + def load_elliptic_curve_private_numbers(self, numbers): """ Return an EllipticCurvePublicKey provider using the given numbers. """ diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py index 163dd0ee..ce9e6dee 100644 --- a/cryptography/hazmat/backends/multibackend.py +++ b/cryptography/hazmat/backends/multibackend.py @@ -13,6 +13,8 @@ from __future__ import absolute_import, division, print_function +import warnings + from cryptography import utils from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.hazmat.backends.interfaces import ( @@ -297,6 +299,12 @@ class MultiBackend(object): ) def elliptic_curve_private_key_from_numbers(self, numbers): + warnings.warn( + "elliptic_curve_private_key_from_numbers is deprecated and will " + "be removed in a future version.", + utils.DeprecatedIn06, + stacklevel=2 + ) for b in self._filtered_backends(EllipticCurveBackend): try: return b.elliptic_curve_private_key_from_numbers(numbers) @@ -308,7 +316,25 @@ class MultiBackend(object): _Reasons.UNSUPPORTED_ELLIPTIC_CURVE ) + def load_elliptic_curve_private_numbers(self, numbers): + for b in self._filtered_backends(EllipticCurveBackend): + try: + return b.load_elliptic_curve_private_numbers(numbers) + except UnsupportedAlgorithm: + continue + + raise UnsupportedAlgorithm( + "This backend does not support this elliptic curve.", + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE + ) + def elliptic_curve_public_key_from_numbers(self, numbers): + warnings.warn( + "elliptic_curve_public_key_from_numbers is deprecated and will " + "be removed in a future version.", + utils.DeprecatedIn06, + stacklevel=2 + ) for b in self._filtered_backends(EllipticCurveBackend): try: return b.elliptic_curve_public_key_from_numbers(numbers) @@ -320,6 +346,18 @@ class MultiBackend(object): _Reasons.UNSUPPORTED_ELLIPTIC_CURVE ) + def load_elliptic_curve_public_numbers(self, numbers): + for b in self._filtered_backends(EllipticCurveBackend): + try: + return b.load_elliptic_curve_public_numbers(numbers) + except UnsupportedAlgorithm: + continue + + raise UnsupportedAlgorithm( + "This backend does not support this elliptic curve.", + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE + ) + def load_pem_private_key(self, data, password): for b in self._filtered_backends(PEMSerializationBackend): return b.load_pem_private_key(data, password) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 389ef0be..9a36674a 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -479,9 +479,7 @@ class Backend(object): ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) assert ec_cdata != self._ffi.NULL ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) - sn = self._ec_key_curve_sn(ec_cdata) - curve = self._sn_to_elliptic_curve(sn) - return _EllipticCurvePrivateKey(self, ec_cdata, curve) + return _EllipticCurvePrivateKey(self, ec_cdata) else: raise UnsupportedAlgorithm("Unsupported key type.") @@ -508,25 +506,10 @@ class Backend(object): ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) assert ec_cdata != self._ffi.NULL ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) - sn = self._ec_key_curve_sn(ec_cdata) - curve = self._sn_to_elliptic_curve(sn) - return _EllipticCurvePublicKey(self, ec_cdata, curve) + return _EllipticCurvePublicKey(self, ec_cdata) else: raise UnsupportedAlgorithm("Unsupported key type.") - def _ec_key_curve_sn(self, ec_key): - group = self._lib.EC_KEY_get0_group(ec_key) - assert group != self._ffi.NULL - - nid = self._lib.EC_GROUP_get_curve_name(group) - assert nid != self._lib.NID_undef - - curve_name = self._lib.OBJ_nid2sn(nid) - assert curve_name != self._ffi.NULL - - sn = self._ffi.string(curve_name).decode('ascii') - return sn - def _pem_password_cb(self, password): """ Generate a pem_password_cb function pointer that copied the password to @@ -997,17 +980,17 @@ class Backend(object): if self.elliptic_curve_supported(curve): curve_nid = self._elliptic_curve_to_nid(curve) - ctx = self._lib.EC_KEY_new_by_curve_name(curve_nid) - assert ctx != self._ffi.NULL - ctx = self._ffi.gc(ctx, self._lib.EC_KEY_free) + ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid) + assert ec_cdata != self._ffi.NULL + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) - res = self._lib.EC_KEY_generate_key(ctx) + res = self._lib.EC_KEY_generate_key(ec_cdata) assert res == 1 - res = self._lib.EC_KEY_check_key(ctx) + res = self._lib.EC_KEY_check_key(ec_cdata) assert res == 1 - return _EllipticCurvePrivateKey(self, ctx, curve) + return _EllipticCurvePrivateKey(self, ec_cdata) else: raise UnsupportedAlgorithm( "Backend object does not support {0}.".format(curve.name), @@ -1015,35 +998,52 @@ class Backend(object): ) def elliptic_curve_private_key_from_numbers(self, numbers): + warnings.warn( + "elliptic_curve_private_key_from_numbers is deprecated and will " + "be removed in a future version.", + utils.DeprecatedIn06, + stacklevel=2 + ) + return self.load_elliptic_curve_private_numbers(numbers) + + def load_elliptic_curve_private_numbers(self, numbers): public = numbers.public_numbers curve_nid = self._elliptic_curve_to_nid(public.curve) - ctx = self._lib.EC_KEY_new_by_curve_name(curve_nid) - assert ctx != self._ffi.NULL - ctx = self._ffi.gc(ctx, self._lib.EC_KEY_free) + ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid) + assert ec_cdata != self._ffi.NULL + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) - ctx = self._ec_key_set_public_key_affine_coordinates( - ctx, public.x, public.y) + ec_cdata = self._ec_key_set_public_key_affine_coordinates( + ec_cdata, public.x, public.y) res = self._lib.EC_KEY_set_private_key( - ctx, self._int_to_bn(numbers.private_value)) + ec_cdata, self._int_to_bn(numbers.private_value)) assert res == 1 - return _EllipticCurvePrivateKey(self, ctx, - numbers.public_numbers.curve) + return _EllipticCurvePrivateKey(self, ec_cdata) def elliptic_curve_public_key_from_numbers(self, numbers): + warnings.warn( + "elliptic_curve_public_key_from_numbers is deprecated and will be " + "removed in a future version.", + utils.DeprecatedIn06, + stacklevel=2 + ) + return self.load_elliptic_curve_public_numbers(numbers) + + def load_elliptic_curve_public_numbers(self, numbers): curve_nid = self._elliptic_curve_to_nid(numbers.curve) - ctx = self._lib.EC_KEY_new_by_curve_name(curve_nid) - assert ctx != self._ffi.NULL - ctx = self._ffi.gc(ctx, self._lib.EC_KEY_free) + ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid) + assert ec_cdata != self._ffi.NULL + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) - ctx = self._ec_key_set_public_key_affine_coordinates( - ctx, numbers.x, numbers.y) + ec_cdata = self._ec_key_set_public_key_affine_coordinates( + ec_cdata, numbers.x, numbers.y) - return _EllipticCurvePublicKey(self, ctx, numbers.curve) + return _EllipticCurvePublicKey(self, ec_cdata) def _elliptic_curve_to_nid(self, curve): """ @@ -1065,15 +1065,6 @@ class Backend(object): ) return curve_nid - def _sn_to_elliptic_curve(self, sn): - try: - return ec._CURVE_TYPES[sn]() - except KeyError: - raise UnsupportedAlgorithm( - "{0} is not a supported elliptic curve".format(sn), - _Reasons.UNSUPPORTED_ELLIPTIC_CURVE - ) - @contextmanager def _tmp_bn_ctx(self): bn_ctx = self._lib.BN_CTX_new() @@ -1085,30 +1076,19 @@ class Backend(object): finally: self._lib.BN_CTX_end(bn_ctx) - def _ec_key_set_public_key_affine_coordinates(self, ctx, x, y): + def _ec_key_determine_group_get_set_funcs(self, ctx): """ - This is a port of EC_KEY_set_public_key_affine_coordinates that was - added in 1.0.1. - - Sets the public key point in the EC_KEY context to the affine x and y - values. + Given an EC_KEY determine the group and what methods are required to + get/set point coordinates. """ - assert ctx != self._ffi.NULL - bn_x = self._int_to_bn(x) - bn_y = self._int_to_bn(y) - nid_two_field = self._lib.OBJ_sn2nid(b"characteristic-two-field") assert nid_two_field != self._lib.NID_undef group = self._lib.EC_KEY_get0_group(ctx) assert group != self._ffi.NULL - point = self._lib.EC_POINT_new(group) - assert point != self._ffi.NULL - point = self._ffi.gc(point, self._lib.EC_POINT_free) - method = self._lib.EC_GROUP_method_of(group) assert method != self._ffi.NULL @@ -1124,6 +1104,28 @@ class Backend(object): assert set_func and get_func + return set_func, get_func, group + + def _ec_key_set_public_key_affine_coordinates(self, ctx, x, y): + """ + This is a port of EC_KEY_set_public_key_affine_coordinates that was + added in 1.0.1. + + Sets the public key point in the EC_KEY context to the affine x and y + values. + """ + + bn_x = self._int_to_bn(x) + bn_y = self._int_to_bn(y) + + set_func, get_func, group = ( + self._ec_key_determine_group_get_set_funcs(ctx) + ) + + point = self._lib.EC_POINT_new(group) + assert point != self._ffi.NULL + point = self._ffi.gc(point, self._lib.EC_POINT_free) + with self._tmp_bn_ctx() as bn_ctx: check_x = self._lib.BN_CTX_get(bn_ctx) check_y = self._lib.BN_CTX_get(bn_ctx) diff --git a/cryptography/hazmat/backends/openssl/ec.py b/cryptography/hazmat/backends/openssl/ec.py index 611dba2c..9371a9a9 100644 --- a/cryptography/hazmat/backends/openssl/ec.py +++ b/cryptography/hazmat/backends/openssl/ec.py @@ -63,6 +63,30 @@ def _truncate_digest_for_ecdsa(ec_key_cdata, digest, backend): return digest +def _ec_key_curve_sn(backend, ec_key): + group = backend._lib.EC_KEY_get0_group(ec_key) + assert group != backend._ffi.NULL + + nid = backend._lib.EC_GROUP_get_curve_name(group) + assert nid != backend._lib.NID_undef + + curve_name = backend._lib.OBJ_nid2sn(nid) + assert curve_name != backend._ffi.NULL + + sn = backend._ffi.string(curve_name).decode('ascii') + return sn + + +def _sn_to_elliptic_curve(backend, sn): + try: + return ec._CURVE_TYPES[sn]() + except KeyError: + raise UnsupportedAlgorithm( + "{0} is not a supported elliptic curve".format(sn), + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE + ) + + @utils.register_interface(interfaces.AsymmetricSignatureContext) class _ECDSASignatureContext(object): def __init__(self, backend, private_key, algorithm): @@ -129,12 +153,14 @@ class _ECDSAVerificationContext(object): return True -@utils.register_interface(interfaces.EllipticCurvePrivateKey) +@utils.register_interface(interfaces.EllipticCurvePrivateKeyWithNumbers) class _EllipticCurvePrivateKey(object): - def __init__(self, backend, ec_key_cdata, curve): + def __init__(self, backend, ec_key_cdata): self._backend = backend self._ec_key = ec_key_cdata - self._curve = curve + + sn = _ec_key_curve_sn(backend, ec_key_cdata) + self._curve = _sn_to_elliptic_curve(backend, sn) @property def curve(self): @@ -169,16 +195,26 @@ class _EllipticCurvePrivateKey(object): assert res == 1 return _EllipticCurvePublicKey( - self._backend, public_ec_key, self._curve + self._backend, public_ec_key + ) + + def private_numbers(self): + bn = self._backend._lib.EC_KEY_get0_private_key(self._ec_key) + private_value = self._backend._bn_to_int(bn) + return ec.EllipticCurvePrivateNumbers( + private_value=private_value, + public_numbers=self.public_key().public_numbers() ) -@utils.register_interface(interfaces.EllipticCurvePublicKey) +@utils.register_interface(interfaces.EllipticCurvePublicKeyWithNumbers) class _EllipticCurvePublicKey(object): - def __init__(self, backend, ec_key_cdata, curve): + def __init__(self, backend, ec_key_cdata): self._backend = backend self._ec_key = ec_key_cdata - self._curve = curve + + sn = _ec_key_curve_sn(backend, ec_key_cdata) + self._curve = _sn_to_elliptic_curve(backend, sn) @property def curve(self): @@ -193,3 +229,26 @@ class _EllipticCurvePublicKey(object): raise UnsupportedAlgorithm( "Unsupported elliptic curve signature algorithm.", _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) + + def public_numbers(self): + set_func, get_func, group = ( + self._backend._ec_key_determine_group_get_set_funcs(self._ec_key) + ) + point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) + assert point != self._backend._ffi.NULL + + with self._backend._tmp_bn_ctx() as bn_ctx: + bn_x = self._backend._lib.BN_CTX_get(bn_ctx) + bn_y = self._backend._lib.BN_CTX_get(bn_ctx) + + res = get_func(group, point, bn_x, bn_y, bn_ctx) + assert res == 1 + + x = self._backend._bn_to_int(bn_x) + y = self._backend._bn_to_int(bn_y) + + return ec.EllipticCurvePublicNumbers( + x=x, + y=y, + curve=self._curve + ) diff --git a/cryptography/hazmat/primitives/asymmetric/ec.py b/cryptography/hazmat/primitives/asymmetric/ec.py index 98eca276..6dcf39cf 100644 --- a/cryptography/hazmat/primitives/asymmetric/ec.py +++ b/cryptography/hazmat/primitives/asymmetric/ec.py @@ -238,7 +238,10 @@ class EllipticCurvePublicNumbers(object): self._curve = curve def public_key(self, backend): - return backend.elliptic_curve_public_key_from_numbers(self) + try: + return backend.load_elliptic_curve_public_numbers(self) + except AttributeError: + return backend.elliptic_curve_public_key_from_numbers(self) @property def curve(self): @@ -268,7 +271,10 @@ class EllipticCurvePrivateNumbers(object): self._public_numbers = public_numbers def private_key(self, backend): - return backend.elliptic_curve_private_key_from_numbers(self) + try: + return backend.load_elliptic_curve_private_numbers(self) + except AttributeError: + return backend.elliptic_curve_private_key_from_numbers(self) @property def private_value(self): diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py index d60f9e0e..c7ad0cf8 100644 --- a/cryptography/hazmat/primitives/interfaces.py +++ b/cryptography/hazmat/primitives/interfaces.py @@ -444,6 +444,15 @@ class EllipticCurvePrivateKey(object): @six.add_metaclass(abc.ABCMeta) +class EllipticCurvePrivateKeyWithNumbers(EllipticCurvePrivateKey): + @abc.abstractmethod + def private_numbers(self): + """ + Returns an EllipticCurvePrivateNumbers. + """ + + +@six.add_metaclass(abc.ABCMeta) class EllipticCurvePublicKey(object): @abc.abstractmethod def verifier(self, signature, signature_algorithm): @@ -456,3 +465,12 @@ class EllipticCurvePublicKey(object): """ The EllipticCurve that this key is on. """ + + +@six.add_metaclass(abc.ABCMeta) +class EllipticCurvePublicKeyWithNumbers(EllipticCurvePublicKey): + @abc.abstractmethod + def public_numbers(self): + """ + Returns an EllipticCurvePublicNumbers. + """ diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst index e8e1bac2..3b414339 100644 --- a/docs/hazmat/backends/interfaces.rst +++ b/docs/hazmat/backends/interfaces.rst @@ -558,7 +558,7 @@ A specific ``backend`` may provide one or more of these interfaces. :class:`~cryptography.hazmat.primitives.interfaces.EllipticCurve` provider. - .. method:: elliptic_curve_private_key_from_numbers(numbers) + .. method:: load_elliptic_curve_private_numbers(numbers) :param numbers: An instance of a :class:`~cryptography.hazmat.primitives.interfaces.EllipticCurvePrivateNumbers` @@ -568,7 +568,7 @@ A specific ``backend`` may provide one or more of these interfaces. :class:`~cryptography.hazmat.primitives.interfaces.EllipticCurvePrivateKey` provider. - .. method:: elliptic_curve_public_key_from_numbers(numbers) + .. method:: load_elliptic_curve_public_numbers(numbers) :param numbers: An instance of a :class:`~cryptography.hazmat.primitives.interfaces.EllipticCurvePublicNumbers` diff --git a/docs/hazmat/primitives/interfaces.rst b/docs/hazmat/primitives/interfaces.rst index ac47c1e1..2d594c8d 100644 --- a/docs/hazmat/primitives/interfaces.rst +++ b/docs/hazmat/primitives/interfaces.rst @@ -416,7 +416,7 @@ DSA Extends :class:`DSAPublicKey`. - .. method:: private_numbers() + .. method:: public_numbers() Create a :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicNumbers` @@ -492,6 +492,23 @@ Elliptic Curve The EllipticCurvePublicKey object for this private key. +.. class:: EllipticCurvePrivateKeyWithNumbers + + .. versionadded:: 0.6 + + Extends :class:`EllipticCurvePrivateKey`. + + .. method:: private_numbers() + + Create a + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateNumbers` + object. + + :returns: An + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateNumbers` + instance. + + .. class:: EllipticCurvePublicKey .. versionadded:: 0.5 @@ -518,6 +535,23 @@ Elliptic Curve The elliptic curve for this key. +.. class:: EllipticCurvePublicKeyWithNumbers + + .. versionadded:: 0.6 + + Extends :class:`EllipticCurvePublicKey`. + + .. method:: public_numbers() + + Create a + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicNumbers` + object. + + :returns: An + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicNumbers` + instance. + + Hash algorithms --------------- diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index 45c12b34..61bda54c 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -13,6 +13,8 @@ from __future__ import absolute_import, division, print_function +import pytest + from cryptography import utils from cryptography.exceptions import ( UnsupportedAlgorithm, _Reasons @@ -191,6 +193,10 @@ class DummyEllipticCurveBackend(object): if not self.elliptic_curve_supported(curve): raise UnsupportedAlgorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE) + def load_elliptic_curve_private_numbers(self, numbers): + if not self.elliptic_curve_supported(numbers.public_numbers.curve): + raise UnsupportedAlgorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE) + def elliptic_curve_private_key_from_numbers(self, numbers): if not self.elliptic_curve_supported(numbers.public_numbers.curve): raise UnsupportedAlgorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE) @@ -199,6 +205,10 @@ class DummyEllipticCurveBackend(object): if not self.elliptic_curve_supported(numbers.curve): raise UnsupportedAlgorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE) + def load_elliptic_curve_public_numbers(self, numbers): + if not self.elliptic_curve_supported(numbers.curve): + raise UnsupportedAlgorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE) + @utils.register_interface(PKCS8SerializationBackend) class DummyPKCS8SerializationBackend(object): @@ -463,7 +473,7 @@ class TestMultiBackend(object): backend.generate_elliptic_curve_private_key(ec.SECT283K1()) - backend.elliptic_curve_private_key_from_numbers( + backend.load_elliptic_curve_private_numbers( ec.EllipticCurvePrivateNumbers( 1, ec.EllipticCurvePublicNumbers( @@ -474,7 +484,7 @@ class TestMultiBackend(object): ) ) - backend.elliptic_curve_public_key_from_numbers( + backend.load_elliptic_curve_public_numbers( ec.EllipticCurvePublicNumbers( 2, 3, @@ -493,6 +503,51 @@ class TestMultiBackend(object): backend.generate_elliptic_curve_private_key(ec.SECT163K1()) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE): + backend.load_elliptic_curve_private_numbers( + ec.EllipticCurvePrivateNumbers( + 1, + ec.EllipticCurvePublicNumbers( + 2, + 3, + ec.SECT163K1() + ) + ) + ) + + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE): + backend.load_elliptic_curve_public_numbers( + ec.EllipticCurvePublicNumbers( + 2, + 3, + ec.SECT163K1() + ) + ) + + def test_deprecated_elliptic_curve(self): + backend = MultiBackend([ + DummyEllipticCurveBackend([ + ec.SECT283K1 + ]) + ]) + + assert backend.elliptic_curve_signature_algorithm_supported( + ec.ECDSA(hashes.SHA256()), + ec.SECT163K1() + ) is False + + pub_numbers = ec.EllipticCurvePublicNumbers(2, 3, ec.SECT283K1()) + numbers = ec.EllipticCurvePrivateNumbers(1, pub_numbers) + + pytest.deprecated_call( + backend.elliptic_curve_private_key_from_numbers, + numbers + ) + pytest.deprecated_call( + backend.elliptic_curve_public_key_from_numbers, + pub_numbers + ) + + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE): backend.elliptic_curve_private_key_from_numbers( ec.EllipticCurvePrivateNumbers( 1, diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 110bbdba..b00543fe 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -27,13 +27,15 @@ from cryptography.exceptions import InternalError, _Reasons from cryptography.hazmat.backends.openssl.backend import ( Backend, backend ) +from cryptography.hazmat.backends.openssl.ec import _sn_to_elliptic_curve from cryptography.hazmat.primitives import hashes, interfaces -from cryptography.hazmat.primitives.asymmetric import dsa, padding, rsa +from cryptography.hazmat.primitives.asymmetric import dsa, ec, padding, rsa from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import CBC, CTR from cryptography.hazmat.primitives.interfaces import BlockCipherAlgorithm +from ..primitives.test_ec import _skip_curve_unsupported from ...utils import load_vectors_from_file, raises_unsupported_algorithm @@ -508,7 +510,7 @@ class TestOpenSSLEllipticCurve(object): def test_sn_to_elliptic_curve_not_supported(self): with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE): - backend._sn_to_elliptic_curve(b"fake") + _sn_to_elliptic_curve(backend, b"fake") class TestDeprecatedRSABackendMethods(object): @@ -569,3 +571,41 @@ class TestDeprecatedDSABackendMethods(object): b"\x00" * 128, hashes.SHA1() ) + + +@pytest.mark.elliptic +class TestDeprecatedECBackendMethods(object): + def test_elliptic_curve_private_key_from_numbers(self): + d = 5634846038258869671139984276180670841223409490498798721258 + y = 4131560123026307384858369684985976479488628761329758810693 + x = 3402090428547195623222463880060959356423657484435591627791 + curve = ec.SECP192R1() + _skip_curve_unsupported(backend, curve) + pub_numbers = ec.EllipticCurvePublicNumbers( + x=x, + y=y, + curve=curve + ) + numbers = ec.EllipticCurvePrivateNumbers( + private_value=d, + public_numbers=pub_numbers + ) + pytest.deprecated_call( + backend.elliptic_curve_private_key_from_numbers, + numbers + ) + + def test_elliptic_curve_public_key_from_numbers(self): + y = 4131560123026307384858369684985976479488628761329758810693 + x = 3402090428547195623222463880060959356423657484435591627791 + curve = ec.SECP192R1() + _skip_curve_unsupported(backend, curve) + pub_numbers = ec.EllipticCurvePublicNumbers( + x=x, + y=y, + curve=curve + ) + pytest.deprecated_call( + backend.elliptic_curve_public_key_from_numbers, + pub_numbers + ) diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py index 65461f70..c53a0cb6 100644 --- a/tests/hazmat/primitives/test_ec.py +++ b/tests/hazmat/primitives/test_ec.py @@ -20,6 +20,7 @@ import os import pytest from cryptography import exceptions, utils +from cryptography.hazmat.backends.interfaces import EllipticCurveBackend from cryptography.hazmat.primitives import hashes, interfaces from cryptography.hazmat.primitives.asymmetric import ec @@ -70,6 +71,15 @@ class DummySignatureAlgorithm(object): pass +@utils.register_interface(EllipticCurveBackend) +class DeprecatedDummyECBackend(object): + def elliptic_curve_private_key_from_numbers(self, numbers): + return b"private_key" + + def elliptic_curve_public_key_from_numbers(self, numbers): + return b"public_key" + + @pytest.mark.elliptic def test_skip_curve_unsupported(backend): with pytest.raises(pytest.skip.Exception): @@ -129,6 +139,42 @@ def test_ec_numbers(): @pytest.mark.elliptic +class TestECWithNumbers(object): + @pytest.mark.parametrize( + ("vector", "hash_type"), + list(itertools.product( + load_vectors_from_file( + os.path.join( + "asymmetric", "ECDSA", "FIPS_186-3", "KeyPair.rsp"), + load_fips_ecdsa_key_pair_vectors + ), + _HASH_TYPES.values() + )) + ) + def test_with_numbers(self, backend, vector, hash_type): + curve_type = ec._CURVE_TYPES[vector['curve']] + + _skip_ecdsa_vector(backend, curve_type, hash_type) + + key = ec.EllipticCurvePrivateNumbers( + vector['d'], + ec.EllipticCurvePublicNumbers( + vector['x'], + vector['y'], + curve_type() + ) + ).private_key(backend) + assert key + + if isinstance(key, interfaces.EllipticCurvePrivateKeyWithNumbers): + priv_num = key.private_numbers() + assert priv_num.private_value == vector['d'] + assert priv_num.public_numbers.x == vector['x'] + assert priv_num.public_numbers.y == vector['y'] + assert curve_type().name == priv_num.public_numbers.curve.name + + +@pytest.mark.elliptic class TestECDSAVectors(object): @pytest.mark.parametrize( ("vector", "hash_type"), @@ -282,3 +328,14 @@ class TestECDSAVectors(object): verifier.verify() else: verifier.verify() + + def test_deprecated_public_private_key_load(self): + b = DeprecatedDummyECBackend() + pub_numbers = ec.EllipticCurvePublicNumbers( + 2, + 3, + ec.SECT283K1() + ) + numbers = ec.EllipticCurvePrivateNumbers(1, pub_numbers) + assert numbers.private_key(b) == b"private_key" + assert pub_numbers.public_key(b) == b"public_key" |