aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rst27
-rw-r--r--README.rst4
-rw-r--r--cryptography/hazmat/backends/interfaces.py4
-rw-r--r--cryptography/hazmat/backends/multibackend.py38
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py126
-rw-r--r--cryptography/hazmat/backends/openssl/ec.py73
-rw-r--r--cryptography/hazmat/primitives/asymmetric/ec.py10
-rw-r--r--cryptography/hazmat/primitives/interfaces.py18
-rw-r--r--docs/hazmat/backends/interfaces.rst4
-rw-r--r--docs/hazmat/primitives/interfaces.rst36
-rw-r--r--tests/hazmat/backends/test_multibackend.py59
-rw-r--r--tests/hazmat/backends/test_openssl.py44
-rw-r--r--tests/hazmat/primitives/test_ec.py57
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
~~~~~~~~~~~~~~~~~~
diff --git a/README.rst b/README.rst
index 5e1a82a8..465dd555 100644
--- a/README.rst
+++ b/README.rst
@@ -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"