aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2015-12-25 22:35:19 -0600
committerPaul Kehrer <paul.l.kehrer@gmail.com>2015-12-26 11:19:02 -0600
commit23c0bbc2dc007aa507b22f407c3a0048be98a1a4 (patch)
tree42370a4977fa7365d2e3d1aa9a9ffeaf71afbc9c
parentd67d77f666417bff7ea52e2754f7a680c7a83b0c (diff)
downloadcryptography-23c0bbc2dc007aa507b22f407c3a0048be98a1a4.tar.gz
cryptography-23c0bbc2dc007aa507b22f407c3a0048be98a1a4.tar.bz2
cryptography-23c0bbc2dc007aa507b22f407c3a0048be98a1a4.zip
add invaliditydate class for crl entry extensions
-rw-r--r--CHANGELOG.rst2
-rw-r--r--docs/x509/reference.rst27
-rw-r--r--src/cryptography/hazmat/backends/openssl/x509.py4
-rw-r--r--src/cryptography/x509/__init__.py3
-rw-r--r--src/cryptography/x509/extensions.py28
-rw-r--r--tests/test_x509.py6
-rw-r--r--tests/test_x509_ext.py24
7 files changed, 87 insertions, 7 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 4052ff50..39c6f611 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -16,7 +16,7 @@ Changelog
* :class:`~cryptography.x509.CertificateIssuer`
* :class:`~cryptography.x509.CRLReason`
- * ``InvalidityDate``
+ * :class:`~cryptography.x509.InvalidityDate`
* The :class:`~cryptography.x509.Certificate` class now has
:attr:`~cryptography.x509.Certificate.signature` and
:attr:`~cryptography.x509.Certificate.tbs_certificate_bytes` attributes.
diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst
index 51de0747..72fd44be 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -907,7 +907,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.24, name=invalidityDate)>, critical=False, value=<InvalidityDate(invalidity_date=2015-01-01 00:00:00)>)>
<Extension(oid=<ObjectIdentifier(oid=2.5.29.21, name=cRLReason)>, critical=False, value=<CRLReason(reason=ReasonFlags.key_compromise)>)>
X.509 Revoked Certificate Builder
@@ -2011,6 +2011,31 @@ These extensions are only valid within a :class:`RevokedCertificate` object.
:type: An element from :class:`~cryptography.x509.ReasonFlags`
+.. class:: InvalidityDate(invalidity_date)
+
+ .. versionadded:: 1.2
+
+ Invalidity date is an extension that is only valid inside
+ :class:`~cryptography.x509.RevokedCertificate` objects. It provides
+ the date on which it is known or suspected that the private key was
+ compromised or that the certificate otherwise became invalid.
+ This date may be earlier than the revocation date in the CRL entry,
+ which is the date at which the CA processed the revocation.
+
+ :param invalidity_date: The :class:`datetime.datetime` when it is known
+ or suspected that the private key was compromised.
+
+ .. attribute:: oid
+
+ :type: :class:`ObjectIdentifier`
+
+ Returns
+ :attr:`~cryptography.x509.oid.CRLEntryExtensionOID.INVALIDITY_DATE`.
+
+ .. attribute:: invalidity_date
+
+ :type: :class:`datetime.datetime`
+
Object Identifiers
~~~~~~~~~~~~~~~~~~
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index 2650b5d4..1376ab72 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -717,7 +717,9 @@ def _decode_invalidity_date(backend, inv_date):
backend._ffi.cast("ASN1_STRING *", generalized_time)
)
).decode("ascii")
- return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ")
+ return x509.InvalidityDate(
+ datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ")
+ )
def _decode_cert_issuer(backend, ext):
diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py
index 89e7f063..dc19161e 100644
--- a/src/cryptography/x509/__init__.py
+++ b/src/cryptography/x509/__init__.py
@@ -18,7 +18,7 @@ from cryptography.x509.extensions import (
CRLNumber, CRLReason, CertificateIssuer, CertificatePolicies,
DistributionPoint, DuplicateExtension, ExtendedKeyUsage, Extension,
ExtensionNotFound, ExtensionType, Extensions, GeneralNames,
- InhibitAnyPolicy, IssuerAlternativeName, KeyUsage,
+ InhibitAnyPolicy, InvalidityDate, IssuerAlternativeName, KeyUsage,
NameConstraints, NoticeReference, OCSPNoCheck, PolicyInformation,
ReasonFlags, SubjectAlternativeName, SubjectKeyIdentifier,
UnsupportedExtension, UserNotice
@@ -168,4 +168,5 @@ __all__ = [
"CRLExtensionOID",
"CertificateIssuer",
"CRLReason",
+ "InvalidityDate",
]
diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py
index 6ae00927..22cba682 100644
--- a/src/cryptography/x509/extensions.py
+++ b/src/cryptography/x509/extensions.py
@@ -5,6 +5,7 @@
from __future__ import absolute_import, division, print_function
import abc
+import datetime
import hashlib
import ipaddress
from enum import Enum
@@ -1001,3 +1002,30 @@ class CRLReason(object):
return not self == other
reason = utils.read_only_property("_reason")
+
+
+@utils.register_interface(ExtensionType)
+class InvalidityDate(object):
+ oid = CRLEntryExtensionOID.INVALIDITY_DATE
+
+ def __init__(self, invalidity_date):
+ if not isinstance(invalidity_date, datetime.datetime):
+ raise TypeError("invalidity_date must be a datetime.datetime")
+
+ self._invalidity_date = invalidity_date
+
+ def __repr__(self):
+ return "<InvalidityDate(invalidity_date={0})>".format(
+ self._invalidity_date
+ )
+
+ def __eq__(self, other):
+ if not isinstance(other, InvalidityDate):
+ return NotImplemented
+
+ return self.invalidity_date == other.invalidity_date
+
+ def __ne__(self, other):
+ return not self == other
+
+ invalidity_date = utils.read_only_property("_invalidity_date")
diff --git a/tests/test_x509.py b/tests/test_x509.py
index 757df442..560324b0 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -387,9 +387,9 @@ class TestRevokedCertificate(object):
x509.CertificateIssuer).value
assert issuer == x509.CertificateIssuer(exp_issuer)
- date = rev1.extensions.get_extension_for_oid(
- x509.OID_INVALIDITY_DATE).value
- assert date == datetime.datetime(2015, 1, 1, 0, 0)
+ date = rev1.extensions.get_extension_for_class(
+ x509.InvalidityDate).value
+ assert date == x509.InvalidityDate(datetime.datetime(2015, 1, 1, 0, 0))
# Check if all reason flags can be found in the CRL.
flags = set(x509.ReasonFlags)
diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py
index b8105a4b..91a07654 100644
--- a/tests/test_x509_ext.py
+++ b/tests/test_x509_ext.py
@@ -5,6 +5,7 @@
from __future__ import absolute_import, division, print_function
import binascii
+import datetime
import ipaddress
import os
@@ -135,6 +136,29 @@ class TestCRLReason(object):
)
+class TestInvalidityDate(object):
+ def test_invalid_invalidity_date(self):
+ with pytest.raises(TypeError):
+ x509.InvalidityDate("notadate")
+
+ def test_eq(self):
+ invalid1 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1))
+ invalid2 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1))
+ assert invalid1 == invalid2
+
+ def test_ne(self):
+ invalid1 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1))
+ invalid2 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 2))
+ assert invalid1 != invalid2
+ assert invalid1 != object()
+
+ def test_repr(self):
+ invalid1 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1))
+ assert repr(invalid1) == (
+ "<InvalidityDate(invalidity_date=2015-01-01 01:01:00)>"
+ )
+
+
class TestNoticeReference(object):
def test_notice_numbers_not_all_int(self):
with pytest.raises(TypeError):