trz_gateway_common/x509/
time.rs1use std::num::TryFromIntError;
2use std::sync::OnceLock;
3use std::time::Duration;
4use std::time::SystemTime;
5use std::time::SystemTimeError;
6use std::time::UNIX_EPOCH;
7
8use nameth::NamedEnumValues as _;
9use nameth::nameth;
10use openssl::asn1::Asn1Time;
11use openssl::asn1::Asn1TimeRef;
12use openssl::error::ErrorStack;
13
14pub fn system_to_asn1_time(system: SystemTime) -> Result<Asn1Time, SystemToAsn1TimeError> {
15 let unix_seconds = system.duration_since(UNIX_EPOCH)?.as_secs();
16 Ok(Asn1Time::from_unix(unix_seconds as i64)?)
17}
18
19#[nameth]
20#[derive(thiserror::Error, Debug)]
21pub enum SystemToAsn1TimeError {
22 #[error("[{n}] Can't convert time earlier than UNIX_EPOCH: {0}", n = self.name())]
23 SystemTimeError(#[from] SystemTimeError),
24
25 #[error("[{n}] Failed to convert UNIX seconds to Asn1Time: {0}", n = self.name())]
26 Asn1TimeError(#[from] ErrorStack),
27}
28
29pub fn asn1_to_system_time(asn1: &Asn1TimeRef) -> Result<SystemTime, Asn1ToSystemTimeError> {
30 static UNIX_EPOCH_ASN1TIME: OnceLock<Asn1Time> = OnceLock::new();
31 let epoch = UNIX_EPOCH_ASN1TIME
32 .get_or_init(|| system_to_asn1_time(UNIX_EPOCH).expect("UNIX_EPOCH as Asn1Time"));
33 let diff = epoch.diff(asn1)?;
34
35 let days = diff.days.try_into()?;
36 let secs = diff.secs.try_into()?;
37
38 const SECOND: Duration = Duration::from_secs(1);
39 Ok(SystemTime::UNIX_EPOCH + SECOND * 3600 * 24 * days + SECOND * secs)
40}
41
42#[nameth]
43#[derive(thiserror::Error, Debug)]
44pub enum Asn1ToSystemTimeError {
45 #[error("[{n}] Can't convert time earlier than UNIX_EPOCH: {0}", n = self.name())]
46 SystemTimeError(#[from] TryFromIntError),
47
48 #[error("[{n}] Failed to convert Asn1Time to UNIX seconds: {0}", n = self.name())]
49 Asn1TimeError(#[from] ErrorStack),
50}
51
52#[cfg(test)]
53mod tests {
54 use std::time::Duration;
55 use std::time::SystemTime;
56 use std::time::UNIX_EPOCH;
57
58 use super::asn1_to_system_time;
59 use super::system_to_asn1_time;
60
61 #[test]
62 fn convert() {
63 let system = SystemTime::now();
64 let system = system
65 - Duration::from_nanos(system.duration_since(UNIX_EPOCH).unwrap().subsec_nanos() as u64);
66 let asn1 = system_to_asn1_time(system).unwrap();
67 let system2 = asn1_to_system_time(&asn1).unwrap();
68 assert_eq!(system, system2);
69 }
70
71 #[test]
72 fn fifty_years() {
73 let fifty = SystemTime::now() + Duration::from_secs(1) * 3600 * 24 * 365 * 50;
74 let fifty = fifty
75 - Duration::from_nanos(fifty.duration_since(UNIX_EPOCH).unwrap().subsec_nanos() as u64);
76 let asn1 = system_to_asn1_time(fifty).unwrap();
77 let system = asn1_to_system_time(&asn1).unwrap();
78 assert_eq!(fifty, system);
79 }
80}