openmls/key_packages/
lifetime.rs1#[cfg(target_arch = "wasm32")]
2use fluvio_wasm_timer::{SystemTime, UNIX_EPOCH};
3#[cfg(not(target_arch = "wasm32"))]
4use std::time::{SystemTime, UNIX_EPOCH};
5
6use serde::{Deserialize, Serialize};
7use tls_codec::{TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize};
8
9use crate::treesync::errors::LifetimeError;
10
11const DEFAULT_KEY_PACKAGE_LIFETIME_SECONDS: u64 = 60 * 60 * 24 * 28 * 3;
14
15const DEFAULT_KEY_PACKAGE_LIFETIME_MARGIN_SECONDS: u64 = 60 * 60;
19
20const MAX_LEAF_NODE_LIFETIME_RANGE_SECONDS: u64 =
23 DEFAULT_KEY_PACKAGE_LIFETIME_MARGIN_SECONDS + DEFAULT_KEY_PACKAGE_LIFETIME_SECONDS;
24
25#[derive(
43 PartialEq,
44 Eq,
45 Copy,
46 Clone,
47 Debug,
48 TlsSerialize,
49 TlsSize,
50 TlsDeserialize,
51 TlsDeserializeBytes,
52 Serialize,
53 Deserialize,
54)]
55pub struct Lifetime {
56 not_before: u64,
57 not_after: u64,
58}
59
60impl Lifetime {
61 pub fn new(t: u64) -> Self {
65 let lifetime_margin: u64 = DEFAULT_KEY_PACKAGE_LIFETIME_MARGIN_SECONDS;
66 let now = SystemTime::now()
67 .duration_since(UNIX_EPOCH)
68 .expect("SystemTime before UNIX EPOCH!")
69 .as_secs();
70 let not_before = now - lifetime_margin;
71 let not_after = now + t;
72 Self {
73 not_before,
74 not_after,
75 }
76 }
77
78 pub fn init(not_before: u64, not_after: u64) -> Self {
80 Self {
81 not_before,
82 not_after,
83 }
84 }
85
86 pub fn validate(&self) -> Result<(), LifetimeError> {
88 self.validate_with_time(SystemTime::now())
89 }
90
91 pub fn validate_with_time(&self, now: SystemTime) -> Result<(), LifetimeError> {
94 let duration_since_unix_epoch = now
95 .duration_since(UNIX_EPOCH)
96 .map_err(|_| LifetimeError::SystemTimeBeforeUnixEpoch)?
97 .as_secs();
98 if self.not_after <= duration_since_unix_epoch {
99 Err(LifetimeError::Expired {
100 not_after: self.not_after,
101 now: duration_since_unix_epoch,
102 })
103 } else if self.not_before > duration_since_unix_epoch {
104 Err(LifetimeError::NotValidYet {
105 not_before: self.not_before,
106 now: duration_since_unix_epoch,
107 })
108 } else {
109 Ok(())
110 }
111 }
112
113 pub fn has_acceptable_range(&self) -> bool {
117 self.not_after.saturating_sub(self.not_before) <= MAX_LEAF_NODE_LIFETIME_RANGE_SECONDS
118 }
119
120 pub fn not_before(&self) -> u64 {
122 self.not_before
123 }
124
125 pub fn not_after(&self) -> u64 {
127 self.not_after
128 }
129}
130
131impl Default for Lifetime {
132 fn default() -> Self {
133 Lifetime::new(DEFAULT_KEY_PACKAGE_LIFETIME_SECONDS)
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use core::time::Duration;
140 #[cfg(target_arch = "wasm32")]
141 use fluvio_wasm_timer::SystemTime;
142 #[cfg(not(target_arch = "wasm32"))]
143 use std::time::SystemTime;
144
145 use tls_codec::{Deserialize, Serialize};
146
147 use super::Lifetime;
148
149 #[test]
150 fn lifetime() {
151 let ext = Lifetime::default();
153 ext.validate().expect("Default Lifetime should be valid");
154
155 let ext = Lifetime::new(0);
157 let now_plus_1s = SystemTime::now() + Duration::from_secs(1);
158 let e = ext
159 .validate_with_time(now_plus_1s)
160 .expect_err("Lifetime should be expired");
161 assert!(matches!(e, super::LifetimeError::Expired { .. }));
162
163 let five_hours_before_now = SystemTime::now() - Duration::from_hours(5);
164 let e = ext
165 .validate_with_time(five_hours_before_now)
166 .expect_err("Lifetime should not be valid yet");
167 assert!(matches!(e, super::LifetimeError::NotValidYet { .. }));
168
169 let serialized = ext
171 .tls_serialize_detached()
172 .expect("error encoding life time extension");
173 let ext_deserialized = Lifetime::tls_deserialize(&mut serialized.as_slice())
174 .expect("Error deserializing lifetime");
175 ext_deserialized
176 .validate_with_time(now_plus_1s)
177 .expect_err("Lifetime should be expired");
178 }
179}