Repository: pyca/cryptography

Issue:
x509.CSR: implement equality
Since `x509.Certificate.__eq__` is implemented, I would expect a similar behavior for `x509.CertificateSigningRequest.__eq__`. Thanks!

```
(venv)jakub@iks:~/dev/letsencrypt/letsencrypt/acme/jose/testdata$ pip show cryptography

---
Name: cryptography
Version: 0.9.2
Location: /home/jakub/dev/letsencrypt/letsencrypt/venv/lib/python2.7/site-packages
Requires: idna, pyasn1, six, setuptools, enum34, ipaddress, cffi
(venv)jakub@iks:~/dev/letsencrypt/letsencrypt/acme/jose/testdata$ cat t2.py
from cryptography import x509
from cryptography.hazmat.backends import default_backend

with open("cert.der") as cert_file:
    data = cert_file.read()
    cert1 = x509.load_der_x509_certificate(data, default_backend())
    cert2 = x509.load_der_x509_certificate(data, default_backend())

with open("csr.der") as req_file:
    data = req_file.read()
    req1 = x509.load_der_x509_csr(data, default_backend())
    req2 = x509.load_der_x509_csr(data, default_backend())

print repr(cert1)
print repr(req1)
print cert1 == cert2, req1 == req2
(venv)jakub@iks:~/dev/letsencrypt/letsencrypt/acme/jose/testdata$ python t2.py
<cryptography.hazmat.backends.openssl.x509._Certificate object at 0x7f44e221a550>
<cryptography.hazmat.backends.openssl.x509._CertificateSigningRequest object at 0x7f44e221a710>
True False
```



Discussion:

Resolving patch:
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -701,6 +701,17 @@ def __init__(self, backend, x509_req):
         self._backend = backend
         self._x509_req = x509_req
 
+    def __eq__(self, other):
+        if not isinstance(other, _CertificateSigningRequest):
+            return NotImplemented
+
+        self_bytes = self.public_bytes(serialization.Encoding.DER)
+        other_bytes = other.public_bytes(serialization.Encoding.DER)
+        return self_bytes == other_bytes
+
+    def __ne__(self, other):
+        return not self == other
+
     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
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -1391,6 +1391,18 @@ def __ne__(self, other):
 
 @six.add_metaclass(abc.ABCMeta)
 class CertificateSigningRequest(object):
+    @abc.abstractmethod
+    def __eq__(self, other):
+        """
+        Checks equality.
+        """
+
+    @abc.abstractmethod
+    def __ne__(self, other):
+        """
+        Checks not equal.
+        """
+
     @abc.abstractmethod
     def public_key(self):
         """


Test patch:
diff --git a/tests/test_x509.py b/tests/test_x509.py
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -694,6 +694,35 @@ def test_public_bytes_match(self, request_path, loader_func, encoding,
         serialized = request.public_bytes(encoding)
         assert serialized == request_bytes
 
+    def test_eq(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
+        )
+
+        assert request1 == request2
+
+    def test_ne(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", "san_rsa_sha1.pem"),
+            x509.load_pem_x509_csr,
+            backend
+        )
+
+        assert request1 != request2
+        assert request1 != object()
+
 
 @pytest.mark.requires_backend_interface(interface=X509Backend)
 class TestCertificateSigningRequestBuilder(object):