trz_gateway_common/x509/
validity.rs1use std::ops::Deref;
2use std::time::SystemTime;
3
4use nameth::NamedEnumValues as _;
5use nameth::nameth;
6use openssl::asn1::Asn1Time;
7use openssl::asn1::Asn1TimeRef;
8use openssl::error::ErrorStack;
9use openssl::x509::X509Builder;
10use openssl::x509::X509Ref;
11
12use super::time::Asn1ToSystemTimeError;
13use super::time::SystemToAsn1TimeError;
14use super::time::asn1_to_system_time;
15use super::time::system_to_asn1_time;
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19pub struct Validity<T = SystemTime> {
20 pub from: T,
21 pub to: T,
22}
23
24pub(super) fn set_validity(
25 builder: &mut X509Builder,
26 validity: Validity<Asn1Time>,
27) -> Result<(), ValidityError<ErrorStack>> {
28 builder
29 .set_not_before(&validity.from)
30 .map_err(ValidityError::NotBefore)?;
31 builder
32 .set_not_after(&validity.to)
33 .map_err(ValidityError::NotAfter)?;
34 Ok(())
35}
36
37impl<T> Validity<T> {
38 pub fn try_map<F, U, E>(self, f: F) -> Result<Validity<U>, ValidityError<E>>
39 where
40 F: Fn(T) -> Result<U, E>,
41 E: std::error::Error,
42 {
43 Ok(Validity {
44 from: f(self.from).map_err(ValidityError::NotBefore)?,
45 to: f(self.to).map_err(ValidityError::NotAfter)?,
46 })
47 }
48
49 pub fn map<F, U>(self, f: F) -> Validity<U>
50 where
51 F: Fn(T) -> U,
52 {
53 Validity {
54 from: f(self.from),
55 to: f(self.to),
56 }
57 }
58}
59
60impl TryFrom<Validity> for Validity<Asn1Time> {
61 type Error = ValidityError<SystemToAsn1TimeError>;
62
63 fn try_from(value: Validity) -> Result<Self, Self::Error> {
64 value.try_map(system_to_asn1_time)
65 }
66}
67
68impl<'t> TryFrom<Validity<&'t Asn1TimeRef>> for Validity {
69 type Error = ValidityError<Asn1ToSystemTimeError>;
70
71 fn try_from(value: Validity<&'t Asn1TimeRef>) -> Result<Self, Self::Error> {
72 value.try_map(asn1_to_system_time)
73 }
74}
75
76impl<'t> TryFrom<&'t X509Ref> for Validity {
77 type Error = ValidityError<Asn1ToSystemTimeError>;
78
79 fn try_from(x509: &'t X509Ref) -> Result<Self, Self::Error> {
80 Validity {
81 from: x509.not_before(),
82 to: x509.not_after(),
83 }
84 .try_map(asn1_to_system_time)
85 }
86}
87
88#[nameth]
89#[derive(thiserror::Error, Debug)]
90pub enum ValidityError<E: std::error::Error> {
91 #[error("[{n}] Failed to process the 'not before' field: {0}", n = self.name())]
92 NotBefore(E),
93
94 #[error("[{n}] Failed to process the 'not after' field: {0}", n = self.name())]
95 NotAfter(E),
96}
97
98impl<T> Validity<T> {
99 pub fn as_deref(&self) -> Validity<&T::Target>
100 where
101 T: Deref,
102 {
103 Validity {
104 from: &self.from,
105 to: &self.to,
106 }
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use openssl::asn1::Asn1Time;
113
114 use super::Validity;
115
116 #[test]
117 fn convert() -> Result<(), Box<dyn std::error::Error>> {
118 for _ in 0..100 {
119 let one_year = Validity {
120 from: Asn1Time::days_from_now(0)?,
121 to: Asn1Time::days_from_now(365)?,
122 };
123 let system_time: Validity = Validity {
124 from: Asn1Time::days_from_now(0)?,
125 to: Asn1Time::days_from_now(365)?,
126 }
127 .as_deref()
128 .try_into()?;
129 let one_year2: Validity<Asn1Time> = system_time.try_into()?;
130 if one_year == one_year2 {
131 return Ok(());
132 }
133 }
134 panic!()
135 }
136}