Support EC WithNumbers on OpenSSL backend + tests
diff --git a/cryptography/hazmat/backends/openssl/ec.py b/cryptography/hazmat/backends/openssl/ec.py
index 611dba2..879d674 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,50 @@
             raise UnsupportedAlgorithm(
                 "Unsupported elliptic curve signature algorithm.",
                 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+    def public_numbers(self):
+        bn_ctx = self._backend._lib.BN_CTX_new()
+        assert bn_ctx != self._backend._ffi.NULL
+        bn_ctx = self._backend._ffi.gc(bn_ctx, self._backend._lib.BN_CTX_free)
+
+        group = self._backend._lib.EC_KEY_get0_group(self._ec_key)
+        assert group != self._backend._ffi.NULL
+
+        method = self._backend._lib.EC_GROUP_method_of(group)
+        assert method != self._backend._ffi.NULL
+
+        nid = self._backend._lib.EC_METHOD_get_field_type(method)
+        assert nid != self._backend._lib.NID_undef
+
+        nid_two_field = self._backend._lib.OBJ_sn2nid(
+            b"characteristic-two-field"
+        )
+        assert nid_two_field != self._backend._lib.NID_undef
+
+        if nid == nid_two_field and self._backend._lib.Cryptography_HAS_EC2M:
+            get_func = self._backend._lib.EC_POINT_get_affine_coordinates_GF2m
+        else:
+            get_func = self._backend._lib.EC_POINT_get_affine_coordinates_GFp
+
+        point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key)
+        assert point != self._backend._ffi.NULL
+
+        try:
+            self._backend._lib.BN_CTX_start(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)
+        finally:
+            self._backend._lib.BN_CTX_end(bn_ctx)
+
+        return ec.EllipticCurvePublicNumbers(
+            x=x,
+            y=y,
+            curve=self._curve
+        )
diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py
index 65461f7..a2613db 100644
--- a/tests/hazmat/primitives/test_ec.py
+++ b/tests/hazmat/primitives/test_ec.py
@@ -129,6 +129,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 = _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"),