From e9b17622c10a47693af39f76bffecb8755d8d9fb Mon Sep 17 00:00:00 2001 From: BiagioFesta <15035284+BiagioFesta@users.noreply.github.com> Date: Tue, 9 Sep 2025 19:02:47 +0200 Subject: [PATCH] CertContext: method to retrieve time when added to store --- Cargo.toml | 2 ++ src/cert.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index f879c3b..0fcf8b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ no-default-features = true [dependencies] rustls = { version = "0.23", default-features = false, features = ["std"] } +time = { version = "0.3.43", default-features = false, optional = true } windows-sys = { version = "0.60", features = ["Win32_Foundation", "Win32_Security_Cryptography"] } [dev-dependencies] @@ -29,4 +30,5 @@ aws-lc-rs = ["rustls/aws_lc_rs"] fips = ["rustls/fips"] logging = ["rustls/logging"] ring = ["rustls/ring"] +time = ["dep:time"] tls12 = ["rustls/tls12"] diff --git a/src/cert.rs b/src/cert.rs index ee27298..708043c 100644 --- a/src/cert.rs +++ b/src/cert.rs @@ -161,4 +161,50 @@ impl CertContext { } } } + + /// Returns the time when the certificate was added to the store. + /// + /// `None` if the property is not set. + #[cfg(feature = "time")] + pub fn timestamp(&self) -> Result> { + use std::time::Duration; + use windows_sys::core::HRESULT; + use windows_sys::Win32::Foundation::{GetLastError, CRYPT_E_NOT_FOUND, FILETIME}; + + // Duration between Windows epoch (1601-01-01) and Unix epoch (1970-01-01) + const WINDOWS_TO_UNIX_EPOCH: Duration = Duration::from_secs(11_644_473_600); + + let mut filetime = FILETIME::default(); + let mut size = mem::size_of::() as u32; + + let success = unsafe { + CertGetCertificateContextProperty( + self.inner(), + CERT_DATE_STAMP_PROP_ID, + &mut filetime as *mut _ as *mut _, + &mut size, + ) + } != 0; + + if !success { + let error = unsafe { GetLastError() }; + return match error as HRESULT { + CRYPT_E_NOT_FOUND => Ok(None), + _ => Err(CngError::WindowsError(error)), + }; + } + + let ticks = ((filetime.dwHighDateTime as u64) << 32) | filetime.dwLowDateTime as u64; + + // Each tick is 100 nanoseconds (FILETIME is in 100ns units) + let duration_since_windows_epoch = Duration::from_nanos(ticks * 100); + + let duration_since_unix_epoch = duration_since_windows_epoch + .checked_sub(WINDOWS_TO_UNIX_EPOCH) + .unwrap_or(Duration::ZERO); + + let timestamp = time::UtcDateTime::UNIX_EPOCH + duration_since_unix_epoch; + + Ok(Some(timestamp)) + } }