Merge pull request #2129 from alex/hash-csr

Fixed #2127 -- added __hash__ to CSR
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index 399e6a6..d78c60f 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -724,6 +724,9 @@
     def __ne__(self, other):
         return not self == other
 
+    def __hash__(self):
+        return hash(self.public_bytes(serialization.Encoding.DER))
+
     def public_key(self):
         pkey = self._backend._lib.X509_REQ_get_pubkey(self._x509_req)
         assert pkey != self._backend._ffi.NULL
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py
index d9d6db4..33c6416 100644
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -1444,6 +1444,12 @@
         """
 
     @abc.abstractmethod
+    def __hash__(self):
+        """
+        Computes a hash.
+        """
+
+    @abc.abstractmethod
     def public_key(self):
         """
         Returns the public key
diff --git a/tests/test_x509.py b/tests/test_x509.py
index ccb24d7..9c97e96 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -746,6 +746,26 @@
         assert request1 != request2
         assert request1 != object()
 
+    def test_hash(self, backend):
+        request1 = _load_cert(
+            os.path.join("x509", "requests", "rsa_sha1.pem"),
+            x509.load_pem_x509_csr,
+            backend
+        )
+        request2 = _load_cert(
+            os.path.join("x509", "requests", "rsa_sha1.pem"),
+            x509.load_pem_x509_csr,
+            backend
+        )
+        request3 = _load_cert(
+            os.path.join("x509", "requests", "san_rsa_sha1.pem"),
+            x509.load_pem_x509_csr,
+            backend
+        )
+
+        assert hash(request1) == hash(request2)
+        assert hash(request1) != hash(request3)
+
 
 @pytest.mark.requires_backend_interface(interface=X509Backend)
 class TestCertificateSigningRequestBuilder(object):