aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rst2
-rw-r--r--docs/x509/reference.rst24
-rw-r--r--src/cryptography/hazmat/backends/openssl/x509.py2
-rw-r--r--src/cryptography/x509/__init__.py3
-rw-r--r--src/cryptography/x509/extensions.py25
-rw-r--r--tests/test_x509.py10
-rw-r--r--tests/test_x509_ext.py23
7 files changed, 80 insertions, 9 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index ab6468d8..4052ff50 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -15,7 +15,7 @@ Changelog
are:
* :class:`~cryptography.x509.CertificateIssuer`
- * ``CRLReason``
+ * :class:`~cryptography.x509.CRLReason`
* ``InvalidityDate``
* The :class:`~cryptography.x509.Certificate` class now has
:attr:`~cryptography.x509.Certificate.signature` and
diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst
index 1f25ac14..51de0747 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -908,7 +908,7 @@ X.509 Revoked Certificate Object
>>> 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.21, name=cRLReason)>, critical=False, value=<CRLReason(reason=ReasonFlags.key_compromise)>)>
X.509 Revoked Certificate Builder
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1989,6 +1989,28 @@ These extensions are only valid within a :class:`RevokedCertificate` object.
: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`
+
Object Identifiers
~~~~~~~~~~~~~~~~~~
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index 05390809..2650b5d4 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -700,7 +700,7 @@ def _decode_crl_reason(backend, enum):
code = backend._lib.ASN1_ENUMERATED_get(enum)
try:
- return _CRL_REASON_CODE_TO_ENUM[code]
+ return x509.CRLReason(_CRL_REASON_CODE_TO_ENUM[code])
except KeyError:
raise ValueError("Unsupported reason code: {0}".format(code))
diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py
index 9946daa0..89e7f063 100644
--- a/src/cryptography/x509/__init__.py
+++ b/src/cryptography/x509/__init__.py
@@ -15,7 +15,7 @@ from cryptography.x509.base import (
from cryptography.x509.extensions import (
AccessDescription, AuthorityInformationAccess,
AuthorityKeyIdentifier, BasicConstraints, CRLDistributionPoints,
- CRLNumber, CertificateIssuer, CertificatePolicies,
+ CRLNumber, CRLReason, CertificateIssuer, CertificatePolicies,
DistributionPoint, DuplicateExtension, ExtendedKeyUsage, Extension,
ExtensionNotFound, ExtensionType, Extensions, GeneralNames,
InhibitAnyPolicy, IssuerAlternativeName, KeyUsage,
@@ -167,4 +167,5 @@ __all__ = [
"_GENERAL_NAMES",
"CRLExtensionOID",
"CertificateIssuer",
+ "CRLReason",
]
diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py
index 3c017ea1..6ae00927 100644
--- a/src/cryptography/x509/extensions.py
+++ b/src/cryptography/x509/extensions.py
@@ -976,3 +976,28 @@ class CertificateIssuer(object):
def __ne__(self, other):
return not self == other
+
+
+@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
+
+ reason = utils.read_only_property("_reason")
diff --git a/tests/test_x509.py b/tests/test_x509.py
index c91f08ba..757df442 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -379,9 +379,9 @@ class TestRevokedCertificate(object):
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_class(
x509.CertificateIssuer).value
@@ -395,12 +395,12 @@ class TestRevokedCertificate(object):
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
diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py
index 037512a4..b8105a4b 100644
--- a/tests/test_x509_ext.py
+++ b/tests/test_x509_ext.py
@@ -112,6 +112,29 @@ class TestCertificateIssuer(object):
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_repr(self):
+ reason1 = x509.CRLReason(x509.ReasonFlags.unspecified)
+ assert repr(reason1) == (
+ "<CRLReason(reason=ReasonFlags.unspecified)>"
+ )
+
+
class TestNoticeReference(object):
def test_notice_numbers_not_all_int(self):
with pytest.raises(TypeError):