aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFacundo Tuesca <facundo.tuesca@trailofbits.com>2024-04-21 21:09:12 +0200
committerGitHub <noreply@github.com>2024-04-21 15:09:12 -0400
commit83d90df3df4b3e858119348d06ffffd3c4cbd706 (patch)
treed1de418a663f936d5b97b851966f1323ecf0ebea
parentad2427d43170a6df9774059eb6abf96fe3ff408a (diff)
downloadpyca-cryptography-83d90df3df4b3e858119348d06ffffd3c4cbd706.zip
pyca-cryptography-83d90df3df4b3e858119348d06ffffd3c4cbd706.tar.gz
pyca-cryptography-83d90df3df4b3e858119348d06ffffd3c4cbd706.tar.bz2
Add timezone-aware API variant for `x509.InvalidityDate.invalidity_date` (#10848)
-rw-r--r--CHANGELOG.rst3
-rw-r--r--docs/x509/reference.rst8
-rw-r--r--src/cryptography/x509/extensions.py7
-rw-r--r--src/rust/src/x509/extensions.rs2
-rw-r--r--tests/x509/test_x509_ext.py20
5 files changed, 39 insertions, 1 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 8a97f7d..e7153b2 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -41,6 +41,9 @@ Changelog
:attr:`~cryptography.x509.CertificateSigningRequest.public_key_algorithm_oid`
to determine the :class:`~cryptography.hazmat._oid.PublicKeyAlgorithmOID`
Object Identifier of the public key found inside the certificate.
+* Added :attr:`~cryptography.x509.InvalidityDate.invalidity_date_utc`, a
+ timezone-aware alternative to the naïve ``datetime`` attribute
+ :attr:`~cryptography.x509.InvalidityDate.invalidity_date`.
.. _v42-0-5:
diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst
index 0d0db19..6aa0f66 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -3148,6 +3148,14 @@ These extensions are only valid within a :class:`RevokedCertificate` object.
:type: :class:`datetime.datetime`
+ .. attribute:: invalidity_date_utc
+
+ .. versionadded:: 43.0.0
+
+ :type: :class:`datetime.datetime`
+
+ The invalidity date in UTC as a timezone-aware datetime object.
+
OCSP Extensions
~~~~~~~~~~~~~~~
diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py
index 1842a9e..5e7486a 100644
--- a/src/cryptography/x509/extensions.py
+++ b/src/cryptography/x509/extensions.py
@@ -1788,6 +1788,13 @@ class InvalidityDate(ExtensionType):
def invalidity_date(self) -> datetime.datetime:
return self._invalidity_date
+ @property
+ def invalidity_date_utc(self) -> datetime.datetime:
+ if self._invalidity_date.tzinfo is None:
+ return self._invalidity_date.replace(tzinfo=datetime.timezone.utc)
+ else:
+ return self._invalidity_date.astimezone(tz=datetime.timezone.utc)
+
def public_bytes(self) -> bytes:
return rust_x509.encode_extension_value(self)
diff --git a/src/rust/src/x509/extensions.rs b/src/rust/src/x509/extensions.rs
index 2e9f3d1..bb8e9a5 100644
--- a/src/rust/src/x509/extensions.rs
+++ b/src/rust/src/x509/extensions.rs
@@ -530,7 +530,7 @@ pub(crate) fn encode_extension(
Ok(Some(asn1::write_single(&asn1::SequenceOfWriter::new(gns))?))
}
&oid::INVALIDITY_DATE_OID => {
- let py_dt = ext.getattr(pyo3::intern!(py, "invalidity_date"))?;
+ let py_dt = ext.getattr(pyo3::intern!(py, "invalidity_date_utc"))?;
let dt = x509::py_to_datetime(py, py_dt)?;
Ok(Some(asn1::write_single(&asn1::GeneralizedTime::new(dt)?)?))
}
diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py
index 491271a..44e8299 100644
--- a/tests/x509/test_x509_ext.py
+++ b/tests/x509/test_x509_ext.py
@@ -444,6 +444,26 @@ class TestInvalidityDate:
ext = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1))
assert ext.public_bytes() == b"\x18\x0f20150101010100Z"
+ def test_timezone_aware_api(self):
+ naive_date = datetime.datetime(2015, 1, 1, 1, 1)
+ ext_naive = x509.InvalidityDate(invalidity_date=naive_date)
+ assert ext_naive.invalidity_date_utc == datetime.datetime(
+ 2015, 1, 1, 1, 1, tzinfo=datetime.timezone.utc
+ )
+
+ tz_aware_date = datetime.datetime(
+ 2015,
+ 1,
+ 1,
+ 1,
+ 1,
+ tzinfo=datetime.timezone(datetime.timedelta(hours=-8)),
+ )
+ ext_aware = x509.InvalidityDate(invalidity_date=tz_aware_date)
+ assert ext_aware.invalidity_date_utc == datetime.datetime(
+ 2015, 1, 1, 9, 1, tzinfo=datetime.timezone.utc
+ )
+
class TestNoticeReference:
def test_notice_numbers_not_all_int(self):