ECDSA backend
diff --git a/cryptography/exceptions.py b/cryptography/exceptions.py
index b4ee8fe..c64b67f 100644
--- a/cryptography/exceptions.py
+++ b/cryptography/exceptions.py
@@ -21,6 +21,7 @@
     UNSUPPORTED_PADDING = object()
     UNSUPPORTED_MGF = object()
     UNSUPPORTED_PUBLIC_KEY_ALGORITHM = object()
+    UNSUPPORTED_ELLIPTIC_CURVE = object()
 
 
 class UnsupportedAlgorithm(Exception):
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index ffe0966..9cf92f9 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -25,13 +25,13 @@
     UnsupportedAlgorithm, _Reasons
 )
 from cryptography.hazmat.backends.interfaces import (
-    CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
-    PBKDF2HMACBackend, PKCS8SerializationBackend, RSABackend,
+    CMACBackend, CipherBackend, DSABackend, EllipticCurveBackend, HMACBackend,
+    HashBackend, PBKDF2HMACBackend, PKCS8SerializationBackend, RSABackend,
     TraditionalOpenSSLSerializationBackend
 )
 from cryptography.hazmat.bindings.openssl.binding import Binding
 from cryptography.hazmat.primitives import hashes, interfaces
-from cryptography.hazmat.primitives.asymmetric import dsa, rsa
+from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
 from cryptography.hazmat.primitives.asymmetric.padding import (
     MGF1, OAEP, PKCS1v15, PSS
 )
@@ -51,12 +51,13 @@
 @utils.register_interface(CipherBackend)
 @utils.register_interface(CMACBackend)
 @utils.register_interface(DSABackend)
+@utils.register_interface(EllipticCurveBackend)
 @utils.register_interface(HashBackend)
 @utils.register_interface(HMACBackend)
 @utils.register_interface(PBKDF2HMACBackend)
+@utils.register_interface(PKCS8SerializationBackend)
 @utils.register_interface(RSABackend)
 @utils.register_interface(TraditionalOpenSSLSerializationBackend)
-@utils.register_interface(PKCS8SerializationBackend)
 class Backend(object):
     """
     OpenSSL API binding interfaces.
@@ -425,8 +426,8 @@
         The char* is the storage for the BIO and it must stay alive until the
         BIO is finished with.
         """
-        data_char_p = backend._ffi.new("char[]", data)
-        bio = backend._lib.BIO_new_mem_buf(
+        data_char_p = self._ffi.new("char[]", data)
+        bio = self._lib.BIO_new_mem_buf(
             data_char_p, len(data)
         )
         assert bio != self._ffi.NULL
@@ -890,6 +891,239 @@
 
         return self._evp_pkey_to_private_key(evp_pkey)
 
+    def elliptic_curve_supported(self, curve):
+        if self._lib.Cryptography_HAS_EC != 1:
+            return False
+
+        curves = self._supported_curves()
+        return curve.name.encode("ascii") in curves
+
+    def elliptic_curve_signature_algorithm_supported(
+        self, signature_algorithm, curve
+    ):
+        if self._lib.Cryptography_HAS_EC != 1:
+            return False
+
+        # We only support ECDSA right now.
+        if isinstance(signature_algorithm, ec.ECDSA) is False:
+            return False
+
+        # Before 0.9.8m OpenSSL can't cope with digests longer than the curve.
+        if (
+            self._lib.OPENSSL_VERSION_NUMBER < 0x009080df and
+            curve.key_size < signature_algorithm.algorithm.digest_size * 8
+        ):
+            return False
+
+        if not self.elliptic_curve_supported(curve):
+            return False
+        else:
+            return True
+
+    def _supported_curves(self):
+        if self._lib.Cryptography_HAS_EC != 1:
+            return []
+
+        num_curves = self._lib.EC_get_builtin_curves(self._ffi.NULL, 0)
+        curve_array = self._ffi.new("EC_builtin_curve[]", num_curves)
+        num_curves_assigned = self._lib.EC_get_builtin_curves(
+            curve_array, num_curves)
+        assert num_curves == num_curves_assigned
+
+        curves = [
+            self._ffi.string(self._lib.OBJ_nid2sn(curve.nid)).decode()
+            for curve in curve_array
+        ]
+
+        curve_aliases = {
+            "prime192v1": "secp192r1",
+            "prime256v1": "secp256r1"
+        }
+        return [
+            curve_aliases.get(curve, curve)
+            for curve in curves
+        ]
+
+    def _create_ecdsa_signature_ctx(self, private_key, ecdsa):
+        return _ECDSASignatureContext(self, private_key, ecdsa.algorithm)
+
+    def _create_ecdsa_verification_ctx(self, public_key, signature, ecdsa):
+        return _ECDSAVerificationContext(self, public_key, signature,
+                                         ecdsa.algorithm)
+
+    def generate_elliptic_curve_private_key(self, curve):
+        """
+        Generate a new private key on the named 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)
+
+        res = self._lib.EC_KEY_generate_key(ctx)
+        assert res == 1
+
+        res = self._lib.EC_KEY_check_key(ctx)
+        assert res == 1
+
+        return _EllipticCurvePrivateKey(self, ctx, curve)
+
+    def elliptic_curve_private_key_from_numbers(self, numbers):
+        ec_key = self._ec_key_cdata_from_private_numbers(numbers)
+        return _EllipticCurvePrivateKey(self, ec_key,
+                                        numbers.public_numbers.curve)
+
+    def elliptic_curve_public_key_from_numbers(self, numbers):
+        ec_key = self._ec_key_cdata_from_public_numbers(numbers)
+        return _EllipticCurvePublicKey(self, ec_key, numbers.curve)
+
+    def _elliptic_curve_to_nid(self, curve):
+        """
+        Get the NID for a curve name.
+        """
+
+        curve_aliases = {
+            "secp192r1": "prime192v1",
+            "secp256r1": "prime256v1"
+        }
+
+        curve_name = curve_aliases.get(curve.name, curve.name)
+
+        curve_nid = self._lib.OBJ_sn2nid(curve_name.encode())
+        if curve_nid == self._lib.NID_undef:
+            raise UnsupportedAlgorithm(
+                "{0} is not a supported elliptic curve".format(curve.name),
+                _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+            )
+        return curve_nid
+
+    def _ec_key_cdata_from_private_numbers(self, numbers):
+        """
+        Build an EC_KEY from a private key object.
+        """
+
+        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)
+
+        ctx = self._ec_key_set_public_key_affine_coordinates(
+            ctx, public.x, public.y)
+
+        res = self._lib.EC_KEY_set_private_key(
+            ctx, self._int_to_bn(numbers.private_value))
+        assert res == 1
+
+        return ctx
+
+    def _ec_key_cdata_from_public_numbers(self, numbers):
+        """
+        Build an EC_KEY from a public key object.
+        """
+
+        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)
+
+        ctx = self._ec_key_set_public_key_affine_coordinates(
+            ctx, numbers.x, numbers.y)
+
+        return ctx
+
+    def _public_ec_key_from_private_ec_key(self, private_key_cdata):
+        """
+        Copy the public portions out of one EC key into a new one.
+        """
+
+        group = self._lib.EC_KEY_get0_group(private_key_cdata)
+        assert group != self._ffi.NULL
+
+        curve_nid = self._lib.EC_GROUP_get_curve_name(group)
+
+        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)
+
+        point = self._lib.EC_KEY_get0_public_key(private_key_cdata)
+        assert point != self._ffi.NULL
+
+        res = self._lib.EC_KEY_set_public_key(ctx, point)
+        assert res == 1
+
+        return ctx
+
+    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.
+        """
+
+        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
+
+        bn_ctx = self._lib.BN_CTX_new()
+        assert bn_ctx != self._ffi.NULL
+        bn_ctx = self._ffi.gc(bn_ctx, self._lib.BN_CTX_free)
+
+        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
+
+        nid = self._lib.EC_METHOD_get_field_type(method)
+        assert nid != self._lib.NID_undef
+
+        check_x = self._lib.BN_CTX_get(bn_ctx)
+        check_y = self._lib.BN_CTX_get(bn_ctx)
+
+        if nid == nid_two_field and self._lib.Cryptography_HAS_EC2M:
+            set_func = self._lib.EC_POINT_set_affine_coordinates_GF2m
+            get_func = self._lib.EC_POINT_get_affine_coordinates_GF2m
+        else:
+            set_func = self._lib.EC_POINT_set_affine_coordinates_GFp
+            get_func = self._lib.EC_POINT_get_affine_coordinates_GFp
+
+        assert set_func and get_func
+
+        res = set_func(group, point, bn_x, bn_y, bn_ctx)
+        assert res == 1
+
+        res = get_func(group, point, check_x, check_y, bn_ctx)
+        assert res == 1
+
+        assert (
+            self._lib.BN_cmp(bn_x, check_x) == 0 and
+            self._lib.BN_cmp(bn_y, check_y) == 0
+        )
+
+        res = self._lib.EC_KEY_set_public_key(ctx, point)
+        assert res == 1
+
+        res = self._lib.EC_KEY_check_key(ctx)
+        assert res == 1
+
+        return ctx
+
 
 class GetCipherByName(object):
     def __init__(self, fmt):
@@ -1727,4 +1961,156 @@
         )
 
 
+def _truncate_digest_for_ecdsa(ec_key_cdata, digest, backend):
+    _lib = backend._lib
+    _ffi = backend._ffi
+
+    digest_len = len(digest)
+
+    group = _lib.EC_KEY_get0_group(ec_key_cdata)
+
+    bn_ctx = _lib.BN_CTX_new()
+    assert bn_ctx != _ffi.NULL
+    bn_ctx = _ffi.gc(bn_ctx, _lib.BN_CTX_free)
+
+    order = _lib.BN_CTX_get(bn_ctx)
+    assert order != _ffi.NULL
+
+    res = _lib.EC_GROUP_get_order(group, order, bn_ctx)
+    assert res == 1
+
+    order_bits = _lib.BN_num_bits(order)
+
+    if 8 * digest_len > order_bits:
+        digest_len = (order_bits + 7) // 8
+        digest = digest[:digest_len]
+
+    if 8 * digest_len > order_bits:
+        rshift = 8 - (order_bits & 0x7)
+        assert rshift > 0 and rshift < 8
+
+        mask = 0xFF >> rshift << rshift
+
+        # Set the bottom rshift bits to 0
+        digest = digest[:-1] + six.int2byte(six.byte2int(digest[-1]) & mask)
+
+    return digest
+
+
+@utils.register_interface(interfaces.AsymmetricSignatureContext)
+class _ECDSASignatureContext(object):
+    def __init__(self, backend, private_key, algorithm):
+        self._backend = backend
+        self._private_key = private_key
+        self._digest = hashes.Hash(algorithm, backend)
+
+    def update(self, data):
+        self._digest.update(data)
+
+    def finalize(self):
+        ec_key = self._private_key._ec_key
+
+        digest = self._digest.finalize()
+
+        digest = _truncate_digest_for_ecdsa(ec_key, digest, self._backend)
+
+        max_size = self._backend._lib.ECDSA_size(ec_key)
+        assert max_size > 0
+
+        sigbuf = self._backend._ffi.new("char[]", max_size)
+        siglen_ptr = self._backend._ffi.new("unsigned int[]", 1)
+        res = self._backend._lib.ECDSA_sign(
+            0,
+            digest,
+            len(digest),
+            sigbuf,
+            siglen_ptr,
+            ec_key
+        )
+        assert res == 1
+        return self._backend._ffi.buffer(sigbuf)[:siglen_ptr[0]]
+
+
+@utils.register_interface(interfaces.AsymmetricVerificationContext)
+class _ECDSAVerificationContext(object):
+    def __init__(self, backend, public_key, signature, algorithm):
+        self._backend = backend
+        self._public_key = public_key
+        self._signature = signature
+        self._digest = hashes.Hash(algorithm, backend)
+
+    def update(self, data):
+        self._digest.update(data)
+
+    def verify(self):
+        ec_key = self._public_key._ec_key
+
+        digest = self._digest.finalize()
+
+        digest = _truncate_digest_for_ecdsa(ec_key, digest, self._backend)
+
+        res = self._backend._lib.ECDSA_verify(
+            0,
+            digest,
+            len(digest),
+            self._signature,
+            len(self._signature),
+            ec_key
+        )
+        if res != 1:
+            self._backend._consume_errors()
+            raise InvalidSignature
+        return True
+
+
+@utils.register_interface(interfaces.EllipticCurvePrivateKey)
+class _EllipticCurvePrivateKey(object):
+    def __init__(self, backend, ec_key_cdata, curve):
+        self._backend = backend
+        self._ec_key = ec_key_cdata
+        self._curve = curve
+
+    @property
+    def curve(self):
+        return self._curve
+
+    def signer(self, signature_algorithm):
+        if isinstance(signature_algorithm, ec.ECDSA):
+            return self._backend._create_ecdsa_signature_ctx(
+                self, signature_algorithm)
+        else:
+            raise UnsupportedAlgorithm(
+                "Unsupported elliptic curve signature algorithm.",
+                _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+    def public_key(self):
+        public_ec_key = self._backend._public_ec_key_from_private_ec_key(
+            self._ec_key
+        )
+
+        return _EllipticCurvePublicKey(
+            self._backend, public_ec_key, self._curve)
+
+
+@utils.register_interface(interfaces.EllipticCurvePublicKey)
+class _EllipticCurvePublicKey(object):
+    def __init__(self, backend, ec_key_cdata, curve):
+        self._backend = backend
+        self._ec_key = ec_key_cdata
+        self._curve = curve
+
+    @property
+    def curve(self):
+        return self._curve
+
+    def verifier(self, signature, signature_algorithm):
+        if isinstance(signature_algorithm, ec.ECDSA):
+            return self._backend._create_ecdsa_verification_ctx(
+                self, signature, signature_algorithm)
+        else:
+            raise UnsupportedAlgorithm(
+                "Unsupported elliptic curve signature algorithm.",
+                _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+
 backend = Backend()
diff --git a/cryptography/hazmat/primitives/asymmetric/ec.py b/cryptography/hazmat/primitives/asymmetric/ec.py
index 1e49ad7..220a419 100644
--- a/cryptography/hazmat/primitives/asymmetric/ec.py
+++ b/cryptography/hazmat/primitives/asymmetric/ec.py
@@ -15,9 +15,189 @@
 
 import six
 
+from cryptography import utils
 from cryptography.hazmat.primitives import interfaces
 
 
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT571R1(object):
+    @property
+    def name(self):
+        return "sect571r1"
+
+    @property
+    def key_size(self):
+        return 571
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT409R1(object):
+    @property
+    def name(self):
+        return "sect409r1"
+
+    @property
+    def key_size(self):
+        return 409
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT283R1(object):
+    @property
+    def name(self):
+        return "sect283r1"
+
+    @property
+    def key_size(self):
+        return 283
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT233R1(object):
+    @property
+    def name(self):
+        return "sect233r1"
+
+    @property
+    def key_size(self):
+        return 233
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT163R2(object):
+    @property
+    def name(self):
+        return "sect163r2"
+
+    @property
+    def key_size(self):
+        return 163
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT571K1(object):
+    @property
+    def name(self):
+        return "sect571k1"
+
+    @property
+    def key_size(self):
+        return 571
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT409K1(object):
+    @property
+    def name(self):
+        return "sect409k1"
+
+    @property
+    def key_size(self):
+        return 409
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT283K1(object):
+    @property
+    def name(self):
+        return "sect283k1"
+
+    @property
+    def key_size(self):
+        return 283
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT233K1(object):
+    @property
+    def name(self):
+        return "sect233k1"
+
+    @property
+    def key_size(self):
+        return 233
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT163K1(object):
+    @property
+    def name(self):
+        return "sect163k1"
+
+    @property
+    def key_size(self):
+        return 163
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECP521R1(object):
+    @property
+    def name(self):
+        return "secp521r1"
+
+    @property
+    def key_size(self):
+        return 521
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECP384R1(object):
+    @property
+    def name(self):
+        return "secp384r1"
+
+    @property
+    def key_size(self):
+        return 384
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECP256R1(object):
+    @property
+    def name(self):
+        return "secp256r1"
+
+    @property
+    def key_size(self):
+        return 256
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECP224R1(object):
+    @property
+    def name(self):
+        return "secp224r1"
+
+    @property
+    def key_size(self):
+        return 224
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECP192R1(object):
+    @property
+    def name(self):
+        return "secp192r1"
+
+    @property
+    def key_size(self):
+        return 192
+
+
+@utils.register_interface(interfaces.EllipticCurveSignatureAlgorithm)
+class ECDSA(object):
+    def __init__(self, algorithm):
+        self._algorithm = algorithm
+
+    @property
+    def algorithm(self):
+        return self._algorithm
+
+
+def generate_private_key(curve, backend):
+    return backend.generate_elliptic_curve_private_key(curve)
+
+
 class EllipticCurvePublicNumbers(object):
     def __init__(self, x, y, curve):
         if (
@@ -33,6 +213,9 @@
         self._x = x
         self._curve = curve
 
+    def public_key(self, backend):
+        return backend.elliptic_curve_public_key_from_numbers(self)
+
     @property
     def curve(self):
         return self._curve
@@ -60,6 +243,9 @@
         self._private_value = private_value
         self._public_numbers = public_numbers
 
+    def private_key(self, backend):
+        return backend.elliptic_curve_private_key_from_numbers(self)
+
     @property
     def private_value(self):
         return self._private_value
diff --git a/docs/hazmat/primitives/asymmetric/ec.rst b/docs/hazmat/primitives/asymmetric/ec.rst
index f88b965..798fbab 100644
--- a/docs/hazmat/primitives/asymmetric/ec.rst
+++ b/docs/hazmat/primitives/asymmetric/ec.rst
@@ -1,11 +1,30 @@
 .. hazmat::
 
-Elliptic Curve
-==============
+Elliptic Curve Cryptography
+===========================
 
 .. currentmodule:: cryptography.hazmat.primitives.asymmetric.ec
 
 
+,, method:: generate_private_key(curve, backend):
+
+    .. versionadded:: 0.5
+
+    Generate a new private key on ``curve`` for use with ``backend``.
+
+    :param backend: A
+        :class:`~cryptography.hazmat.primtives.interfaces.EllipticCurve`
+        provider.
+
+    :param backend: A
+        :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`
+        provider.
+
+    :returns: A new instance of a
+        :class:`~cryptography.hazmat.primtivies.interfaces.EllipticCurvePrivateKey`
+        provider.
+
+
 .. class:: EllipticCurvePrivateNumbers(private_value, public_numbers)
 
     .. versionadded:: 0.5
@@ -25,6 +44,19 @@
 
         The private value.
 
+    .. method:: private_key(backend)
+
+        Convert a collection of numbers into a private key suitable for doing
+        actual cryptographic operations.
+
+        :param backend: A
+            :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`
+            provider.
+
+        :returns: A new instance of a
+            :class:`~cryptography.hazmat.primtivies.interfaces.EllipticCurvePrivateKey`
+            provider.
+
 
 .. class:: EllipticCurvePublicNumbers(x, y, curve)
 
@@ -49,3 +81,149 @@
         :type: int
 
         The affine y component of the public point used for verifying.
+
+    .. method:: public_key(backend)
+
+        Convert a collection of numbers into a public key suitable for doing
+        actual cryptographic operations.
+
+        :param backend: A
+            :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`
+            provider.
+
+        :returns: A new instance of a
+            :class:`~cryptography.hazmat.primtivies.interfaces.EllipticCurvePublicKey`
+            provider.
+
+
+Elliptic Curve Signature Algorithms
+-----------------------------------
+
+.. class:: ECDSA(algorithm)
+    .. versionadded:: 0.5
+
+    The ECDSA signature algorithm first standardized in NIST publication
+    `FIPS 186-3`_, and later in `FIPS 186-4`_.
+
+    :param algorithm: An instance of a
+        :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm`
+        provider.
+
+    .. code-block:: pycon
+
+        >>> from cryptography.hazmat.backends import default_backend
+        >>> from cryptography.hazmat.primitives import hashes
+        >>> from cryptography.hazmat.primitives.asymmetric import ec
+        >>> private_key = ec.generate_private_key(
+        ...     ec.SECT283K1(), default_backend()
+        ... )
+        >>> signer = private_key.signer(ec.ECDSA(hashes.SHA256()))
+        >>> signer.update(b"this is some data I'd like")
+        >>> signer.update(b" to sign")
+        >>> signature = signer.finalize()
+
+Elliptic Curves
+---------------
+
+All named curves are providers of
+:class:`~cryptography.hazmat.primtives.interfaces.EllipticCurve`.
+
+There is `some concern`_ that the non-Koblitz NIST curves (identified by names
+that start with "B" or "P") may have been intentionally weakened by their
+generation process.
+
+
+.. class:: SECT571K1
+    .. versionadded:: 0.5
+
+    SECG curve ``sect571k1``. Also called NIST K-571.
+
+
+.. class:: SECT409K1
+    .. versionadded:: 0.5
+
+    SECG curve ``sect409k1``. Also called NIST K-409.
+
+
+.. class:: SECT283K1
+    .. versionadded:: 0.5
+
+    SECG curve ``sect283k1``. Also called NIST K-283.
+
+
+.. class:: SECT233K1
+    .. versionadded:: 0.5
+
+    SECG curve ``sect233k1``. Also called NIST K-233.
+
+
+.. class:: SECT163K1
+    .. versionadded:: 0.5
+
+    SECG curve ``sect163k1``. Also called NIST K-163.
+
+
+.. class:: SECT571R1
+    .. versionadded:: 0.5
+
+    SECG curve ``sect571r1``. Also called NIST B-571.
+
+
+.. class:: SECT409R1
+    .. versionadded:: 0.5
+
+    SECG curve ``sect409r1``. Also called NIST B-409.
+
+
+.. class:: SECT283R1
+    .. versionadded:: 0.5
+
+    SECG curve ``sect283r1``. Also called NIST B-283.
+
+
+.. class:: SECT233R1
+    .. versionadded:: 0.5
+
+    SECG curve ``sect233r1``. Also called NIST B-233.
+
+
+.. class:: SECT163R2
+    .. versionadded:: 0.5
+
+    SECG curve ``sect163r2``. Also called NIST B-163.
+
+
+.. class:: SECP521R1
+    .. versionadded:: 0.5
+
+    SECG curve ``secp521r1``. Also called NIST P-521.
+
+
+.. class:: SECP384R1
+    .. versionadded:: 0.5
+
+    SECG curve ``secp384r1``. Also called NIST P-384.
+
+
+.. class:: SECP256R1
+    .. versionadded:: 0.5
+
+    SECG curve ``secp256r1``. Also called NIST P-256.
+
+
+.. class:: SECT224R1
+    .. versionadded:: 0.5
+
+    SECG curve ``secp224r1``. Also called NIST P-224.
+
+
+.. class:: SECP192R1
+    .. versionadded:: 0.5
+
+    SECG curve ``secp192r1``. Also called NIST P-192.
+
+
+
+.. _`FIPS 186-3`: http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf
+.. _`FIPS 186-4`: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
+.. _`some concern`: https://crypto.stackexchange.com/questions/10263/should-we-trust-the-nist-recommended-ecc-parameters
diff --git a/docs/hazmat/primitives/interfaces.rst b/docs/hazmat/primitives/interfaces.rst
index 34e4e93..d5ca59a 100644
--- a/docs/hazmat/primitives/interfaces.rst
+++ b/docs/hazmat/primitives/interfaces.rst
@@ -411,7 +411,6 @@
     `EdDSA`_.
 
     .. classmethod:: signer(signature_algorithm)
-
         Sign data which can be verified later by others using the public key.
 
         :param signature_algorithm: An instance of a
@@ -421,7 +420,6 @@
         :returns:
             :class:`~cryptography.hazmat.primitives.interfaces.AsymmetricSignatureContext`
 
-    .. attribute:: curve
 
         :type: :class:`~cryptography.hazmat.primitives.interfaces.EllipticCurve`
 
@@ -440,8 +438,7 @@
 
     An elliptic curve public key.
 
-    .. classmethod:: verifier(signer, signature_algorithm)
-
+    .. classmethod:: verifier(signature, signature_algorithm)
         Verify data was signed by the private key associated with this public
         key.
 
diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt
index 9baf082..d5a2bee 100644
--- a/docs/spelling_wordlist.txt
+++ b/docs/spelling_wordlist.txt
@@ -27,6 +27,7 @@
 introspectability
 invariants
 iOS
+Koblitz
 metadata
 pickleable
 plaintext
diff --git a/pytest.ini b/pytest.ini
index 9b44f19..00a2c7f 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -11,3 +11,4 @@
     traditional_openssl_serialization: this test requires a backend providing TraditionalOpenSSLSerializationBackend
     pkcs8_serialization: this test requires a backend providing PKCS8SerializationBackend
     supported: parametrized test requiring only_if and skip_message
+    elliptic: this test requires a backend providing EllipticCurveBackend
diff --git a/tests/conftest.py b/tests/conftest.py
index b1326dc..af14638 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -17,8 +17,8 @@
 
 from cryptography.hazmat.backends import _available_backends
 from cryptography.hazmat.backends.interfaces import (
-    CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
-    PBKDF2HMACBackend, PKCS8SerializationBackend, RSABackend,
+    CMACBackend, CipherBackend, DSABackend, EllipticCurveBackend, HMACBackend,
+    HashBackend, PBKDF2HMACBackend, PKCS8SerializationBackend, RSABackend,
     TraditionalOpenSSLSerializationBackend
 )
 from .utils import check_backend_support, check_for_iface, select_backends
@@ -46,11 +46,8 @@
         TraditionalOpenSSLSerializationBackend,
         item
     )
-    check_for_iface(
-        "pkcs8_serialization",
-        PKCS8SerializationBackend,
-        item
-    )
+    check_for_iface("pkcs8_serialization", PKCS8SerializationBackend, item)
+    check_for_iface("elliptic", EllipticCurveBackend, item)
     check_backend_support(item)
 
 
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index bfcdf14..aa2122f 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -19,7 +19,9 @@
 
 from cryptography import utils
 from cryptography.exceptions import InternalError, _Reasons
-from cryptography.hazmat.backends.openssl.backend import Backend, backend
+from cryptography.hazmat.backends.openssl.backend import (
+    Backend, backend
+)
 from cryptography.hazmat.primitives import hashes, interfaces
 from cryptography.hazmat.primitives.asymmetric import dsa, padding, rsa
 from cryptography.hazmat.primitives.ciphers import Cipher
@@ -445,3 +447,22 @@
         key = pretend.stub(type="unsupported")
         with raises_unsupported_algorithm(None):
             backend._evp_pkey_to_private_key(key)
+
+
+class TestOpenSSLNoEllipticCurve(object):
+    def test_elliptic_curve_supported(self, monkeypatch):
+        monkeypatch.setattr(backend._lib, "Cryptography_HAS_EC", 0)
+
+        assert backend.elliptic_curve_supported(None) is False
+
+    def test_elliptic_curve_signature_algorithm_supported(self, monkeypatch):
+        monkeypatch.setattr(backend._lib, "Cryptography_HAS_EC", 0)
+
+        assert backend.elliptic_curve_signature_algorithm_supported(
+            None, None
+        ) is False
+
+    def test_supported_curves(self, monkeypatch):
+        monkeypatch.setattr(backend._lib, "Cryptography_HAS_EC", 0)
+
+        assert backend._supported_curves() == []
diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py
index 53985fe..1879f4f 100644
--- a/tests/hazmat/primitives/test_ec.py
+++ b/tests/hazmat/primitives/test_ec.py
@@ -14,66 +14,286 @@
 
 from __future__ import absolute_import, division, print_function
 
+import itertools
+import os
+
 import pytest
 
-from cryptography import utils
-from cryptography.hazmat.primitives import interfaces
+from cryptography import exceptions, utils
+from cryptography.hazmat.primitives import hashes, interfaces
 from cryptography.hazmat.primitives.asymmetric import ec
 
+from ...utils import (
+    der_encode_dsa_signature, load_fips_ecdsa_key_pair_vectors,
+    load_fips_ecdsa_signing_vectors, load_vectors_from_file,
+    raises_unsupported_algorithm
+)
+
+_CURVE_TYPES = {
+    "secp192r1": ec.SECP192R1,
+    "secp224r1": ec.SECP224R1,
+    "secp256r1": ec.SECP256R1,
+    "secp384r1": ec.SECP384R1,
+    "secp521r1": ec.SECP521R1,
+
+    "sect163k1": ec.SECT163K1,
+    "sect233k1": ec.SECT233K1,
+    "sect283k1": ec.SECT283K1,
+    "sect409k1": ec.SECT409K1,
+    "sect571k1": ec.SECT571K1,
+
+    "sect163r2": ec.SECT163R2,
+    "sect233r1": ec.SECT233R1,
+    "sect283r1": ec.SECT283R1,
+    "sect409r1": ec.SECT409R1,
+    "sect571r1": ec.SECT571R1,
+}
+
+_HASH_TYPES = {
+    "SHA-1": hashes.SHA1,
+    "SHA-224": hashes.SHA224,
+    "SHA-256": hashes.SHA256,
+    "SHA-384": hashes.SHA384,
+    "SHA-512": hashes.SHA512,
+}
+
+
+def _skip_ecdsa_vector(backend, curve_type, hash_type):
+    if not backend.elliptic_curve_signature_algorithm_supported(
+        ec.ECDSA(hash_type()),
+        curve_type()
+    ):
+        pytest.skip(
+            "ECDSA not supported with this hash {0} and curve {1}".format(
+                hash_type().name, curve_type().name
+            )
+        )
+
 
 @utils.register_interface(interfaces.EllipticCurve)
 class DummyCurve(object):
     name = "dummy-curve"
+    key_size = 1
 
 
-class TestECC(object):
-    def test_ec_numbers(self):
-        numbers = ec.EllipticCurvePrivateNumbers(
-            1,
+@utils.register_interface(interfaces.EllipticCurveSignatureAlgorithm)
+class DummySignatureAlgorithm(object):
+    pass
+
+
+def test_ec_numbers():
+    numbers = ec.EllipticCurvePrivateNumbers(
+        1,
+        ec.EllipticCurvePublicNumbers(
+            2, 3, DummyCurve()
+        )
+    )
+
+    assert numbers.private_value == 1
+    assert numbers.public_numbers.x == 2
+    assert numbers.public_numbers.y == 3
+    assert isinstance(numbers.public_numbers.curve, DummyCurve)
+
+    with pytest.raises(TypeError):
+        ec.EllipticCurvePrivateNumbers(
+            None,
             ec.EllipticCurvePublicNumbers(
                 2, 3, DummyCurve()
             )
         )
 
-        assert numbers.private_value == 1
-        assert numbers.public_numbers.x == 2
-        assert numbers.public_numbers.y == 3
-        assert isinstance(numbers.public_numbers.curve, DummyCurve)
+    with pytest.raises(TypeError):
+        ec.EllipticCurvePrivateNumbers(
+            1,
+            ec.EllipticCurvePublicNumbers(
+                None, 3, DummyCurve()
+            )
+        )
 
-        with pytest.raises(TypeError):
-            ec.EllipticCurvePrivateNumbers(
-                None,
-                ec.EllipticCurvePublicNumbers(
-                    2, 3, DummyCurve()
+    with pytest.raises(TypeError):
+        ec.EllipticCurvePrivateNumbers(
+            1,
+            ec.EllipticCurvePublicNumbers(
+                2, None, DummyCurve()
+            )
+        )
+
+    with pytest.raises(TypeError):
+        ec.EllipticCurvePrivateNumbers(
+            1,
+            ec.EllipticCurvePublicNumbers(
+                2, 3, None
+            )
+        )
+
+    with pytest.raises(TypeError):
+        ec.EllipticCurvePrivateNumbers(
+            1,
+            None
+        )
+
+
+@pytest.mark.elliptic
+class TestECDSAVectors(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_signing_with_example_keys(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
+
+        pkey = key.public_key()
+        assert pkey
+
+        signer = key.signer(ec.ECDSA(hash_type()))
+        signer.update(b"YELLOW SUBMARINE")
+        signature = signer.finalize()
+
+        verifier = pkey.verifier(signature, ec.ECDSA(hash_type()))
+        verifier.update(b"YELLOW SUBMARINE")
+        verifier.verify()
+
+    @pytest.mark.parametrize(
+        "curve", _CURVE_TYPES.values()
+    )
+    def test_generate_vector_curves(self, backend, curve):
+        if not backend.elliptic_curve_supported(curve()):
+            pytest.skip(
+                "Curve {0} is not supported by this backend {1}".format(
+                    curve().name, backend
                 )
             )
 
-        with pytest.raises(TypeError):
-            ec.EllipticCurvePrivateNumbers(
-                1,
-                ec.EllipticCurvePublicNumbers(
-                    None, 3, DummyCurve()
+        key = ec.generate_private_key(curve(), backend)
+        assert key
+        assert isinstance(key.curve, curve)
+        assert key.curve.key_size
+
+        pkey = key.public_key()
+        assert pkey
+        assert isinstance(pkey.curve, curve)
+        assert key.curve.key_size == pkey.curve.key_size
+
+    def test_generate_unknown_curve(self, backend):
+        with raises_unsupported_algorithm(
+            exceptions._Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+        ):
+            ec.generate_private_key(DummyCurve(), backend)
+
+        assert backend.elliptic_curve_signature_algorithm_supported(
+            ec.ECDSA(hashes.SHA256()),
+            DummyCurve()
+        ) is False
+
+    def test_unknown_signature_algoritm(self, backend):
+        if not backend.elliptic_curve_supported(ec.SECP192R1()):
+            pytest.skip(
+                "Curve secp192r1 is not supported by this backend {0}".format(
+                    backend
                 )
             )
 
-        with pytest.raises(TypeError):
-            ec.EllipticCurvePrivateNumbers(
-                1,
-                ec.EllipticCurvePublicNumbers(
-                    2, None, DummyCurve()
-                )
-            )
+        key = ec.generate_private_key(ec.SECP192R1(), backend)
 
-        with pytest.raises(TypeError):
-            ec.EllipticCurvePrivateNumbers(
-                1,
-                ec.EllipticCurvePublicNumbers(
-                    2, 3, None
-                )
-            )
+        with raises_unsupported_algorithm(
+            exceptions._Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+        ):
+            key.signer(DummySignatureAlgorithm())
 
-        with pytest.raises(TypeError):
-            ec.EllipticCurvePrivateNumbers(
-                1,
-                None
-            )
+        with raises_unsupported_algorithm(
+            exceptions._Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+        ):
+            key.public_key().verifier(b"", DummySignatureAlgorithm())
+
+        assert backend.elliptic_curve_signature_algorithm_supported(
+            DummySignatureAlgorithm(),
+            ec.SECP192R1()
+        ) is False
+
+    @pytest.mark.parametrize(
+        "vector",
+        load_vectors_from_file(
+            os.path.join(
+                "asymmetric", "ECDSA", "FIPS_186-3", "SigGen.txt"),
+            load_fips_ecdsa_signing_vectors
+        )
+    )
+    def test_signatures(self, backend, vector):
+        hash_type = _HASH_TYPES[vector['digest_algorithm']]
+        curve_type = _CURVE_TYPES[vector['curve']]
+
+        _skip_ecdsa_vector(backend, curve_type, hash_type)
+
+        key = ec.EllipticCurvePublicNumbers(
+            vector['x'],
+            vector['y'],
+            curve_type()
+        ).public_key(backend)
+
+        signature = der_encode_dsa_signature(
+            vector['r'],
+            vector['s']
+        )
+
+        verifier = key.verifier(
+            signature,
+            ec.ECDSA(hash_type())
+        )
+        verifier.update(vector['message'])
+        assert verifier.verify()
+
+    @pytest.mark.parametrize(
+        "vector",
+        load_vectors_from_file(
+            os.path.join(
+                "asymmetric", "ECDSA", "FIPS_186-3", "SigVer.rsp"),
+            load_fips_ecdsa_signing_vectors
+        )
+    )
+    def test_signature_failures(self, backend, vector):
+        hash_type = _HASH_TYPES[vector['digest_algorithm']]
+        curve_type = _CURVE_TYPES[vector['curve']]
+
+        _skip_ecdsa_vector(backend, curve_type, hash_type)
+
+        key = ec.EllipticCurvePublicNumbers(
+            vector['x'],
+            vector['y'],
+            curve_type()
+        ).public_key(backend)
+
+        signature = der_encode_dsa_signature(
+            vector['r'],
+            vector['s']
+        )
+
+        verifier = key.verifier(
+            signature,
+            ec.ECDSA(hash_type())
+        )
+        verifier.update(vector['message'])
+
+        if vector["fail"] is True:
+            with pytest.raises(exceptions.InvalidSignature):
+                verifier.verify()
+        else:
+            verifier.verify()