Merge pull request #1193 from reaperhulk/simplify-some-ec-things

reorganize OpenSSL EC backend to remove some unneeded indirection
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 0f26be4..e057b63 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -28,9 +28,20 @@
 * Deprecated :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`
   in favor of backend specific providers of the
   :class:`~cryptography.hazmat.primitives.interfaces.RSAPublicKey` interface.
+* Deprecated :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`
+  in favor of backend specific providers of the
+  :class:`~cryptography.hazmat.primitives.interfaces.DSAPrivateKey` interface.
+* Deprecated :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`
+  in favor of backend specific providers of the
+  :class:`~cryptography.hazmat.primitives.interfaces.DSAPublicKey` interface.
+* Deprecated :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters`
+  in favor of backend specific providers of the
+  :class:`~cryptography.hazmat.primitives.interfaces.DSAParameters` interface.
 * Deprecated ``encrypt_rsa``, ``decrypt_rsa``, ``create_rsa_signature_ctx`` and
   ``create_rsa_verification_ctx`` on
   :class:`~cryptography.hazmat.backends.interfaces.RSABackend`.
+* Deprecated ``create_dsa_signature_ctx`` and ``create_dsa_verification_ctx``
+  on :class:`~cryptography.hazmat.backends.interfaces.DSABackend`.
 
 0.4 - 2014-05-03
 ~~~~~~~~~~~~~~~~
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 9f002f1..e8fc3a4 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -633,12 +633,24 @@
         return self.generate_dsa_private_key(parameters)
 
     def create_dsa_signature_ctx(self, private_key, algorithm):
+        warnings.warn(
+            "create_dsa_signature_ctx is deprecated and will be removed in "
+            "a future version.",
+            utils.DeprecatedIn05,
+            stacklevel=2
+        )
         dsa_cdata = self._dsa_cdata_from_private_key(private_key)
         key = _DSAPrivateKey(self, dsa_cdata)
         return _DSASignatureContext(self, key, algorithm)
 
     def create_dsa_verification_ctx(self, public_key, signature,
                                     algorithm):
+        warnings.warn(
+            "create_dsa_verification_ctx is deprecated and will be removed in "
+            "a future version.",
+            utils.DeprecatedIn05,
+            stacklevel=2
+        )
         dsa_cdata = self._dsa_cdata_from_public_key(public_key)
         key = _DSAPublicKey(self, dsa_cdata)
         return _DSAVerificationContext(self, key, signature, algorithm)
@@ -743,122 +755,6 @@
         key = _RSAPublicKey(self, rsa_cdata)
         return key.encrypt(plaintext, padding)
 
-    def _enc_dec_rsa(self, key, data, padding):
-        if isinstance(padding, PKCS1v15):
-            padding_enum = self._lib.RSA_PKCS1_PADDING
-        elif isinstance(padding, OAEP):
-            padding_enum = self._lib.RSA_PKCS1_OAEP_PADDING
-            if not isinstance(padding._mgf, MGF1):
-                raise UnsupportedAlgorithm(
-                    "Only MGF1 is supported by this backend.",
-                    _Reasons.UNSUPPORTED_MGF
-                )
-
-            if not isinstance(padding._mgf._algorithm, hashes.SHA1):
-                raise UnsupportedAlgorithm(
-                    "This backend supports only SHA1 inside MGF1 when "
-                    "using OAEP.",
-                    _Reasons.UNSUPPORTED_HASH
-                )
-
-            if padding._label is not None and padding._label != b"":
-                raise ValueError("This backend does not support OAEP labels.")
-
-            if not isinstance(padding._algorithm, hashes.SHA1):
-                raise UnsupportedAlgorithm(
-                    "This backend only supports SHA1 when using OAEP.",
-                    _Reasons.UNSUPPORTED_HASH
-                )
-        else:
-            raise UnsupportedAlgorithm(
-                "{0} is not supported by this backend.".format(
-                    padding.name
-                ),
-                _Reasons.UNSUPPORTED_PADDING
-            )
-
-        if self._lib.Cryptography_HAS_PKEY_CTX:
-            return self._enc_dec_rsa_pkey_ctx(key, data, padding_enum)
-        else:
-            return self._enc_dec_rsa_098(key, data, padding_enum)
-
-    def _enc_dec_rsa_pkey_ctx(self, key, data, padding_enum):
-        evp_pkey = key._evp_pkey
-
-        if isinstance(key, _RSAPublicKey):
-            init = self._lib.EVP_PKEY_encrypt_init
-            crypt = self._lib.Cryptography_EVP_PKEY_encrypt
-        else:
-            init = self._lib.EVP_PKEY_decrypt_init
-            crypt = self._lib.Cryptography_EVP_PKEY_decrypt
-
-        pkey_ctx = self._lib.EVP_PKEY_CTX_new(
-            evp_pkey, self._ffi.NULL
-        )
-        assert pkey_ctx != self._ffi.NULL
-        pkey_ctx = self._ffi.gc(pkey_ctx, self._lib.EVP_PKEY_CTX_free)
-        res = init(pkey_ctx)
-        assert res == 1
-        res = self._lib.EVP_PKEY_CTX_set_rsa_padding(
-            pkey_ctx, padding_enum)
-        assert res > 0
-        buf_size = self._lib.EVP_PKEY_size(evp_pkey)
-        assert buf_size > 0
-        outlen = self._ffi.new("size_t *", buf_size)
-        buf = self._ffi.new("char[]", buf_size)
-        res = crypt(
-            pkey_ctx,
-            buf,
-            outlen,
-            data,
-            len(data)
-        )
-        if res <= 0:
-            self._handle_rsa_enc_dec_error(key)
-
-        return self._ffi.buffer(buf)[:outlen[0]]
-
-    def _enc_dec_rsa_098(self, key, data, padding_enum):
-        rsa_cdata = key._rsa_cdata
-
-        if isinstance(key, _RSAPublicKey):
-            crypt = self._lib.RSA_public_encrypt
-        else:
-            crypt = self._lib.RSA_private_decrypt
-
-        key_size = self._lib.RSA_size(rsa_cdata)
-        assert key_size > 0
-        buf = self._ffi.new("unsigned char[]", key_size)
-        res = crypt(
-            len(data),
-            data,
-            buf,
-            rsa_cdata,
-            padding_enum
-        )
-        if res < 0:
-            self._handle_rsa_enc_dec_error(key)
-
-        return self._ffi.buffer(buf)[:res]
-
-    def _handle_rsa_enc_dec_error(self, key):
-        errors = self._consume_errors()
-        assert errors
-        assert errors[0].lib == self._lib.ERR_LIB_RSA
-        if isinstance(key, _RSAPublicKey):
-            assert (errors[0].reason ==
-                    self._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE)
-            raise ValueError(
-                "Data too long for key size. Encrypt less data or use a "
-                "larger key size."
-            )
-        else:
-            assert (
-                errors[0].reason == self._lib.RSA_R_BLOCK_TYPE_IS_NOT_01 or
-                errors[0].reason == self._lib.RSA_R_BLOCK_TYPE_IS_NOT_02
-            )
-            raise ValueError("Decryption failed.")
-
     def cmac_algorithm_supported(self, algorithm):
         return (
             self._lib.Cryptography_HAS_CMAC == 1
diff --git a/cryptography/hazmat/backends/openssl/rsa.py b/cryptography/hazmat/backends/openssl/rsa.py
index a62a89f..6f28c54 100644
--- a/cryptography/hazmat/backends/openssl/rsa.py
+++ b/cryptography/hazmat/backends/openssl/rsa.py
@@ -22,7 +22,7 @@
 from cryptography.hazmat.primitives import hashes, interfaces
 from cryptography.hazmat.primitives.asymmetric import rsa
 from cryptography.hazmat.primitives.asymmetric.padding import (
-    MGF1, PKCS1v15, PSS
+    MGF1, OAEP, PKCS1v15, PSS
 )
 from cryptography.hazmat.primitives.interfaces import (
     RSAPrivateKeyWithNumbers, RSAPublicKeyWithNumbers
@@ -45,6 +45,110 @@
         return salt
 
 
+def _enc_dec_rsa(backend, key, data, padding):
+    if isinstance(padding, PKCS1v15):
+        padding_enum = backend._lib.RSA_PKCS1_PADDING
+    elif isinstance(padding, OAEP):
+        padding_enum = backend._lib.RSA_PKCS1_OAEP_PADDING
+        if not isinstance(padding._mgf, MGF1):
+            raise UnsupportedAlgorithm(
+                "Only MGF1 is supported by this backend.",
+                _Reasons.UNSUPPORTED_MGF
+            )
+
+        if not isinstance(padding._mgf._algorithm, hashes.SHA1):
+            raise UnsupportedAlgorithm(
+                "This backend supports only SHA1 inside MGF1 when "
+                "using OAEP.",
+                _Reasons.UNSUPPORTED_HASH
+            )
+
+        if padding._label is not None and padding._label != b"":
+            raise ValueError("This backend does not support OAEP labels.")
+
+        if not isinstance(padding._algorithm, hashes.SHA1):
+            raise UnsupportedAlgorithm(
+                "This backend only supports SHA1 when using OAEP.",
+                _Reasons.UNSUPPORTED_HASH
+            )
+    else:
+        raise UnsupportedAlgorithm(
+            "{0} is not supported by this backend.".format(
+                padding.name
+            ),
+            _Reasons.UNSUPPORTED_PADDING
+        )
+
+    if backend._lib.Cryptography_HAS_PKEY_CTX:
+        return _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum)
+    else:
+        return _enc_dec_rsa_098(backend, key, data, padding_enum)
+
+
+def _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum):
+    if isinstance(key, _RSAPublicKey):
+        init = backend._lib.EVP_PKEY_encrypt_init
+        crypt = backend._lib.Cryptography_EVP_PKEY_encrypt
+    else:
+        init = backend._lib.EVP_PKEY_decrypt_init
+        crypt = backend._lib.Cryptography_EVP_PKEY_decrypt
+
+    pkey_ctx = backend._lib.EVP_PKEY_CTX_new(
+        key._evp_pkey, backend._ffi.NULL
+    )
+    assert pkey_ctx != backend._ffi.NULL
+    pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free)
+    res = init(pkey_ctx)
+    assert res == 1
+    res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(
+        pkey_ctx, padding_enum)
+    assert res > 0
+    buf_size = backend._lib.EVP_PKEY_size(key._evp_pkey)
+    assert buf_size > 0
+    outlen = backend._ffi.new("size_t *", buf_size)
+    buf = backend._ffi.new("char[]", buf_size)
+    res = crypt(pkey_ctx, buf, outlen, data, len(data))
+    if res <= 0:
+        _handle_rsa_enc_dec_error(backend, key)
+
+    return backend._ffi.buffer(buf)[:outlen[0]]
+
+
+def _enc_dec_rsa_098(backend, key, data, padding_enum):
+    if isinstance(key, _RSAPublicKey):
+        crypt = backend._lib.RSA_public_encrypt
+    else:
+        crypt = backend._lib.RSA_private_decrypt
+
+    key_size = backend._lib.RSA_size(key._rsa_cdata)
+    assert key_size > 0
+    buf = backend._ffi.new("unsigned char[]", key_size)
+    res = crypt(len(data), data, buf, key._rsa_cdata, padding_enum)
+    if res < 0:
+        _handle_rsa_enc_dec_error(backend, key)
+
+    return backend._ffi.buffer(buf)[:res]
+
+
+def _handle_rsa_enc_dec_error(backend, key):
+    errors = backend._consume_errors()
+    assert errors
+    assert errors[0].lib == backend._lib.ERR_LIB_RSA
+    if isinstance(key, _RSAPublicKey):
+        assert (errors[0].reason ==
+                backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE)
+        raise ValueError(
+            "Data too long for key size. Encrypt less data or use a "
+            "larger key size."
+        )
+    else:
+        assert (
+            errors[0].reason == backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_01 or
+            errors[0].reason == backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_02
+        )
+        raise ValueError("Decryption failed.")
+
+
 @utils.register_interface(interfaces.AsymmetricSignatureContext)
 class _RSASignatureContext(object):
     def __init__(self, backend, private_key, padding, algorithm):
@@ -436,7 +540,7 @@
         if key_size_bytes != len(ciphertext):
             raise ValueError("Ciphertext length must be equal to key size.")
 
-        return self._backend._enc_dec_rsa(self, ciphertext, padding)
+        return _enc_dec_rsa(self._backend, self, ciphertext, padding)
 
     def public_key(self):
         ctx = self._backend._lib.RSA_new()
@@ -490,7 +594,7 @@
         )
 
     def encrypt(self, plaintext, padding):
-        return self._backend._enc_dec_rsa(self, plaintext, padding)
+        return _enc_dec_rsa(self._backend, self, plaintext, padding)
 
     def public_numbers(self):
         return rsa.RSAPublicNumbers(
diff --git a/cryptography/hazmat/primitives/asymmetric/dsa.py b/cryptography/hazmat/primitives/asymmetric/dsa.py
index 7a8a61c..04b2272 100644
--- a/cryptography/hazmat/primitives/asymmetric/dsa.py
+++ b/cryptography/hazmat/primitives/asymmetric/dsa.py
@@ -13,6 +13,8 @@
 
 from __future__ import absolute_import, division, print_function
 
+import warnings
+
 import six
 
 from cryptography import utils
@@ -56,6 +58,12 @@
 @utils.register_interface(interfaces.DSAParameters)
 class DSAParameters(object):
     def __init__(self, modulus, subgroup_order, generator):
+        warnings.warn(
+            "The DSAParameters class is deprecated and will be removed in a "
+            "future version.",
+            utils.DeprecatedIn05,
+            stacklevel=2
+        )
         _check_dsa_parameters(
             DSAParameterNumbers(
                 p=modulus,
@@ -70,6 +78,11 @@
 
     @classmethod
     def generate(cls, key_size, backend):
+        warnings.warn(
+            "generate is deprecated and will be removed in a future version.",
+            utils.DeprecatedIn05,
+            stacklevel=2
+        )
         if not isinstance(backend, DSABackend):
             raise UnsupportedAlgorithm(
                 "Backend object does not implement DSABackend.",
@@ -112,6 +125,12 @@
 @utils.register_interface(interfaces.DSAPrivateKey)
 class DSAPrivateKey(object):
     def __init__(self, modulus, subgroup_order, generator, x, y):
+        warnings.warn(
+            "The DSAPrivateKey class is deprecated and will be removed in a "
+            "future version.",
+            utils.DeprecatedIn05,
+            stacklevel=2
+        )
         if (
             not isinstance(x, six.integer_types) or
             not isinstance(y, six.integer_types)
@@ -140,6 +159,11 @@
 
     @classmethod
     def generate(cls, parameters, backend):
+        warnings.warn(
+            "generate is deprecated and will be removed in a future version.",
+            utils.DeprecatedIn05,
+            stacklevel=2
+        )
         if not isinstance(backend, DSABackend):
             raise UnsupportedAlgorithm(
                 "Backend object does not implement DSABackend.",
@@ -189,6 +213,12 @@
 @utils.register_interface(interfaces.DSAPublicKey)
 class DSAPublicKey(object):
     def __init__(self, modulus, subgroup_order, generator, y):
+        warnings.warn(
+            "The DSAPublicKey class is deprecated and will be removed in a "
+            "future version.",
+            utils.DeprecatedIn05,
+            stacklevel=2
+        )
         _check_dsa_parameters(
             DSAParameterNumbers(
                 p=modulus,
diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst
index fea935c..8622912 100644
--- a/docs/hazmat/backends/interfaces.rst
+++ b/docs/hazmat/backends/interfaces.rst
@@ -439,6 +439,8 @@
 
     .. method:: create_dsa_signature_ctx(private_key, algorithm)
 
+        .. deprecated:: 0.5
+
         :param private_key: An instance of a
             :class:`~cryptography.hazmat.primitives.interfaces.DSAPrivateKey`
             provider.
@@ -452,6 +454,8 @@
 
     .. method:: create_dsa_verification_ctx(public_key, signature, algorithm)
 
+        .. deprecated:: 0.5
+
         :param public_key: An instance of a
             :class:`~cryptography.hazmat.primitives.interfaces.DSAPublicKey`
             provider.
diff --git a/docs/hazmat/primitives/asymmetric/dsa.rst b/docs/hazmat/primitives/asymmetric/dsa.rst
index 095c49b..6cb624d 100644
--- a/docs/hazmat/primitives/asymmetric/dsa.rst
+++ b/docs/hazmat/primitives/asymmetric/dsa.rst
@@ -7,6 +7,9 @@
 
 `DSA`_ is a `public-key`_ algorithm for signing messages.
 
+Generation
+~~~~~~~~~~
+
 .. function:: generate_private_key(key_size, backend)
 
     .. versionadded:: 0.5
@@ -28,6 +31,10 @@
     :return: A :class:`~cryptography.hazmat.primitives.interfaces.DSAPrivateKey`
         provider.
 
+    :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if
+        the provided ``backend`` does not implement
+        :class:`~cryptography.hazmat.backends.interfaces.DSABackend`
+
 .. function:: generate_parameters(key_size, backend)
 
     .. versionadded:: 0.5
@@ -52,208 +59,41 @@
         the provided ``backend`` does not implement
         :class:`~cryptography.hazmat.backends.interfaces.DSABackend`
 
-.. class:: DSAParameters(modulus, subgroup_order, generator)
+Signing
+~~~~~~~
 
-    .. versionadded:: 0.4
+Using a :class:`~cryptography.hazmat.primitives.interfaces.DSAPrivateKey`
+provider.
 
-    DSA Parameters are required for generating a DSA private key.
+.. doctest::
 
-    You should use :meth:`~generate` to generate new parameters.
+    >>> from cryptography.hazmat.backends import default_backend
+    >>> from cryptography.hazmat.primitives import hashes
+    >>> from cryptography.hazmat.primitives.asymmetric import dsa
+    >>> private_key = dsa.generate_private_key(
+    ...     key_size=1024,
+    ...     backend=default_backend()
+    ... )
+    >>> signer = private_key.signer(hashes.SHA256())
+    >>> data = b"this is some data I'd like to sign"
+    >>> signer.update(data)
+    >>> signature = signer.finalize()
 
-    .. warning::
-        This method only checks a limited set of properties of its arguments.
-        Using DSA parameters that you do not trust or with incorrect arguments
-        may lead to insecure operation, crashes, and other undefined behavior.
-        We recommend that you only ever load parameters that were generated
-        with software you trust.
+Verification
+~~~~~~~~~~~~
 
+Using a :class:`~cryptography.hazmat.primitives.interfaces.DSAPublicKey`
+provider.
 
-    This class conforms to the
-    :class:`~cryptography.hazmat.primitives.interfaces.DSAParameters`
-    interface.
+.. doctest::
 
-    :raises TypeError: This is raised when the arguments are not all integers.
+    >>> public_key = private_key.public_key()
+    >>> verifier = public_key.verifier(signature, hashes.SHA256())
+    >>> verifier.update(data)
+    >>> verifier.verify()
 
-    :raises ValueError: This is raised when the values of ``modulus``,
-                        ``subgroup_order``, or ``generator`` do
-                        not match the bounds specified in `FIPS 186-4`_.
-
-    .. classmethod:: generate(key_size, backend)
-
-        Generate a new ``DSAParameters`` instance using ``backend``.
-
-        :param int key_size: The length of the modulus in bits. It should be
-            either 1024, 2048 or 3072. For keys generated in 2014 this should
-            be `at least 2048`_ (See page 41).  Note that some applications
-            (such as SSH) have not yet gained support for larger key sizes
-            specified in FIPS 186-3 and are still restricted to only the
-            1024-bit keys specified in FIPS 186-2.
-
-        :return: A new instance of ``DSAParameters``
-
-        :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if
-            the provided ``backend`` does not implement
-            :class:`~cryptography.hazmat.backends.interfaces.DSABackend`
-
-
-.. class:: DSAPrivateKey(modulus, subgroup_order, generator, x, y)
-
-    .. versionadded:: 0.4
-
-    A DSA private key is required for signing messages.
-
-    You should use :meth:`~generate` to generate new keys.
-
-    .. warning::
-        This method only checks a limited set of properties of its arguments.
-        Using a DSA private key that you do not trust or with incorrect
-        parameters may lead to insecure operation, crashes, and other undefined
-        behavior. We recommend that you only ever load private keys that were
-        generated with software you trust.
-
-
-    This class conforms to the
-    :class:`~cryptography.hazmat.primitives.interfaces.DSAPrivateKey`
-    interface.
-
-    :raises TypeError: This is raised when the arguments are not all integers.
-
-    :raises ValueError: This is raised when the values of ``modulus``,
-                        ``subgroup_order``, or ``generator`` do
-                        not match the bounds specified in `FIPS 186-4`_.
-
-    .. classmethod:: generate(parameters, backend)
-
-        Generate a new ``DSAPrivateKey`` instance using ``backend``.
-
-        :param parameters: A
-            :class:`~cryptography.hazmat.primitives.interfaces.DSAParameters`
-            provider.
-        :param backend: A
-            :class:`~cryptography.hazmat.backends.interfaces.DSABackend`
-            provider.
-        :return: A new instance of ``DSAPrivateKey``.
-
-        :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if
-            the provided ``backend`` does not implement
-            :class:`~cryptography.hazmat.backends.interfaces.DSABackend`
-
-        :raises ValueError: This is raised if the key size is not (1024 or 2048 or 3072)
-            or if the OpenSSL version is older than 1.0.0 and the key size is larger than 1024
-            because older OpenSSL versions don't support a key size larger than 1024.
-
-    .. method:: signer(algorithm, backend)
-
-        .. versionadded:: 0.4
-
-        Sign data which can be verified later by others using the public key.
-
-        .. doctest::
-
-            >>> from cryptography.hazmat.backends import default_backend
-            >>> from cryptography.hazmat.primitives import hashes
-            >>> from cryptography.hazmat.primitives.asymmetric import dsa
-            >>> parameters = dsa.DSAParameters.generate(
-            ...     key_size=1024,
-            ...     backend=default_backend()
-            ... )
-            >>> private_key = dsa.DSAPrivateKey.generate(
-            ...     parameters=parameters,
-            ...     backend=default_backend()
-            ... )
-            >>> signer = private_key.signer(
-            ...     hashes.SHA256(),
-            ...     default_backend()
-            ... )
-            >>> data = b"this is some data I'd like to sign"
-            >>> signer.update(data)
-            >>> signature = signer.finalize()
-
-        :param algorithm: An instance of a
-            :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm`
-            provider.
-
-        :param backend: A
-            :class:`~cryptography.hazmat.backends.interfaces.RSABackend`
-            provider.
-
-        :returns:
-            :class:`~cryptography.hazmat.primitives.interfaces.AsymmetricSignatureContext`
-
-        :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if
-            the provided ``backend`` does not implement
-            :class:`~cryptography.hazmat.backends.interfaces.DSABackend`
-
-
-.. class:: DSAPublicKey(modulus, subgroup_order, generator, y)
-
-    .. versionadded:: 0.4
-
-    A DSA public key is required for verifying messages.
-
-    Normally you do not need to directly construct public keys because you'll
-    be loading them from a file, generating them automatically or receiving
-    them from a 3rd party.
-
-    This class conforms to the
-    :class:`~cryptography.hazmat.primitives.interfaces.DSAPublicKey`
-    interface.
-
-    :raises TypeError: This is raised when the arguments are not all integers.
-
-    :raises ValueError: This is raised when the values of ``modulus``,
-                        ``subgroup_order``, ``generator``, or ``y``
-                        do not match the bounds specified in `FIPS 186-4`_.
-
-    .. method:: verifier(signature, algorithm, backend)
-
-        .. versionadded:: 0.4
-
-        Verify data was signed by the private key associated with this public
-        key.
-
-        .. doctest::
-
-            >>> from cryptography.hazmat.backends import default_backend
-            >>> from cryptography.hazmat.primitives import hashes
-            >>> from cryptography.hazmat.primitives.asymmetric import dsa
-            >>> parameters = dsa.DSAParameters.generate(
-            ...     key_size=1024,
-            ...     backend=default_backend()
-            ... )
-            >>> private_key = dsa.DSAPrivateKey.generate(
-            ...     parameters=parameters,
-            ...     backend=default_backend()
-            ... )
-            >>> signer = private_key.signer(
-            ...     hashes.SHA256(),
-            ...     default_backend()
-            ... )
-            >>> data = b"this is some data I'd like to sign"
-            >>> signer.update(data)
-            >>> signature = signer.finalize()
-            >>> public_key = private_key.public_key()
-            >>> verifier = public_key.verifier(
-            ...     signature,
-            ...     hashes.SHA256(),
-            ...     default_backend()
-            ... )
-            >>> verifier.update(data)
-            >>> verifier.verify()
-
-        :param bytes signature: The signature to verify. DER encoded as
-            specified in :rfc:`6979`.
-
-        :param algorithm: An instance of a
-            :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm`
-            provider.
-
-        :param backend: A
-            :class:`~cryptography.hazmat.backends.interfaces.DSABackend`
-            provider.
-
-        :returns:
-            :class:`~cryptography.hazmat.primitives.interfaces.AsymmetricVerificationContext`
+Numbers
+~~~~~~~
 
 .. class:: DSAParameterNumbers(p, q, g)
 
@@ -322,6 +162,175 @@
         The :class:`~cryptography.hazmat.primitives.dsa.DSAPublicNumbers`
         associated with the private key.
 
+Deprecated Concrete Classes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These classes were deprecated in version 0.5 in favor of backend specific
+providers of the
+:class:`~cryptography.hazmat.primitives.interfaces.DSAParameters`,
+:class:`~cryptography.hazmat.primitives.interfaces.DSAPrivateKey`, and
+:class:`~cryptography.hazmat.primitives.interfaces.DSAPublicKey` interfaces.
+>>>>>>> deprecate concrete DSA classes and update DSA docs
+
+.. class:: DSAParameters(modulus, subgroup_order, generator)
+
+    .. versionadded:: 0.4
+
+    .. deprecated:: 0.5
+
+    DSA Parameters are required for generating a DSA private key.
+
+    You should use :meth:`~generate` to generate new parameters.
+
+    .. warning::
+        This method only checks a limited set of properties of its arguments.
+        Using DSA parameters that you do not trust or with incorrect arguments
+        may lead to insecure operation, crashes, and other undefined behavior.
+        We recommend that you only ever load parameters that were generated
+        with software you trust.
+
+
+    This class conforms to the
+    :class:`~cryptography.hazmat.primitives.interfaces.DSAParameters`
+    interface.
+
+    :raises TypeError: This is raised when the arguments are not all integers.
+
+    :raises ValueError: This is raised when the values of ``modulus``,
+                        ``subgroup_order``, or ``generator`` do
+                        not match the bounds specified in `FIPS 186-4`_.
+
+    .. classmethod:: generate(key_size, backend)
+
+        Generate a new ``DSAParameters`` instance using ``backend``.
+
+        :param int key_size: The length of the modulus in bits. It should be
+            either 1024, 2048 or 3072. For keys generated in 2014 this should
+            be `at least 2048`_ (See page 41).  Note that some applications
+            (such as SSH) have not yet gained support for larger key sizes
+            specified in FIPS 186-3 and are still restricted to only the
+            1024-bit keys specified in FIPS 186-2.
+
+        :return: A new instance of ``DSAParameters``
+
+        :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if
+            the provided ``backend`` does not implement
+            :class:`~cryptography.hazmat.backends.interfaces.DSABackend`
+
+
+.. class:: DSAPrivateKey(modulus, subgroup_order, generator, x, y)
+
+    .. versionadded:: 0.4
+
+    .. deprecated:: 0.5
+
+    A DSA private key is required for signing messages.
+
+    You should use :meth:`~generate` to generate new keys.
+
+    .. warning::
+        This method only checks a limited set of properties of its arguments.
+        Using a DSA private key that you do not trust or with incorrect
+        parameters may lead to insecure operation, crashes, and other undefined
+        behavior. We recommend that you only ever load private keys that were
+        generated with software you trust.
+
+
+    This class conforms to the
+    :class:`~cryptography.hazmat.primitives.interfaces.DSAPrivateKey`
+    interface.
+
+    :raises TypeError: This is raised when the arguments are not all integers.
+
+    :raises ValueError: This is raised when the values of ``modulus``,
+                        ``subgroup_order``, or ``generator`` do
+                        not match the bounds specified in `FIPS 186-4`_.
+
+    .. classmethod:: generate(parameters, backend)
+
+        Generate a new ``DSAPrivateKey`` instance using ``backend``.
+
+        :param parameters: A
+            :class:`~cryptography.hazmat.primitives.interfaces.DSAParameters`
+            provider.
+        :param backend: A
+            :class:`~cryptography.hazmat.backends.interfaces.DSABackend`
+            provider.
+        :return: A new instance of ``DSAPrivateKey``.
+
+        :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if
+            the provided ``backend`` does not implement
+            :class:`~cryptography.hazmat.backends.interfaces.DSABackend`
+
+        :raises ValueError: This is raised if the key size is not (1024 or 2048 or 3072)
+            or if the OpenSSL version is older than 1.0.0 and the key size is larger than 1024
+            because older OpenSSL versions don't support a key size larger than 1024.
+
+    .. method:: signer(algorithm, backend)
+
+        .. versionadded:: 0.4
+
+        Sign data which can be verified later by others using the public key.
+
+        :param algorithm: An instance of a
+            :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm`
+            provider.
+
+        :param backend: A
+            :class:`~cryptography.hazmat.backends.interfaces.RSABackend`
+            provider.
+
+        :returns:
+            :class:`~cryptography.hazmat.primitives.interfaces.AsymmetricSignatureContext`
+
+        :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if
+            the provided ``backend`` does not implement
+            :class:`~cryptography.hazmat.backends.interfaces.DSABackend`
+
+
+.. class:: DSAPublicKey(modulus, subgroup_order, generator, y)
+
+    .. versionadded:: 0.4
+
+    .. deprecated:: 0.5
+
+    A DSA public key is required for verifying messages.
+
+    Normally you do not need to directly construct public keys because you'll
+    be loading them from a file, generating them automatically or receiving
+    them from a 3rd party.
+
+    This class conforms to the
+    :class:`~cryptography.hazmat.primitives.interfaces.DSAPublicKey`
+    interface.
+
+    :raises TypeError: This is raised when the arguments are not all integers.
+
+    :raises ValueError: This is raised when the values of ``modulus``,
+                        ``subgroup_order``, ``generator``, or ``y``
+                        do not match the bounds specified in `FIPS 186-4`_.
+
+    .. method:: verifier(signature, algorithm, backend)
+
+        .. versionadded:: 0.4
+
+        Verify data was signed by the private key associated with this public
+        key.
+
+        :param bytes signature: The signature to verify. DER encoded as
+            specified in :rfc:`6979`.
+
+        :param algorithm: An instance of a
+            :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm`
+            provider.
+
+        :param backend: A
+            :class:`~cryptography.hazmat.backends.interfaces.DSABackend`
+            provider.
+
+        :returns:
+            :class:`~cryptography.hazmat.primitives.interfaces.AsymmetricVerificationContext`
+
 .. _`DSA`: https://en.wikipedia.org/wiki/Digital_Signature_Algorithm
 .. _`public-key`: https://en.wikipedia.org/wiki/Public-key_cryptography
 .. _`FIPS 186-4`: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index bd99c8f..696a0f7 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -524,3 +524,25 @@
             ct,
             padding.PKCS1v15()
         )
+
+
+class TestDeprecatedDSABackendMethods(object):
+    def test_create_dsa_signature_ctx(self):
+        params = dsa.DSAParameters.generate(1024, backend)
+        key = dsa.DSAPrivateKey.generate(params, backend)
+        pytest.deprecated_call(
+            backend.create_dsa_signature_ctx,
+            key,
+            hashes.SHA1()
+        )
+
+    def test_create_dsa_verification_ctx(self):
+        params = dsa.DSAParameters.generate(1024, backend)
+        key = dsa.DSAPrivateKey.generate(params, backend)
+        public_key = key.public_key()
+        pytest.deprecated_call(
+            backend.create_dsa_verification_ctx,
+            public_key,
+            b"\x00" * 128,
+            hashes.SHA1()
+        )
diff --git a/tests/hazmat/primitives/test_dsa.py b/tests/hazmat/primitives/test_dsa.py
index 531b448..8c87cfd 100644
--- a/tests/hazmat/primitives/test_dsa.py
+++ b/tests/hazmat/primitives/test_dsa.py
@@ -698,9 +698,17 @@
             verifier.verify()
 
     def test_dsa_verify_invalid_asn1(self, backend):
-        parameters = dsa.DSAParameters.generate(1024, backend)
-        private_key = dsa.DSAPrivateKey.generate(parameters, backend)
-        public_key = private_key.public_key()
+        parameters = pytest.deprecated_call(
+            dsa.DSAParameters.generate,
+            1024,
+            backend
+        )
+        private_key = pytest.deprecated_call(
+            dsa.DSAPrivateKey.generate,
+            parameters,
+            backend
+        )
+        public_key = pytest.deprecated_call(private_key.public_key)
         verifier = public_key.verifier(b'fakesig', hashes.SHA1(), backend)
         verifier.update(b'fakesig')
         with pytest.raises(InvalidSignature):