add crl.get_revoked_certificate method (#4331)

* add crl.get_revoked_certificate method

* lexicographic is the best ographic

* rename
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 8b4e974..c8db7e7 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -16,6 +16,9 @@
   ``cryptography`` release.
 * Fixed multiple issues preventing ``cryptography`` from compiling against
   LibreSSL 2.7.x.
+* Added
+  :class:`~cryptography.x509.CertificateRevocationList.get_revoked_certificate_by_serial_number`
+  for quick serial number searches in CRLs.
 * The :class:`~cryptography.x509.RelativeDistinguishedName` class now
   preserves the order of attributes. Duplicate attributes now raise an error
   instead of silently discarding duplicates.
diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst
index 64097bf..bc3dd55 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -463,6 +463,15 @@
             >>> crl.fingerprint(hashes.SHA256())
             b'e\xcf.\xc4:\x83?1\xdc\xf3\xfc\x95\xd7\xb3\x87\xb3\x8e\xf8\xb93!\x87\x07\x9d\x1b\xb4!\xb9\xe4W\xf4\x1f'
 
+    .. method:: get_revoked_certificate_by_serial_number(serial_number)
+
+        .. versionadded:: 2.3
+
+        :param serial_number: The serial as a Python integer.
+        :returns: :class:`~cryptography.x509.RevokedCertificate` if the
+            ``serial_number`` is present in the CRL or ``None`` if it
+            is not.
+
     .. attribute:: signature_hash_algorithm
 
         :type: :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`
diff --git a/src/_cffi_src/openssl/x509.py b/src/_cffi_src/openssl/x509.py
index 97ade5b..59fdbf7 100644
--- a/src/_cffi_src/openssl/x509.py
+++ b/src/_cffi_src/openssl/x509.py
@@ -238,6 +238,8 @@
 X509_EXTENSION *X509_CRL_get_ext(X509_CRL *, int);
 int X509_CRL_get_ext_count(X509_CRL *);
 
+int X509_CRL_get0_by_serial(X509_CRL *, X509_REVOKED **, ASN1_INTEGER *);
+
 /* these CRYPTO_EX_DATA functions became macros in 1.1.0 */
 int X509_get_ex_new_index(long, void *, CRYPTO_EX_new *, CRYPTO_EX_dup *,
                           CRYPTO_EX_free *);
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index 9637fc0..b870eeb 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -16,6 +16,9 @@
     _REVOKED_CERTIFICATE_EXTENSION_PARSER, _asn1_integer_to_int,
     _asn1_string_to_bytes, _decode_x509_name, _obj2txt, _parse_asn1_time
 )
+from cryptography.hazmat.backends.openssl.encode_asn1 import (
+    _encode_asn1_int_gc
+)
 from cryptography.hazmat.primitives import hashes, serialization
 from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
 
@@ -235,6 +238,22 @@
         h.update(der)
         return h.finalize()
 
+    def get_revoked_certificate_by_serial_number(self, serial_number):
+        revoked = self._backend._ffi.new("X509_REVOKED **")
+        asn1_int = _encode_asn1_int_gc(self._backend, serial_number)
+        res = self._backend._lib.X509_CRL_get0_by_serial(
+            self._x509_crl, revoked, asn1_int
+        )
+        if res == 0:
+            return None
+        else:
+            self._backend.openssl_assert(
+                revoked[0] != self._backend._ffi.NULL
+            )
+            return _RevokedCertificate(
+                self._backend, self._x509_crl, revoked[0]
+            )
+
     @property
     def signature_hash_algorithm(self):
         oid = self.signature_algorithm_oid
diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py
index 45b603f..b14499c 100644
--- a/src/cryptography/x509/base.py
+++ b/src/cryptography/x509/base.py
@@ -189,6 +189,13 @@
         Returns bytes using digest passed.
         """
 
+    @abc.abstractmethod
+    def get_revoked_certificate_by_serial_number(self, serial_number):
+        """
+        Returns an instance of RevokedCertificate or None if the serial_number
+        is not in the CRL.
+        """
+
     @abc.abstractproperty
     def signature_hash_algorithm(self):
         """
diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py
index fe57784..5905e33 100644
--- a/tests/x509/test_x509.py
+++ b/tests/x509/test_x509.py
@@ -181,6 +181,18 @@
         # Check that len() works for CRLs.
         assert len(crl) == 12
 
+    def test_get_revoked_certificate_by_serial_number(self, backend):
+        crl = _load_cert(
+            os.path.join(
+                "x509", "PKITS_data", "crls", "LongSerialNumberCACRL.crl"),
+            x509.load_der_x509_crl,
+            backend
+        )
+        serial_number = 725064303890588110203033396814564464046290047507
+        revoked = crl.get_revoked_certificate_by_serial_number(serial_number)
+        assert revoked.serial_number == serial_number
+        assert crl.get_revoked_certificate_by_serial_number(500) is None
+
     def test_revoked_cert_retrieval_retain_only_revoked(self, backend):
         """
         This test attempts to trigger the crash condition described in