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}