Merge pull request #2217 from reaperhulk/extensions-oids

Add OIDs to extension types and add ExtensionType interface
diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst
index 61971fe..baf8b1e 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -909,14 +909,28 @@
 
         Returns an instance of the extension type corresponding to the OID.
 
+.. class:: ExtensionType
+
+    .. versionadded:: 1.0
+
+    This is the interface against which all the following extension types are
+    registered.
+
 .. class:: KeyUsage
 
     .. versionadded:: 0.9
 
     The key usage extension defines the purpose of the key contained in the
     certificate.  The usage restriction might be employed when a key that could
-    be used for more than one operation is to be restricted. It corresponds to
-    :data:`OID_KEY_USAGE`.
+    be used for more than one operation is to be restricted.
+
+    .. attribute:: oid
+
+        .. versionadded:: 1.0
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns :data:`OID_KEY_USAGE`.
 
     .. attribute:: digital_signature
 
@@ -1007,8 +1021,15 @@
 
     Basic constraints is an X.509 extension type that defines whether a given
     certificate is allowed to sign additional certificates and what path
-    length restrictions may exist. It corresponds to
-    :data:`OID_BASIC_CONSTRAINTS`.
+    length restrictions may exist.
+
+    .. attribute:: oid
+
+        .. versionadded:: 1.0
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns :data:`OID_BASIC_CONSTRAINTS`.
 
     .. attribute:: ca
 
@@ -1038,6 +1059,15 @@
     purposes indicated in the key usage extension. The object is
     iterable to obtain the list of :ref:`extended key usage OIDs <eku_oids>`.
 
+    .. attribute:: oid
+
+        .. versionadded:: 1.0
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns :data:`OID_EXTENDED_KEY_USAGE`.
+
+
 .. class:: OCSPNoCheck
 
     .. versionadded:: 1.0
@@ -1051,6 +1081,14 @@
     extension is only relevant when the certificate is an authorized OCSP
     responder.
 
+    .. attribute:: oid
+
+        .. versionadded:: 1.0
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns :data:`OID_OCSP_NO_CHECK`.
+
 .. class:: NameConstraints
 
     .. versionadded:: 1.0
@@ -1060,6 +1098,14 @@
     beneath the CA certificate must (or must not) be in. For specific details
     on the way this extension should be processed see :rfc:`5280`.
 
+    .. attribute:: oid
+
+        .. versionadded:: 1.0
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns :data:`OID_NAME_CONSTRAINTS`.
+
     .. attribute:: permitted_subtrees
 
         :type: list of :class:`GeneralName` objects or None
@@ -1087,6 +1133,14 @@
     certificate chain. For more information about generation and use of this
     extension see `RFC 5280 section 4.2.1.1`_.
 
+    .. attribute:: oid
+
+        .. versionadded:: 1.0
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns :data:`OID_AUTHORITY_KEY_IDENTIFIER`.
+
     .. attribute:: key_identifier
 
         :type: bytes
@@ -1113,6 +1167,14 @@
     The subject key identifier extension provides a means of identifying
     certificates that contain a particular public key.
 
+    .. attribute:: oid
+
+        .. versionadded:: 1.0
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns :data:`OID_SUBJECT_KEY_IDENTIFIER`.
+
     .. attribute:: digest
 
         :type: bytes
@@ -1128,6 +1190,14 @@
     of identities for which the certificate is valid. The object is iterable to
     get every element.
 
+    .. attribute:: oid
+
+        .. versionadded:: 1.0
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns :data:`OID_SUBJECT_ALTERNATIVE_NAME`.
+
     .. method:: get_values_for_type(type)
 
         :param type: A :class:`GeneralName` provider. This is one of the
@@ -1158,6 +1228,14 @@
     of identities for the certificate issuer. The object is iterable to
     get every element.
 
+    .. attribute:: oid
+
+        .. versionadded:: 1.0
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns :data:`OID_ISSUER_ALTERNATIVE_NAME`.
+
     .. method:: get_values_for_type(type)
 
         :param type: A :class:`GeneralName` provider. This is one of the
@@ -1176,6 +1254,14 @@
     validation services (such as OCSP) and issuer data. It is an iterable,
     containing one or more :class:`AccessDescription` instances.
 
+    .. attribute:: oid
+
+        .. versionadded:: 1.0
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns :data:`OID_AUTHORITY_INFORMATION_ACCESS`.
+
 
 .. class:: AccessDescription
 
@@ -1206,6 +1292,14 @@
     obtained. It is an iterable, containing one or more
     :class:`DistributionPoint` instances.
 
+    .. attribute:: oid
+
+        .. versionadded:: 1.0
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns :data:`OID_CRL_DISTRIBUTION_POINTS`.
+
 .. class:: DistributionPoint
 
     .. versionadded:: 0.9
@@ -1304,6 +1398,14 @@
     certificates issued by the subject of this certificate, but not in
     additional certificates in the path.
 
+    .. attribute:: oid
+
+        .. versionadded:: 1.0
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns :data:`OID_INHIBIT_ANY_POLICY`.
+
     .. attribute:: skip_certs
 
         :type: int
@@ -1315,6 +1417,14 @@
     The certificate policies extension is an iterable, containing one or more
     :class:`PolicyInformation` instances.
 
+    .. attribute:: oid
+
+        .. versionadded:: 1.0
+
+        :type: :class:`ObjectIdentifier`
+
+        Returns :data:`OID_CERTIFICATE_POLICIES`.
+
 Certificate Policies Classes
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -1668,6 +1778,11 @@
     Corresponds to the dotted string ``"1.3.6.1.5.5.7.1.1"``. The identifier
     for the :class:`AuthorityInformationAccess` extension type.
 
+.. data:: OID_INHIBIT_ANY_POLICY
+
+    Corresponds to the dotted string ``"2.5.29.54"``. The identifier
+    for the :class:`InhibitAnyPolicy` extension type.
+
 .. data:: OID_OCSP_NO_CHECK
 
     Corresponds to the dotted string ``"1.3.6.1.5.5.7.48.1.5"``. The identifier
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py
index 02e938a..08a0c7c 100644
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -313,7 +313,19 @@
         return not self == other
 
 
+@six.add_metaclass(abc.ABCMeta)
+class ExtensionType(object):
+    @abc.abstractproperty
+    def oid(self):
+        """
+        Returns the oid associated with the given extension type.
+        """
+
+
+@utils.register_interface(ExtensionType)
 class ExtendedKeyUsage(object):
+    oid = OID_EXTENDED_KEY_USAGE
+
     def __init__(self, usages):
         if not all(isinstance(x, ObjectIdentifier) for x in usages):
             raise TypeError(
@@ -341,11 +353,15 @@
         return not self == other
 
 
+@utils.register_interface(ExtensionType)
 class OCSPNoCheck(object):
-    pass
+    oid = OID_OCSP_NO_CHECK
 
 
+@utils.register_interface(ExtensionType)
 class BasicConstraints(object):
+    oid = OID_BASIC_CONSTRAINTS
+
     def __init__(self, ca, path_length):
         if not isinstance(ca, bool):
             raise TypeError("ca must be a boolean value")
@@ -381,7 +397,10 @@
         return not self == other
 
 
+@utils.register_interface(ExtensionType)
 class KeyUsage(object):
+    oid = OID_KEY_USAGE
+
     def __init__(self, digital_signature, content_commitment, key_encipherment,
                  data_encipherment, key_agreement, key_cert_sign, crl_sign,
                  encipher_only, decipher_only):
@@ -464,7 +483,10 @@
         return not self == other
 
 
+@utils.register_interface(ExtensionType)
 class AuthorityInformationAccess(object):
+    oid = OID_AUTHORITY_INFORMATION_ACCESS
+
     def __init__(self, descriptions):
         if not all(isinstance(x, AccessDescription) for x in descriptions):
             raise TypeError(
@@ -528,7 +550,10 @@
     access_location = utils.read_only_property("_access_location")
 
 
+@utils.register_interface(ExtensionType)
 class CertificatePolicies(object):
+    oid = OID_CERTIFICATE_POLICIES
+
     def __init__(self, policies):
         if not all(isinstance(x, PolicyInformation) for x in policies):
             raise TypeError(
@@ -665,7 +690,10 @@
     notice_numbers = utils.read_only_property("_notice_numbers")
 
 
+@utils.register_interface(ExtensionType)
 class SubjectKeyIdentifier(object):
+    oid = OID_SUBJECT_KEY_IDENTIFIER
+
     def __init__(self, digest):
         self._digest = digest
 
@@ -686,7 +714,10 @@
         return not self == other
 
 
+@utils.register_interface(ExtensionType)
 class NameConstraints(object):
+    oid = OID_NAME_CONSTRAINTS
+
     def __init__(self, permitted_subtrees, excluded_subtrees):
         if permitted_subtrees is not None:
             if not all(
@@ -750,7 +781,10 @@
     excluded_subtrees = utils.read_only_property("_excluded_subtrees")
 
 
+@utils.register_interface(ExtensionType)
 class CRLDistributionPoints(object):
+    oid = OID_CRL_DISTRIBUTION_POINTS
+
     def __init__(self, distribution_points):
         if not all(
             isinstance(x, DistributionPoint) for x in distribution_points
@@ -870,7 +904,10 @@
     remove_from_crl = "removeFromCRL"
 
 
+@utils.register_interface(ExtensionType)
 class InhibitAnyPolicy(object):
+    oid = OID_INHIBIT_ANY_POLICY
+
     def __init__(self, skip_certs):
         if not isinstance(skip_certs, six.integer_types):
             raise TypeError("skip_certs must be an integer")
@@ -1160,7 +1197,10 @@
         return not self == other
 
 
+@utils.register_interface(ExtensionType)
 class SubjectAlternativeName(object):
+    oid = OID_SUBJECT_ALTERNATIVE_NAME
+
     def __init__(self, general_names):
         self._general_names = GeneralNames(general_names)
 
@@ -1186,7 +1226,10 @@
         return not self == other
 
 
+@utils.register_interface(ExtensionType)
 class IssuerAlternativeName(object):
+    oid = OID_ISSUER_ALTERNATIVE_NAME
+
     def __init__(self, general_names):
         self._general_names = GeneralNames(general_names)
 
@@ -1212,7 +1255,10 @@
         return not self == other
 
 
+@utils.register_interface(ExtensionType)
 class AuthorityKeyIdentifier(object):
+    oid = OID_AUTHORITY_KEY_IDENTIFIER
+
     def __init__(self, key_identifier, authority_cert_issuer,
                  authority_cert_serial_number):
         if authority_cert_issuer or authority_cert_serial_number: