diff options
-rw-r--r-- | CHANGELOG.rst | 1 | ||||
-rw-r--r-- | docs/x509/reference.rst | 32 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/decode_asn1.py | 7 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/encode_asn1.py | 7 | ||||
-rw-r--r-- | src/cryptography/x509/__init__.py | 5 | ||||
-rw-r--r-- | src/cryptography/x509/extensions.py | 28 | ||||
-rw-r--r-- | src/cryptography/x509/oid.py | 2 | ||||
-rw-r--r-- | tests/x509/test_x509.py | 13 | ||||
-rw-r--r-- | tests/x509/test_x509_crlbuilder.py | 1 | ||||
-rw-r--r-- | tests/x509/test_x509_ext.py | 30 |
10 files changed, 121 insertions, 5 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 51488ce7..d239d754 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -41,6 +41,7 @@ Changelog * Added support for using labels with :class:`~cryptography.hazmat.primitives.asymmetric.padding.OAEP` when using OpenSSL 1.0.2 or greater. +* Add support for the :class:`~cryptography.x509.DeltaCRLIndicator` extension. * Add support for the :class:`~cryptography.x509.TLSFeature` extension. This is commonly used for enabling ``OCSP Must-Staple`` in certificates. diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index 71ac9d99..dea7ee3b 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -1954,6 +1954,30 @@ X.509 Extensions :attr:`~cryptography.x509.oid.ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS`. +.. class:: DeltaCRLIndicator(crl_number) + + .. versionadded:: 2.1 + + The delta CRL indicator is a CRL extension that identifies a CRL as being + a delta CRL. Delta CRLs contain updates to revocation information + previously distributed, rather than all the information that would appear + in a complete CRL. + + :param int crl_number: The CRL number of the complete CRL that the + delta CRL is updating. + + .. attribute:: oid + + :type: :class:`ObjectIdentifier` + + Returns + :attr:`~cryptography.x509.oid.ExtensionOID.DELTA_CRL_INDICATOR`. + + .. attribute:: crl_number + + :type: int + + .. class:: AuthorityInformationAccess(descriptions) .. versionadded:: 0.9 @@ -2749,6 +2773,14 @@ instances. The following common OIDs are available as constants. the ``CRLNumber`` extension type. This extension only has meaning for certificate revocation lists. + .. attribute:: DELTA_CRL_INDICATOR + + .. versionadded:: 2.1 + + Corresponds to the dotted string ``"2.5.29.27"``. The identifier for + the ``DeltaCRLIndicator`` extension type. This extension only has + meaning for certificate revocation lists. + .. attribute:: PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS .. versionadded:: 1.9 diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 6ed4aeb7..1326a94e 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -152,6 +152,12 @@ def _decode_crl_number(backend, ext): return x509.CRLNumber(_asn1_integer_to_int(backend, asn1_int)) +def _decode_delta_crl_indicator(backend, ext): + asn1_int = backend._ffi.cast("ASN1_INTEGER *", ext) + asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free) + return x509.DeltaCRLIndicator(_asn1_integer_to_int(backend, asn1_int)) + + class _X509ExtensionParser(object): def __init__(self, ext_count, get_ext, handlers): self.ext_count = ext_count @@ -742,6 +748,7 @@ _REVOKED_EXTENSION_HANDLERS = { _CRL_EXTENSION_HANDLERS = { ExtensionOID.CRL_NUMBER: _decode_crl_number, + ExtensionOID.DELTA_CRL_INDICATOR: _decode_delta_crl_indicator, ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier, ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name, ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( diff --git a/src/cryptography/hazmat/backends/openssl/encode_asn1.py b/src/cryptography/hazmat/backends/openssl/encode_asn1.py index 6d9f9567..5ceb29c0 100644 --- a/src/cryptography/hazmat/backends/openssl/encode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/encode_asn1.py @@ -133,8 +133,8 @@ def _encode_name_entry(backend, attribute): return name_entry -def _encode_crl_number(backend, crl_number): - return _encode_asn1_int_gc(backend, crl_number.crl_number) +def _encode_crl_number_delta_crl_indicator(backend, ext): + return _encode_asn1_int_gc(backend, ext.crl_number) def _encode_crl_reason(backend, crl_reason): @@ -598,7 +598,8 @@ _CRL_EXTENSION_ENCODE_HANDLERS = { ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( _encode_authority_information_access ), - ExtensionOID.CRL_NUMBER: _encode_crl_number, + ExtensionOID.CRL_NUMBER: _encode_crl_number_delta_crl_indicator, + ExtensionOID.DELTA_CRL_INDICATOR: _encode_crl_number_delta_crl_indicator, } _CRL_ENTRY_EXTENSION_ENCODE_HANDLERS = { diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py index 176ed8ca..e168adb7 100644 --- a/src/cryptography/x509/__init__.py +++ b/src/cryptography/x509/__init__.py @@ -18,8 +18,8 @@ from cryptography.x509.extensions import ( AccessDescription, AuthorityInformationAccess, AuthorityKeyIdentifier, BasicConstraints, CRLDistributionPoints, CRLNumber, CRLReason, CertificateIssuer, CertificatePolicies, - DistributionPoint, DuplicateExtension, ExtendedKeyUsage, Extension, - ExtensionNotFound, ExtensionType, Extensions, GeneralNames, + DeltaCRLIndicator, DistributionPoint, DuplicateExtension, ExtendedKeyUsage, + Extension, ExtensionNotFound, ExtensionType, Extensions, GeneralNames, InhibitAnyPolicy, InvalidityDate, IssuerAlternativeName, KeyUsage, NameConstraints, NoticeReference, OCSPNoCheck, PolicyConstraints, PolicyInformation, PrecertificateSignedCertificateTimestamps, ReasonFlags, @@ -119,6 +119,7 @@ __all__ = [ "load_der_x509_crl", "random_serial_number", "InvalidVersion", + "DeltaCRLIndicator", "DuplicateExtension", "ExtensionNotFound", "UnsupportedGeneralNameType", diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 442000e3..beb20bad 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -376,6 +376,34 @@ class BasicConstraints(object): @utils.register_interface(ExtensionType) +class DeltaCRLIndicator(object): + oid = ExtensionOID.DELTA_CRL_INDICATOR + + def __init__(self, crl_number): + if not isinstance(crl_number, six.integer_types): + raise TypeError("crl_number must be an integer") + + self._crl_number = crl_number + + crl_number = utils.read_only_property("_crl_number") + + def __eq__(self, other): + if not isinstance(other, DeltaCRLIndicator): + return NotImplemented + + return self.crl_number == other.crl_number + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.crl_number) + + def __repr__(self): + return "<DeltaCRLIndicator(crl_number={0.crl_number})>".format(self) + + +@utils.register_interface(ExtensionType) class CRLDistributionPoints(object): oid = ExtensionOID.CRL_DISTRIBUTION_POINTS diff --git a/src/cryptography/x509/oid.py b/src/cryptography/x509/oid.py index 7f8c9031..fedea310 100644 --- a/src/cryptography/x509/oid.py +++ b/src/cryptography/x509/oid.py @@ -87,6 +87,7 @@ class ExtensionOID(object): OCSP_NO_CHECK = ObjectIdentifier("1.3.6.1.5.5.7.48.1.5") TLS_FEATURE = ObjectIdentifier("1.3.6.1.5.5.7.1.24") CRL_NUMBER = ObjectIdentifier("2.5.29.20") + DELTA_CRL_INDICATOR = ObjectIdentifier("2.5.29.27") PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS = ( ObjectIdentifier("1.3.6.1.4.1.11129.2.4.2") ) @@ -256,6 +257,7 @@ _OID_NAMES = { ExtensionOID.SUBJECT_INFORMATION_ACCESS: "subjectInfoAccess", ExtensionOID.OCSP_NO_CHECK: "OCSPNoCheck", ExtensionOID.CRL_NUMBER: "cRLNumber", + ExtensionOID.DELTA_CRL_INDICATOR: "deltaCRLIndicator", ExtensionOID.TLS_FEATURE: "TLSFeature", AuthorityInformationAccessOID.OCSP: "OCSP", AuthorityInformationAccessOID.CA_ISSUERS: "caIssuers", diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 1833a4a2..d0ce46d8 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -232,6 +232,19 @@ class TestCertificateRevocationList(object): x509.UniformResourceIdentifier(b"https://cryptography.io"), ]) + def test_delta_crl_indicator(self, backend): + crl = _load_cert( + os.path.join("x509", "custom", "crl_delta_crl_indicator.pem"), + x509.load_pem_x509_crl, + backend + ) + + dci = crl.extensions.get_extension_for_oid( + ExtensionOID.DELTA_CRL_INDICATOR + ) + assert dci.value == x509.DeltaCRLIndicator(12345678901234567890) + assert dci.critical is False + def test_signature(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_all_reasons.pem"), diff --git a/tests/x509/test_x509_crlbuilder.py b/tests/x509/test_x509_crlbuilder.py index b90805ff..e90fd3fd 100644 --- a/tests/x509/test_x509_crlbuilder.py +++ b/tests/x509/test_x509_crlbuilder.py @@ -209,6 +209,7 @@ class TestCertificateRevocationListBuilder(object): "extension", [ x509.CRLNumber(13), + x509.DeltaCRLIndicator(12345678901234567890), x509.AuthorityKeyIdentifier( b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08" b"\xcbY", diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index b9400b64..9f0b1b0b 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -326,6 +326,36 @@ class TestCRLReason(object): ) +class TestDeltaCRLIndicator(object): + def test_not_int(self): + with pytest.raises(TypeError): + x509.DeltaCRLIndicator("notanint") + + def test_eq(self): + delta1 = x509.DeltaCRLIndicator(1) + delta2 = x509.DeltaCRLIndicator(1) + assert delta1 == delta2 + + def test_ne(self): + delta1 = x509.DeltaCRLIndicator(1) + delta2 = x509.DeltaCRLIndicator(2) + assert delta1 != delta2 + assert delta1 != object() + + def test_repr(self): + delta1 = x509.DeltaCRLIndicator(2) + assert repr(delta1) == ( + "<DeltaCRLIndicator(crl_number=2)>" + ) + + def test_hash(self): + delta1 = x509.DeltaCRLIndicator(1) + delta2 = x509.DeltaCRLIndicator(1) + delta3 = x509.DeltaCRLIndicator(2) + assert hash(delta1) == hash(delta2) + assert hash(delta1) != hash(delta3) + + class TestInvalidityDate(object): def test_invalid_invalidity_date(self): with pytest.raises(TypeError): |