Merge pull request #2553 from reaperhulk/098-change

Build our own 0.9.8 on travis
diff --git a/.mention-bot b/.mention-bot
index 3c998c9..a05018e 100644
--- a/.mention-bot
+++ b/.mention-bot
@@ -1,3 +1,3 @@
 {
-    "userBlacklist": ["dreid"]
+    "userBlacklist": ["dreid", "exarkun", "dstufft"]
 }
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 3e24633..717c9e7 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,6 +6,21 @@
 
 .. note:: This version is not yet released and is under active development.
 
+* **BACKWARDS INCOMPATIBLE:**
+  :class:`~cryptography.x509.RevokedCertificate`
+  :attr:`~cryptography.x509.RevokedCertificate.extensions` now uses extension
+  classes rather than returning raw values inside the
+  :class:`~cryptography.x509.Extension`
+  :attr:`~cryptography.x509.Extension.value`. The new classes
+  are:
+
+  * :class:`~cryptography.x509.CertificateIssuer`
+  * :class:`~cryptography.x509.CRLReason`
+  * :class:`~cryptography.x509.InvalidityDate`
+* Deprecated support for OpenSSL 0.9.8 and 1.0.0. At this time there is no time
+  table for actually dropping support, however we strongly encourage all users
+  to upgrade, as those versions no longer receives support from the OpenSSL
+  project.
 * The :class:`~cryptography.x509.Certificate` class now has
   :attr:`~cryptography.x509.Certificate.signature` and
   :attr:`~cryptography.x509.Certificate.tbs_certificate_bytes` attributes.
@@ -31,6 +46,11 @@
   * :class:`~cryptography.x509.AuthorityKeyIdentifier`
   * :class:`~cryptography.x509.CRLNumber`
   * :class:`~cryptography.x509.IssuerAlternativeName`
+* Added :class:`~cryptography.x509.CertificateRevocationListBuilder` and
+  :class:`~cryptography.x509.RevokedCertificateBuilder` to allow creation of
+  CRLs.
+* Unrecognized non-critical X.509 extensions are now parsed into an
+  :class:`~cryptography.x509.UnrecognizedExtension` object.
 
 1.1.2 - 2015-12-10
 ~~~~~~~~~~~~~~~~~~
diff --git a/docs/conf.py b/docs/conf.py
index 5a4c41b..dcc9c62 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -71,7 +71,7 @@
 
 # General information about the project.
 project = 'Cryptography'
-copyright = '2013-2015, Individual Contributors'
+copyright = '2013-2016, Individual Contributors'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
diff --git a/docs/development/submitting-patches.rst b/docs/development/submitting-patches.rst
index 6610584..563bc81 100644
--- a/docs/development/submitting-patches.rst
+++ b/docs/development/submitting-patches.rst
@@ -151,6 +151,6 @@
 
 .. _`Write comments as complete sentences.`: http://nedbatchelder.com/blog/201401/comments_should_be_sentences.html
 .. _`syntax`: http://sphinx-doc.org/domains.html#info-field-lists
-.. _`Studies have shown`: https://smartbear.com/smartbear/media/pdfs/wp-cc-11-best-practices-of-peer-code-review.pdf
+.. _`Studies have shown`: https://smartbear.com/SmartBear/media/pdfs/11_Best_Practices_for_Peer_Code_Review.pdf
 .. _`our mailing list`: https://mail.python.org/mailman/listinfo/cryptography-dev
-.. _`doc8`: https://github.com/stackforge/doc8
+.. _`doc8`: https://github.com/openstack/doc8
diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst
index 70766d5..ad945f2 100644
--- a/docs/development/test-vectors.rst
+++ b/docs/development/test-vectors.rst
@@ -141,6 +141,10 @@
 * ``unsupported_extension.pem`` - An RSA 2048 bit self-signed certificate
   containing an unsupported extension type. The OID was encoded as
   "1.2.3.4" with an ``extnValue`` of "value".
+* ``unsupported_extension_2.pem`` - A ``secp256r1`` certificate
+  containing two unsupported extensions. The OIDs are ``1.3.6.1.4.1.41482.2``
+  with an ``extnValue`` of ``1.3.6.1.4.1.41482.1.2`` and
+  ``1.3.6.1.4.1.45724.2.1.1`` with an ``extnValue`` of ``\x03\x02\x040``
 * ``unsupported_extension_critical.pem`` - An RSA 2048 bit self-signed
   certificate containing an unsupported extension type marked critical. The OID
   was encoded as "1.2.3.4" with an ``extnValue`` of "value".
diff --git a/docs/faq.rst b/docs/faq.rst
index 0b7bdce..10c8656 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -14,5 +14,5 @@
 
 If you prefer NaCl's design, we highly recommend `PyNaCl`_.
 
-.. _`NaCl`: http://nacl.cr.yp.to/
+.. _`NaCl`: https://nacl.cr.yp.to/
 .. _`PyNaCl`: https://pynacl.readthedocs.org
diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst
index 442bd0d..73011dd 100644
--- a/docs/hazmat/backends/interfaces.rst
+++ b/docs/hazmat/backends/interfaces.rst
@@ -547,8 +547,8 @@
             :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`
             that will be used to generate the request signature.
 
-        :returns: A new object with the
-            :class:`~cryptography.x509.CertificateSigningRequest` interface.
+        :returns: A new instance of
+            :class:`~cryptography.x509.CertificateSigningRequest`.
 
     .. method:: create_x509_certificate(builder, private_key, algorithm)
 
@@ -567,9 +567,36 @@
             :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`
             that will be used to generate the certificate signature.
 
-        :returns: A new object with the
-            :class:`~cryptography.x509.Certificate` interface.
+        :returns: A new instance of :class:`~cryptography.x509.Certificate`.
 
+    .. method:: create_x509_crl(builder, private_key, algorithm)
+
+        .. versionadded:: 1.2
+
+        :param builder: An instance of
+            :class:`~cryptography.x509.CertificateRevocationListBuilder`.
+
+        :param private_key: The
+            :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`,
+            :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey` or
+            :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`
+            that will be used to sign the CRL.
+
+        :param algorithm: The
+            :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`
+            that will be used to generate the CRL signature.
+
+        :returns: A new instance of
+            :class:`~cryptography.x509.CertificateRevocationList`.
+
+    .. method:: create_x509_revoked_certificate(builder)
+
+        .. versionadded:: 1.2
+
+        :param builder: An instance of RevokedCertificateBuilder.
+
+        :returns: A new instance of
+            :class:`~cryptography.x509.RevokedCertificate`.
 
 .. class:: DHBackend
 
diff --git a/docs/hazmat/bindings/openssl.rst b/docs/hazmat/bindings/openssl.rst
index 0ec0a3d..99cd7a4 100644
--- a/docs/hazmat/bindings/openssl.rst
+++ b/docs/hazmat/bindings/openssl.rst
@@ -46,4 +46,4 @@
 
 .. _`CFFI`: https://cffi.readthedocs.org/
 .. _`OpenSSL`: https://www.openssl.org/
-.. _`thread safety facilities`: https://www.openssl.org/docs/crypto/threads.html
+.. _`thread safety facilities`: https://www.openssl.org/docs/manmaster/crypto/threads.html
diff --git a/docs/hazmat/primitives/asymmetric/ec.rst b/docs/hazmat/primitives/asymmetric/ec.rst
index c1619dd..8e3a365 100644
--- a/docs/hazmat/primitives/asymmetric/ec.rst
+++ b/docs/hazmat/primitives/asymmetric/ec.rst
@@ -504,7 +504,7 @@
 .. _`some concern`: https://crypto.stackexchange.com/questions/10263/should-we-trust-the-nist-recommended-ecc-parameters
 .. _`less than 224 bits`: http://www.ecrypt.eu.org/ecrypt2/documents/D.SPA.20.pdf
 .. _`elliptic curve diffie-hellman is faster than diffie-hellman`: http://digitalcommons.unl.edu/cgi/viewcontent.cgi?article=1100&context=cseconfwork
-.. _`minimize the number of security concerns for elliptic-curve cryptography`: http://cr.yp.to/ecdh/curve25519-20060209.pdf
+.. _`minimize the number of security concerns for elliptic-curve cryptography`: https://cr.yp.to/ecdh/curve25519-20060209.pdf
 .. _`SafeCurves`: http://safecurves.cr.yp.to/
 .. _`ECDSA`: https://en.wikipedia.org/wiki/ECDSA
 .. _`EdDSA`: https://en.wikipedia.org/wiki/EdDSA
diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst
index f14f403..b94c0e1 100644
--- a/docs/hazmat/primitives/asymmetric/serialization.rst
+++ b/docs/hazmat/primitives/asymmetric/serialization.rst
@@ -118,7 +118,12 @@
         :class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend`
         provider.
 
-    :returns: A new instance of a private key.
+    :returns: One of
+        :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`,
+        :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`,
+        or
+        :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`
+        depending on the contents of ``data``.
 
     :raises ValueError: If the PEM data could not be decrypted or if its
         structure could not be decoded successfully.
@@ -136,7 +141,8 @@
     .. versionadded:: 0.6
 
     Deserialize a public key from PEM encoded data to one of the supported
-    asymmetric public key types.
+    asymmetric public key types. The PEM encoded data is typically a
+    ``subjectPublicKeyInfo`` payload as specified in :rfc:`5280`.
 
     .. doctest::
 
@@ -151,7 +157,13 @@
         :class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend`
         provider.
 
-    :returns: A new instance of a public key.
+
+    :returns: One of
+        :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`,
+        :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`,
+        or
+        :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`
+        depending on the contents of ``data``.
 
     :raises ValueError: If the PEM data's structure could not be decoded
         successfully.
@@ -183,7 +195,12 @@
         :class:`~cryptography.hazmat.backends.interfaces.DERSerializationBackend`
         provider.
 
-    :returns: A new instance of a private key.
+    :returns: One of
+        :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`,
+        :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`,
+        or
+        :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`
+        depending on the contents of ``data``.
 
     :raises ValueError: If the DER data could not be decrypted or if its
         structure could not be decoded successfully.
@@ -210,7 +227,8 @@
     .. versionadded:: 0.8
 
     Deserialize a public key from DER encoded data to one of the supported
-    asymmetric public key types.
+    asymmetric public key types. The DER encoded data is typically a
+    ``subjectPublicKeyInfo`` payload as specified in :rfc:`5280`.
 
     :param bytes data: The DER encoded key data.
 
@@ -218,7 +236,12 @@
         :class:`~cryptography.hazmat.backends.interfaces.DERSerializationBackend`
         provider.
 
-    :returns: A new instance of a public key.
+    :returns: One of
+        :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`,
+        :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`,
+        or
+        :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`
+        depending on the contents of ``data``.
 
     :raises ValueError: If the DER data's structure could not be decoded
         successfully.
@@ -275,7 +298,12 @@
         :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`
         depending on the key's type.
 
-    :returns: A new instance of a public key type.
+    :returns: One of
+        :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`,
+        :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`,
+        or
+        :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`
+        depending on the contents of ``data``.
 
     :raises ValueError: If the OpenSSH data could not be properly decoded or
         if the key is not in the proper format.
diff --git a/docs/installation.rst b/docs/installation.rst
index 16c42d2..f9d2261 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -21,6 +21,10 @@
 * x86-64 Debian Wheezy (7.x), Jessie (8.x), and Debian Sid (unstable)
 * 32-bit and 64-bit Python on 64-bit Windows Server 2012
 
+.. warning::
+    Python 2.6 is no longer supported by the Python core team. A future version
+    of cryptography will drop support for this version.
+
 We test compiling with ``clang`` as well as ``gcc`` and use the following
 OpenSSL releases:
 
@@ -33,6 +37,11 @@
 * ``OpenSSL 1.0.1f``
 * ``OpenSSL 1.0.2-latest``
 
+.. warning::
+    OpenSSL versions 0.9.8 and 1.0.0 are no longer supported by the OpenSSL
+    project. A future version of cryptography will drop support for these
+    releases.
+
 On Windows
 ----------
 
@@ -58,6 +67,8 @@
     C:\> set INCLUDE=C:\OpenSSL-win64\include;%INCLUDE%
     C:\> pip install cryptography
 
+If you need to rebuild ``cryptography`` for any reason be sure to clear the
+local `wheel cache`_.
 
 .. _build-on-linux:
 
@@ -173,7 +184,7 @@
 -----------------------------
 
 The wheel package on OS X is a statically linked build (as of 1.0.1) so for
-users on 10.10 (Yosemite) and above you only need one step:
+users with pip 1.5 or above you only need one step:
 
 .. code-block:: console
 
@@ -182,8 +193,8 @@
 If you want to build cryptography yourself or are on an older OS X version
 cryptography requires the presence of a C compiler, development headers, and
 the proper libraries. On OS X much of this is provided by Apple's Xcode
-development tools.  To install the Xcode command line tools open a terminal
-window and run:
+development tools.  To install the Xcode command line tools (on OS X 10.9+)
+open a terminal window and run:
 
 .. code-block:: console
 
@@ -227,6 +238,9 @@
     $ sudo port install openssl
     $ env CRYPTOGRAPHY_OSX_NO_LINK_FLAGS=1 LDFLAGS="/opt/local/lib/libssl.a /opt/local/lib/libcrypto.a" CFLAGS="-I/opt/local/include" pip install cryptography
 
+If you need to rebuild ``cryptography`` for any reason be sure to clear the
+local `wheel cache`_.
+
 Building cryptography with conda
 --------------------------------
 
@@ -257,3 +271,4 @@
 .. _`Greg Wilson's blog post`: http://software-carpentry.org/blog/2014/04/mr-biczo-was-right.html
 .. _virtualenv: https://virtualenv.pypa.io/en/latest/
 .. _openssl.org: https://openssl.org/source/
+.. _`wheel cache`: https://pip.pypa.io/en/stable/reference/pip_install/#caching
diff --git a/docs/limitations.rst b/docs/limitations.rst
index 0dfc49c..503bdfe 100644
--- a/docs/limitations.rst
+++ b/docs/limitations.rst
@@ -15,5 +15,5 @@
 Likelihood: unlikely, Remediation Cost: expensive to repair" and we do not
 consider this a high risk for most users.
 
-.. _`Memory wiping`:  http://blogs.msdn.com/b/oldnewthing/archive/2013/05/29/10421912.aspx
+.. _`Memory wiping`:  https://blogs.msdn.microsoft.com/oldnewthing/20130529-00/?p=4223/
 .. _`CERT secure coding guidelines`: https://www.securecoding.cert.org/confluence/display/c/MEM03-C.+Clear+sensitive+information+stored+in+reusable+resources
diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst
index 4f4ce4f..8bb3f40 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -761,6 +761,113 @@
         key embedded in the CSR). This data may be used to validate the CSR
         signature.
 
+X.509 Certificate Revocation List Builder
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. class:: CertificateRevocationListBuilder
+
+    .. versionadded:: 1.2
+
+    .. doctest::
+
+        >>> from cryptography import x509
+        >>> from cryptography.hazmat.backends import default_backend
+        >>> from cryptography.hazmat.primitives import hashes
+        >>> from cryptography.hazmat.primitives.asymmetric import rsa
+        >>> from cryptography.x509.oid import NameOID
+        >>> import datetime
+        >>> one_day = datetime.timedelta(1, 0, 0)
+        >>> private_key = rsa.generate_private_key(
+        ...     public_exponent=65537,
+        ...     key_size=2048,
+        ...     backend=default_backend()
+        ... )
+        >>> builder = x509.CertificateRevocationListBuilder()
+        >>> builder = builder.issuer_name(x509.Name([
+        ...     x509.NameAttribute(NameOID.COMMON_NAME, u'cryptography.io CA'),
+        ... ]))
+        >>> builder = builder.last_update(datetime.datetime.today())
+        >>> builder = builder.next_update(datetime.datetime.today() + one_day)
+        >>> revoked_cert = x509.RevokedCertificateBuilder().serial_number(
+        ...     333
+        ... ).revocation_date(
+        ...     datetime.datetime.today()
+        ... ).build(default_backend())
+        >>> builder = builder.add_revoked_certificate(revoked_cert)
+        >>> crl = builder.sign(
+        ...     private_key=private_key, algorithm=hashes.SHA256(),
+        ...     backend=default_backend()
+        ... )
+        >>> len(crl)
+        1
+
+    .. method:: issuer_name(name)
+
+        Sets the issuer's distinguished name.
+
+        :param name: The :class:`~cryptography.x509.Name` that describes the
+            issuer (CA).
+
+    .. method:: last_update(time)
+
+        Sets this CRL's activation time.  This is the time from which
+        clients can start trusting this CRL.  It may be different from
+        the time at which this CRL was created. This is also known as the
+        ``thisUpdate`` time.
+
+        :param time: The :class:`datetime.datetime` object (in UTC) that marks
+            the activation time for this CRL.  The CRL may not be trusted if it
+            is used before this time.
+
+    .. method:: next_update(time)
+
+        Sets this CRL's next update time. This is the time by which
+        a new CRL will be issued. The CA is allowed to issue a new CRL before
+        this date, however clients are not required to check for it.
+
+        :param time: The :class:`datetime.datetime` object (in UTC) that marks
+            the next update time for this CRL.
+
+    .. method:: add_extension(extension, critical)
+
+        Adds an X.509 extension to this CRL.
+
+        :param extension: An extension with the
+            :class:`~cryptography.x509.ExtensionType` interface.
+
+        :param critical: Set to ``True`` if the extension must be understood and
+             handled by whoever reads the CRL.
+
+    .. method:: add_revoked_certificate(revoked_certificate)
+
+        Adds a revoked certificate to this CRL.
+
+        :param revoked_certificate: An instance of
+            :class:`~cryptography.x509.RevokedCertificate`. These can be
+            obtained from an existing CRL or created with
+            :class:`~cryptography.x509.RevokedCertificateBuilder`.
+
+    .. method:: sign(private_key, algorithm, backend)
+
+        Sign this CRL using the CA's private key.
+
+        :param private_key: The
+            :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`,
+            :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey` or
+            :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`
+            that will be used to sign the certificate.
+
+        :param algorithm: The
+            :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` that
+            will be used to generate the signature.
+
+        :param backend: Backend that will be used to build the CRL.
+            Must support the
+            :class:`~cryptography.hazmat.backends.interfaces.X509Backend`
+            interface.
+
+        :returns: :class:`~cryptography.x509.CertificateRevocationList`
+
 X.509 Revoked Certificate Object
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -800,8 +907,66 @@
 
             >>> for ext in revoked_certificate.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)>
+            <Extension(oid=<ObjectIdentifier(oid=2.5.29.24, name=invalidityDate)>, critical=False, value=<InvalidityDate(invalidity_date=2015-01-01 00:00:00)>)>
+            <Extension(oid=<ObjectIdentifier(oid=2.5.29.21, name=cRLReason)>, critical=False, value=<CRLReason(reason=ReasonFlags.key_compromise)>)>
+
+X.509 Revoked Certificate Builder
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. class:: RevokedCertificateBuilder
+
+    This class is used to create :class:`~cryptography.x509.RevokedCertificate`
+    objects that can be used with the
+    :class:`~cryptography.x509.CertificateRevocationListBuilder`.
+
+    .. versionadded:: 1.2
+
+    .. doctest::
+
+        >>> from cryptography import x509
+        >>> from cryptography.hazmat.backends import default_backend
+        >>> import datetime
+        >>> builder = x509.RevokedCertificateBuilder()
+        >>> builder = builder.revocation_date(datetime.datetime.today())
+        >>> builder = builder.serial_number(3333)
+        >>> revoked_certificate = builder.build(default_backend())
+        >>> isinstance(revoked_certificate, x509.RevokedCertificate)
+        True
+
+    .. method:: serial_number(serial_number)
+
+        Sets the revoked certificate's serial number.
+
+        :param serial_number: Integer number that is used to identify the
+            revoked certificate.
+
+    .. method:: revocation_date(time)
+
+        Sets the certificate's revocation date.
+
+        :param time: The :class:`datetime.datetime` object (in UTC) that marks the
+            revocation time for the certificate.
+
+    .. method:: add_extension(extension, critical)
+
+        Adds an X.509 extension to this revoked certificate.
+
+        :param extension: An instance of one of the
+            :ref:`CRL entry extensions <crl_entry_extensions>`.
+
+        :param critical: Set to ``True`` if the extension must be understood and
+             handled.
+
+    .. method:: build(backend)
+
+        Create a revoked certificate object using the provided backend.
+
+        :param backend: Backend that will be used to build the revoked
+            certificate.  Must support the
+            :class:`~cryptography.hazmat.backends.interfaces.X509Backend`
+            interface.
+
+        :returns: :class:`~cryptography.x509.RevokedCertificate`
 
 X.509 CSR (Certificate Signing Request) Builder Object
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1715,6 +1880,27 @@
 
         :type: int
 
+.. class:: UnrecognizedExtension
+
+    .. versionadded:: 1.2
+
+    A generic extension class used to hold the raw value of **non-critical**
+    extensions that ``cryptography`` does not know how to parse. Extensions
+    marked critical will raise
+    :class:`~cryptography.x509.UnsupportedExtension`.
+
+    .. attribute:: oid
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns the OID associated with this extension.
+
+    .. attribute:: value
+
+        :type: byte
+
+        Returns the DER encoded bytes payload of the extension.
+
 .. class:: CertificatePolicies(policies)
 
     .. versionadded:: 0.9
@@ -1801,6 +1987,89 @@
 
         A list of integers.
 
+.. _crl_entry_extensions:
+
+CRL Entry Extensions
+~~~~~~~~~~~~~~~~~~~~
+
+These extensions are only valid within a :class:`RevokedCertificate` object.
+
+.. class:: CertificateIssuer(general_names)
+
+    .. versionadded:: 1.2
+
+    The certificate issuer is an extension that is only valid inside
+    :class:`~cryptography.x509.RevokedCertificate` objects.  If the
+    ``indirectCRL`` property of the parent CRL's IssuingDistributionPoint
+    extension is set, then this extension identifies the certificate issuer
+    associated with the revoked certificate. The object is iterable to get
+    every element.
+
+    :param list general_names: A list of :class:`GeneralName` instances.
+
+    .. attribute:: oid
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns
+        :attr:`~cryptography.x509.oid.CRLEntryExtensionOID.CERTIFICATE_ISSUER`.
+
+    .. method:: get_values_for_type(type)
+
+        :param type: A :class:`GeneralName` instance. This is one of the
+            :ref:`general name classes <general_name_classes>`.
+
+        :returns: A list of values extracted from the matched general names.
+            The type of the returned values depends on the :class:`GeneralName`.
+
+.. class:: CRLReason(reason)
+
+    .. versionadded:: 1.2
+
+    CRL reason (also known as ``reasonCode``) is an extension that is only
+    valid inside :class:`~cryptography.x509.RevokedCertificate` objects. It
+    identifies a reason for the certificate revocation.
+
+    :param reason: A value from the
+        :class:`~cryptography.x509.oid.CRLEntryExtensionOID` enum.
+
+    .. attribute:: oid
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns
+        :attr:`~cryptography.x509.oid.CRLEntryExtensionOID.CRL_REASON`.
+
+    .. attribute:: reason
+
+        :type: An element from :class:`~cryptography.x509.ReasonFlags`
+
+.. class:: InvalidityDate(invalidity_date)
+
+    .. versionadded:: 1.2
+
+    Invalidity date is an extension that is only valid inside
+    :class:`~cryptography.x509.RevokedCertificate` objects. It provides
+    the date on which it is known or suspected that the private key was
+    compromised or that the certificate otherwise became invalid.
+    This date may be earlier than the revocation date in the CRL entry,
+    which is the date at which the CA processed the revocation.
+
+    :param invalidity_date: The :class:`datetime.datetime` when it is known
+        or suspected that the private key was compromised.
+
+    .. attribute:: oid
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns
+        :attr:`~cryptography.x509.oid.CRLEntryExtensionOID.INVALIDITY_DATE`.
+
+    .. attribute:: invalidity_date
+
+        :type: :class:`datetime.datetime`
+
+
 Object Identifiers
 ~~~~~~~~~~~~~~~~~~
 
@@ -2123,6 +2392,22 @@
         the ``CRLNumber`` extension type. This extension only has meaning
         for certificate revocation lists.
 
+.. class:: CRLEntryExtensionOID
+
+    .. versionadded:: 1.2
+
+    .. attribute:: CERTIFICATE_ISSUER
+
+        Corresponds to the dotted string ``"2.5.29.29"``.
+
+    .. attribute:: CRL_REASON
+
+        Corresponds to the dotted string ``"2.5.29.21"``.
+
+    .. attribute:: INVALIDITY_DATE
+
+        Corresponds to the dotted string ``"2.5.29.24"``.
+
 Exceptions
 ~~~~~~~~~~
 .. currentmodule:: cryptography.x509
@@ -2150,7 +2435,8 @@
 
 .. class:: UnsupportedExtension
 
-    This is raised when a certificate contains an unsupported extension type.
+    This is raised when a certificate contains an unsupported extension type
+    that is marked ``critical``.
 
     .. attribute:: oid
 
diff --git a/setup.py b/setup.py
index 19f1e66..3b67e8f 100644
--- a/setup.py
+++ b/setup.py
@@ -37,7 +37,7 @@
     "idna>=2.0",
     "pyasn1>=0.1.8",
     "six>=1.4.1",
-    "setuptools",
+    "setuptools>=1.0",
 ]
 setup_requirements = []
 
diff --git a/src/_cffi_src/build_commoncrypto.py b/src/_cffi_src/build_commoncrypto.py
index 1c2692a..4e69b6d 100644
--- a/src/_cffi_src/build_commoncrypto.py
+++ b/src/_cffi_src/build_commoncrypto.py
@@ -22,6 +22,7 @@
         "seckey",
         "seckeychain",
         "sectransform",
+        "sectrust",
     ],
     extra_link_args=[
         "-framework", "Security", "-framework", "CoreFoundation"
diff --git a/src/_cffi_src/build_constant_time.py b/src/_cffi_src/build_constant_time.py
index 6d9a8f5..7a11f7b 100644
--- a/src/_cffi_src/build_constant_time.py
+++ b/src/_cffi_src/build_constant_time.py
@@ -5,9 +5,8 @@
 from __future__ import absolute_import, division, print_function
 
 import os
-import sys
 
-from _cffi_src.utils import build_ffi, extra_link_args
+from _cffi_src.utils import build_ffi, compiler_type, extra_link_args
 
 
 with open(os.path.join(
@@ -24,5 +23,5 @@
     module_name="_constant_time",
     cdef_source=types,
     verify_source=functions,
-    extra_link_args=extra_link_args(sys.platform),
+    extra_link_args=extra_link_args(compiler_type()),
 )
diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py
index c856e3d..c47b308 100644
--- a/src/_cffi_src/build_openssl.py
+++ b/src/_cffi_src/build_openssl.py
@@ -7,7 +7,9 @@
 import os
 import sys
 
-from _cffi_src.utils import build_ffi_for_binding, extra_link_args
+from _cffi_src.utils import (
+    build_ffi_for_binding, compiler_type, extra_link_args
+)
 
 
 def _get_openssl_libraries(platform):
@@ -92,5 +94,5 @@
     pre_include=_OSX_PRE_INCLUDE,
     post_include=_OSX_POST_INCLUDE,
     libraries=_get_openssl_libraries(sys.platform),
-    extra_link_args=extra_link_args(sys.platform),
+    extra_link_args=extra_link_args(compiler_type()),
 )
diff --git a/src/_cffi_src/build_padding.py b/src/_cffi_src/build_padding.py
index 5df93d8..4c5096a 100644
--- a/src/_cffi_src/build_padding.py
+++ b/src/_cffi_src/build_padding.py
@@ -5,9 +5,8 @@
 from __future__ import absolute_import, division, print_function
 
 import os
-import sys
 
-from _cffi_src.utils import build_ffi, extra_link_args
+from _cffi_src.utils import build_ffi, compiler_type, extra_link_args
 
 
 with open(os.path.join(
@@ -24,5 +23,5 @@
     module_name="_padding",
     cdef_source=types,
     verify_source=functions,
-    extra_link_args=extra_link_args(sys.platform),
+    extra_link_args=extra_link_args(compiler_type()),
 )
diff --git a/src/_cffi_src/commoncrypto/sectrust.py b/src/_cffi_src/commoncrypto/sectrust.py
new file mode 100644
index 0000000..b787afa
--- /dev/null
+++ b/src/_cffi_src/commoncrypto/sectrust.py
@@ -0,0 +1,22 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+INCLUDES = """
+#include <Security/SecTrust.h>
+"""
+
+TYPES = """
+"""
+
+FUNCTIONS = """
+OSStatus SecTrustCopyAnchorCertificates(CFArrayRef *);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
diff --git a/src/_cffi_src/openssl/asn1.py b/src/_cffi_src/openssl/asn1.py
index ddf4b9c..30bd245 100644
--- a/src/_cffi_src/openssl/asn1.py
+++ b/src/_cffi_src/openssl/asn1.py
@@ -95,13 +95,16 @@
 
 /*  ASN1 GENERALIZEDTIME */
 int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *, const char *);
+ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *, time_t);
 void ASN1_GENERALIZEDTIME_free(ASN1_GENERALIZEDTIME *);
+int i2d_ASN1_GENERALIZEDTIME(ASN1_GENERALIZEDTIME *, unsigned char **);
 
 /*  ASN1 ENUMERATED */
 ASN1_ENUMERATED *ASN1_ENUMERATED_new(void);
 void ASN1_ENUMERATED_free(ASN1_ENUMERATED *);
 int ASN1_ENUMERATED_set(ASN1_ENUMERATED *, long);
 long ASN1_ENUMERATED_get(ASN1_ENUMERATED *);
+int i2d_ASN1_ENUMERATED(ASN1_ENUMERATED *, unsigned char **);
 
 ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **, const unsigned char **, long,
                           const ASN1_ITEM *);
diff --git a/src/_cffi_src/openssl/bignum.py b/src/_cffi_src/openssl/bignum.py
index ae03500..455afdc 100644
--- a/src/_cffi_src/openssl/bignum.py
+++ b/src/_cffi_src/openssl/bignum.py
@@ -71,6 +71,8 @@
 """
 
 MACROS = """
+int BN_num_bytes(const BIGNUM *);
+
 int BN_zero(BIGNUM *);
 int BN_one(BIGNUM *);
 int BN_mod(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
diff --git a/src/_cffi_src/openssl/err.py b/src/_cffi_src/openssl/err.py
index 6ec1377..9d97be1 100644
--- a/src/_cffi_src/openssl/err.py
+++ b/src/_cffi_src/openssl/err.py
@@ -230,6 +230,7 @@
 static const int RSA_R_BLOCK_TYPE_IS_NOT_01;
 static const int RSA_R_BLOCK_TYPE_IS_NOT_02;
 static const int RSA_R_PKCS_DECODING_ERROR;
+static const int RSA_R_OAEP_DECODING_ERROR;
 static const int RSA_F_RSA_SIGN;
 """
 
diff --git a/src/_cffi_src/openssl/pem.py b/src/_cffi_src/openssl/pem.py
index 846e64e..4eb6bb4 100644
--- a/src/_cffi_src/openssl/pem.py
+++ b/src/_cffi_src/openssl/pem.py
@@ -79,6 +79,7 @@
 int PEM_write_bio_ECPrivateKey(BIO *, EC_KEY *, const EVP_CIPHER *,
                                unsigned char *, int, pem_password_cb *,
                                void *);
+int PEM_write_bio_DHparams(BIO *, DH *);
 """
 
 CUSTOMIZATIONS = """
diff --git a/src/_cffi_src/openssl/x509.py b/src/_cffi_src/openssl/x509.py
index 0fc49ac..c5eb600 100644
--- a/src/_cffi_src/openssl/x509.py
+++ b/src/_cffi_src/openssl/x509.py
@@ -193,6 +193,8 @@
 int X509_REVOKED_add_ext(X509_REVOKED *, X509_EXTENSION*, int);
 int X509_REVOKED_add1_ext_i2d(X509_REVOKED *, int, void *, int, unsigned long);
 
+int X509_REVOKED_set_revocationDate(X509_REVOKED *, ASN1_TIME *);
+
 X509_CRL *X509_CRL_new(void);
 X509_CRL *d2i_X509_CRL_bio(BIO *, X509_CRL **);
 X509_EXTENSION *X509_CRL_get_ext(X509_CRL *, int);
@@ -268,6 +270,8 @@
 """
 
 MACROS = """
+X509_REVOKED *Cryptography_X509_REVOKED_dup(X509_REVOKED *);
+
 int i2d_X509_CINF(X509_CINF *, unsigned char **);
 int i2d_X509_CRL_INFO(X509_CRL_INFO *, unsigned char **);
 int i2d_X509_REQ_INFO(X509_REQ_INFO *, unsigned char **);
@@ -290,6 +294,7 @@
 int sk_X509_EXTENSION_num(X509_EXTENSIONS *);
 X509_EXTENSION *sk_X509_EXTENSION_value(X509_EXTENSIONS *, int);
 int sk_X509_EXTENSION_push(X509_EXTENSIONS *, X509_EXTENSION *);
+int sk_X509_EXTENSION_insert(X509_EXTENSIONS *, X509_EXTENSION *, int);
 X509_EXTENSION *sk_X509_EXTENSION_delete(X509_EXTENSIONS *, int);
 void sk_X509_EXTENSION_free(X509_EXTENSIONS *);
 
@@ -362,4 +367,12 @@
 EC_KEY *(*o2i_ECPublicKey)(EC_KEY **, const unsigned char **, long) = NULL;
 int (*i2o_ECPublicKey)(EC_KEY *, unsigned char **) = NULL;
 #endif
+
+/* X509_REVOKED_dup only exists on 1.0.2+. It is implemented using
+   IMPLEMENT_ASN1_DUP_FUNCTION. The below is the equivalent so we have
+   it available on all OpenSSLs. */
+X509_REVOKED *Cryptography_X509_REVOKED_dup(X509_REVOKED *rev) {
+    return ASN1_item_dup(ASN1_ITEM_rptr(X509_REVOKED), rev);
+}
+
 """
diff --git a/src/_cffi_src/utils.py b/src/_cffi_src/utils.py
index 0b00353..bdce2f3 100644
--- a/src/_cffi_src/utils.py
+++ b/src/_cffi_src/utils.py
@@ -5,6 +5,8 @@
 from __future__ import absolute_import, division, print_function
 
 import sys
+from distutils.ccompiler import new_compiler
+from distutils.dist import Distribution
 
 from cffi import FFI
 
@@ -79,10 +81,23 @@
     return ffi
 
 
-def extra_link_args(platform):
-    if platform != "win32":
-        return []
+def extra_link_args(compiler_type):
+    if compiler_type == 'msvc':
+        # Enable NX and ASLR for Windows builds on MSVC. These are enabled by
+        # default on Python 3.3+ but not on 2.x.
+        return ['/NXCOMPAT', '/DYNAMICBASE']
     else:
-        # Enable NX and ASLR for Windows builds. These are enabled by default
-        # on Python 3.3+ but not on 2.x.
-        return ["/NXCOMPAT", "/DYNAMICBASE"]
+        return []
+
+
+def compiler_type():
+    """
+    Gets the compiler type from distutils. On Windows with MSVC it will be
+    "msvc". On OS X and linux it is "unix".
+    """
+    dist = Distribution()
+    dist.parse_config_files()
+    cmd = dist.get_command_obj('build')
+    cmd.ensure_finalized()
+    compiler = new_compiler(compiler=cmd.compiler)
+    return compiler.compiler_type
diff --git a/src/cryptography/__about__.py b/src/cryptography/__about__.py
index fbc1e73..f25cbc8 100644
--- a/src/cryptography/__about__.py
+++ b/src/cryptography/__about__.py
@@ -20,4 +20,4 @@
 __email__ = "cryptography-dev@python.org"
 
 __license__ = "BSD or Apache License, Version 2.0"
-__copyright__ = "Copyright 2013-2015 {0}".format(__author__)
+__copyright__ = "Copyright 2013-2016 {0}".format(__author__)
diff --git a/src/cryptography/hazmat/backends/interfaces.py b/src/cryptography/hazmat/backends/interfaces.py
index 92d9653..5b9e6f3 100644
--- a/src/cryptography/hazmat/backends/interfaces.py
+++ b/src/cryptography/hazmat/backends/interfaces.py
@@ -292,6 +292,20 @@
         Create and sign an X.509 certificate from a CertificateBuilder object.
         """
 
+    @abc.abstractmethod
+    def create_x509_crl(self, builder, private_key, algorithm):
+        """
+        Create and sign an X.509 CertificateRevocationList from a
+        CertificateRevocationListBuilder object.
+        """
+
+    @abc.abstractmethod
+    def create_x509_revoked_certificate(self, builder):
+        """
+        Create a RevokedCertificate object from a RevokedCertificateBuilder
+        object.
+        """
+
 
 @six.add_metaclass(abc.ABCMeta)
 class DHBackend(object):
diff --git a/src/cryptography/hazmat/backends/multibackend.py b/src/cryptography/hazmat/backends/multibackend.py
index bbaaf42..65f1853 100644
--- a/src/cryptography/hazmat/backends/multibackend.py
+++ b/src/cryptography/hazmat/backends/multibackend.py
@@ -384,3 +384,21 @@
             "This backend does not support X.509.",
             _Reasons.UNSUPPORTED_X509
         )
+
+    def create_x509_crl(self, builder, private_key, algorithm):
+        for b in self._filtered_backends(X509Backend):
+            return b.create_x509_crl(builder, private_key, algorithm)
+
+        raise UnsupportedAlgorithm(
+            "This backend does not support X.509.",
+            _Reasons.UNSUPPORTED_X509
+        )
+
+    def create_x509_revoked_certificate(self, builder):
+        for b in self._filtered_backends(X509Backend):
+            return b.create_x509_revoked_certificate(builder)
+
+        raise UnsupportedAlgorithm(
+            "This backend does not support X.509.",
+            _Reasons.UNSUPPORTED_X509
+        )
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index e69554f..e8b0322 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -37,8 +37,9 @@
     _RSAPrivateKey, _RSAPublicKey
 )
 from cryptography.hazmat.backends.openssl.x509 import (
-    _Certificate, _CertificateRevocationList, _CertificateSigningRequest,
-    _DISTPOINT_TYPE_FULLNAME, _DISTPOINT_TYPE_RELATIVENAME
+    _CRL_ENTRY_REASON_ENUM_TO_CODE, _Certificate, _CertificateRevocationList,
+    _CertificateSigningRequest, _DISTPOINT_TYPE_FULLNAME,
+    _DISTPOINT_TYPE_RELATIVENAME, _RevokedCertificate
 )
 from cryptography.hazmat.bindings._openssl import ffi as _ffi
 from cryptography.hazmat.bindings.openssl import binding
@@ -53,7 +54,7 @@
 from cryptography.hazmat.primitives.ciphers.modes import (
     CBC, CFB, CFB8, CTR, ECB, GCM, OFB
 )
-from cryptography.x509.oid import ExtensionOID, NameOID
+from cryptography.x509.oid import CRLEntryExtensionOID, ExtensionOID, NameOID
 
 
 _MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"])
@@ -115,10 +116,9 @@
     return s
 
 
-def _encode_inhibit_any_policy(backend, inhibit_any_policy):
-    asn1int = _encode_asn1_int_gc(backend, inhibit_any_policy.skip_certs)
-    pp = backend._ffi.new('unsigned char **')
-    r = backend._lib.i2d_ASN1_INTEGER(asn1int, pp)
+def _encode_extension_to_der(backend, i2d_func, value):
+    pp = backend._ffi.new("unsigned char **")
+    r = i2d_func(value, pp)
     backend.openssl_assert(r > 0)
     pp = backend._ffi.gc(
         pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
@@ -126,6 +126,13 @@
     return pp, r
 
 
+def _encode_inhibit_any_policy(backend, inhibit_any_policy):
+    asn1int = _encode_asn1_int_gc(backend, inhibit_any_policy.skip_certs)
+    return _encode_extension_to_der(
+        backend, backend._lib.i2d_ASN1_INTEGER, asn1int
+    )
+
+
 def _encode_name(backend, attributes):
     """
     The X509_NAME created will not be gc'd. Use _encode_name_gc if needed.
@@ -153,6 +160,41 @@
     return subject
 
 
+def _encode_crl_number(backend, crl_number):
+    asn1int = _encode_asn1_int_gc(backend, crl_number.crl_number)
+    return _encode_extension_to_der(
+        backend, backend._lib.i2d_ASN1_INTEGER, asn1int
+    )
+
+
+def _encode_crl_reason(backend, crl_reason):
+    asn1enum = backend._lib.ASN1_ENUMERATED_new()
+    backend.openssl_assert(asn1enum != backend._ffi.NULL)
+    asn1enum = backend._ffi.gc(asn1enum, backend._lib.ASN1_ENUMERATED_free)
+    res = backend._lib.ASN1_ENUMERATED_set(
+        asn1enum, _CRL_ENTRY_REASON_ENUM_TO_CODE[crl_reason.reason]
+    )
+    backend.openssl_assert(res == 1)
+
+    return _encode_extension_to_der(
+        backend, backend._lib.i2d_ASN1_ENUMERATED, asn1enum
+    )
+
+
+def _encode_invalidity_date(backend, invalidity_date):
+    time = backend._lib.ASN1_GENERALIZEDTIME_set(
+        backend._ffi.NULL, calendar.timegm(
+            invalidity_date.invalidity_date.timetuple()
+        )
+    )
+    backend.openssl_assert(time != backend._ffi.NULL)
+    time = backend._ffi.gc(time, backend._lib.ASN1_GENERALIZEDTIME_free)
+
+    return _encode_extension_to_der(
+        backend, backend._lib.i2d_ASN1_GENERALIZEDTIME, time
+    )
+
+
 def _encode_certificate_policies(backend, certificate_policies):
     cp = backend._lib.sk_POLICYINFO_new_null()
     backend.openssl_assert(cp != backend._ffi.NULL)
@@ -200,13 +242,9 @@
 
             pi.qualifiers = pqis
 
-    pp = backend._ffi.new('unsigned char **')
-    r = backend._lib.i2d_CERTIFICATEPOLICIES(cp, pp)
-    backend.openssl_assert(r > 0)
-    pp = backend._ffi.gc(
-        pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
+    return _encode_extension_to_der(
+        backend, backend._lib.i2d_CERTIFICATEPOLICIES, cp
     )
-    return pp, r
 
 
 def _encode_notice_reference(backend, notice):
@@ -282,13 +320,9 @@
         res = set_bit(ku, 8, 0)
         backend.openssl_assert(res == 1)
 
-    pp = backend._ffi.new('unsigned char **')
-    r = backend._lib.i2d_ASN1_BIT_STRING(ku, pp)
-    backend.openssl_assert(r > 0)
-    pp = backend._ffi.gc(
-        pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
+    return _encode_extension_to_der(
+        backend, backend._lib.i2d_ASN1_BIT_STRING, ku
     )
-    return pp, r
 
 
 def _encode_authority_key_identifier(backend, authority_keyid):
@@ -312,13 +346,9 @@
             backend, authority_keyid.authority_cert_serial_number
         )
 
-    pp = backend._ffi.new('unsigned char **')
-    r = backend._lib.i2d_AUTHORITY_KEYID(akid, pp)
-    backend.openssl_assert(r > 0)
-    pp = backend._ffi.gc(
-        pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
+    return _encode_extension_to_der(
+        backend, backend._lib.i2d_AUTHORITY_KEYID, akid
     )
-    return pp, r
 
 
 def _encode_basic_constraints(backend, basic_constraints):
@@ -332,14 +362,9 @@
             backend, basic_constraints.path_length
         )
 
-    # Fetch the encoded payload.
-    pp = backend._ffi.new('unsigned char **')
-    r = backend._lib.i2d_BASIC_CONSTRAINTS(constraints, pp)
-    backend.openssl_assert(r > 0)
-    pp = backend._ffi.gc(
-        pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
+    return _encode_extension_to_der(
+        backend, backend._lib.i2d_BASIC_CONSTRAINTS, constraints
     )
-    return pp, r
 
 
 def _encode_authority_information_access(backend, authority_info_access):
@@ -359,13 +384,9 @@
         res = backend._lib.sk_ACCESS_DESCRIPTION_push(aia, ad)
         backend.openssl_assert(res >= 1)
 
-    pp = backend._ffi.new('unsigned char **')
-    r = backend._lib.i2d_AUTHORITY_INFO_ACCESS(aia, pp)
-    backend.openssl_assert(r > 0)
-    pp = backend._ffi.gc(
-        pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
+    return _encode_extension_to_der(
+        backend, backend._lib.i2d_AUTHORITY_INFO_ACCESS, aia
     )
-    return pp, r
 
 
 def _encode_general_names(backend, names):
@@ -384,24 +405,16 @@
     general_names = backend._ffi.gc(
         general_names, backend._lib.GENERAL_NAMES_free
     )
-    pp = backend._ffi.new("unsigned char **")
-    r = backend._lib.i2d_GENERAL_NAMES(general_names, pp)
-    backend.openssl_assert(r > 0)
-    pp = backend._ffi.gc(
-        pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
+    return _encode_extension_to_der(
+        backend, backend._lib.i2d_GENERAL_NAMES, general_names
     )
-    return pp, r
 
 
 def _encode_subject_key_identifier(backend, ski):
     asn1_str = _encode_asn1_str_gc(backend, ski.digest, len(ski.digest))
-    pp = backend._ffi.new("unsigned char **")
-    r = backend._lib.i2d_ASN1_OCTET_STRING(asn1_str, pp)
-    backend.openssl_assert(r > 0)
-    pp = backend._ffi.gc(
-        pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
+    return _encode_extension_to_der(
+        backend, backend._lib.i2d_ASN1_OCTET_STRING, asn1_str
     )
-    return pp, r
 
 
 def _encode_general_name(backend, name):
@@ -499,15 +512,10 @@
         res = backend._lib.sk_ASN1_OBJECT_push(eku, obj)
         backend.openssl_assert(res >= 1)
 
-    pp = backend._ffi.new('unsigned char **')
-    r = backend._lib.i2d_EXTENDED_KEY_USAGE(
-        backend._ffi.cast("EXTENDED_KEY_USAGE *", eku), pp
+    eku_ptr = backend._ffi.cast("EXTENDED_KEY_USAGE *", eku)
+    return _encode_extension_to_der(
+        backend, backend._lib.i2d_EXTENDED_KEY_USAGE, eku_ptr
     )
-    backend.openssl_assert(r > 0)
-    pp = backend._ffi.gc(
-        pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
-    )
-    return pp, r
 
 
 _CRLREASONFLAGS = {
@@ -562,13 +570,9 @@
         res = backend._lib.sk_DIST_POINT_push(cdp, dp)
         backend.openssl_assert(res >= 1)
 
-    pp = backend._ffi.new('unsigned char **')
-    r = backend._lib.i2d_CRL_DIST_POINTS(cdp, pp)
-    backend.openssl_assert(r > 0)
-    pp = backend._ffi.gc(
-        pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
+    return _encode_extension_to_der(
+        backend, backend._lib.i2d_CRL_DIST_POINTS, cdp
     )
-    return pp, r
 
 
 def _encode_name_constraints(backend, name_constraints):
@@ -584,13 +588,9 @@
     )
     nc.excludedSubtrees = excluded
 
-    pp = backend._ffi.new('unsigned char **')
-    r = backend._lib.Cryptography_i2d_NAME_CONSTRAINTS(nc, pp)
-    assert r > 0
-    pp = backend._ffi.gc(
-        pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
+    return _encode_extension_to_der(
+        backend, backend._lib.Cryptography_i2d_NAME_CONSTRAINTS, nc
     )
-    return pp, r
 
 
 def _encode_general_subtree(backend, subtrees):
@@ -625,6 +625,21 @@
     ExtensionOID.NAME_CONSTRAINTS: _encode_name_constraints,
 }
 
+_CRL_EXTENSION_ENCODE_HANDLERS = {
+    ExtensionOID.ISSUER_ALTERNATIVE_NAME: _encode_alt_name,
+    ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _encode_authority_key_identifier,
+    ExtensionOID.AUTHORITY_INFORMATION_ACCESS: (
+        _encode_authority_information_access
+    ),
+    ExtensionOID.CRL_NUMBER: _encode_crl_number,
+}
+
+_CRL_ENTRY_EXTENSION_ENCODE_HANDLERS = {
+    CRLEntryExtensionOID.CERTIFICATE_ISSUER: _encode_alt_name,
+    CRLEntryExtensionOID.CRL_REASON: _encode_crl_reason,
+    CRLEntryExtensionOID.INVALIDITY_DATE: _encode_invalidity_date,
+}
+
 
 class _PasswordUserdata(object):
     def __init__(self, password):
@@ -899,17 +914,14 @@
         assert bn != self._ffi.NULL
         if six.PY3:
             # Python 3 has constant time from_bytes, so use that.
-
-            bn_num_bytes = (self._lib.BN_num_bits(bn) + 7) // 8
+            bn_num_bytes = self._lib.BN_num_bytes(bn)
             bin_ptr = self._ffi.new("unsigned char[]", bn_num_bytes)
             bin_len = self._lib.BN_bn2bin(bn, bin_ptr)
             # A zero length means the BN has value 0
             self.openssl_assert(bin_len >= 0)
             return int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big")
-
         else:
             # Under Python 2 the best we can do is hex()
-
             hex_cdata = self._lib.BN_bn2hex(bn)
             self.openssl_assert(hex_cdata != self._ffi.NULL)
             hex_str = self._ffi.string(hex_cdata)
@@ -1312,30 +1324,21 @@
         self.openssl_assert(res == 1)
 
         # Add extensions.
-        extensions = self._lib.sk_X509_EXTENSION_new_null()
-        self.openssl_assert(extensions != self._ffi.NULL)
-        extensions = self._ffi.gc(
-            extensions,
-            self._lib.sk_X509_EXTENSION_free,
+        sk_extension = self._lib.sk_X509_EXTENSION_new_null()
+        self.openssl_assert(sk_extension != self._ffi.NULL)
+        sk_extension = self._ffi.gc(
+            sk_extension, self._lib.sk_X509_EXTENSION_free
         )
-        for extension in builder._extensions:
-            try:
-                encode = _EXTENSION_ENCODE_HANDLERS[extension.oid]
-            except KeyError:
-                raise NotImplementedError('Extension not yet supported.')
-
-            pp, r = encode(self, extension.value)
-            obj = _txt2obj_gc(self, extension.oid.dotted_string)
-            extension = self._lib.X509_EXTENSION_create_by_OBJ(
-                self._ffi.NULL,
-                obj,
-                1 if extension.critical else 0,
-                _encode_asn1_str_gc(self, pp[0], r),
-            )
-            self.openssl_assert(extension != self._ffi.NULL)
-            res = self._lib.sk_X509_EXTENSION_push(extensions, extension)
-            self.openssl_assert(res >= 1)
-        res = self._lib.X509_REQ_add_extensions(x509_req, extensions)
+        # gc is not necessary for CSRs, as sk_X509_EXTENSION_free
+        # will release all the X509_EXTENSIONs.
+        self._create_x509_extensions(
+            extensions=builder._extensions,
+            handlers=_EXTENSION_ENCODE_HANDLERS,
+            x509_obj=sk_extension,
+            add_func=self._lib.sk_X509_EXTENSION_insert,
+            gc=False
+        )
+        res = self._lib.X509_REQ_add_extensions(x509_req, sk_extension)
         self.openssl_assert(res == 1)
 
         # Sign the request using the requester's private key.
@@ -1416,24 +1419,13 @@
         self.openssl_assert(res != self._ffi.NULL)
 
         # Add extensions.
-        for i, extension in enumerate(builder._extensions):
-            try:
-                encode = _EXTENSION_ENCODE_HANDLERS[extension.oid]
-            except KeyError:
-                raise NotImplementedError('Extension not yet supported.')
-
-            pp, r = encode(self, extension.value)
-            obj = _txt2obj_gc(self, extension.oid.dotted_string)
-            extension = self._lib.X509_EXTENSION_create_by_OBJ(
-                self._ffi.NULL,
-                obj,
-                1 if extension.critical else 0,
-                _encode_asn1_str_gc(self, pp[0], r)
-            )
-            self.openssl_assert(extension != self._ffi.NULL)
-            extension = self._ffi.gc(extension, self._lib.X509_EXTENSION_free)
-            res = self._lib.X509_add_ext(x509_cert, extension, i)
-            self.openssl_assert(res == 1)
+        self._create_x509_extensions(
+            extensions=builder._extensions,
+            handlers=_EXTENSION_ENCODE_HANDLERS,
+            x509_obj=x509_cert,
+            add_func=self._lib.X509_add_ext,
+            gc=True
+        )
 
         # Set the issuer name.
         res = self._lib.X509_set_issuer_name(
@@ -1455,6 +1447,147 @@
 
         return _Certificate(self, x509_cert)
 
+    def create_x509_crl(self, builder, private_key, algorithm):
+        if not isinstance(builder, x509.CertificateRevocationListBuilder):
+            raise TypeError('Builder type mismatch.')
+        if not isinstance(algorithm, hashes.HashAlgorithm):
+            raise TypeError('Algorithm must be a registered hash algorithm.')
+
+        if self._lib.OPENSSL_VERSION_NUMBER <= 0x10001000:
+            if isinstance(private_key, _DSAPrivateKey):
+                raise NotImplementedError(
+                    "CRL signatures aren't implemented for DSA"
+                    " keys on OpenSSL versions less than 1.0.1."
+                )
+            if isinstance(private_key, _EllipticCurvePrivateKey):
+                raise NotImplementedError(
+                    "CRL signatures aren't implemented for EC"
+                    " keys on OpenSSL versions less than 1.0.1."
+                )
+
+        evp_md = self._lib.EVP_get_digestbyname(
+            algorithm.name.encode('ascii')
+        )
+        self.openssl_assert(evp_md != self._ffi.NULL)
+
+        # Create an empty CRL.
+        x509_crl = self._lib.X509_CRL_new()
+        x509_crl = self._ffi.gc(x509_crl, backend._lib.X509_CRL_free)
+
+        # Set the x509 CRL version. We only support v2 (integer value 1).
+        res = self._lib.X509_CRL_set_version(x509_crl, 1)
+        self.openssl_assert(res == 1)
+
+        # Set the issuer name.
+        res = self._lib.X509_CRL_set_issuer_name(
+            x509_crl, _encode_name_gc(self, list(builder._issuer_name))
+        )
+        self.openssl_assert(res == 1)
+
+        # Set the last update time.
+        last_update = self._lib.ASN1_TIME_set(
+            self._ffi.NULL, calendar.timegm(builder._last_update.timetuple())
+        )
+        self.openssl_assert(last_update != self._ffi.NULL)
+        last_update = self._ffi.gc(last_update, self._lib.ASN1_TIME_free)
+        res = self._lib.X509_CRL_set_lastUpdate(x509_crl, last_update)
+        self.openssl_assert(res == 1)
+
+        # Set the next update time.
+        next_update = self._lib.ASN1_TIME_set(
+            self._ffi.NULL, calendar.timegm(builder._next_update.timetuple())
+        )
+        self.openssl_assert(next_update != self._ffi.NULL)
+        next_update = self._ffi.gc(next_update, self._lib.ASN1_TIME_free)
+        res = self._lib.X509_CRL_set_nextUpdate(x509_crl, next_update)
+        self.openssl_assert(res == 1)
+
+        # Add extensions.
+        self._create_x509_extensions(
+            extensions=builder._extensions,
+            handlers=_CRL_EXTENSION_ENCODE_HANDLERS,
+            x509_obj=x509_crl,
+            add_func=self._lib.X509_CRL_add_ext,
+            gc=True
+        )
+
+        # add revoked certificates
+        for revoked_cert in builder._revoked_certificates:
+            # Duplicating because the X509_CRL takes ownership and will free
+            # this memory when X509_CRL_free is called.
+            revoked = self._lib.Cryptography_X509_REVOKED_dup(
+                revoked_cert._x509_revoked
+            )
+            self.openssl_assert(revoked != self._ffi.NULL)
+            res = self._lib.X509_CRL_add0_revoked(x509_crl, revoked)
+            self.openssl_assert(res == 1)
+
+        res = self._lib.X509_CRL_sign(
+            x509_crl, private_key._evp_pkey, evp_md
+        )
+        if res == 0:
+            errors = self._consume_errors()
+            self.openssl_assert(errors[0][1] == self._lib.ERR_LIB_RSA)
+            self.openssl_assert(
+                errors[0][3] == self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY
+            )
+            raise ValueError("Digest too big for RSA key")
+
+        return _CertificateRevocationList(self, x509_crl)
+
+    def _create_x509_extensions(self, extensions, handlers, x509_obj,
+                                add_func, gc):
+        for i, extension in enumerate(extensions):
+            try:
+                encode = handlers[extension.oid]
+            except KeyError:
+                raise NotImplementedError(
+                    'Extension not supported: {0}'.format(extension.oid)
+                )
+
+            pp, r = encode(self, extension.value)
+            obj = _txt2obj_gc(self, extension.oid.dotted_string)
+            x509_extension = self._lib.X509_EXTENSION_create_by_OBJ(
+                self._ffi.NULL,
+                obj,
+                1 if extension.critical else 0,
+                _encode_asn1_str_gc(self, pp[0], r)
+            )
+            self.openssl_assert(x509_extension != self._ffi.NULL)
+            if gc:
+                x509_extension = self._ffi.gc(
+                    x509_extension, self._lib.X509_EXTENSION_free
+                )
+            res = add_func(x509_obj, x509_extension, i)
+            self.openssl_assert(res >= 1)
+
+    def create_x509_revoked_certificate(self, builder):
+        if not isinstance(builder, x509.RevokedCertificateBuilder):
+            raise TypeError('Builder type mismatch.')
+
+        x509_revoked = self._lib.X509_REVOKED_new()
+        self.openssl_assert(x509_revoked != self._ffi.NULL)
+        x509_revoked = self._ffi.gc(x509_revoked, self._lib.X509_REVOKED_free)
+        serial_number = _encode_asn1_int_gc(self, builder._serial_number)
+        res = self._lib.X509_REVOKED_set_serialNumber(
+            x509_revoked, serial_number
+        )
+        self.openssl_assert(res == 1)
+        res = self._lib.ASN1_TIME_set(
+            x509_revoked.revocationDate,
+            calendar.timegm(builder._revocation_date.timetuple())
+        )
+        self.openssl_assert(res != self._ffi.NULL)
+        # add CRL entry extensions
+        self._create_x509_extensions(
+            extensions=builder._extensions,
+            handlers=_CRL_ENTRY_EXTENSION_ENCODE_HANDLERS,
+            x509_obj=x509_revoked,
+            add_func=self._lib.X509_REVOKED_add_ext,
+            gc=True
+        )
+        return _RevokedCertificate(self, None, x509_revoked)
+
     def load_pem_private_key(self, data, password):
         return self._load_key(
             self._lib.PEM_read_bio_PrivateKey,
@@ -2136,6 +2269,9 @@
         generalized_time = self._ffi.gc(
             generalized_time, self._lib.ASN1_GENERALIZEDTIME_free
         )
+        return self._parse_asn1_generalized_time(generalized_time)
+
+    def _parse_asn1_generalized_time(self, generalized_time):
         time = self._asn1_string_to_ascii(
             self._ffi.cast("ASN1_STRING *", generalized_time)
         )
diff --git a/src/cryptography/hazmat/backends/openssl/rsa.py b/src/cryptography/hazmat/backends/openssl/rsa.py
index 664f6d3..033cd3b 100644
--- a/src/cryptography/hazmat/backends/openssl/rsa.py
+++ b/src/cryptography/hazmat/backends/openssl/rsa.py
@@ -138,6 +138,7 @@
         decoding_errors = [
             backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_01,
             backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_02,
+            backend._lib.RSA_R_OAEP_DECODING_ERROR,
         ]
         if backend._lib.Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR:
             decoding_errors.append(backend._lib.RSA_R_PKCS_DECODING_ERROR)
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index 7e89ac6..b8614e0 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -4,8 +4,8 @@
 
 from __future__ import absolute_import, division, print_function
 
-import datetime
 import ipaddress
+import operator
 
 from email.utils import parseaddr
 
@@ -19,7 +19,7 @@
 from cryptography.exceptions import UnsupportedAlgorithm
 from cryptography.hazmat.primitives import hashes, serialization
 from cryptography.x509.oid import (
-    CRLExtensionOID, CertificatePoliciesOID, ExtensionOID
+    CRLEntryExtensionOID, CertificatePoliciesOID, ExtensionOID
 )
 
 
@@ -213,6 +213,15 @@
                         "Critical extension {0} is not currently supported"
                         .format(oid), oid
                     )
+                else:
+                    # Dump the DER payload into an UnrecognizedExtension object
+                    data = backend._lib.X509_EXTENSION_get_data(ext)
+                    backend.openssl_assert(data != backend._ffi.NULL)
+                    der = backend._ffi.buffer(data.data, data.length)[:]
+                    unrecognized = x509.UnrecognizedExtension(oid, der)
+                    extensions.append(
+                        x509.Extension(oid, critical, unrecognized)
+                    )
             else:
                 # For extensions which are not supported by OpenSSL we pass the
                 # extension object directly to the parsing routine so it can
@@ -679,7 +688,19 @@
     return x509.InhibitAnyPolicy(skip_certs)
 
 
-_CRL_REASON_CODE_TO_ENUM = {
+#    CRLReason ::= ENUMERATED {
+#        unspecified             (0),
+#        keyCompromise           (1),
+#        cACompromise            (2),
+#        affiliationChanged      (3),
+#        superseded              (4),
+#        cessationOfOperation    (5),
+#        certificateHold         (6),
+#             -- value 7 is not used
+#        removeFromCRL           (8),
+#        privilegeWithdrawn      (9),
+#        aACompromise           (10) }
+_CRL_ENTRY_REASON_CODE_TO_ENUM = {
     0: x509.ReasonFlags.unspecified,
     1: x509.ReasonFlags.key_compromise,
     2: x509.ReasonFlags.ca_compromise,
@@ -693,13 +714,27 @@
 }
 
 
+_CRL_ENTRY_REASON_ENUM_TO_CODE = {
+    x509.ReasonFlags.unspecified: 0,
+    x509.ReasonFlags.key_compromise: 1,
+    x509.ReasonFlags.ca_compromise: 2,
+    x509.ReasonFlags.affiliation_changed: 3,
+    x509.ReasonFlags.superseded: 4,
+    x509.ReasonFlags.cessation_of_operation: 5,
+    x509.ReasonFlags.certificate_hold: 6,
+    x509.ReasonFlags.remove_from_crl: 8,
+    x509.ReasonFlags.privilege_withdrawn: 9,
+    x509.ReasonFlags.aa_compromise: 10
+}
+
+
 def _decode_crl_reason(backend, enum):
     enum = backend._ffi.cast("ASN1_ENUMERATED *", enum)
     enum = backend._ffi.gc(enum, backend._lib.ASN1_ENUMERATED_free)
     code = backend._lib.ASN1_ENUMERATED_get(enum)
 
     try:
-        return _CRL_REASON_CODE_TO_ENUM[code]
+        return x509.CRLReason(_CRL_ENTRY_REASON_CODE_TO_ENUM[code])
     except KeyError:
         raise ValueError("Unsupported reason code: {0}".format(code))
 
@@ -711,12 +746,9 @@
     generalized_time = backend._ffi.gc(
         generalized_time, backend._lib.ASN1_GENERALIZEDTIME_free
     )
-    time = backend._ffi.string(
-        backend._lib.ASN1_STRING_data(
-            backend._ffi.cast("ASN1_STRING *", generalized_time)
-        )
-    ).decode("ascii")
-    return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ")
+    return x509.InvalidityDate(
+        backend._parse_asn1_generalized_time(generalized_time)
+    )
 
 
 def _decode_cert_issuer(backend, ext):
@@ -739,16 +771,24 @@
         backend._consume_errors()
         raise ValueError(
             "The {0} extension is corrupted and can't be parsed".format(
-                CRLExtensionOID.CERTIFICATE_ISSUER))
+                CRLEntryExtensionOID.CERTIFICATE_ISSUER))
 
     gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free)
-    return x509.GeneralNames(_decode_general_names(backend, gns))
+    return x509.CertificateIssuer(_decode_general_names(backend, gns))
 
 
 @utils.register_interface(x509.RevokedCertificate)
 class _RevokedCertificate(object):
-    def __init__(self, backend, x509_revoked):
+    def __init__(self, backend, crl, x509_revoked):
         self._backend = backend
+        # The X509_REVOKED_value is a X509_REVOKED * that has
+        # no reference counting. This means when X509_CRL_free is
+        # called then the CRL and all X509_REVOKED * are freed. Since
+        # you can retain a reference to a single revoked certificate
+        # and let the CRL fall out of scope we need to retain a
+        # private reference to the CRL inside the RevokedCertificate
+        # object to prevent the gc from being called inappropriately.
+        self._crl = crl
         self._x509_revoked = x509_revoked
 
     @property
@@ -853,26 +893,34 @@
         self._backend.openssl_assert(res == 1)
         return self._backend._read_mem_bio(bio)
 
-    def _revoked_certificates(self):
+    def _revoked_cert(self, idx):
         revoked = self._backend._lib.X509_CRL_get_REVOKED(self._x509_crl)
-        revoked_list = []
-        if revoked != self._backend._ffi.NULL:
-            num = self._backend._lib.sk_X509_REVOKED_num(revoked)
-            for i in range(num):
-                r = self._backend._lib.sk_X509_REVOKED_value(revoked, i)
-                self._backend.openssl_assert(r != self._backend._ffi.NULL)
-                revoked_list.append(_RevokedCertificate(self._backend, r))
-
-        return revoked_list
+        r = self._backend._lib.sk_X509_REVOKED_value(revoked, idx)
+        self._backend.openssl_assert(r != self._backend._ffi.NULL)
+        return _RevokedCertificate(self._backend, self, r)
 
     def __iter__(self):
-        return iter(self._revoked_certificates())
+        for i in range(len(self)):
+            yield self._revoked_cert(i)
 
     def __getitem__(self, idx):
-        return self._revoked_certificates()[idx]
+        if isinstance(idx, slice):
+            start, stop, step = idx.indices(len(self))
+            return [self._revoked_cert(i) for i in range(start, stop, step)]
+        else:
+            idx = operator.index(idx)
+            if idx < 0:
+                idx += len(self)
+            if not 0 <= idx < len(self):
+                raise IndexError
+            return self._revoked_cert(idx)
 
     def __len__(self):
-        return len(self._revoked_certificates())
+        revoked = self._backend._lib.X509_CRL_get_REVOKED(self._x509_crl)
+        if revoked == self._backend._ffi.NULL:
+            return 0
+        else:
+            return self._backend._lib.sk_X509_REVOKED_num(revoked)
 
     @property
     def extensions(self):
@@ -975,13 +1023,13 @@
 }
 
 _REVOKED_EXTENSION_HANDLERS = {
-    CRLExtensionOID.CRL_REASON: _decode_crl_reason,
-    CRLExtensionOID.INVALIDITY_DATE: _decode_invalidity_date,
-    CRLExtensionOID.CERTIFICATE_ISSUER: _decode_cert_issuer,
+    CRLEntryExtensionOID.CRL_REASON: _decode_crl_reason,
+    CRLEntryExtensionOID.INVALIDITY_DATE: _decode_invalidity_date,
+    CRLEntryExtensionOID.CERTIFICATE_ISSUER: _decode_cert_issuer,
 }
 
 _REVOKED_UNSUPPORTED_EXTENSIONS = set([
-    CRLExtensionOID.CERTIFICATE_ISSUER,
+    CRLEntryExtensionOID.CERTIFICATE_ISSUER,
 ])
 
 _CRL_EXTENSION_HANDLERS = {
diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py
index 07b6b9a..8e41943 100644
--- a/src/cryptography/hazmat/bindings/openssl/binding.py
+++ b/src/cryptography/hazmat/bindings/openssl/binding.py
@@ -8,6 +8,7 @@
 import os
 import threading
 import types
+import warnings
 
 from cryptography.exceptions import InternalError
 from cryptography.hazmat.bindings._openssl import ffi, lib
@@ -180,3 +181,11 @@
 # condition registering the OpenSSL locks. On Python 3.4+ the import lock
 # is per module so this approach will not work.
 Binding.init_static_locks()
+
+if Binding.lib.SSLeay() < 0x10001000:
+    warnings.warn(
+        "OpenSSL versions less than 1.0.1 are no longer supported by the "
+        "OpenSSL project, please upgrade. A future version of cryptography "
+        "will drop support for these versions.",
+        DeprecationWarning
+    )
diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py
index 4449e85..b85d50d 100644
--- a/src/cryptography/utils.py
+++ b/src/cryptography/utils.py
@@ -12,7 +12,10 @@
 import warnings
 
 
+# the functions deprecated in 1.0 are on an arbitrarily extended deprecation
+# cycle and should not be removed until we agree on when that cycle ends.
 DeprecatedIn10 = DeprecationWarning
+DeprecatedIn12 = PendingDeprecationWarning
 
 
 def read_only_property(name):
diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py
index c4434fd..a1deb7f 100644
--- a/src/cryptography/x509/__init__.py
+++ b/src/cryptography/x509/__init__.py
@@ -6,20 +6,22 @@
 
 from cryptography.x509.base import (
     Certificate, CertificateBuilder, CertificateRevocationList,
+    CertificateRevocationListBuilder,
     CertificateSigningRequest, CertificateSigningRequestBuilder,
-    InvalidVersion, RevokedCertificate,
+    InvalidVersion, RevokedCertificate, RevokedCertificateBuilder,
     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,
     AuthorityKeyIdentifier, BasicConstraints, CRLDistributionPoints,
-    CRLNumber, CertificatePolicies, DistributionPoint, DuplicateExtension,
-    ExtendedKeyUsage, Extension, ExtensionNotFound, ExtensionType, Extensions,
-    GeneralNames, InhibitAnyPolicy, IssuerAlternativeName, KeyUsage,
+    CRLNumber, CRLReason, CertificateIssuer, CertificatePolicies,
+    DistributionPoint, DuplicateExtension, ExtendedKeyUsage, Extension,
+    ExtensionNotFound, ExtensionType, Extensions, GeneralNames,
+    InhibitAnyPolicy, InvalidityDate, IssuerAlternativeName, KeyUsage,
     NameConstraints, NoticeReference, OCSPNoCheck, PolicyInformation,
     ReasonFlags, SubjectAlternativeName, SubjectKeyIdentifier,
-    UnsupportedExtension, UserNotice
+    UnrecognizedExtension, UnsupportedExtension, UserNotice
 )
 from cryptography.x509.general_name import (
     DNSName, DirectoryName, GeneralName, IPAddress, OtherName, RFC822Name,
@@ -28,9 +30,9 @@
 )
 from cryptography.x509.name import Name, NameAttribute
 from cryptography.x509.oid import (
-    AuthorityInformationAccessOID, CRLExtensionOID, CertificatePoliciesOID,
-    ExtendedKeyUsageOID, ExtensionOID, NameOID, ObjectIdentifier,
-    SignatureAlgorithmOID, _SIG_OIDS_TO_HASH
+    AuthorityInformationAccessOID, CRLEntryExtensionOID, CRLExtensionOID,
+    CertificatePoliciesOID, ExtendedKeyUsageOID, ExtensionOID, NameOID,
+    ObjectIdentifier, SignatureAlgorithmOID, _SIG_OIDS_TO_HASH
 )
 
 
@@ -95,9 +97,9 @@
 OID_CPS_QUALIFIER = CertificatePoliciesOID.CPS_QUALIFIER
 OID_CPS_USER_NOTICE = CertificatePoliciesOID.CPS_USER_NOTICE
 
-OID_CERTIFICATE_ISSUER = CRLExtensionOID.CERTIFICATE_ISSUER
-OID_CRL_REASON = CRLExtensionOID.CRL_REASON
-OID_INVALIDITY_DATE = CRLExtensionOID.INVALIDITY_DATE
+OID_CERTIFICATE_ISSUER = CRLEntryExtensionOID.CERTIFICATE_ISSUER
+OID_CRL_REASON = CRLEntryExtensionOID.CRL_REASON
+OID_INVALIDITY_DATE = CRLEntryExtensionOID.INVALIDITY_DATE
 
 OID_CA_ISSUERS = AuthorityInformationAccessOID.CA_ISSUERS
 OID_OCSP = AuthorityInformationAccessOID.OCSP
@@ -152,8 +154,10 @@
     "OtherName",
     "Certificate",
     "CertificateRevocationList",
+    "CertificateRevocationListBuilder",
     "CertificateSigningRequest",
     "RevokedCertificate",
+    "RevokedCertificateBuilder",
     "CertificateSigningRequestBuilder",
     "CertificateBuilder",
     "Version",
@@ -161,4 +165,9 @@
     "OID_CA_ISSUERS",
     "OID_OCSP",
     "_GENERAL_NAMES",
+    "CRLExtensionOID",
+    "CertificateIssuer",
+    "CRLReason",
+    "InvalidityDate",
+    "UnrecognizedExtension",
 ]
diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py
index 057d0e9..55e965f 100644
--- a/src/cryptography/x509/base.py
+++ b/src/cryptography/x509/base.py
@@ -518,3 +518,159 @@
             raise ValueError("A certificate must have a public key")
 
         return backend.create_x509_certificate(self, private_key, algorithm)
+
+
+class CertificateRevocationListBuilder(object):
+    def __init__(self, issuer_name=None, last_update=None, next_update=None,
+                 extensions=[], revoked_certificates=[]):
+        self._issuer_name = issuer_name
+        self._last_update = last_update
+        self._next_update = next_update
+        self._extensions = extensions
+        self._revoked_certificates = revoked_certificates
+
+    def issuer_name(self, issuer_name):
+        if not isinstance(issuer_name, Name):
+            raise TypeError('Expecting x509.Name object.')
+        if self._issuer_name is not None:
+            raise ValueError('The issuer name may only be set once.')
+        return CertificateRevocationListBuilder(
+            issuer_name, self._last_update, self._next_update,
+            self._extensions, self._revoked_certificates
+        )
+
+    def last_update(self, last_update):
+        if not isinstance(last_update, datetime.datetime):
+            raise TypeError('Expecting datetime object.')
+        if self._last_update is not None:
+            raise ValueError('Last update may only be set once.')
+        if last_update <= _UNIX_EPOCH:
+            raise ValueError('The last update date must be after the unix'
+                             ' epoch (1970 January 1).')
+        if self._next_update is not None and last_update > self._next_update:
+            raise ValueError(
+                'The last update date must be before the next update date.'
+            )
+        return CertificateRevocationListBuilder(
+            self._issuer_name, last_update, self._next_update,
+            self._extensions, self._revoked_certificates
+        )
+
+    def next_update(self, next_update):
+        if not isinstance(next_update, datetime.datetime):
+            raise TypeError('Expecting datetime object.')
+        if self._next_update is not None:
+            raise ValueError('Last update may only be set once.')
+        if next_update <= _UNIX_EPOCH:
+            raise ValueError('The last update date must be after the unix'
+                             ' epoch (1970 January 1).')
+        if self._last_update is not None and next_update < self._last_update:
+            raise ValueError(
+                'The next update date must be after the last update date.'
+            )
+        return CertificateRevocationListBuilder(
+            self._issuer_name, self._last_update, next_update,
+            self._extensions, self._revoked_certificates
+        )
+
+    def add_extension(self, extension, critical):
+        """
+        Adds an X.509 extension to the certificate revocation list.
+        """
+        if not isinstance(extension, ExtensionType):
+            raise TypeError("extension must be an ExtensionType")
+
+        extension = Extension(extension.oid, critical, extension)
+
+        # TODO: This is quadratic in the number of extensions
+        for e in self._extensions:
+            if e.oid == extension.oid:
+                raise ValueError('This extension has already been set.')
+        return CertificateRevocationListBuilder(
+            self._issuer_name, self._last_update, self._next_update,
+            self._extensions + [extension], self._revoked_certificates
+        )
+
+    def add_revoked_certificate(self, revoked_certificate):
+        """
+        Adds a revoked certificate to the CRL.
+        """
+        if not isinstance(revoked_certificate, RevokedCertificate):
+            raise TypeError("Must be an instance of RevokedCertificate")
+
+        return CertificateRevocationListBuilder(
+            self._issuer_name, self._last_update,
+            self._next_update, self._extensions,
+            self._revoked_certificates + [revoked_certificate]
+        )
+
+    def sign(self, private_key, algorithm, backend):
+        if self._issuer_name is None:
+            raise ValueError("A CRL must have an issuer name")
+
+        if self._last_update is None:
+            raise ValueError("A CRL must have a last update time")
+
+        if self._next_update is None:
+            raise ValueError("A CRL must have a next update time")
+
+        return backend.create_x509_crl(self, private_key, algorithm)
+
+
+class RevokedCertificateBuilder(object):
+    def __init__(self, serial_number=None, revocation_date=None,
+                 extensions=[]):
+        self._serial_number = serial_number
+        self._revocation_date = revocation_date
+        self._extensions = extensions
+
+    def serial_number(self, number):
+        if not isinstance(number, six.integer_types):
+            raise TypeError('Serial number must be of integral type.')
+        if self._serial_number is not None:
+            raise ValueError('The serial number may only be set once.')
+        if number < 0:
+            raise ValueError('The serial number should be non-negative.')
+        if utils.bit_length(number) > 160:  # As defined in RFC 5280
+            raise ValueError('The serial number should not be more than 160 '
+                             'bits.')
+        return RevokedCertificateBuilder(
+            number, self._revocation_date, self._extensions
+        )
+
+    def revocation_date(self, time):
+        if not isinstance(time, datetime.datetime):
+            raise TypeError('Expecting datetime object.')
+        if self._revocation_date is not None:
+            raise ValueError('The revocation date may only be set once.')
+        if time <= _UNIX_EPOCH:
+            raise ValueError('The revocation date must be after the unix'
+                             ' epoch (1970 January 1).')
+        return RevokedCertificateBuilder(
+            self._serial_number, time, self._extensions
+        )
+
+    def add_extension(self, extension, critical):
+        if not isinstance(extension, ExtensionType):
+            raise TypeError("extension must be an ExtensionType")
+
+        extension = Extension(extension.oid, critical, extension)
+
+        # TODO: This is quadratic in the number of extensions
+        for e in self._extensions:
+            if e.oid == extension.oid:
+                raise ValueError('This extension has already been set.')
+        return RevokedCertificateBuilder(
+            self._serial_number, self._revocation_date,
+            self._extensions + [extension]
+        )
+
+    def build(self, backend):
+        if self._serial_number is None:
+            raise ValueError("A revoked certificate must have a serial number")
+        if self._revocation_date is None:
+            raise ValueError(
+                "A revoked certificate must have a revocation date"
+            )
+
+        return backend.create_x509_revoked_certificate(self)
diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py
index 15feb71..f7b5d7f 100644
--- a/src/cryptography/x509/extensions.py
+++ b/src/cryptography/x509/extensions.py
@@ -5,6 +5,7 @@
 from __future__ import absolute_import, division, print_function
 
 import abc
+import datetime
 import hashlib
 import ipaddress
 from enum import Enum
@@ -18,7 +19,9 @@
 from cryptography.hazmat.primitives import constant_time, serialization
 from cryptography.x509.general_name import GeneralName, IPAddress, OtherName
 from cryptography.x509.name import Name
-from cryptography.x509.oid import ExtensionOID, ObjectIdentifier
+from cryptography.x509.oid import (
+    CRLEntryExtensionOID, ExtensionOID, ObjectIdentifier
+)
 
 
 class _SubjectPublicKeyInfo(univ.Sequence):
@@ -88,6 +91,13 @@
         raise ExtensionNotFound("No {0} extension was found".format(oid), oid)
 
     def get_extension_for_class(self, extclass):
+        if extclass is UnrecognizedExtension:
+            raise TypeError(
+                "UnrecognizedExtension can't be used with "
+                "get_extension_for_class because more than one instance of the"
+                " class may be present."
+            )
+
         for ext in self:
             if isinstance(ext.value, extclass):
                 return ext
@@ -102,6 +112,9 @@
     def __len__(self):
         return len(self._extensions)
 
+    def __getitem__(self, idx):
+        return self._extensions[idx]
+
     def __repr__(self):
         return (
             "<Extensions({0})>".format(self._extensions)
@@ -127,6 +140,9 @@
     def __ne__(self, other):
         return not self == other
 
+    def __hash__(self):
+        return hash(self.crl_number)
+
     def __repr__(self):
         return "<CRLNumber({0})>".format(self.crl_number)
 
@@ -226,6 +242,9 @@
     def __ne__(self, other):
         return not self == other
 
+    def __hash__(self):
+        return hash(self.digest)
+
 
 @utils.register_interface(ExtensionType)
 class AuthorityInformationAccess(object):
@@ -258,6 +277,9 @@
     def __ne__(self, other):
         return not self == other
 
+    def __getitem__(self, idx):
+        return self._descriptions[idx]
+
 
 class AccessDescription(object):
     def __init__(self, access_method, access_location):
@@ -330,6 +352,9 @@
     def __ne__(self, other):
         return not self == other
 
+    def __hash__(self):
+        return hash((self.ca, self.path_length))
+
 
 @utils.register_interface(ExtensionType)
 class CRLDistributionPoints(object):
@@ -364,6 +389,9 @@
     def __ne__(self, other):
         return not self == other
 
+    def __getitem__(self, idx):
+        return self._distribution_points[idx]
+
 
 class DistributionPoint(object):
     def __init__(self, full_name, relative_name, reasons, crl_issuer):
@@ -486,6 +514,9 @@
     def __ne__(self, other):
         return not self == other
 
+    def __getitem__(self, idx):
+        return self._policies[idx]
+
 
 class PolicyInformation(object):
     def __init__(self, policy_identifier, policy_qualifiers):
@@ -885,6 +916,9 @@
     def __ne__(self, other):
         return not self == other
 
+    def __getitem__(self, idx):
+        return self._general_names[idx]
+
 
 @utils.register_interface(ExtensionType)
 class SubjectAlternativeName(object):
@@ -911,6 +945,9 @@
 
         return self._general_names == other._general_names
 
+    def __getitem__(self, idx):
+        return self._general_names[idx]
+
     def __ne__(self, other):
         return not self == other
 
@@ -942,3 +979,127 @@
 
     def __ne__(self, other):
         return not self == other
+
+    def __getitem__(self, idx):
+        return self._general_names[idx]
+
+
+@utils.register_interface(ExtensionType)
+class CertificateIssuer(object):
+    oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER
+
+    def __init__(self, general_names):
+        self._general_names = GeneralNames(general_names)
+
+    def __iter__(self):
+        return iter(self._general_names)
+
+    def __len__(self):
+        return len(self._general_names)
+
+    def get_values_for_type(self, type):
+        return self._general_names.get_values_for_type(type)
+
+    def __repr__(self):
+        return "<CertificateIssuer({0})>".format(self._general_names)
+
+    def __eq__(self, other):
+        if not isinstance(other, CertificateIssuer):
+            return NotImplemented
+
+        return self._general_names == other._general_names
+
+    def __ne__(self, other):
+        return not self == other
+
+    def __getitem__(self, idx):
+        return self._general_names[idx]
+
+
+@utils.register_interface(ExtensionType)
+class CRLReason(object):
+    oid = CRLEntryExtensionOID.CRL_REASON
+
+    def __init__(self, reason):
+        if not isinstance(reason, ReasonFlags):
+            raise TypeError("reason must be an element from ReasonFlags")
+
+        self._reason = reason
+
+    def __repr__(self):
+        return "<CRLReason(reason={0})>".format(self._reason)
+
+    def __eq__(self, other):
+        if not isinstance(other, CRLReason):
+            return NotImplemented
+
+        return self.reason == other.reason
+
+    def __ne__(self, other):
+        return not self == other
+
+    def __hash__(self):
+        return hash(self.reason)
+
+    reason = utils.read_only_property("_reason")
+
+
+@utils.register_interface(ExtensionType)
+class InvalidityDate(object):
+    oid = CRLEntryExtensionOID.INVALIDITY_DATE
+
+    def __init__(self, invalidity_date):
+        if not isinstance(invalidity_date, datetime.datetime):
+            raise TypeError("invalidity_date must be a datetime.datetime")
+
+        self._invalidity_date = invalidity_date
+
+    def __repr__(self):
+        return "<InvalidityDate(invalidity_date={0})>".format(
+            self._invalidity_date
+        )
+
+    def __eq__(self, other):
+        if not isinstance(other, InvalidityDate):
+            return NotImplemented
+
+        return self.invalidity_date == other.invalidity_date
+
+    def __ne__(self, other):
+        return not self == other
+
+    def __hash__(self):
+        return hash(self.invalidity_date)
+
+    invalidity_date = utils.read_only_property("_invalidity_date")
+
+
+@utils.register_interface(ExtensionType)
+class UnrecognizedExtension(object):
+    def __init__(self, oid, value):
+        if not isinstance(oid, ObjectIdentifier):
+            raise TypeError("oid must be an ObjectIdentifier")
+        self._oid = oid
+        self._value = value
+
+    oid = utils.read_only_property("_oid")
+    value = utils.read_only_property("_value")
+
+    def __repr__(self):
+        return (
+            "<UnrecognizedExtension(oid={0.oid}, value={0.value!r})>".format(
+                self
+            )
+        )
+
+    def __eq__(self, other):
+        if not isinstance(other, UnrecognizedExtension):
+            return NotImplemented
+
+        return self.oid == other.oid and self.value == other.value
+
+    def __ne__(self, other):
+        return not self == other
+
+    def __hash__(self):
+        return hash((self.oid, self.value))
diff --git a/src/cryptography/x509/oid.py b/src/cryptography/x509/oid.py
index 94295d6..ced1510 100644
--- a/src/cryptography/x509/oid.py
+++ b/src/cryptography/x509/oid.py
@@ -88,12 +88,20 @@
     CRL_NUMBER = ObjectIdentifier("2.5.29.20")
 
 
-class CRLExtensionOID(object):
+class CRLEntryExtensionOID(object):
     CERTIFICATE_ISSUER = ObjectIdentifier("2.5.29.29")
     CRL_REASON = ObjectIdentifier("2.5.29.21")
     INVALIDITY_DATE = ObjectIdentifier("2.5.29.24")
 
 
+CRLExtensionOID = utils.deprecated(
+    CRLEntryExtensionOID,
+    __name__,
+    "CRLExtensionOID has been renamed to CRLEntryExtensionOID",
+    utils.DeprecatedIn12
+)
+
+
 class NameOID(object):
     COMMON_NAME = ObjectIdentifier("2.5.4.3")
     COUNTRY_NAME = ObjectIdentifier("2.5.4.6")
@@ -220,9 +228,9 @@
     ExtensionOID.SUBJECT_ALTERNATIVE_NAME: "subjectAltName",
     ExtensionOID.ISSUER_ALTERNATIVE_NAME: "issuerAltName",
     ExtensionOID.BASIC_CONSTRAINTS: "basicConstraints",
-    CRLExtensionOID.CRL_REASON: "cRLReason",
-    CRLExtensionOID.INVALIDITY_DATE: "invalidityDate",
-    CRLExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer",
+    CRLEntryExtensionOID.CRL_REASON: "cRLReason",
+    CRLEntryExtensionOID.INVALIDITY_DATE: "invalidityDate",
+    CRLEntryExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer",
     ExtensionOID.NAME_CONSTRAINTS: "nameConstraints",
     ExtensionOID.CRL_DISTRIBUTION_POINTS: "cRLDistributionPoints",
     ExtensionOID.CERTIFICATE_POLICIES: "certificatePolicies",
diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py
index 81a64ce..7483571 100644
--- a/tests/hazmat/backends/test_multibackend.py
+++ b/tests/hazmat/backends/test_multibackend.py
@@ -218,6 +218,12 @@
     def create_x509_certificate(self, builder, private_key, algorithm):
         pass
 
+    def create_x509_crl(self, builder, private_key, algorithm):
+        pass
+
+    def create_x509_revoked_certificate(self, builder):
+        pass
+
 
 class TestMultiBackend(object):
     def test_ciphers(self):
@@ -514,6 +520,8 @@
         backend.load_der_x509_csr(b"reqdata")
         backend.create_x509_csr(object(), b"privatekey", hashes.SHA1())
         backend.create_x509_certificate(object(), b"privatekey", hashes.SHA1())
+        backend.create_x509_crl(object(), b"privatekey", hashes.SHA1())
+        backend.create_x509_revoked_certificate(object())
 
         backend = MultiBackend([])
         with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509):
@@ -534,3 +542,9 @@
             backend.create_x509_certificate(
                 object(), b"privatekey", hashes.SHA1()
             )
+        with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509):
+            backend.create_x509_crl(
+                object(), b"privatekey", hashes.SHA1()
+            )
+        with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509):
+            backend.create_x509_revoked_certificate(object())
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index d048fe6..ad2daf7 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -4,6 +4,7 @@
 
 from __future__ import absolute_import, division, print_function
 
+import datetime
 import os
 import subprocess
 import sys
@@ -13,7 +14,7 @@
 
 import pytest
 
-from cryptography import utils
+from cryptography import utils, x509
 from cryptography.exceptions import InternalError, _Reasons
 from cryptography.hazmat.backends.interfaces import RSABackend
 from cryptography.hazmat.backends.openssl.backend import (
@@ -500,8 +501,108 @@
         with pytest.raises(TypeError):
             backend.create_x509_certificate(object(), private_key, DummyHash())
 
+    @pytest.mark.skipif(
+        backend._lib.OPENSSL_VERSION_NUMBER >= 0x10001000,
+        reason="Requires an older OpenSSL. Must be < 1.0.1"
+    )
+    def test_sign_with_dsa_private_key_is_unsupported(self):
+        private_key = DSA_KEY_2048.private_key(backend)
+        builder = x509.CertificateBuilder()
+        builder = builder.subject_name(
+            x509.Name([x509.NameAttribute(x509.NameOID.COUNTRY_NAME, u'US')])
+        ).issuer_name(
+            x509.Name([x509.NameAttribute(x509.NameOID.COUNTRY_NAME, u'US')])
+        ).serial_number(
+            1
+        ).public_key(
+            private_key.public_key()
+        ).not_valid_before(
+            datetime.datetime(2002, 1, 1, 12, 1)
+        ).not_valid_after(
+            datetime.datetime(2032, 1, 1, 12, 1)
+        )
 
-class TestOpenSSLSerialisationWithOpenSSL(object):
+        with pytest.raises(NotImplementedError):
+            builder.sign(private_key, hashes.SHA512(), backend)
+
+    @pytest.mark.skipif(
+        backend._lib.OPENSSL_VERSION_NUMBER >= 0x10001000,
+        reason="Requires an older OpenSSL. Must be < 1.0.1"
+    )
+    def test_sign_with_ec_private_key_is_unsupported(self):
+        _skip_curve_unsupported(backend, ec.SECP256R1())
+        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
+        builder = x509.CertificateBuilder()
+        builder = builder.subject_name(
+            x509.Name([x509.NameAttribute(x509.NameOID.COUNTRY_NAME, u'US')])
+        ).issuer_name(
+            x509.Name([x509.NameAttribute(x509.NameOID.COUNTRY_NAME, u'US')])
+        ).serial_number(
+            1
+        ).public_key(
+            private_key.public_key()
+        ).not_valid_before(
+            datetime.datetime(2002, 1, 1, 12, 1)
+        ).not_valid_after(
+            datetime.datetime(2032, 1, 1, 12, 1)
+        )
+
+        with pytest.raises(NotImplementedError):
+            builder.sign(private_key, hashes.SHA512(), backend)
+
+
+class TestOpenSSLSignX509CertificateRevocationList(object):
+    def test_invalid_builder(self):
+        private_key = RSA_KEY_2048.private_key(backend)
+
+        with pytest.raises(TypeError):
+            backend.create_x509_crl(object(), private_key, hashes.SHA256())
+
+    @pytest.mark.skipif(
+        backend._lib.OPENSSL_VERSION_NUMBER >= 0x10001000,
+        reason="Requires an older OpenSSL. Must be < 1.0.1"
+    )
+    def test_sign_with_dsa_private_key_is_unsupported(self):
+        private_key = DSA_KEY_2048.private_key(backend)
+        builder = x509.CertificateRevocationListBuilder()
+        builder = builder.issuer_name(
+            x509.Name([x509.NameAttribute(x509.NameOID.COUNTRY_NAME, u'US')])
+        ).last_update(
+            datetime.datetime(2002, 1, 1, 12, 1)
+        ).next_update(
+            datetime.datetime(2032, 1, 1, 12, 1)
+        )
+
+        with pytest.raises(NotImplementedError):
+            builder.sign(private_key, hashes.SHA1(), backend)
+
+    @pytest.mark.skipif(
+        backend._lib.OPENSSL_VERSION_NUMBER >= 0x10001000,
+        reason="Requires an older OpenSSL. Must be < 1.0.1"
+    )
+    def test_sign_with_ec_private_key_is_unsupported(self):
+        _skip_curve_unsupported(backend, ec.SECP256R1())
+        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
+        builder = x509.CertificateRevocationListBuilder()
+        builder = builder.issuer_name(
+            x509.Name([x509.NameAttribute(x509.NameOID.COUNTRY_NAME, u'US')])
+        ).last_update(
+            datetime.datetime(2002, 1, 1, 12, 1)
+        ).next_update(
+            datetime.datetime(2032, 1, 1, 12, 1)
+        )
+
+        with pytest.raises(NotImplementedError):
+            builder.sign(private_key, hashes.SHA512(), backend)
+
+
+class TestOpenSSLCreateRevokedCertificate(object):
+    def test_invalid_builder(self):
+        with pytest.raises(TypeError):
+            backend.create_x509_revoked_certificate(object())
+
+
+class TestOpenSSLSerializationWithOpenSSL(object):
     def test_pem_password_cb_buffer_too_small(self):
         ffi_cb, userdata = backend._pem_password_cb(b"aa")
         handle = backend._ffi.new_handle(userdata)
diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py
index 0b83fd6..b6213d6 100644
--- a/tests/hazmat/primitives/test_rsa.py
+++ b/tests/hazmat/primitives/test_rsa.py
@@ -1194,6 +1194,43 @@
         )
         assert message == binascii.unhexlify(example["message"])
 
+    @pytest.mark.supported(
+        only_if=lambda backend: backend.rsa_padding_supported(
+            padding.OAEP(
+                mgf=padding.MGF1(algorithm=hashes.SHA1()),
+                algorithm=hashes.SHA1(),
+                label=None
+            )
+        ),
+        skip_message="Does not support OAEP."
+    )
+    def test_invalid_oaep_decryption(self, backend):
+        # More recent versions of OpenSSL may raise RSA_R_OAEP_DECODING_ERROR
+        # This test triggers it and confirms that we properly handle it. Other
+        # backends should also return the proper ValueError.
+        private_key = RSA_KEY_512.private_key(backend)
+
+        ciphertext = private_key.public_key().encrypt(
+            b'secure data',
+            padding.OAEP(
+                mgf=padding.MGF1(algorithm=hashes.SHA1()),
+                algorithm=hashes.SHA1(),
+                label=None
+            )
+        )
+
+        private_key_alt = RSA_KEY_512_ALT.private_key(backend)
+
+        with pytest.raises(ValueError):
+            private_key_alt.decrypt(
+                ciphertext,
+                padding.OAEP(
+                    mgf=padding.MGF1(algorithm=hashes.SHA1()),
+                    algorithm=hashes.SHA1(),
+                    label=None
+                )
+            )
+
     def test_unsupported_oaep_mgf(self, backend):
         private_key = RSA_KEY_512.private_key(backend)
         with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_MGF):
diff --git a/tests/test_x509.py b/tests/test_x509.py
index ae2746e..6145edb 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -173,6 +173,20 @@
         # Check that len() works for CRLs.
         assert len(crl) == 12
 
+    def test_revoked_cert_retrieval_retain_only_revoked(self, backend):
+        """
+        This test attempts to trigger the crash condition described in
+        https://github.com/pyca/cryptography/issues/2557
+        PyPy does gc at its own pace, so it will only be reliable on CPython.
+        """
+        revoked = _load_cert(
+            os.path.join("x509", "custom", "crl_all_reasons.pem"),
+            x509.load_pem_x509_crl,
+            backend
+        )[11]
+        assert revoked.revocation_date == datetime.datetime(2015, 1, 1, 0, 0)
+        assert revoked.serial_number == 11
+
     def test_extensions(self, backend):
         crl = _load_cert(
             os.path.join("x509", "custom", "crl_ian_aia_aki.pem"),
@@ -318,7 +332,6 @@
 
 @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"),
@@ -342,12 +355,12 @@
             backend
         )
 
-        exp_issuer = x509.GeneralNames([
+        exp_issuer = [
             x509.DirectoryName(x509.Name([
                 x509.NameAttribute(x509.OID_COUNTRY_NAME, u"US"),
                 x509.NameAttribute(x509.OID_COMMON_NAME, u"cryptography.io"),
             ]))
-        ])
+        ]
 
         # First revoked cert doesn't have extensions, test if it is handled
         # correctly.
@@ -366,29 +379,28 @@
         rev1 = crl[1]
         assert isinstance(rev1.extensions, x509.Extensions)
 
-        reason = rev1.extensions.get_extension_for_oid(
-            x509.OID_CRL_REASON).value
-        assert reason == x509.ReasonFlags.unspecified
+        reason = rev1.extensions.get_extension_for_class(
+            x509.CRLReason).value
+        assert reason == x509.CRLReason(x509.ReasonFlags.unspecified)
 
-        issuer = rev1.extensions.get_extension_for_oid(
-            x509.OID_CERTIFICATE_ISSUER).value
-        assert issuer == exp_issuer
+        issuer = rev1.extensions.get_extension_for_class(
+            x509.CertificateIssuer).value
+        assert issuer == x509.CertificateIssuer(exp_issuer)
 
-        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"
+        date = rev1.extensions.get_extension_for_class(
+            x509.InvalidityDate).value
+        assert date == x509.InvalidityDate(datetime.datetime(2015, 1, 1, 0, 0))
 
         # Check if all reason flags can be found in the CRL.
         flags = set(x509.ReasonFlags)
         for rev in crl:
             try:
-                r = rev.extensions.get_extension_for_oid(x509.OID_CRL_REASON)
+                r = rev.extensions.get_extension_for_class(x509.CRLReason)
             except x509.ExtensionNotFound:
                 # Not all revoked certs have a reason extension.
                 pass
             else:
-                flags.discard(r.value)
+                flags.discard(r.value.reason)
 
         assert len(flags) == 0
 
@@ -446,6 +458,23 @@
         with pytest.raises(ValueError):
             crl[0].extensions
 
+    def test_indexing(self, backend):
+        crl = _load_cert(
+            os.path.join("x509", "custom", "crl_all_reasons.pem"),
+            x509.load_pem_x509_crl,
+            backend
+        )
+
+        with pytest.raises(IndexError):
+            crl[-13]
+        with pytest.raises(IndexError):
+            crl[12]
+
+        assert crl[-1].serial_number == crl[11].serial_number
+        assert len(crl[2:4]) == 2
+        assert crl[2:4][0].serial_number == crl[2].serial_number
+        assert crl[2:4][1].serial_number == crl[3].serial_number
+
 
 @pytest.mark.requires_backend_interface(interface=RSABackend)
 @pytest.mark.requires_backend_interface(interface=X509Backend)
@@ -1064,7 +1093,11 @@
             backend
         )
         extensions = request.extensions
-        assert len(extensions) == 0
+        assert len(extensions) == 1
+        assert extensions[0].oid == x509.ObjectIdentifier("1.2.3.4")
+        assert extensions[0].value == x509.UnrecognizedExtension(
+            x509.ObjectIdentifier("1.2.3.4"), b"value"
+        )
 
     def test_request_basic_constraints(self, backend):
         request = _load_cert(
@@ -1710,57 +1743,6 @@
         with pytest.raises(TypeError):
             builder.sign(private_key, object(), backend)
 
-    @pytest.mark.requires_backend_interface(interface=DSABackend)
-    @pytest.mark.requires_backend_interface(interface=X509Backend)
-    def test_sign_with_dsa_private_key_is_unsupported(self, backend):
-        if backend._lib.OPENSSL_VERSION_NUMBER >= 0x10001000:
-            pytest.skip("Requires an older OpenSSL. Must be < 1.0.1")
-
-        private_key = DSA_KEY_2048.private_key(backend)
-        builder = x509.CertificateBuilder()
-        builder = builder.subject_name(
-            x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
-        ).issuer_name(
-            x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
-        ).serial_number(
-            1
-        ).public_key(
-            private_key.public_key()
-        ).not_valid_before(
-            datetime.datetime(2002, 1, 1, 12, 1)
-        ).not_valid_after(
-            datetime.datetime(2032, 1, 1, 12, 1)
-        )
-
-        with pytest.raises(NotImplementedError):
-            builder.sign(private_key, hashes.SHA512(), backend)
-
-    @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
-    @pytest.mark.requires_backend_interface(interface=X509Backend)
-    def test_sign_with_ec_private_key_is_unsupported(self, backend):
-        if backend._lib.OPENSSL_VERSION_NUMBER >= 0x10001000:
-            pytest.skip("Requires an older OpenSSL. Must be < 1.0.1")
-
-        _skip_curve_unsupported(backend, ec.SECP256R1())
-        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
-        builder = x509.CertificateBuilder()
-        builder = builder.subject_name(
-            x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
-        ).issuer_name(
-            x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
-        ).serial_number(
-            1
-        ).public_key(
-            private_key.public_key()
-        ).not_valid_before(
-            datetime.datetime(2002, 1, 1, 12, 1)
-        ).not_valid_after(
-            datetime.datetime(2032, 1, 1, 12, 1)
-        )
-
-        with pytest.raises(NotImplementedError):
-            builder.sign(private_key, hashes.SHA512(), backend)
-
     @pytest.mark.parametrize(
         "cdp",
         [
diff --git a/tests/test_x509_crlbuilder.py b/tests/test_x509_crlbuilder.py
new file mode 100644
index 0000000..32a0748
--- /dev/null
+++ b/tests/test_x509_crlbuilder.py
@@ -0,0 +1,449 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import datetime
+
+import pytest
+
+from cryptography import x509
+from cryptography.hazmat.backends.interfaces import (
+    DSABackend, EllipticCurveBackend, RSABackend, X509Backend
+)
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.asymmetric import ec
+from cryptography.x509.oid import AuthorityInformationAccessOID, NameOID
+
+from .hazmat.primitives.fixtures_dsa import DSA_KEY_2048
+from .hazmat.primitives.fixtures_rsa import RSA_KEY_2048, RSA_KEY_512
+from .hazmat.primitives.test_ec import _skip_curve_unsupported
+
+
+class TestCertificateRevocationListBuilder(object):
+    def test_issuer_name_invalid(self):
+        builder = x509.CertificateRevocationListBuilder()
+        with pytest.raises(TypeError):
+            builder.issuer_name("notanx509name")
+
+    def test_set_issuer_name_twice(self):
+        builder = x509.CertificateRevocationListBuilder().issuer_name(
+            x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
+        )
+        with pytest.raises(ValueError):
+            builder.issuer_name(
+                x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
+            )
+
+    def test_last_update_invalid(self):
+        builder = x509.CertificateRevocationListBuilder()
+        with pytest.raises(TypeError):
+            builder.last_update("notadatetime")
+
+    def test_last_update_before_unix_epoch(self):
+        builder = x509.CertificateRevocationListBuilder()
+        with pytest.raises(ValueError):
+            builder.last_update(datetime.datetime(1960, 8, 10))
+
+    def test_set_last_update_twice(self):
+        builder = x509.CertificateRevocationListBuilder().last_update(
+            datetime.datetime(2002, 1, 1, 12, 1)
+        )
+        with pytest.raises(ValueError):
+            builder.last_update(datetime.datetime(2002, 1, 1, 12, 1))
+
+    def test_next_update_invalid(self):
+        builder = x509.CertificateRevocationListBuilder()
+        with pytest.raises(TypeError):
+            builder.next_update("notadatetime")
+
+    def test_next_update_before_unix_epoch(self):
+        builder = x509.CertificateRevocationListBuilder()
+        with pytest.raises(ValueError):
+            builder.next_update(datetime.datetime(1960, 8, 10))
+
+    def test_set_next_update_twice(self):
+        builder = x509.CertificateRevocationListBuilder().next_update(
+            datetime.datetime(2002, 1, 1, 12, 1)
+        )
+        with pytest.raises(ValueError):
+            builder.next_update(datetime.datetime(2002, 1, 1, 12, 1))
+
+    def test_last_update_after_next_update(self):
+        builder = x509.CertificateRevocationListBuilder()
+
+        builder = builder.next_update(
+            datetime.datetime(2002, 1, 1, 12, 1)
+        )
+        with pytest.raises(ValueError):
+            builder.last_update(datetime.datetime(2003, 1, 1, 12, 1))
+
+    def test_next_update_after_last_update(self):
+        builder = x509.CertificateRevocationListBuilder()
+
+        builder = builder.last_update(
+            datetime.datetime(2002, 1, 1, 12, 1)
+        )
+        with pytest.raises(ValueError):
+            builder.next_update(datetime.datetime(2001, 1, 1, 12, 1))
+
+    def test_add_extension_checks_for_duplicates(self):
+        builder = x509.CertificateRevocationListBuilder().add_extension(
+            x509.CRLNumber(1), False
+        )
+
+        with pytest.raises(ValueError):
+            builder.add_extension(x509.CRLNumber(2), False)
+
+    def test_add_invalid_extension(self):
+        builder = x509.CertificateRevocationListBuilder()
+
+        with pytest.raises(TypeError):
+            builder.add_extension(
+                object(), False
+            )
+
+    def test_add_invalid_revoked_certificate(self):
+        builder = x509.CertificateRevocationListBuilder()
+
+        with pytest.raises(TypeError):
+            builder.add_revoked_certificate(object())
+
+    @pytest.mark.requires_backend_interface(interface=RSABackend)
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_no_issuer_name(self, backend):
+        private_key = RSA_KEY_2048.private_key(backend)
+        builder = x509.CertificateRevocationListBuilder().last_update(
+            datetime.datetime(2002, 1, 1, 12, 1)
+        ).next_update(
+            datetime.datetime(2030, 1, 1, 12, 1)
+        )
+
+        with pytest.raises(ValueError):
+            builder.sign(private_key, hashes.SHA256(), backend)
+
+    @pytest.mark.requires_backend_interface(interface=RSABackend)
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_no_last_update(self, backend):
+        private_key = RSA_KEY_2048.private_key(backend)
+        builder = x509.CertificateRevocationListBuilder().issuer_name(
+            x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
+        ).next_update(
+            datetime.datetime(2030, 1, 1, 12, 1)
+        )
+
+        with pytest.raises(ValueError):
+            builder.sign(private_key, hashes.SHA256(), backend)
+
+    @pytest.mark.requires_backend_interface(interface=RSABackend)
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_no_next_update(self, backend):
+        private_key = RSA_KEY_2048.private_key(backend)
+        builder = x509.CertificateRevocationListBuilder().issuer_name(
+            x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
+        ).last_update(
+            datetime.datetime(2030, 1, 1, 12, 1)
+        )
+
+        with pytest.raises(ValueError):
+            builder.sign(private_key, hashes.SHA256(), backend)
+
+    @pytest.mark.requires_backend_interface(interface=RSABackend)
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_sign_empty_list(self, backend):
+        private_key = RSA_KEY_2048.private_key(backend)
+        last_update = datetime.datetime(2002, 1, 1, 12, 1)
+        next_update = datetime.datetime(2030, 1, 1, 12, 1)
+        builder = x509.CertificateRevocationListBuilder().issuer_name(
+            x509.Name([
+                x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
+            ])
+        ).last_update(last_update).next_update(next_update)
+
+        crl = builder.sign(private_key, hashes.SHA256(), backend)
+        assert len(crl) == 0
+        assert crl.last_update == last_update
+        assert crl.next_update == next_update
+
+    @pytest.mark.parametrize(
+        "extension",
+        [
+            x509.CRLNumber(13),
+            x509.AuthorityKeyIdentifier(
+                b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08"
+                b"\xcbY",
+                None,
+                None
+            ),
+            x509.AuthorityInformationAccess([
+                x509.AccessDescription(
+                    AuthorityInformationAccessOID.CA_ISSUERS,
+                    x509.DNSName(u"cryptography.io")
+                )
+            ]),
+            x509.IssuerAlternativeName([
+                x509.UniformResourceIdentifier(u"https://cryptography.io"),
+            ])
+        ]
+    )
+    @pytest.mark.requires_backend_interface(interface=RSABackend)
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_sign_extensions(self, backend, extension):
+        private_key = RSA_KEY_2048.private_key(backend)
+        last_update = datetime.datetime(2002, 1, 1, 12, 1)
+        next_update = datetime.datetime(2030, 1, 1, 12, 1)
+        builder = x509.CertificateRevocationListBuilder().issuer_name(
+            x509.Name([
+                x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
+            ])
+        ).last_update(
+            last_update
+        ).next_update(
+            next_update
+        ).add_extension(
+            extension, False
+        )
+
+        crl = builder.sign(private_key, hashes.SHA256(), backend)
+        assert len(crl) == 0
+        assert len(crl.extensions) == 1
+        ext = crl.extensions.get_extension_for_class(type(extension))
+        assert ext.critical is False
+        assert ext.value == extension
+
+    @pytest.mark.requires_backend_interface(interface=RSABackend)
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_sign_multiple_extensions_critical(self, backend):
+        private_key = RSA_KEY_2048.private_key(backend)
+        last_update = datetime.datetime(2002, 1, 1, 12, 1)
+        next_update = datetime.datetime(2030, 1, 1, 12, 1)
+        ian = x509.IssuerAlternativeName([
+            x509.UniformResourceIdentifier(u"https://cryptography.io"),
+        ])
+        crl_number = x509.CRLNumber(13)
+        builder = x509.CertificateRevocationListBuilder().issuer_name(
+            x509.Name([
+                x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
+            ])
+        ).last_update(
+            last_update
+        ).next_update(
+            next_update
+        ).add_extension(
+            crl_number, False
+        ).add_extension(
+            ian, True
+        )
+
+        crl = builder.sign(private_key, hashes.SHA256(), backend)
+        assert len(crl) == 0
+        assert len(crl.extensions) == 2
+        ext1 = crl.extensions.get_extension_for_class(x509.CRLNumber)
+        assert ext1.critical is False
+        assert ext1.value == crl_number
+        ext2 = crl.extensions.get_extension_for_class(
+            x509.IssuerAlternativeName
+        )
+        assert ext2.critical is True
+        assert ext2.value == ian
+
+    @pytest.mark.requires_backend_interface(interface=RSABackend)
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_add_unsupported_extension(self, backend):
+        private_key = RSA_KEY_2048.private_key(backend)
+        last_update = datetime.datetime(2002, 1, 1, 12, 1)
+        next_update = datetime.datetime(2030, 1, 1, 12, 1)
+        builder = x509.CertificateRevocationListBuilder().issuer_name(
+            x509.Name([
+                x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
+            ])
+        ).last_update(
+            last_update
+        ).next_update(
+            next_update
+        ).add_extension(
+            x509.OCSPNoCheck(), False
+        )
+        with pytest.raises(NotImplementedError):
+            builder.sign(private_key, hashes.SHA256(), backend)
+
+    @pytest.mark.requires_backend_interface(interface=RSABackend)
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_sign_rsa_key_too_small(self, backend):
+        private_key = RSA_KEY_512.private_key(backend)
+        last_update = datetime.datetime(2002, 1, 1, 12, 1)
+        next_update = datetime.datetime(2030, 1, 1, 12, 1)
+        builder = x509.CertificateRevocationListBuilder().issuer_name(
+            x509.Name([
+                x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
+            ])
+        ).last_update(
+            last_update
+        ).next_update(
+            next_update
+        )
+
+        with pytest.raises(ValueError):
+            builder.sign(private_key, hashes.SHA512(), backend)
+
+    @pytest.mark.requires_backend_interface(interface=RSABackend)
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_sign_with_invalid_hash(self, backend):
+        private_key = RSA_KEY_2048.private_key(backend)
+        last_update = datetime.datetime(2002, 1, 1, 12, 1)
+        next_update = datetime.datetime(2030, 1, 1, 12, 1)
+        builder = x509.CertificateRevocationListBuilder().issuer_name(
+            x509.Name([
+                x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
+            ])
+        ).last_update(
+            last_update
+        ).next_update(
+            next_update
+        )
+
+        with pytest.raises(TypeError):
+            builder.sign(private_key, object(), backend)
+
+    @pytest.mark.requires_backend_interface(interface=DSABackend)
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_sign_dsa_key(self, backend):
+        if backend._lib.OPENSSL_VERSION_NUMBER < 0x10001000:
+            pytest.skip("Requires a newer OpenSSL. Must be >= 1.0.1")
+        private_key = DSA_KEY_2048.private_key(backend)
+        invalidity_date = x509.InvalidityDate(
+            datetime.datetime(2002, 1, 1, 0, 0)
+        )
+        ian = x509.IssuerAlternativeName([
+            x509.UniformResourceIdentifier(u"https://cryptography.io"),
+        ])
+        revoked_cert0 = x509.RevokedCertificateBuilder().serial_number(
+            2
+        ).revocation_date(
+            datetime.datetime(2012, 1, 1, 1, 1)
+        ).add_extension(
+            invalidity_date, False
+        ).build(backend)
+        last_update = datetime.datetime(2002, 1, 1, 12, 1)
+        next_update = datetime.datetime(2030, 1, 1, 12, 1)
+        builder = x509.CertificateRevocationListBuilder().issuer_name(
+            x509.Name([
+                x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
+            ])
+        ).last_update(
+            last_update
+        ).next_update(
+            next_update
+        ).add_revoked_certificate(
+            revoked_cert0
+        ).add_extension(
+            ian, False
+        )
+
+        crl = builder.sign(private_key, hashes.SHA256(), backend)
+        assert crl.extensions.get_extension_for_class(
+            x509.IssuerAlternativeName
+        ).value == ian
+        assert crl[0].serial_number == revoked_cert0.serial_number
+        assert crl[0].revocation_date == revoked_cert0.revocation_date
+        assert len(crl[0].extensions) == 1
+        ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
+        assert ext.critical is False
+        assert ext.value == invalidity_date
+
+    @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_sign_ec_key_unsupported(self, backend):
+        if backend._lib.OPENSSL_VERSION_NUMBER < 0x10001000:
+            pytest.skip("Requires a newer OpenSSL. Must be >= 1.0.1")
+        _skip_curve_unsupported(backend, ec.SECP256R1())
+        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
+        invalidity_date = x509.InvalidityDate(
+            datetime.datetime(2002, 1, 1, 0, 0)
+        )
+        ian = x509.IssuerAlternativeName([
+            x509.UniformResourceIdentifier(u"https://cryptography.io"),
+        ])
+        revoked_cert0 = x509.RevokedCertificateBuilder().serial_number(
+            2
+        ).revocation_date(
+            datetime.datetime(2012, 1, 1, 1, 1)
+        ).add_extension(
+            invalidity_date, False
+        ).build(backend)
+        last_update = datetime.datetime(2002, 1, 1, 12, 1)
+        next_update = datetime.datetime(2030, 1, 1, 12, 1)
+        builder = x509.CertificateRevocationListBuilder().issuer_name(
+            x509.Name([
+                x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
+            ])
+        ).last_update(
+            last_update
+        ).next_update(
+            next_update
+        ).add_revoked_certificate(
+            revoked_cert0
+        ).add_extension(
+            ian, False
+        )
+
+        crl = builder.sign(private_key, hashes.SHA256(), backend)
+        assert crl.extensions.get_extension_for_class(
+            x509.IssuerAlternativeName
+        ).value == ian
+        assert crl[0].serial_number == revoked_cert0.serial_number
+        assert crl[0].revocation_date == revoked_cert0.revocation_date
+        assert len(crl[0].extensions) == 1
+        ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
+        assert ext.critical is False
+        assert ext.value == invalidity_date
+
+    @pytest.mark.requires_backend_interface(interface=RSABackend)
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_sign_with_revoked_certificates(self, backend):
+        private_key = RSA_KEY_2048.private_key(backend)
+        last_update = datetime.datetime(2002, 1, 1, 12, 1)
+        next_update = datetime.datetime(2030, 1, 1, 12, 1)
+        invalidity_date = x509.InvalidityDate(
+            datetime.datetime(2002, 1, 1, 0, 0)
+        )
+        revoked_cert0 = x509.RevokedCertificateBuilder().serial_number(
+            38
+        ).revocation_date(
+            datetime.datetime(2011, 1, 1, 1, 1)
+        ).build(backend)
+        revoked_cert1 = x509.RevokedCertificateBuilder().serial_number(
+            2
+        ).revocation_date(
+            datetime.datetime(2012, 1, 1, 1, 1)
+        ).add_extension(
+            invalidity_date, False
+        ).build(backend)
+        builder = x509.CertificateRevocationListBuilder().issuer_name(
+            x509.Name([
+                x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
+            ])
+        ).last_update(
+            last_update
+        ).next_update(
+            next_update
+        ).add_revoked_certificate(
+            revoked_cert0
+        ).add_revoked_certificate(
+            revoked_cert1
+        )
+
+        crl = builder.sign(private_key, hashes.SHA256(), backend)
+        assert len(crl) == 2
+        assert crl.last_update == last_update
+        assert crl.next_update == next_update
+        assert crl[0].serial_number == revoked_cert0.serial_number
+        assert crl[0].revocation_date == revoked_cert0.revocation_date
+        assert len(crl[0].extensions) == 0
+        assert crl[1].serial_number == revoked_cert1.serial_number
+        assert crl[1].revocation_date == revoked_cert1.revocation_date
+        assert len(crl[1].extensions) == 1
+        ext = crl[1].extensions.get_extension_for_class(x509.InvalidityDate)
+        assert ext.critical is False
+        assert ext.value == invalidity_date
diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py
index d9743c8..03a3730 100644
--- a/tests/test_x509_ext.py
+++ b/tests/test_x509_ext.py
@@ -5,6 +5,7 @@
 from __future__ import absolute_import, division, print_function
 
 import binascii
+import datetime
 import ipaddress
 import os
 
@@ -74,6 +75,173 @@
         assert ext1 != object()
 
 
+class TestUnrecognizedExtension(object):
+    def test_invalid_oid(self):
+        with pytest.raises(TypeError):
+            x509.UnrecognizedExtension("notanoid", b"somedata")
+
+    def test_eq(self):
+        ext1 = x509.UnrecognizedExtension(
+            x509.ObjectIdentifier("1.2.3.4"), b"\x03\x02\x01"
+        )
+        ext2 = x509.UnrecognizedExtension(
+            x509.ObjectIdentifier("1.2.3.4"), b"\x03\x02\x01"
+        )
+        assert ext1 == ext2
+
+    def test_ne(self):
+        ext1 = x509.UnrecognizedExtension(
+            x509.ObjectIdentifier("1.2.3.4"), b"\x03\x02\x01"
+        )
+        ext2 = x509.UnrecognizedExtension(
+            x509.ObjectIdentifier("1.2.3.4"), b"\x03\x02\x02"
+        )
+        ext3 = x509.UnrecognizedExtension(
+            x509.ObjectIdentifier("1.2.3.5"), b"\x03\x02\x01"
+        )
+        assert ext1 != ext2
+        assert ext1 != ext3
+        assert ext1 != object()
+
+    def test_repr(self):
+        ext1 = x509.UnrecognizedExtension(
+            x509.ObjectIdentifier("1.2.3.4"), b"\x03\x02\x01"
+        )
+        if six.PY3:
+            assert repr(ext1) == (
+                "<UnrecognizedExtension(oid=<ObjectIdentifier(oid=1.2.3.4, "
+                "name=Unknown OID)>, value=b'\\x03\\x02\\x01')>"
+            )
+        else:
+            assert repr(ext1) == (
+                "<UnrecognizedExtension(oid=<ObjectIdentifier(oid=1.2.3.4, "
+                "name=Unknown OID)>, value='\\x03\\x02\\x01')>"
+            )
+
+    def test_hash(self):
+        ext1 = x509.UnrecognizedExtension(
+            x509.ObjectIdentifier("1.2.3.4"), b"\x03\x02\x01"
+        )
+        ext2 = x509.UnrecognizedExtension(
+            x509.ObjectIdentifier("1.2.3.4"), b"\x03\x02\x01"
+        )
+        ext3 = x509.UnrecognizedExtension(
+            x509.ObjectIdentifier("1.2.3.5"), b"\x03\x02\x01"
+        )
+        assert hash(ext1) == hash(ext2)
+        assert hash(ext1) != hash(ext3)
+
+
+class TestCertificateIssuer(object):
+    def test_iter_names(self):
+        ci = x509.CertificateIssuer([
+            x509.DNSName(u"cryptography.io"),
+            x509.DNSName(u"crypto.local"),
+        ])
+        assert len(ci) == 2
+        assert list(ci) == [
+            x509.DNSName(u"cryptography.io"),
+            x509.DNSName(u"crypto.local"),
+        ]
+
+    def test_indexing(self):
+        ci = x509.CertificateIssuer([
+            x509.DNSName(u"cryptography.io"),
+            x509.DNSName(u"crypto.local"),
+            x509.DNSName(u"another.local"),
+            x509.RFC822Name(u"email@another.local"),
+            x509.UniformResourceIdentifier(u"http://another.local"),
+        ])
+        assert ci[-1] == ci[4]
+        assert ci[2:6:2] == [ci[2], ci[4]]
+
+    def test_eq(self):
+        ci1 = x509.CertificateIssuer([x509.DNSName(u"cryptography.io")])
+        ci2 = x509.CertificateIssuer([x509.DNSName(u"cryptography.io")])
+        assert ci1 == ci2
+
+    def test_ne(self):
+        ci1 = x509.CertificateIssuer([x509.DNSName(u"cryptography.io")])
+        ci2 = x509.CertificateIssuer([x509.DNSName(u"somethingelse.tld")])
+        assert ci1 != ci2
+        assert ci1 != object()
+
+    def test_repr(self):
+        ci = x509.CertificateIssuer([x509.DNSName(u"cryptography.io")])
+        assert repr(ci) == (
+            "<CertificateIssuer(<GeneralNames([<DNSName(value=cryptography.io"
+            ")>])>)>"
+        )
+
+    def test_get_values_for_type(self):
+        ci = x509.CertificateIssuer(
+            [x509.DNSName(u"cryptography.io")]
+        )
+        names = ci.get_values_for_type(x509.DNSName)
+        assert names == [u"cryptography.io"]
+
+
+class TestCRLReason(object):
+    def test_invalid_reason_flags(self):
+        with pytest.raises(TypeError):
+            x509.CRLReason("notareason")
+
+    def test_eq(self):
+        reason1 = x509.CRLReason(x509.ReasonFlags.unspecified)
+        reason2 = x509.CRLReason(x509.ReasonFlags.unspecified)
+        assert reason1 == reason2
+
+    def test_ne(self):
+        reason1 = x509.CRLReason(x509.ReasonFlags.unspecified)
+        reason2 = x509.CRLReason(x509.ReasonFlags.ca_compromise)
+        assert reason1 != reason2
+        assert reason1 != object()
+
+    def test_hash(self):
+        reason1 = x509.CRLReason(x509.ReasonFlags.unspecified)
+        reason2 = x509.CRLReason(x509.ReasonFlags.unspecified)
+        reason3 = x509.CRLReason(x509.ReasonFlags.ca_compromise)
+
+        assert hash(reason1) == hash(reason2)
+        assert hash(reason1) != hash(reason3)
+
+    def test_repr(self):
+        reason1 = x509.CRLReason(x509.ReasonFlags.unspecified)
+        assert repr(reason1) == (
+            "<CRLReason(reason=ReasonFlags.unspecified)>"
+        )
+
+
+class TestInvalidityDate(object):
+    def test_invalid_invalidity_date(self):
+        with pytest.raises(TypeError):
+            x509.InvalidityDate("notadate")
+
+    def test_eq(self):
+        invalid1 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1))
+        invalid2 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1))
+        assert invalid1 == invalid2
+
+    def test_ne(self):
+        invalid1 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1))
+        invalid2 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 2))
+        assert invalid1 != invalid2
+        assert invalid1 != object()
+
+    def test_repr(self):
+        invalid1 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1))
+        assert repr(invalid1) == (
+            "<InvalidityDate(invalidity_date=2015-01-01 01:01:00)>"
+        )
+
+    def test_hash(self):
+        invalid1 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1))
+        invalid2 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1))
+        invalid3 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 2))
+        assert hash(invalid1) == hash(invalid2)
+        assert hash(invalid1) != hash(invalid3)
+
+
 class TestNoticeReference(object):
     def test_notice_numbers_not_all_int(self):
         with pytest.raises(TypeError):
@@ -269,6 +437,16 @@
         assert cp != cp2
         assert cp != object()
 
+    def test_indexing(self):
+        pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), [u"test"])
+        pi2 = x509.PolicyInformation(x509.ObjectIdentifier("1.2.4"), [u"test"])
+        pi3 = x509.PolicyInformation(x509.ObjectIdentifier("1.2.5"), [u"test"])
+        pi4 = x509.PolicyInformation(x509.ObjectIdentifier("1.2.6"), [u"test"])
+        pi5 = x509.PolicyInformation(x509.ObjectIdentifier("1.2.7"), [u"test"])
+        cp = x509.CertificatePolicies([pi, pi2, pi3, pi4, pi5])
+        assert cp[-1] == cp[4]
+        assert cp[2:6:2] == [cp[2], cp[4]]
+
 
 @pytest.mark.requires_backend_interface(interface=RSABackend)
 @pytest.mark.requires_backend_interface(interface=X509Backend)
@@ -595,6 +773,20 @@
         assert ski != ski2
         assert ski != object()
 
+    def test_hash(self):
+        ski1 = x509.SubjectKeyIdentifier(
+            binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9")
+        )
+        ski2 = x509.SubjectKeyIdentifier(
+            binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9")
+        )
+        ski3 = x509.SubjectKeyIdentifier(
+            binascii.unhexlify(b"aa8098456f6ff7ff3ac9092384932230498bc980")
+        )
+
+        assert hash(ski1) == hash(ski2)
+        assert hash(ski1) != hash(ski3)
+
 
 class TestAuthorityKeyIdentifier(object):
     def test_authority_cert_issuer_not_generalname(self):
@@ -720,6 +912,13 @@
             "<BasicConstraints(ca=True, path_length=None)>"
         )
 
+    def test_hash(self):
+        na = x509.BasicConstraints(ca=True, path_length=None)
+        na2 = x509.BasicConstraints(ca=True, path_length=None)
+        na3 = x509.BasicConstraints(ca=True, path_length=0)
+        assert hash(na) == hash(na2)
+        assert hash(na) != hash(na3)
+
     def test_eq(self):
         na = x509.BasicConstraints(ca=True, path_length=None)
         na2 = x509.BasicConstraints(ca=True, path_length=None)
@@ -833,17 +1032,33 @@
 
         assert exc.value.oid == x509.ObjectIdentifier("1.2.3.4")
 
+    @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
     def test_unsupported_extension(self, backend):
-        # TODO: this will raise an exception when all extensions are complete
         cert = _load_cert(
             os.path.join(
-                "x509", "custom", "unsupported_extension.pem"
+                "x509", "custom", "unsupported_extension_2.pem"
             ),
             x509.load_pem_x509_certificate,
             backend
         )
         extensions = cert.extensions
-        assert len(extensions) == 0
+        assert len(extensions) == 2
+        assert extensions[0].critical is False
+        assert extensions[0].oid == x509.ObjectIdentifier(
+            "1.3.6.1.4.1.41482.2"
+        )
+        assert extensions[0].value == x509.UnrecognizedExtension(
+            x509.ObjectIdentifier("1.3.6.1.4.1.41482.2"),
+            b"1.3.6.1.4.1.41482.1.2"
+        )
+        assert extensions[1].critical is False
+        assert extensions[1].oid == x509.ObjectIdentifier(
+            "1.3.6.1.4.1.45724.2.1.1"
+        )
+        assert extensions[1].value == x509.UnrecognizedExtension(
+            x509.ObjectIdentifier("1.3.6.1.4.1.45724.2.1.1"),
+            b"\x03\x02\x040"
+        )
 
     def test_no_extensions_get_for_class(self, backend):
         cert = _load_cert(
@@ -858,6 +1073,21 @@
             exts.get_extension_for_class(x509.IssuerAlternativeName)
         assert exc.value.oid == ExtensionOID.ISSUER_ALTERNATIVE_NAME
 
+    def test_unrecognized_extension_for_class(self):
+        exts = x509.Extensions([])
+        with pytest.raises(TypeError):
+            exts.get_extension_for_class(x509.UnrecognizedExtension)
+
+    def test_indexing(self, backend):
+        cert = _load_cert(
+            os.path.join("x509", "cryptography.io.pem"),
+            x509.load_pem_x509_certificate,
+            backend
+        )
+        exts = cert.extensions
+        assert exts[-1] == exts[7]
+        assert exts[2:6:2] == [exts[2], exts[4]]
+
     def test_one_extension_get_for_class(self, backend):
         cert = _load_cert(
             os.path.join(
@@ -1379,6 +1609,17 @@
             x509.DNSName(u"crypto.local"),
         ]
 
+    def test_indexing(self):
+        gn = x509.GeneralNames([
+            x509.DNSName(u"cryptography.io"),
+            x509.DNSName(u"crypto.local"),
+            x509.DNSName(u"another.local"),
+            x509.RFC822Name(u"email@another.local"),
+            x509.UniformResourceIdentifier(u"http://another.local"),
+        ])
+        assert gn[-1] == gn[4]
+        assert gn[2:6:2] == [gn[2], gn[4]]
+
     def test_invalid_general_names(self):
         with pytest.raises(TypeError):
             x509.GeneralNames(
@@ -1434,6 +1675,17 @@
             x509.DNSName(u"crypto.local"),
         ]
 
+    def test_indexing(self):
+        ian = x509.IssuerAlternativeName([
+            x509.DNSName(u"cryptography.io"),
+            x509.DNSName(u"crypto.local"),
+            x509.DNSName(u"another.local"),
+            x509.RFC822Name(u"email@another.local"),
+            x509.UniformResourceIdentifier(u"http://another.local"),
+        ])
+        assert ian[-1] == ian[4]
+        assert ian[2:6:2] == [ian[2], ian[4]]
+
     def test_invalid_general_names(self):
         with pytest.raises(TypeError):
             x509.IssuerAlternativeName(
@@ -1506,6 +1758,13 @@
         with pytest.raises(TypeError):
             x509.CRLNumber("notanumber")
 
+    def test_hash(self):
+        c1 = x509.CRLNumber(1)
+        c2 = x509.CRLNumber(1)
+        c3 = x509.CRLNumber(2)
+        assert hash(c1) == hash(c2)
+        assert hash(c1) != hash(c3)
+
 
 class TestSubjectAlternativeName(object):
     def test_get_values_for_type(self):
@@ -1526,6 +1785,17 @@
             x509.DNSName(u"crypto.local"),
         ]
 
+    def test_indexing(self):
+        san = x509.SubjectAlternativeName([
+            x509.DNSName(u"cryptography.io"),
+            x509.DNSName(u"crypto.local"),
+            x509.DNSName(u"another.local"),
+            x509.RFC822Name(u"email@another.local"),
+            x509.UniformResourceIdentifier(u"http://another.local"),
+        ])
+        assert san[-1] == san[4]
+        assert san[2:6:2] == [san[2], san[4]]
+
     def test_invalid_general_names(self):
         with pytest.raises(TypeError):
             x509.SubjectAlternativeName(
@@ -2028,6 +2298,32 @@
         assert aia != aia2
         assert aia != object()
 
+    def test_indexing(self):
+        aia = x509.AuthorityInformationAccess([
+            x509.AccessDescription(
+                AuthorityInformationAccessOID.OCSP,
+                x509.UniformResourceIdentifier(u"http://ocsp.domain.com")
+            ),
+            x509.AccessDescription(
+                AuthorityInformationAccessOID.CA_ISSUERS,
+                x509.UniformResourceIdentifier(u"http://domain.com/ca.crt")
+            ),
+            x509.AccessDescription(
+                AuthorityInformationAccessOID.OCSP,
+                x509.UniformResourceIdentifier(u"http://ocsp2.domain.com")
+            ),
+            x509.AccessDescription(
+                AuthorityInformationAccessOID.OCSP,
+                x509.UniformResourceIdentifier(u"http://ocsp3.domain.com")
+            ),
+            x509.AccessDescription(
+                AuthorityInformationAccessOID.OCSP,
+                x509.UniformResourceIdentifier(u"http://ocsp4.domain.com")
+            ),
+        ])
+        assert aia[-1] == aia[4]
+        assert aia[2:6:2] == [aia[2], aia[4]]
+
 
 @pytest.mark.requires_backend_interface(interface=RSABackend)
 @pytest.mark.requires_backend_interface(interface=X509Backend)
@@ -2756,6 +3052,32 @@
         assert cdp != cdp4
         assert cdp != object()
 
+    def test_indexing(self):
+        ci = x509.CRLDistributionPoints([
+            x509.DistributionPoint(
+                None, None, None,
+                [x509.UniformResourceIdentifier(u"uri://thing")],
+            ),
+            x509.DistributionPoint(
+                None, None, None,
+                [x509.UniformResourceIdentifier(u"uri://thing2")],
+            ),
+            x509.DistributionPoint(
+                None, None, None,
+                [x509.UniformResourceIdentifier(u"uri://thing3")],
+            ),
+            x509.DistributionPoint(
+                None, None, None,
+                [x509.UniformResourceIdentifier(u"uri://thing4")],
+            ),
+            x509.DistributionPoint(
+                None, None, None,
+                [x509.UniformResourceIdentifier(u"uri://thing5")],
+            ),
+        ])
+        assert ci[-1] == ci[4]
+        assert ci[2:6:2] == [ci[2], ci[4]]
+
 
 @pytest.mark.requires_backend_interface(interface=RSABackend)
 @pytest.mark.requires_backend_interface(interface=X509Backend)
diff --git a/tests/test_x509_revokedcertbuilder.py b/tests/test_x509_revokedcertbuilder.py
new file mode 100644
index 0000000..5aa9063
--- /dev/null
+++ b/tests/test_x509_revokedcertbuilder.py
@@ -0,0 +1,160 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import datetime
+
+import pytest
+
+from cryptography import x509
+from cryptography.hazmat.backends.interfaces import X509Backend
+
+
+class TestRevokedCertificateBuilder(object):
+    def test_serial_number_must_be_integer(self):
+        with pytest.raises(TypeError):
+            x509.RevokedCertificateBuilder().serial_number("notanx509name")
+
+    def test_serial_number_must_be_non_negative(self):
+        with pytest.raises(ValueError):
+            x509.RevokedCertificateBuilder().serial_number(-1)
+
+    def test_serial_number_must_be_less_than_160_bits_long(self):
+        with pytest.raises(ValueError):
+            # 2 raised to the 160th power is actually 161 bits
+            x509.RevokedCertificateBuilder().serial_number(2 ** 160)
+
+    def test_set_serial_number_twice(self):
+        builder = x509.RevokedCertificateBuilder().serial_number(3)
+        with pytest.raises(ValueError):
+            builder.serial_number(4)
+
+    def test_revocation_date_invalid(self):
+        with pytest.raises(TypeError):
+            x509.RevokedCertificateBuilder().revocation_date("notadatetime")
+
+    def test_revocation_date_before_unix_epoch(self):
+        with pytest.raises(ValueError):
+            x509.RevokedCertificateBuilder().revocation_date(
+                datetime.datetime(1960, 8, 10)
+            )
+
+    def test_set_revocation_date_twice(self):
+        builder = x509.RevokedCertificateBuilder().revocation_date(
+            datetime.datetime(2002, 1, 1, 12, 1)
+        )
+        with pytest.raises(ValueError):
+            builder.revocation_date(datetime.datetime(2002, 1, 1, 12, 1))
+
+    def test_add_extension_checks_for_duplicates(self):
+        builder = x509.RevokedCertificateBuilder().add_extension(
+            x509.CRLReason(x509.ReasonFlags.ca_compromise), False
+        )
+
+        with pytest.raises(ValueError):
+            builder.add_extension(
+                x509.CRLReason(x509.ReasonFlags.ca_compromise), False
+            )
+
+    def test_add_invalid_extension(self):
+        with pytest.raises(TypeError):
+            x509.RevokedCertificateBuilder().add_extension(
+                "notanextension", False
+            )
+
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_no_serial_number(self, backend):
+        builder = x509.RevokedCertificateBuilder().revocation_date(
+            datetime.datetime(2002, 1, 1, 12, 1)
+        )
+
+        with pytest.raises(ValueError):
+            builder.build(backend)
+
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_no_revocation_date(self, backend):
+        builder = x509.RevokedCertificateBuilder().serial_number(3)
+
+        with pytest.raises(ValueError):
+            builder.build(backend)
+
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_create_revoked(self, backend):
+        serial_number = 333
+        revocation_date = datetime.datetime(2002, 1, 1, 12, 1)
+        builder = x509.RevokedCertificateBuilder().serial_number(
+            serial_number
+        ).revocation_date(
+            revocation_date
+        )
+
+        revoked_certificate = builder.build(backend)
+        assert revoked_certificate.serial_number == serial_number
+        assert revoked_certificate.revocation_date == revocation_date
+        assert len(revoked_certificate.extensions) == 0
+
+    @pytest.mark.parametrize(
+        "extension",
+        [
+            x509.InvalidityDate(datetime.datetime(2015, 1, 1, 0, 0)),
+            x509.CRLReason(x509.ReasonFlags.ca_compromise),
+            x509.CertificateIssuer([
+                x509.DNSName(u"cryptography.io"),
+            ])
+        ]
+    )
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_add_extensions(self, backend, extension):
+        serial_number = 333
+        revocation_date = datetime.datetime(2002, 1, 1, 12, 1)
+        builder = x509.RevokedCertificateBuilder().serial_number(
+            serial_number
+        ).revocation_date(
+            revocation_date
+        ).add_extension(
+            extension, False
+        )
+
+        revoked_certificate = builder.build(backend)
+        assert revoked_certificate.serial_number == serial_number
+        assert revoked_certificate.revocation_date == revocation_date
+        assert len(revoked_certificate.extensions) == 1
+        ext = revoked_certificate.extensions.get_extension_for_class(
+            type(extension)
+        )
+        assert ext.critical is False
+        assert ext.value == extension
+
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_add_multiple_extensions(self, backend):
+        serial_number = 333
+        revocation_date = datetime.datetime(2002, 1, 1, 12, 1)
+        invalidity_date = x509.InvalidityDate(
+            datetime.datetime(2015, 1, 1, 0, 0)
+        )
+        certificate_issuer = x509.CertificateIssuer([
+            x509.DNSName(u"cryptography.io"),
+        ])
+        crl_reason = x509.CRLReason(x509.ReasonFlags.aa_compromise)
+        builder = x509.RevokedCertificateBuilder().serial_number(
+            serial_number
+        ).revocation_date(
+            revocation_date
+        ).add_extension(
+            invalidity_date, True
+        ).add_extension(
+            crl_reason, True
+        ).add_extension(
+            certificate_issuer, True
+        )
+
+        revoked_certificate = builder.build(backend)
+        assert len(revoked_certificate.extensions) == 3
+        for ext_data in [invalidity_date, certificate_issuer, crl_reason]:
+            ext = revoked_certificate.extensions.get_extension_for_class(
+                type(ext_data)
+            )
+            assert ext.critical is True
+            assert ext.value == ext_data
diff --git a/vectors/cryptography_vectors/__about__.py b/vectors/cryptography_vectors/__about__.py
index 63f0b57..11bd69f 100644
--- a/vectors/cryptography_vectors/__about__.py
+++ b/vectors/cryptography_vectors/__about__.py
@@ -20,4 +20,4 @@
 __email__ = "cryptography-dev@python.org"
 
 __license__ = "BSD or Apache License, Version 2.0"
-__copyright__ = "Copyright 2013-2015 %s" % __author__
+__copyright__ = "Copyright 2013-2016 %s" % __author__
diff --git a/vectors/cryptography_vectors/x509/custom/unsupported_extension_2.pem b/vectors/cryptography_vectors/x509/custom/unsupported_extension_2.pem
new file mode 100644
index 0000000..4b7d256
--- /dev/null
+++ b/vectors/cryptography_vectors/x509/custom/unsupported_extension_2.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICIjCCAQygAwIBAgIEIHHwozALBgkqhkiG9w0BAQswDzENMAsGA1UEAxMEdGVz
+dDAeFw0xNTA4MTEwOTAwMzNaFw0xNjA4MTAwOTAwMzNaMCkxJzAlBgNVBAMTHll1
+YmljbyBVMkYgRUUgU2VyaWFsIDU0NDMzODA4MzBZMBMGByqGSM49AgEGCCqGSM49
+AwEHA0IABPdFG1pBjBBQVhLrD39Qg1vKjuR2kRdBZnwLI/zgzztQpf4ffpkrkB/3
+E0TXj5zg8gN9sgMkX48geBe+tBEpvMmjOzA5MCIGCSsGAQQBgsQKAgQVMS4zLjYu
+MS40LjEuNDE0ODIuMS4yMBMGCysGAQQBguUcAgEBBAQDAgQwMAsGCSqGSIb3DQEB
+CwOCAQEAb3YpnmHHduNuWEXlLqlnww9034ZeZaojhPAYSLR8d5NPk9gc0hkjQKmI
+aaBM7DsaHbcHMKpXoMGTQSC++NCZTcKvZ0Lt12mp5HRnM1NNBPol8Hte5fLmvW4t
+Q9EzLl4gkz7LSlORxTuwTbae1eQqNdxdeB+0ilMFCEUc+3NGCNM0RWd+sP5+gzMX
+BDQAI1Sc9XaPIg8t3du5JChAl1ifpu/uERZ2WQgtxeBDO6z1Xoa5qz4svf5oURjP
+ZjxS0WUKht48Z2rIjk5lZzERSaY3RrX3UtrnZEIzCmInXOrcRPeAD4ZutpiwuHe6
+2ABsjuMRnKbATbOUiLdknNyPYYQz2g==
+-----END CERTIFICATE-----