Repository: pyca/cryptography

Issue:
Support CRL extensions
Right now we support extensions on revoked certificates within the CRL, but ignore all top level CRL extensions. A list is available in section 5.2 of RFC 5280 (https://tools.ietf.org/html/rfc5280#section-5.2)



Discussion:

Resolving patch:
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -179,6 +179,12 @@ def _decode_ocsp_no_check(backend, ext):
     return x509.OCSPNoCheck()
 
 
+def _decode_crl_number(backend, ext):
+    asn1_int = backend._ffi.cast("ASN1_INTEGER *", ext)
+    asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free)
+    return backend._asn1_integer_to_int(asn1_int)
+
+
 class _X509ExtensionParser(object):
     def __init__(self, ext_count, get_ext, handlers, unsupported_exts=None):
         self.ext_count = ext_count
@@ -870,7 +876,7 @@ def __len__(self):
 
     @property
     def extensions(self):
-        raise NotImplementedError()
+        return _CRL_EXTENSION_PARSER.parse(self._backend, self._x509_crl)
 
 
 @utils.register_interface(x509.CertificateSigningRequest)
@@ -978,6 +984,11 @@ def signature(self):
     CRLExtensionOID.CERTIFICATE_ISSUER,
 ])
 
+_CRL_EXTENSION_HANDLERS = {
+    ExtensionOID.CRL_NUMBER: _decode_crl_number,
+    ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier,
+}
+
 _CERTIFICATE_EXTENSION_PARSER = _X509ExtensionParser(
     ext_count=lambda backend, x: backend._lib.X509_get_ext_count(x),
     get_ext=lambda backend, x, i: backend._lib.X509_get_ext(x, i),
@@ -996,3 +1007,9 @@ def signature(self):
     handlers=_REVOKED_EXTENSION_HANDLERS,
     unsupported_exts=_REVOKED_UNSUPPORTED_EXTENSIONS
 )
+
+_CRL_EXTENSION_PARSER = _X509ExtensionParser(
+    ext_count=lambda backend, x: backend._lib.X509_CRL_get_ext_count(x),
+    get_ext=lambda backend, x, i: backend._lib.X509_CRL_get_ext(x, i),
+    handlers=_CRL_EXTENSION_HANDLERS,
+)
diff --git a/src/cryptography/x509/oid.py b/src/cryptography/x509/oid.py
--- a/src/cryptography/x509/oid.py
+++ b/src/cryptography/x509/oid.py
@@ -85,6 +85,7 @@ class ExtensionOID(object):
     AUTHORITY_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.1")
     SUBJECT_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.11")
     OCSP_NO_CHECK = ObjectIdentifier("1.3.6.1.5.5.7.48.1.5")
+    CRL_NUMBER = ObjectIdentifier("2.5.29.20")
 
 
 class CRLExtensionOID(object):
@@ -234,6 +235,7 @@ class CertificatePoliciesOID(object):
     ExtensionOID.AUTHORITY_INFORMATION_ACCESS: "authorityInfoAccess",
     ExtensionOID.SUBJECT_INFORMATION_ACCESS: "subjectInfoAccess",
     ExtensionOID.OCSP_NO_CHECK: "OCSPNoCheck",
+    ExtensionOID.CRL_NUMBER: "cRLNumber",
     AuthorityInformationAccessOID.OCSP: "OCSP",
     AuthorityInformationAccessOID.CA_ISSUERS: "caIssuers",
     CertificatePoliciesOID.CPS_QUALIFIER: "id-qt-cps",


Test patch:
diff --git a/tests/test_x509.py b/tests/test_x509.py
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -175,14 +175,26 @@ def test_revoked_cert_retrieval(self, backend):
 
     def test_extensions(self, backend):
         crl = _load_cert(
-            os.path.join("x509", "custom", "crl_all_reasons.pem"),
-            x509.load_pem_x509_crl,
+            os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"),
+            x509.load_der_x509_crl,
             backend
         )
 
-        # CRL extensions are currently not supported in the OpenSSL backend.
-        with pytest.raises(NotImplementedError):
-            crl.extensions
+        crl_number = crl.extensions.get_extension_for_oid(
+            ExtensionOID.CRL_NUMBER
+        )
+        aki = crl.extensions.get_extension_for_class(
+            x509.AuthorityKeyIdentifier
+        )
+        assert crl_number.value == 1
+        assert crl_number.critical is False
+        assert aki.value == x509.AuthorityKeyIdentifier(
+            key_identifier=(
+                b'X\x01\x84$\x1b\xbc+R\x94J=\xa5\x10r\x14Q\xf5\xaf:\xc9'
+            ),
+            authority_cert_issuer=None,
+            authority_cert_serial_number=None
+        )
 
     def test_signature(self, backend):
         crl = _load_cert(