coapcore/
time.rs

1//! Traits and types around representing time, as used to consider token expiration.
2
3/// A clock by which time stamps on authorization credentials are compared.
4///
5/// It is yet unspecified whether timestamps are given in Unix time (UTC) or TAI.
6///
7/// # Evolution
8///
9/// Currently this is set up to provide interval and ray time. It may need more interfaces later in
10/// order to also accommodate usages where a `cnonce` is generated (which may then be used to
11/// either just validate a token's time constraints, or may be used together with an `iat` in the
12/// subsequent token to enhance the device's understanding of time).
13///
14/// Given that the 2038 problem can be mitigated also by using a different offset, we might
15/// consider switching to an internal u32 based type that expresses Unix time / TAI with an offset
16/// -- while the 130 years expressible with it are coming to an end, I'm relatively sure that we
17/// can get away with limiting the usable range to 130 years starting from when a concrete firmware
18/// is built.
19pub trait TimeProvider {
20    /// Confidence interval of the clock as lower and upper bound.
21    fn now(&mut self) -> (u64, Option<u64>);
22
23    /// Informs the clock that a credential has been ingested from a trusted AS that claims this
24    /// time to be in the past.
25    #[expect(
26        unused_variables,
27        reason = "Names are human visible part of API description"
28    )]
29    fn past_trusted(&mut self, timestamp: u64) {}
30}
31
32impl<T: TimeProvider> TimeProvider for &mut T {
33    fn now(&mut self) -> (u64, Option<u64>) {
34        (*self).now()
35    }
36
37    fn past_trusted(&mut self, timestamp: u64) {
38        (*self).past_trusted(timestamp)
39    }
40}
41
42/// A time provider that knows nothing.
43///
44/// It ignores any input, and always produces the maximum uncertainty.
45pub struct TimeUnknown;
46
47impl TimeProvider for TimeUnknown {
48    #[inline]
49    fn now(&mut self) -> (u64, Option<u64>) {
50        (0, None)
51    }
52}
53
54/// A processed set of token claims that limit it in time.
55#[derive(Copy, Clone, Debug)]
56pub struct TimeConstraint {
57    // iat would not go in here (that's only to feed a `TimeProvider::past_trusted`; nbf would go
58    // in here but we don't read that yet)
59    exp: Option<u64>,
60}
61
62impl TimeConstraint {
63    /// Creates a [`TimeConstraint`] with no bounds; it is valid at any time.
64    pub fn unbounded() -> Self {
65        Self { exp: None }
66    }
67
68    /// Extract time constraint from a claim.
69    ///
70    /// This is infallible as long as all relevant constraints on the value can be encoded in the
71    /// ace module; doing that is preferable because it eases error tracking.
72    pub fn from_claims_set(claims: &crate::ace::CwtClaimsSet<'_>) -> Self {
73        TimeConstraint {
74            exp: Some(claims.exp),
75        }
76    }
77
78    /// Evaluates the constraint against time provided by the time provider.
79    ///
80    /// Any uncertainty of the time provider is counted for the benefit of the client.
81    pub(crate) fn is_valid_with(&self, time_provider: &mut impl TimeProvider) -> bool {
82        let Some(exp) = self.exp else {
83            return true;
84        };
85        let (now_early, _now_late) = time_provider.now();
86
87        exp > now_early
88    }
89}