1 //! X.501 time types as defined in RFC 5280 2 3 use core::fmt; 4 use core::time::Duration; 5 use der::asn1::{GeneralizedTime, UtcTime}; 6 use der::{Choice, DateTime, Sequence, ValueOrd}; 7 8 #[cfg(feature = "std")] 9 use std::time::SystemTime; 10 11 /// X.501 `Time` as defined in [RFC 5280 Section 4.1.2.5]. 12 /// 13 /// Schema definition from [RFC 5280 Appendix A]: 14 /// 15 /// ```text 16 /// Time ::= CHOICE { 17 /// utcTime UTCTime, 18 /// generalTime GeneralizedTime 19 /// } 20 /// ``` 21 /// 22 /// [RFC 5280 Section 4.1.2.5]: https://tools.ietf.org/html/rfc5280#section-4.1.2.5 23 /// [RFC 5280 Appendix A]: https://tools.ietf.org/html/rfc5280#page-117 24 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] 25 #[derive(Choice, Copy, Clone, Debug, Eq, PartialEq, ValueOrd)] 26 pub enum Time { 27 /// Legacy UTC time (has 2-digit year, valid from 1970 to 2049). 28 /// 29 /// Note: RFC 5280 specifies 1950-2049, however due to common operations working on 30 /// `UNIX_EPOCH` this implementation's lower bound is 1970. 31 #[asn1(type = "UTCTime")] 32 UtcTime(UtcTime), 33 34 /// Modern [`GeneralizedTime`] encoding with 4-digit year. 35 #[asn1(type = "GeneralizedTime")] 36 GeneralTime(GeneralizedTime), 37 } 38 39 impl Time { 40 /// Time used for Certificate who do not expire. 41 pub const INFINITY: Time = 42 Time::GeneralTime(GeneralizedTime::from_date_time(DateTime::INFINITY)); 43 44 /// Get duration since `UNIX_EPOCH`. to_unix_duration(self) -> Duration45 pub fn to_unix_duration(self) -> Duration { 46 match self { 47 Time::UtcTime(t) => t.to_unix_duration(), 48 Time::GeneralTime(t) => t.to_unix_duration(), 49 } 50 } 51 52 /// Get Time as DateTime to_date_time(&self) -> DateTime53 pub fn to_date_time(&self) -> DateTime { 54 match self { 55 Time::UtcTime(t) => t.to_date_time(), 56 Time::GeneralTime(t) => t.to_date_time(), 57 } 58 } 59 60 /// Convert to [`SystemTime`]. 61 #[cfg(feature = "std")] to_system_time(&self) -> SystemTime62 pub fn to_system_time(&self) -> SystemTime { 63 match self { 64 Time::UtcTime(t) => t.to_system_time(), 65 Time::GeneralTime(t) => t.to_system_time(), 66 } 67 } 68 69 /// Convert time to UTCTime representation 70 /// As per RFC 5280: 4.1.2.5, date through 2049 should be expressed as UTC Time. 71 #[cfg(feature = "builder")] rfc5280_adjust_utc_time(&mut self) -> der::Result<()>72 pub(crate) fn rfc5280_adjust_utc_time(&mut self) -> der::Result<()> { 73 if let Time::GeneralTime(t) = self { 74 let date = t.to_date_time(); 75 if date.year() <= UtcTime::MAX_YEAR { 76 *self = Time::UtcTime(UtcTime::from_date_time(date)?); 77 } 78 } 79 80 Ok(()) 81 } 82 } 83 84 impl fmt::Display for Time { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 86 write!(f, "{}", self.to_date_time()) 87 } 88 } 89 90 impl From<UtcTime> for Time { from(time: UtcTime) -> Time91 fn from(time: UtcTime) -> Time { 92 Time::UtcTime(time) 93 } 94 } 95 96 impl From<GeneralizedTime> for Time { from(time: GeneralizedTime) -> Time97 fn from(time: GeneralizedTime) -> Time { 98 Time::GeneralTime(time) 99 } 100 } 101 102 #[cfg(feature = "std")] 103 impl From<Time> for SystemTime { from(time: Time) -> SystemTime104 fn from(time: Time) -> SystemTime { 105 time.to_system_time() 106 } 107 } 108 109 #[cfg(feature = "std")] 110 impl From<&Time> for SystemTime { from(time: &Time) -> SystemTime111 fn from(time: &Time) -> SystemTime { 112 time.to_system_time() 113 } 114 } 115 116 #[cfg(feature = "std")] 117 impl TryFrom<SystemTime> for Time { 118 type Error = der::Error; 119 try_from(time: SystemTime) -> der::Result<Time>120 fn try_from(time: SystemTime) -> der::Result<Time> { 121 Ok(GeneralizedTime::try_from(time)?.into()) 122 } 123 } 124 125 /// X.501 `Validity` as defined in [RFC 5280 Section 4.1.2.5] 126 /// 127 /// ```text 128 /// Validity ::= SEQUENCE { 129 /// notBefore Time, 130 /// notAfter Time 131 /// } 132 /// ``` 133 /// [RFC 5280 Section 4.1.2.5]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.5 134 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] 135 #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] 136 pub struct Validity { 137 /// notBefore value 138 pub not_before: Time, 139 140 /// notAfter value 141 pub not_after: Time, 142 } 143 144 impl Validity { 145 /// Creates a `Validity` which starts now and lasts for `duration`. 146 #[cfg(feature = "std")] from_now(duration: Duration) -> der::Result<Self>147 pub fn from_now(duration: Duration) -> der::Result<Self> { 148 let now = SystemTime::now(); 149 let then = now + duration; 150 151 Ok(Self { 152 not_before: Time::try_from(now)?, 153 not_after: Time::try_from(then)?, 154 }) 155 } 156 } 157