blob: c0ef8bf8aa74e4b008fad32808824d1a891f20d9 [file] [log] [blame] [edit]
//! X.501 time types as defined in RFC 5280
use core::fmt;
use core::time::Duration;
use der::asn1::{GeneralizedTime, UtcTime};
use der::{Choice, DateTime, Sequence, ValueOrd};
#[cfg(feature = "std")]
use std::time::SystemTime;
/// X.501 `Time` as defined in [RFC 5280 Section 4.1.2.5].
///
/// Schema definition from [RFC 5280 Appendix A]:
///
/// ```text
/// Time ::= CHOICE {
/// utcTime UTCTime,
/// generalTime GeneralizedTime
/// }
/// ```
///
/// [RFC 5280 Section 4.1.2.5]: https://tools.ietf.org/html/rfc5280#section-4.1.2.5
/// [RFC 5280 Appendix A]: https://tools.ietf.org/html/rfc5280#page-117
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Choice, Copy, Clone, Debug, Eq, PartialEq, ValueOrd)]
pub enum Time {
/// Legacy UTC time (has 2-digit year, valid from 1970 to 2049).
///
/// Note: RFC 5280 specifies 1950-2049, however due to common operations working on
/// `UNIX_EPOCH` this implementation's lower bound is 1970.
#[asn1(type = "UTCTime")]
UtcTime(UtcTime),
/// Modern [`GeneralizedTime`] encoding with 4-digit year.
#[asn1(type = "GeneralizedTime")]
GeneralTime(GeneralizedTime),
}
impl Time {
/// Time used for Certificate who do not expire.
pub const INFINITY: Time =
Time::GeneralTime(GeneralizedTime::from_date_time(DateTime::INFINITY));
/// Get duration since `UNIX_EPOCH`.
pub fn to_unix_duration(self) -> Duration {
match self {
Time::UtcTime(t) => t.to_unix_duration(),
Time::GeneralTime(t) => t.to_unix_duration(),
}
}
/// Get Time as DateTime
pub fn to_date_time(&self) -> DateTime {
match self {
Time::UtcTime(t) => t.to_date_time(),
Time::GeneralTime(t) => t.to_date_time(),
}
}
/// Convert to [`SystemTime`].
#[cfg(feature = "std")]
pub fn to_system_time(&self) -> SystemTime {
match self {
Time::UtcTime(t) => t.to_system_time(),
Time::GeneralTime(t) => t.to_system_time(),
}
}
/// Convert time to UTCTime representation
/// As per RFC 5280: 4.1.2.5, date through 2049 should be expressed as UTC Time.
#[cfg(feature = "builder")]
pub(crate) fn rfc5280_adjust_utc_time(&mut self) -> der::Result<()> {
if let Time::GeneralTime(t) = self {
let date = t.to_date_time();
if date.year() <= UtcTime::MAX_YEAR {
*self = Time::UtcTime(UtcTime::from_date_time(date)?);
}
}
Ok(())
}
}
impl fmt::Display for Time {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_date_time())
}
}
impl From<UtcTime> for Time {
fn from(time: UtcTime) -> Time {
Time::UtcTime(time)
}
}
impl From<GeneralizedTime> for Time {
fn from(time: GeneralizedTime) -> Time {
Time::GeneralTime(time)
}
}
#[cfg(feature = "std")]
impl From<Time> for SystemTime {
fn from(time: Time) -> SystemTime {
time.to_system_time()
}
}
#[cfg(feature = "std")]
impl From<&Time> for SystemTime {
fn from(time: &Time) -> SystemTime {
time.to_system_time()
}
}
#[cfg(feature = "std")]
impl TryFrom<SystemTime> for Time {
type Error = der::Error;
fn try_from(time: SystemTime) -> der::Result<Time> {
Ok(GeneralizedTime::try_from(time)?.into())
}
}
/// X.501 `Validity` as defined in [RFC 5280 Section 4.1.2.5]
///
/// ```text
/// Validity ::= SEQUENCE {
/// notBefore Time,
/// notAfter Time
/// }
/// ```
/// [RFC 5280 Section 4.1.2.5]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.5
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
pub struct Validity {
/// notBefore value
pub not_before: Time,
/// notAfter value
pub not_after: Time,
}
impl Validity {
/// Creates a `Validity` which starts now and lasts for `duration`.
#[cfg(feature = "std")]
pub fn from_now(duration: Duration) -> der::Result<Self> {
let now = SystemTime::now();
let then = now + duration;
Ok(Self {
not_before: Time::try_from(now)?,
not_after: Time::try_from(then)?,
})
}
}