Merge pull request #1359 from alex/purge-pypi

Refs #1224 -- try to purge PyPI after new tarball is uploaded
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index dfc6d8b..6557749 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,11 +6,38 @@
 
 .. 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 5e1a82a..465dd55 100644
--- a/README.rst
+++ b/README.rst
@@ -5,6 +5,10 @@
     :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 dc720ad..f471b94 100644
--- a/cryptography/hazmat/backends/interfaces.py
+++ b/cryptography/hazmat/backends/interfaces.py
@@ -260,13 +260,13 @@
         """
 
     @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 163dd0e..ce9e6de 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 @@
         )
 
     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 @@
             _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 @@
             _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 389ef0b..9a36674 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -479,9 +479,7 @@
             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 @@
             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 @@
         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 @@
             )
 
     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 @@
             )
         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 @@
         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 @@
 
         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 611dba2..9371a9a 100644
--- a/cryptography/hazmat/backends/openssl/ec.py
+++ b/cryptography/hazmat/backends/openssl/ec.py
@@ -63,6 +63,30 @@
     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 @@
         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 @@
         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 @@
             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 98eca27..6dcf39c 100644
--- a/cryptography/hazmat/primitives/asymmetric/ec.py
+++ b/cryptography/hazmat/primitives/asymmetric/ec.py
@@ -238,7 +238,10 @@
         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 @@
         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 d60f9e0..c7ad0cf 100644
--- a/cryptography/hazmat/primitives/interfaces.py
+++ b/cryptography/hazmat/primitives/interfaces.py
@@ -444,6 +444,15 @@
 
 
 @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 @@
         """
         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 e8e1bac..3b41433 100644
--- a/docs/hazmat/backends/interfaces.rst
+++ b/docs/hazmat/backends/interfaces.rst
@@ -558,7 +558,7 @@
             :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 @@
             :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 ac47c1e..2d594c8 100644
--- a/docs/hazmat/primitives/interfaces.rst
+++ b/docs/hazmat/primitives/interfaces.rst
@@ -416,7 +416,7 @@
 
     Extends :class:`DSAPublicKey`.
 
-    .. method:: private_numbers()
+    .. method:: public_numbers()
 
         Create a
         :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicNumbers`
@@ -492,6 +492,23 @@
         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 @@
         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 45c12b3..61bda54 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 @@
         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 @@
         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 @@
 
         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 @@
             )
         )
 
-        backend.elliptic_curve_public_key_from_numbers(
+        backend.load_elliptic_curve_public_numbers(
             ec.EllipticCurvePublicNumbers(
                 2,
                 3,
@@ -493,6 +503,51 @@
             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 110bbdb..b00543f 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -27,13 +27,15 @@
 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 @@
 
     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 @@
             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 65461f7..c53a0cb 100644
--- a/tests/hazmat/primitives/test_ec.py
+++ b/tests/hazmat/primitives/test_ec.py
@@ -20,6 +20,7 @@
 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 @@
     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 @@
 
 
 @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 @@
                 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"