Merge pull request #1361 from reaperhulk/more-changelog

more changelog entries from the 0.6 cycle
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 51a4c67..5579c41 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,6 +6,11 @@
 
 .. 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
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/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index d0f6937..582623f 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -1103,30 +1103,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
 
@@ -1142,6 +1131,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..369b185 100644
--- a/cryptography/hazmat/backends/openssl/ec.py
+++ b/cryptography/hazmat/backends/openssl/ec.py
@@ -129,7 +129,7 @@
         return True
 
 
-@utils.register_interface(interfaces.EllipticCurvePrivateKey)
+@utils.register_interface(interfaces.EllipticCurvePrivateKeyWithNumbers)
 class _EllipticCurvePrivateKey(object):
     def __init__(self, backend, ec_key_cdata, curve):
         self._backend = backend
@@ -172,8 +172,16 @@
             self._backend, public_ec_key, self._curve
         )
 
+    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):
         self._backend = backend
@@ -193,3 +201,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/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/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/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py
index 3550582..c53a0cb 100644
--- a/tests/hazmat/primitives/test_ec.py
+++ b/tests/hazmat/primitives/test_ec.py
@@ -139,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"),