Don't raise an UnsupportedExtension for critical extensions. (#3550)

* Don't raise an UnsupportedExtension for critical extensions.

Fixes #2903
Fixes #2901
Fixes #3325

* Don't link

* Revert "Don't link"

This reverts commit 4fe847f91d9dd45cdc28a4984c4e44aad62a5de6.

* fix

* Revert "Revert "Don't link""

This reverts commit 856031b5a1fbad04ac218fa94ebf37dcd402f3ed.

* fix

* Deprecate this

* Better changelog entry
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 8935285..8332b8b 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -15,6 +15,11 @@
   :meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey.verify`
   has always been to check whether or not
   :class:`~cryptography.exceptions.InvalidSignature` was raised.
+* Accessing an unrecognized extension marked critical on an X.509 object will
+  no longer raise an ``UnsupportedExtension`` exception, instead an
+  :class:`~cryptography.x509.UnrecognizedExtension` object will be returned.
+  This behavior was based on a poor reading of the RFC, unknown critical
+  extensions only need to be rejected on certificate verification.
 
 
 1.8.1 - 2017-03-10
@@ -488,9 +493,9 @@
   * :class:`~cryptography.x509.CertificatePolicies`
 
   Note that unsupported extensions with the critical flag raise
-  :class:`~cryptography.x509.UnsupportedExtension` while unsupported extensions
-  set to non-critical are silently ignored. Read the
-  :doc:`X.509 documentation</x509/index>` for more information.
+  ``UnsupportedExtension`` while unsupported extensions set to non-critical are
+  silently ignored. Read the :doc:`X.509 documentation</x509/index>` for more
+  information.
 
 0.8.2 - 2015-04-10
 ~~~~~~~~~~~~~~~~~~
diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst
index 1177dba..24d1c07 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -379,9 +379,6 @@
         :raises cryptography.x509.DuplicateExtension: If more than one
             extension of the same type is found within the certificate.
 
-        :raises cryptography.x509.UnsupportedExtension: If the certificate
-            contains an extension that is not supported.
-
         :raises cryptography.x509.UnsupportedGeneralNameType: If an extension
             contains a general name that is not supported.
 
@@ -773,9 +770,6 @@
         :raises cryptography.x509.DuplicateExtension: If more than one
             extension of the same type is found within the certificate signing request.
 
-        :raises cryptography.x509.UnsupportedExtension: If the certificate signing request
-            contains an extension that is not supported.
-
         :raises cryptography.x509.UnsupportedGeneralNameType: If an extension
             contains a general name that is not supported.
 
@@ -2067,10 +2061,8 @@
 
     .. 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`.
+    A generic extension class used to hold the raw value of extensions that
+    ``cryptography`` does not know how to parse.
 
     .. attribute:: oid
 
@@ -2669,17 +2661,6 @@
 
         Returns the OID.
 
-.. class:: UnsupportedExtension
-
-    This is raised when a certificate contains an unsupported extension type
-    that is marked ``critical``.
-
-    .. attribute:: oid
-
-        :type: :class:`ObjectIdentifier`
-
-        Returns the OID.
-
 .. class:: ExtensionNotFound
 
     This is raised when calling :meth:`Extensions.get_extension_for_oid` with
diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py
index b6910d9..19df4c8 100644
--- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py
+++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py
@@ -215,20 +215,14 @@
             try:
                 handler = self.handlers[oid]
             except KeyError:
-                if critical:
-                    raise x509.UnsupportedExtension(
-                        "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)
-                    )
+                # 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:
                 ext_data = backend._lib.X509V3_EXT_d2i(ext)
                 if ext_data == backend._ffi.NULL:
diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py
index bec56d5..16c0500 100644
--- a/src/cryptography/utils.py
+++ b/src/cryptography/utils.py
@@ -15,6 +15,7 @@
 # ubiquity of their use. They should not be removed until we agree on when that
 # cycle ends.
 PersistentlyDeprecated = DeprecationWarning
+DeprecatedIn19 = PendingDeprecationWarning
 
 
 def read_only_property(name):
diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py
index 38ae0f0..c5465fb 100644
--- a/src/cryptography/x509/__init__.py
+++ b/src/cryptography/x509/__init__.py
@@ -4,6 +4,7 @@
 
 from __future__ import absolute_import, division, print_function
 
+from cryptography import utils
 from cryptography.x509 import certificate_transparency
 from cryptography.x509.base import (
     Certificate, CertificateBuilder, CertificateRevocationList,
@@ -109,6 +110,12 @@
 OID_CA_ISSUERS = AuthorityInformationAccessOID.CA_ISSUERS
 OID_OCSP = AuthorityInformationAccessOID.OCSP
 
+UnsupportedExtension = utils.deprecated(
+    UnsupportedExtension,
+    __name__,
+    "UnsupportedExtension is no longer necessary, it is never raised",
+    utils.DeprecatedIn19
+)
 
 __all__ = [
     "certificate_transparency",
diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py
index ba19b3a..aa30f8f 100644
--- a/src/cryptography/x509/extensions.py
+++ b/src/cryptography/x509/extensions.py
@@ -52,9 +52,7 @@
 
 
 class UnsupportedExtension(Exception):
-    def __init__(self, msg, oid):
-        super(UnsupportedExtension, self).__init__(msg)
-        self.oid = oid
+    pass
 
 
 class ExtensionNotFound(Exception):
diff --git a/tests/test_x509.py b/tests/test_x509.py
index de19d0d..c15940e 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -438,8 +438,10 @@
             backend
         )
 
-        with pytest.raises(x509.UnsupportedExtension):
-            crl[0].extensions
+        ext = crl[0].extensions.get_extension_for_oid(
+            x509.ObjectIdentifier("1.2.3.4")
+        )
+        assert ext.value.value == b"\n\x01\x00"
 
     def test_unsupported_reason(self, backend):
         crl = _load_cert(
@@ -1129,10 +1131,10 @@
             x509.load_pem_x509_csr,
             backend
         )
-        with pytest.raises(x509.UnsupportedExtension) as exc:
-            request.extensions
-
-        assert exc.value.oid == x509.ObjectIdentifier('1.2.3.4')
+        ext = request.extensions.get_extension_for_oid(
+            x509.ObjectIdentifier('1.2.3.4')
+        )
+        assert ext.value.value == b"value"
 
     def test_unsupported_extension(self, backend):
         request = _load_cert(
diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py
index 8210b05..eaf5a51 100644
--- a/tests/test_x509_ext.py
+++ b/tests/test_x509_ext.py
@@ -1085,10 +1085,10 @@
             x509.load_pem_x509_certificate,
             backend
         )
-        with pytest.raises(x509.UnsupportedExtension) as exc:
-            cert.extensions
-
-        assert exc.value.oid == x509.ObjectIdentifier("1.2.3.4")
+        ext = cert.extensions.get_extension_for_oid(
+            x509.ObjectIdentifier("1.2.3.4")
+        )
+        assert ext.value.value == b"value"
 
     @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
     def test_unsupported_extension(self, backend):