trz_gateway_common/x509/
validity.rs

1use 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/// Represents the interval of time for certificate validity.
18#[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}