OpenSSL backend code for CRLs
diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst
index 62bdb3a..9f9526e 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -5,6 +5,21 @@
 
 .. testsetup::
 
+    pem_crl_data = b"""
+    -----BEGIN X509 CRL-----
+    MIIBtDCBnQIBAjANBgkqhkiG9w0BAQsFADAnMQswCQYDVQQGEwJVUzEYMBYGA1UE
+    AwwPY3J5cHRvZ3JhcGh5LmlvGA8yMDE1MDEwMTAwMDAwMFoYDzIwMTYwMTAxMDAw
+    MDAwWjA+MDwCAQAYDzIwMTUwMTAxMDAwMDAwWjAmMBgGA1UdGAQRGA8yMDE1MDEw
+    MTAwMDAwMFowCgYDVR0VBAMKAQEwDQYJKoZIhvcNAQELBQADggEBABRA4ww50Lz5
+    zk1j2+aluC4HPHqb7o06h4pTDcCGeXUKXIGeP5ntGGmIoxa26sNoLeOr8+5b43Gf
+    yWraHertllOwaOpNFEe+YZFaE9femtoDbf+GLMvRx/0wDfd3KxPoXnXKMXb2d1w4
+    RCLgmkYx6JyvS+5ciuLQVIKC+l7jwIUeZFLJMUJ8msM4pFYoGameeZmtjMbd/TNg
+    cVBfmZxNMHuLladJxvSo2esARo0TYPhYsgrREKoHwhpzSxdynjn4bOVkILfguwsN
+    qtEEMZFEv5Kb0GqRp2+Iagv2S6dg9JGvxVdsoGjaB6EbYSZ3Psx4aODasIn11uwo
+    X4B9vUQNXqc=
+    -----END X509 CRL-----
+    """.strip()
+
     pem_req_data = b"""
     -----BEGIN CERTIFICATE REQUEST-----
     MIIC0zCCAbsCAQAwWTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAw
@@ -129,6 +144,52 @@
     >>> cert.serial
     2
 
+Loading Certificate Revocation Lists
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. function:: load_pem_x509_crl(data, backend)
+
+    .. versionadded:: 1.1
+
+    Deserialize a certificate revocation list (CRL) from PEM encoded data. PEM
+    requests are base64 decoded and have delimiters that look like
+    ``-----BEGIN X509 CRL-----``. This format is also known as
+    PKCS#10.
+
+    :param bytes data: The PEM encoded request data.
+
+    :param backend: A backend supporting the
+        :class:`~cryptography.hazmat.backends.interfaces.X509Backend`
+        interface.
+
+    :returns: An instance of
+        :class:`~cryptography.x509.CertificateRevocationList`.
+
+.. function:: load_der_x509_crl(data, backend)
+
+    .. versionadded:: 1.1
+
+    Deserialize a certificate revocation list (CRL) from DER encoded data. DER
+    is a binary format.
+
+    :param bytes data: The DER encoded request data.
+
+    :param backend: A backend supporting the
+        :class:`~cryptography.hazmat.backends.interfaces.X509Backend`
+        interface.
+
+    :returns: An instance of
+        :class:`~cryptography.x509.CertificateRevocationList`.
+
+.. doctest::
+
+    >>> from cryptography import x509
+    >>> from cryptography.hazmat.backends import default_backend
+    >>> from cryptography.hazmat.primitives import hashes
+    >>> crl = x509.load_pem_x509_crl(pem_crl_data, default_backend())
+    >>> isinstance(crl.signature_hash_algorithm, hashes.SHA256)
+    True
+
 Loading Certificate Signing Requests
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -349,6 +410,12 @@
         :return bytes: The fingerprint using the supplied hash algorithm, as
             bytes.
 
+        .. doctest::
+
+            >>> from cryptography.hazmat.primitives import hashes
+            >>> crl.fingerprint(hashes.SHA256())
+            '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'
+
     .. attribute:: signature_hash_algorithm
 
         :type: :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`
@@ -357,12 +424,23 @@
         :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` which
         was used in signing this CRL.
 
+        .. doctest::
+
+            >>> from cryptography.hazmat.primitives import hashes
+            >>> isinstance(crl.signature_hash_algorithm, hashes.SHA256)
+            True
+
     .. attribute:: issuer
 
         :type: :class:`Name`
 
         The :class:`Name` of the issuer.
 
+        .. doctest::
+
+            >>> crl.issuer
+            <Name([<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.6, name=countryName)>, value=u'US')>, <NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value=u'cryptography.io')>])>
+
     .. attribute:: next_update
 
         :type: :class:`datetime.datetime`
@@ -370,18 +448,34 @@
         A naïve datetime representing when the next update to this CRL is
         expected.
 
+        .. doctest::
+
+            >>> crl.next_update
+            datetime.datetime(2016, 1, 1, 0, 0)
+
     .. attribute:: last_update
 
         :type: :class:`datetime.datetime`
 
         A naïve datetime representing when the this CRL was last updated.
 
+        .. doctest::
+
+            >>> crl.last_update
+            datetime.datetime(2015, 1, 1, 0, 0)
+
     .. attribute:: revoked_certificates
 
         :type: list of :class:`RevokedCertificate`
 
         The revoked certificates listed in this CRL.
 
+        .. doctest::
+
+            >>> for r in crl.revoked_certificates:
+            ...     print(r.serial_number)
+            0
+
     .. attribute:: extensions
 
         :type: :class:`Extensions`
@@ -610,18 +704,35 @@
 
         An integer representing the serial number of the revoked certificate.
 
+        .. doctest::
+
+            >>> crl.revoked_certificates[0].serial_number
+            0
+
     .. attribute:: revocation_date
 
         :type: :class:`datetime.datetime`
 
         A naïve datetime representing the date this certificates was revoked.
 
+        .. doctest::
+
+            >>> crl.revoked_certificates[0].revocation_date
+            datetime.datetime(2015, 1, 1, 0, 0)
+
     .. attribute:: extensions
 
         :type: :class:`Extensions`
 
         The extensions encoded in the revoked certificate.
 
+        .. doctest::
+
+            >>> for ext in crl.revoked_certificates[0].extensions:
+            ...     print(ext)
+            <Extension(oid=<ObjectIdentifier(oid=2.5.29.24, name=invalidityDate)>, critical=False, value=2015-01-01 00:00:00)>
+            <Extension(oid=<ObjectIdentifier(oid=2.5.29.21, name=cRLReason)>, critical=False, value=ReasonFlags.key_compromise)>
+
 X.509 CSR (Certificate Signing Request) Builder Object
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/src/cryptography/hazmat/backends/multibackend.py b/src/cryptography/hazmat/backends/multibackend.py
index 9db32aa..cda3314 100644
--- a/src/cryptography/hazmat/backends/multibackend.py
+++ b/src/cryptography/hazmat/backends/multibackend.py
@@ -325,6 +325,24 @@
             _Reasons.UNSUPPORTED_X509
         )
 
+    def load_pem_x509_crl(self, data):
+        for b in self._filtered_backends(X509Backend):
+            return b.load_pem_x509_crl(data)
+
+        raise UnsupportedAlgorithm(
+            "This backend does not support X.509.",
+            _Reasons.UNSUPPORTED_X509
+        )
+
+    def load_der_x509_crl(self, data):
+        for b in self._filtered_backends(X509Backend):
+            return b.load_der_x509_crl(data)
+
+        raise UnsupportedAlgorithm(
+            "This backend does not support X.509.",
+            _Reasons.UNSUPPORTED_X509
+        )
+
     def load_der_x509_csr(self, data):
         for b in self._filtered_backends(X509Backend):
             return b.load_der_x509_csr(data)
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index c74d90d..8503b9b 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -39,8 +39,8 @@
     _RSAPrivateKey, _RSAPublicKey
 )
 from cryptography.hazmat.backends.openssl.x509 import (
-    _Certificate, _CertificateSigningRequest, _DISTPOINT_TYPE_FULLNAME,
-    _DISTPOINT_TYPE_RELATIVENAME
+    _Certificate, _CertificateRevocationList, _CertificateSigningRequest,
+    _DISTPOINT_TYPE_FULLNAME, _DISTPOINT_TYPE_RELATIVENAME
 )
 from cryptography.hazmat.bindings.openssl.binding import Binding
 from cryptography.hazmat.primitives import hashes, serialization
@@ -1474,6 +1474,28 @@
         x509 = self._ffi.gc(x509, self._lib.X509_free)
         return _Certificate(self, x509)
 
+    def load_pem_x509_crl(self, data):
+        mem_bio = self._bytes_to_bio(data)
+        x509_crl = self._lib.PEM_read_bio_X509_CRL(
+            mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL
+        )
+        if x509_crl == self._ffi.NULL:
+            self._consume_errors()
+            raise ValueError("Unable to load CRL")
+
+        x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free)
+        return _CertificateRevocationList(self, x509_crl)
+
+    def load_der_x509_crl(self, data):
+        mem_bio = self._bytes_to_bio(data)
+        x509_crl = self._lib.d2i_X509_CRL_bio(mem_bio.bio, self._ffi.NULL)
+        if x509_crl == self._ffi.NULL:
+            self._consume_errors()
+            raise ValueError("Unable to load CRL")
+
+        x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free)
+        return _CertificateRevocationList(self, x509_crl)
+
     def load_pem_x509_csr(self, data):
         mem_bio = self._bytes_to_bio(data)
         x509_req = self._lib.PEM_read_bio_X509_REQ(
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index 70cec16..79b516c 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -4,7 +4,9 @@
 
 from __future__ import absolute_import, division, print_function
 
+import datetime
 import ipaddress
+
 from email.utils import parseaddr
 
 import idna
@@ -637,6 +639,262 @@
     return x509.InhibitAnyPolicy(skip_certs)
 
 
+@utils.register_interface(x509.RevokedCertificate)
+class _RevokedCertificate(object):
+    def __init__(self, backend, x509_revoked):
+        self._backend = backend
+        self._x509_revoked = x509_revoked
+
+        self.__serial_number = None
+        self.__revocation_date = None
+        self.__extensions = None
+
+    @property
+    def serial_number(self):
+        if self.__serial_number:
+            return self.__serial_number
+
+        bn = self._backend._lib.ASN1_INTEGER_to_BN(
+            self._x509_revoked.serialNumber, self._backend._ffi.NULL
+        )
+        assert bn != self._backend._ffi.NULL
+        bn = self._backend._ffi.gc(bn, self._backend._lib.BN_free)
+        self.__serial_number = self._backend._bn_to_int(bn)
+        return self.__serial_number
+
+    @property
+    def revocation_date(self):
+        if self.__revocation_date:
+            return self.__revocation_date
+
+        self.__revocation_date = self._backend._parse_asn1_time(
+            self._x509_revoked.revocationDate)
+        return self.__revocation_date
+
+    @property
+    def extensions(self):
+        if self.__extensions:
+            return self.__extensions
+
+        extensions = []
+        seen_oids = set()
+        extcount = self._backend._lib.X509_REVOKED_get_ext_count(
+            self._x509_revoked)
+        for i in range(0, extcount):
+            ext = self._backend._lib.X509_REVOKED_get_ext(
+                self._x509_revoked, i)
+            assert ext != self._backend._ffi.NULL
+            crit = self._backend._lib.X509_EXTENSION_get_critical(ext)
+            critical = crit == 1
+            oid = x509.ObjectIdentifier(_obj2txt(self._backend, ext.object))
+            if oid in seen_oids:
+                raise x509.DuplicateExtension(
+                    "Duplicate {0} extension found".format(oid), oid
+                )
+
+            if oid == x509.OID_CRL_REASON:
+                value = self._build_crl_reason(ext)
+            elif oid == x509.OID_INVALIDITY_DATE:
+                value = self._build_invalidity_date(ext)
+            elif oid == x509.OID_CERTIFICATE_ISSUER and \
+                    self._backend._lib.OPENSSL_VERSION_NUMBER >= 0x10000000:
+                value = self._build_cert_issuer(ext)
+            elif critical:
+                raise x509.UnsupportedExtension(
+                    "{0} is not currently supported".format(oid), oid
+                )
+            else:
+                # Unsupported non-critical extension, silently skipping for now
+                seen_oids.add(oid)
+                continue
+
+            seen_oids.add(oid)
+            extensions.append(x509.Extension(oid, critical, value))
+
+        self.__extensions = x509.Extensions(extensions)
+        return self.__extensions
+
+    def get_reason(self):
+        """
+        Returns the CRLReason extension if it exists.
+        """
+        try:
+                return self.extensions.get_extension_for_oid(
+                    x509.OID_CRL_REASON).value
+        except x509.ExtensionNotFound:
+                return None
+
+    def get_invalidity_date(self):
+        """
+        Returns the InvalidityDate extension if it exists.
+        """
+        try:
+                return self.extensions.get_extension_for_oid(
+                    x509.OID_INVALIDITY_DATE).value
+        except x509.ExtensionNotFound:
+                return None
+
+    def get_certificate_issuer(self):
+        """
+        Returns the CertificateIssuer extension if it exists.
+        """
+        try:
+                return self.extensions.get_extension_for_oid(
+                    x509.OID_CERTIFICATE_ISSUER).value
+        except x509.ExtensionNotFound:
+                return None
+
+    def _build_crl_reason(self, ext):
+        enum = self._backend._lib.X509V3_EXT_d2i(ext)
+        assert enum != self._backend._ffi.NULL
+        enum = self._backend._ffi.cast("ASN1_ENUMERATED *", enum)
+        enum = self._backend._ffi.gc(
+            enum, self._backend._lib.ASN1_ENUMERATED_free
+        )
+        code = self._backend._lib.ASN1_ENUMERATED_get(enum)
+        if code == 0:
+            return x509.ReasonFlags.unspecified
+        elif code == 1:
+            return x509.ReasonFlags.key_compromise
+        elif code == 2:
+            return x509.ReasonFlags.ca_compromise
+        elif code == 3:
+            return x509.ReasonFlags.affiliation_changed
+        elif code == 4:
+            return x509.ReasonFlags.superseded
+        elif code == 5:
+            return x509.ReasonFlags.cessation_of_operation
+        elif code == 6:
+            return x509.ReasonFlags.certificate_hold
+        elif code == 8:
+            return x509.ReasonFlags.remove_from_crl
+        elif code == 9:
+            return x509.ReasonFlags.privilege_withdrawn
+        elif code == 10:
+            return x509.ReasonFlags.aa_compromise
+        else:
+            raise ValueError("Unsupported reason code: {0}".format(code))
+
+    def _build_invalidity_date(self, ext):
+        generalized_time = self._backend._ffi.cast(
+            "ASN1_GENERALIZEDTIME *",
+            self._backend._lib.X509V3_EXT_d2i(ext)
+        )
+        assert generalized_time != self._backend._ffi.NULL
+        generalized_time = self._backend._ffi.gc(
+            generalized_time, self._backend._lib.ASN1_GENERALIZEDTIME_free
+        )
+        time = self._backend._ffi.string(
+            self._backend._lib.ASN1_STRING_data(
+                self._backend._ffi.cast("ASN1_STRING *", generalized_time)
+            )
+        ).decode("ascii")
+        return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ")
+
+    def _build_cert_issuer(self, ext):
+        gns = self._backend._ffi.cast(
+            "GENERAL_NAMES *", self._backend._lib.X509V3_EXT_d2i(ext)
+        )
+        assert gns != self._backend._ffi.NULL
+        gns = self._backend._ffi.gc(gns, self._backend._lib.GENERAL_NAMES_free)
+        return x509.GeneralNames(_decode_general_names(self._backend, gns))
+
+
+@utils.register_interface(x509.CertificateRevocationList)
+class _CertificateRevocationList(object):
+    def __init__(self, backend, x509_crl):
+        self._backend = backend
+        self._x509_crl = x509_crl
+
+        self.__revoked = None
+        self.__issuer = None
+        self.__next_update = None
+        self.__last_update = None
+
+    def __eq__(self, other):
+        if not isinstance(other, x509.CertificateRevocationList):
+            return NotImplemented
+
+        res = self._backend._lib.X509_CRL_cmp(self._x509_crl, other._x509_crl)
+        return res == 0
+
+    def __ne__(self, other):
+        return not self == other
+
+    def fingerprint(self, algorithm):
+        h = hashes.Hash(algorithm, self._backend)
+        bio = self._backend._create_mem_bio()
+        res = self._backend._lib.i2d_X509_CRL_bio(
+            bio, self._x509_crl
+        )
+        assert res == 1
+        der = self._backend._read_mem_bio(bio)
+        h.update(der)
+        return h.finalize()
+
+    @property
+    def signature_hash_algorithm(self):
+        oid = _obj2txt(self._backend, self._x509_crl.sig_alg.algorithm)
+        try:
+            return x509._SIG_OIDS_TO_HASH[oid]
+        except KeyError:
+            raise UnsupportedAlgorithm(
+                "Signature algorithm OID:{0} not recognized".format(oid)
+            )
+
+    @property
+    def issuer(self):
+        if self.__issuer:
+            return self.__issuer
+
+        issuer = self._backend._lib.X509_CRL_get_issuer(self._x509_crl)
+        assert issuer != self._backend._ffi.NULL
+        self.__issuer = _decode_x509_name(self._backend, issuer)
+        return self.__issuer
+
+    @property
+    def next_update(self):
+        if self.__next_update:
+            return self.__next_update
+
+        nu = self._backend._lib.X509_CRL_get_nextUpdate(self._x509_crl)
+        assert nu != self._backend._ffi.NULL
+        self.__next_update = self._backend._parse_asn1_time(nu)
+        return self.__next_update
+
+    @property
+    def last_update(self):
+        if self.__last_update:
+            return self.__last_update
+
+        lu = self._backend._lib.X509_CRL_get_lastUpdate(self._x509_crl)
+        assert lu != self._backend._ffi.NULL
+        self.__last_update = self._backend._parse_asn1_time(lu)
+        return self.__last_update
+
+    @property
+    def revoked_certificates(self):
+        if self.__revoked:
+            return self.__revoked
+
+        revoked = self._backend._lib.X509_CRL_get_REVOKED(self._x509_crl)
+        assert revoked != self._backend._ffi.NULL
+
+        num = self._backend._lib.sk_X509_REVOKED_num(revoked)
+        revoked_list = []
+        for i in range(num):
+            r = self._backend._lib.sk_X509_REVOKED_value(revoked, i)
+            assert r != self._backend._ffi.NULL
+            revoked_list.append(_RevokedCertificate(self._backend, r))
+
+        self.__revoked = revoked_list
+        return self.__revoked
+
+    @property
+    def extensions(self):
+        raise NotImplementedError()
+
+
 @utils.register_interface(x509.CertificateSigningRequest)
 class _CertificateSigningRequest(object):
     def __init__(self, backend, x509_req):
diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py
index 1aa2598..70e1d3d 100644
--- a/src/cryptography/x509/__init__.py
+++ b/src/cryptography/x509/__init__.py
@@ -8,8 +8,8 @@
     Certificate, CertificateBuilder, CertificateRevocationList,
     CertificateSigningRequest, CertificateSigningRequestBuilder,
     InvalidVersion, RevokedCertificate,
-    Version, load_der_x509_certificate, load_der_x509_csr,
-    load_pem_x509_certificate, load_pem_x509_csr,
+    Version, load_der_x509_certificate, load_der_x509_crl, load_der_x509_csr,
+    load_pem_x509_certificate, load_pem_x509_crl, load_pem_x509_csr,
 )
 from cryptography.x509.extensions import (
     AccessDescription, AuthorityInformationAccess,
@@ -108,6 +108,8 @@
     "load_der_x509_certificate",
     "load_pem_x509_csr",
     "load_der_x509_csr",
+    "load_pem_x509_crl",
+    "load_der_x509_crl",
     "InvalidVersion",
     "DuplicateExtension",
     "UnsupportedExtension",
diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py
index 27eafac..9dc49a6 100644
--- a/src/cryptography/x509/base.py
+++ b/src/cryptography/x509/base.py
@@ -40,6 +40,14 @@
     return backend.load_der_x509_csr(data)
 
 
+def load_pem_x509_crl(data, backend):
+    return backend.load_pem_x509_crl(data)
+
+
+def load_der_x509_crl(data, backend):
+    return backend.load_der_x509_crl(data)
+
+
 class InvalidVersion(Exception):
     def __init__(self, msg, parsed_version):
         super(InvalidVersion, self).__init__(msg)
diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py
index 4d17cdb..618d21b 100644
--- a/tests/hazmat/backends/test_multibackend.py
+++ b/tests/hazmat/backends/test_multibackend.py
@@ -197,6 +197,12 @@
     def load_der_x509_certificate(self, data):
         pass
 
+    def load_pem_x509_crl(self, data):
+        pass
+
+    def load_der_x509_crl(self, data):
+        pass
+
     def load_pem_x509_csr(self, data):
         pass
 
@@ -491,6 +497,8 @@
 
         backend.load_pem_x509_certificate(b"certdata")
         backend.load_der_x509_certificate(b"certdata")
+        backend.load_pem_x509_crl(b"crldata")
+        backend.load_der_x509_crl(b"crldata")
         backend.load_pem_x509_csr(b"reqdata")
         backend.load_der_x509_csr(b"reqdata")
         backend.create_x509_csr(object(), b"privatekey", hashes.SHA1())
@@ -502,6 +510,10 @@
         with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509):
             backend.load_der_x509_certificate(b"certdata")
         with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509):
+            backend.load_pem_x509_crl(b"crldata")
+        with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509):
+            backend.load_der_x509_crl(b"crldata")
+        with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509):
             backend.load_pem_x509_csr(b"reqdata")
         with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509):
             backend.load_der_x509_csr(b"reqdata")
diff --git a/tests/test_x509.py b/tests/test_x509.py
index 220e71a..f5fead5 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -52,6 +52,252 @@
     return cert
 
 
+@pytest.mark.requires_backend_interface(interface=X509Backend)
+class TestCertificateRevocationList(object):
+    def test_load_pem_crl(self, backend):
+        crl = _load_cert(
+            os.path.join("x509", "custom", "crl_all_reasons.pem"),
+            x509.load_pem_x509_crl,
+            backend
+        )
+
+        assert isinstance(crl, x509.CertificateRevocationList)
+        fingerprint = binascii.hexlify(crl.fingerprint(hashes.SHA1()))
+        assert fingerprint == b"3234b0cb4c0cedf6423724b736729dcfc9e441ef"
+        assert isinstance(crl.signature_hash_algorithm, hashes.SHA256)
+
+    def test_load_der_crl(self, backend):
+        crl = _load_cert(
+            os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"),
+            x509.load_der_x509_crl,
+            backend
+        )
+
+        assert isinstance(crl, x509.CertificateRevocationList)
+        fingerprint = binascii.hexlify(crl.fingerprint(hashes.SHA1()))
+        assert fingerprint == b"dd3db63c50f4c4a13e090f14053227cb1011a5ad"
+        assert isinstance(crl.signature_hash_algorithm, hashes.SHA256)
+
+    def test_invalid_pem(self, backend):
+        with pytest.raises(ValueError):
+            x509.load_pem_x509_crl(b"notacrl", backend)
+
+    def test_invalid_der(self, backend):
+        with pytest.raises(ValueError):
+            x509.load_der_x509_crl(b"notacrl", backend)
+
+    def test_unknown_signature_algorithm(self, backend):
+        crl = _load_cert(
+            os.path.join(
+                "x509", "custom", "crl_md2_unknown_crit_entry_ext.pem"
+            ),
+            x509.load_pem_x509_crl,
+            backend
+        )
+
+        with pytest.raises(UnsupportedAlgorithm):
+                crl.signature_hash_algorithm()
+
+    def test_issuer(self, backend):
+        crl = _load_cert(
+            os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"),
+            x509.load_der_x509_crl,
+            backend
+        )
+
+        assert isinstance(crl.issuer, x509.Name)
+        assert list(crl.issuer) == [
+            x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'),
+            x509.NameAttribute(
+                x509.OID_ORGANIZATION_NAME, u'Test Certificates 2011'
+            ),
+            x509.NameAttribute(x509.OID_COMMON_NAME, u'Good CA')
+        ]
+        assert crl.issuer.get_attributes_for_oid(x509.OID_COMMON_NAME) == [
+            x509.NameAttribute(x509.OID_COMMON_NAME, u'Good CA')
+        ]
+
+    def test_equality(self, backend):
+        crl1 = _load_cert(
+            os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"),
+            x509.load_der_x509_crl,
+            backend
+        )
+
+        crl2 = _load_cert(
+            os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"),
+            x509.load_der_x509_crl,
+            backend
+        )
+
+        crl3 = _load_cert(
+            os.path.join("x509", "custom", "crl_all_reasons.pem"),
+            x509.load_pem_x509_crl,
+            backend
+        )
+
+        assert crl1 == crl2
+        assert crl1 != crl3
+        assert crl1 != object()
+
+    def test_update_dates(self, backend):
+        crl = _load_cert(
+            os.path.join("x509", "custom", "crl_all_reasons.pem"),
+            x509.load_pem_x509_crl,
+            backend
+        )
+
+        assert isinstance(crl.next_update, datetime.datetime)
+        assert isinstance(crl.last_update, datetime.datetime)
+
+        assert crl.next_update.isoformat() == "2016-01-01T00:00:00"
+        assert crl.last_update.isoformat() == "2015-01-01T00:00:00"
+
+    def test_revoked_certs(self, backend):
+        crl = _load_cert(
+            os.path.join("x509", "custom", "crl_all_reasons.pem"),
+            x509.load_pem_x509_crl,
+            backend
+        )
+
+        assert isinstance(crl.revoked_certificates, list)
+        for r in crl.revoked_certificates:
+                assert isinstance(r, x509.RevokedCertificate)
+
+    def test_extensions(self, backend):
+        crl = _load_cert(
+            os.path.join("x509", "custom", "crl_all_reasons.pem"),
+            x509.load_pem_x509_crl,
+            backend
+        )
+
+        # CRL extensions are currently not supported in the OpenSSL backend.
+        with pytest.raises(NotImplementedError):
+                crl.extensions
+
+
+@pytest.mark.requires_backend_interface(interface=X509Backend)
+class TestRevokedCertificate(object):
+
+    def test_revoked_basics(self, backend):
+        crl = _load_cert(
+            os.path.join("x509", "custom", "crl_all_reasons.pem"),
+            x509.load_pem_x509_crl,
+            backend
+        )
+
+        for i, rev in enumerate(crl.revoked_certificates):
+            assert isinstance(rev, x509.RevokedCertificate)
+            assert isinstance(rev.serial_number, int)
+            assert isinstance(rev.revocation_date, datetime.datetime)
+            assert isinstance(rev.extensions, x509.Extensions)
+
+            assert rev.serial_number == i
+            assert rev.revocation_date.isoformat() == "2015-01-01T00:00:00"
+
+    def test_revoked_extensions(self, backend):
+        crl = _load_cert(
+            os.path.join("x509", "custom", "crl_all_reasons.pem"),
+            x509.load_pem_x509_crl,
+            backend
+        )
+
+        # First revoked cert doesn't have extensions, test if it is handled
+        # correctly.
+        rev0 = crl.revoked_certificates[0]
+        # It should return an empty Extensions object.
+        assert isinstance(rev0.extensions, x509.Extensions)
+        assert len(rev0.extensions) == 0
+        with pytest.raises(x509.ExtensionNotFound):
+            rev0.extensions.get_extension_for_oid(x509.OID_CRL_REASON)
+
+        assert rev0.get_invalidity_date() is None
+        assert rev0.get_certificate_issuer() is None
+        assert rev0.get_reason() is None
+
+        # Test manual retrieval of extension values.
+        rev1 = crl.revoked_certificates[1]
+        assert isinstance(rev1.extensions, x509.Extensions)
+
+        reason = rev1.extensions.get_extension_for_oid(
+            x509.OID_CRL_REASON).value
+        assert reason == x509.ReasonFlags.unspecified
+
+        date = rev1.extensions.get_extension_for_oid(
+            x509.OID_INVALIDITY_DATE).value
+        assert isinstance(date, datetime.datetime)
+        assert date.isoformat() == "2015-01-01T00:00:00"
+
+        # Test convenience function.
+        assert rev1.get_invalidity_date().isoformat() == "2015-01-01T00:00:00"
+
+        # Check if all reason flags can be found in the CRL.
+        flags = set(x509.ReasonFlags)
+        # The first revoked cert doesn't have a reason.
+        for r in crl.revoked_certificates[1:]:
+            flags.discard(r.get_reason())
+        assert len(flags) == 0
+
+    def test_duplicate_entry_ext(self, backend):
+        crl = _load_cert(
+            os.path.join("x509", "custom", "crl_dup_entry_ext.pem"),
+            x509.load_pem_x509_crl,
+            backend
+        )
+
+        with pytest.raises(x509.DuplicateExtension):
+            crl.revoked_certificates[0].extensions
+
+    def test_unsupported_crit_entry_ext(self, backend):
+        crl = _load_cert(
+            os.path.join(
+                "x509", "custom", "crl_md2_unknown_crit_entry_ext.pem"
+            ),
+            x509.load_pem_x509_crl,
+            backend
+        )
+
+        with pytest.raises(x509.UnsupportedExtension):
+            crl.revoked_certificates[0].extensions
+
+    def test_unsupported_reason(self, backend):
+        crl = _load_cert(
+            os.path.join(
+                "x509", "custom", "crl_unsupported_reason.pem"
+            ),
+            x509.load_pem_x509_crl,
+            backend
+        )
+
+        with pytest.raises(ValueError):
+            crl.revoked_certificates[0].extensions
+
+    def test_cert_issuer_ext(self, backend):
+        if backend._lib.OPENSSL_VERSION_NUMBER < 0x10000000:
+            pytest.skip("Requires a newer OpenSSL. Must be at least 1.0.0")
+
+        crl = _load_cert(
+            os.path.join("x509", "custom", "crl_all_reasons.pem"),
+            x509.load_pem_x509_crl,
+            backend
+        )
+
+        exp_issuer = x509.GeneralNames([
+            x509.DirectoryName(x509.Name([
+                x509.NameAttribute(x509.OID_COUNTRY_NAME, u"US"),
+                x509.NameAttribute(x509.OID_COMMON_NAME, u"cryptography.io"),
+            ]))
+        ])
+
+        rev = crl.revoked_certificates[1]
+        issuer = rev.extensions.get_extension_for_oid(
+            x509.OID_CERTIFICATE_ISSUER).value
+        assert issuer == exp_issuer
+
+        # Test convenience function.
+        assert rev.get_certificate_issuer() == exp_issuer
+
+
 @pytest.mark.requires_backend_interface(interface=RSABackend)
 @pytest.mark.requires_backend_interface(interface=X509Backend)
 class TestRSACertificate(object):