Merge pull request #2670 from joernheissler/x509_req_verify

Add verify method on CertificateSigningRequest
diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst
index 4d28419..5bb4eef 100644
--- a/docs/development/test-vectors.rst
+++ b/docs/development/test-vectors.rst
@@ -283,7 +283,7 @@
   request using RSA and SHA1 with a subject alternative name extension
   generated using OpenSSL.
 * ``two_basic_constraints.pem`` - A certificate signing request
-  for a RSA 2048 bit key containing two basic constraints extensions.
+  for an RSA 2048 bit key containing two basic constraints extensions.
 * ``unsupported_extension.pem`` - A certificate signing request
   for an RSA 2048 bit key containing containing an unsupported
   extension type. The OID was encoded as "1.2.3.4" with an
@@ -292,9 +292,11 @@
   request for an RSA 2048 bit key containing containing an unsupported
   extension type marked critical. The OID was encoded as "1.2.3.4"
   with an ``extnValue`` of "value".
-* ``basic_constraints.pem`` - A certificate signing request for a RSA
+* ``basic_constraints.pem`` - A certificate signing request for an RSA
   2048 bit key containing a basic constraints extension marked as
   critical.
+* ``invalid_signature.pem`` - A certificate signing request for an RSA
+  1024 bit key containing an invalid signature with correct padding.
 
 Custom X.509 Certificate Revocation List Vectors
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst
index 529578b..67427dd 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -761,6 +761,12 @@
         key embedded in the CSR). This data may be used to validate the CSR
         signature.
 
+    .. attribute:: is_signature_valid
+
+        .. versionadded:: 1.3
+
+        Returns True if the CSR signature is correct, False otherwise.
+
 X.509 Certificate Revocation List Builder
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index a6f7d69..c71f8d9 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -362,3 +362,16 @@
     @property
     def signature(self):
         return _asn1_string_to_bytes(self._backend, self._x509_req.signature)
+
+    @property
+    def is_signature_valid(self):
+        pkey = self._backend._lib.X509_REQ_get_pubkey(self._x509_req)
+        self._backend.openssl_assert(pkey != self._backend._ffi.NULL)
+        pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free)
+        res = self._backend._lib.X509_REQ_verify(self._x509_req, pkey)
+
+        if res != 1:
+            self._backend._consume_errors()
+            return False
+
+        return True
diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py
index 55e965f..4a22ed0 100644
--- a/src/cryptography/x509/base.py
+++ b/src/cryptography/x509/base.py
@@ -288,6 +288,12 @@
         2986.
         """
 
+    @abc.abstractproperty
+    def is_signature_valid(self):
+        """
+        Verifies signature of signing request.
+        """
+
 
 @six.add_metaclass(abc.ABCMeta)
 class RevokedCertificate(object):
diff --git a/tests/test_x509.py b/tests/test_x509.py
index 9054c4e..c042169 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -1241,6 +1241,22 @@
         with pytest.raises(TypeError):
             request.public_bytes('NotAnEncoding')
 
+    def test_signature_invalid(self, backend):
+        request = _load_cert(
+            os.path.join("x509", "requests", "invalid_signature.pem"),
+            x509.load_pem_x509_csr,
+            backend
+        )
+        assert not request.is_signature_valid
+
+    def test_signature_valid(self, backend):
+        request = _load_cert(
+            os.path.join("x509", "requests", "rsa_sha256.pem"),
+            x509.load_pem_x509_csr,
+            backend
+        )
+        assert request.is_signature_valid
+
     @pytest.mark.parametrize(
         ("request_path", "loader_func", "encoding"),
         [
diff --git a/vectors/cryptography_vectors/x509/requests/invalid_signature.pem b/vectors/cryptography_vectors/x509/requests/invalid_signature.pem
new file mode 100644
index 0000000..f95bd17
--- /dev/null
+++ b/vectors/cryptography_vectors/x509/requests/invalid_signature.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBTjCBuAIBADAPMQ0wCwYDVQQDDAR0ZXN0MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDOdf0xwr1fUP0+wtYfwi1sqAe78WNSONLjtGYSpEFBNS9T6dW+m3vj
+EaEZ0dI7B+Y5jC53JG8vSoBN/xLzw/CCDgLq8OvftOeS4+FZqznRDucgzbqctVzs
+PshGcfZ3n8DIiEBbSqeMvs02spKXvYxi3M2S5aJ2GVl2wNlzRLcTuwIDAQABoAAw
+DQYJKoZIhvcNAQELBQADgYEAZ7Jbqn9hhMYJ+y4ikTNG6GNu48GINyzXXX3bzv3O
++xGnKbjp99FbJKDOalnG492kZKyg2cCC5UQW8SNZOQpfnjsguB3HZoOrRlExkavY
+IapdMZiK5g6ocViceV4gRybkW/Yh3p7cFzOmaABAWzeyJm3/TcTWBLvx/M7Mj1pE
+8f8=
+-----END CERTIFICATE REQUEST-----