From 97b9e5129eadab20588e38d7bb77d646cc2528a1 Mon Sep 17 00:00:00 2001 From: Honglin Cao Date: Thu, 17 Sep 2026 10:42:32 -0400 Subject: [PATCH] Stamp generated certificates with aware UTC datetimes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit datetime.utcnow() returns a naive datetime holding UTC numbers, which reads as local time to anything that later calls .timestamp() on it — a silent offset equal to the host's UTC offset, invisible on a UTC machine. Python 3.12 already warns on it, and cryptography has been steering callers off naive datetimes, so certificate generation would eventually stop working rather than merely warn. Nothing changes today: cryptography treats a naive datetime as UTC, and utcnow() supplied UTC numbers, so the two mistakes cancelled. Verified under TZ=America/New_York with -W error::DeprecationWarning that generation is silent and that both certificates carry aware UTC bounds, a 1825-day span, and a signature that verifies against the CA. Signed-off-by: Honglin Cao --- centml/sdk/utils/client_certs.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/centml/sdk/utils/client_certs.py b/centml/sdk/utils/client_certs.py index d3c2ec3e..bb000c05 100644 --- a/centml/sdk/utils/client_certs.py +++ b/centml/sdk/utils/client_certs.py @@ -1,6 +1,6 @@ import os from dataclasses import dataclass -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone import click from cryptography import x509 @@ -31,9 +31,9 @@ def generate_ca_client_triplet(service_name: str) -> CAClientCertTriplet: .issuer_name(ca_subject) .public_key(ca_private_key.public_key()) .serial_number(x509.random_serial_number()) - .not_valid_before(datetime.utcnow()) + .not_valid_before(datetime.now(timezone.utc)) # Certificate valid for 5 years (give or take leap years) - .not_valid_after(datetime.utcnow() + timedelta(days=365 * 5)) + .not_valid_after(datetime.now(timezone.utc) + timedelta(days=365 * 5)) .add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True) # We are using SHA384 as it's often paired with secpr384r1, ie # the weak link isn't the hash algorithm. @@ -53,9 +53,9 @@ def generate_ca_client_triplet(service_name: str) -> CAClientCertTriplet: .issuer_name(ca_certificate.subject) .public_key(client_private_key.public_key()) .serial_number(x509.random_serial_number()) - .not_valid_before(datetime.utcnow()) + .not_valid_before(datetime.now(timezone.utc)) # Certificate valid for 5 years (give or take leap years) - .not_valid_after(datetime.utcnow() + timedelta(days=365 * 5)) + .not_valid_after(datetime.now(timezone.utc) + timedelta(days=365 * 5)) .add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=True) # We are using SHA384 as it's often paired with secpr384r1, ie # the weak link isn't the hash algorithm.