1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
#[cfg(target_arch = "wasm32")]
use fluvio_wasm_timer::{SystemTime, UNIX_EPOCH};
#[cfg(not(target_arch = "wasm32"))]
use std::time::{SystemTime, UNIX_EPOCH};
use serde::{Deserialize, Serialize};
use tls_codec::{TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize};
/// This value is used as the default lifetime if no default lifetime is configured.
/// The value is in seconds and amounts to 3 * 28 Days, i.e. about 3 months.
const DEFAULT_KEY_PACKAGE_LIFETIME_SECONDS: u64 = 60 * 60 * 24 * 28 * 3;
/// This value is used as the default amount of time (in seconds) the lifetime
/// of a `KeyPackage` is extended into the past to allow for skewed clocks. The
/// value is in seconds and amounts to 1h.
const DEFAULT_KEY_PACKAGE_LIFETIME_MARGIN_SECONDS: u64 = 60 * 60;
/// The maximum total lifetime range that is acceptable for a leaf node.
/// The value is in seconds and amounts to 3 * 28 Days, i.e., about 3 months.
const MAX_LEAF_NODE_LIFETIME_RANGE_SECONDS: u64 =
DEFAULT_KEY_PACKAGE_LIFETIME_MARGIN_SECONDS + DEFAULT_KEY_PACKAGE_LIFETIME_SECONDS;
/// The lifetime represents the times between which clients will
/// consider a KeyPackage valid. This time is represented as an absolute time,
/// measured in seconds since the Unix epoch (1970-01-01T00:00:00Z).
/// A client MUST NOT use the data in a KeyPackage for any processing before
/// the not_before date, or after the not_after date.
///
/// Applications MUST define a maximum total lifetime that is acceptable for a
/// KeyPackage, and reject any KeyPackage where the total lifetime is longer
/// than this duration.This extension MUST always be present in a KeyPackage.
///
/// ```c
/// // draft-ietf-mls-protocol-16
/// struct {
/// uint64 not_before;
/// uint64 not_after;
/// } Lifetime;
/// ```
#[derive(
PartialEq,
Eq,
Copy,
Clone,
Debug,
TlsSerialize,
TlsSize,
TlsDeserialize,
TlsDeserializeBytes,
Serialize,
Deserialize,
)]
pub struct Lifetime {
not_before: u64,
not_after: u64,
}
impl Lifetime {
/// Create a new lifetime with lifetime `t` (in seconds).
/// Note that the lifetime is extended 1h into the past to adapt to skewed
/// clocks, i.e. `not_before` is set to now - 1h.
pub fn new(t: u64) -> Self {
let lifetime_margin: u64 = DEFAULT_KEY_PACKAGE_LIFETIME_MARGIN_SECONDS;
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("SystemTime before UNIX EPOCH!")
.as_secs();
let not_before = now - lifetime_margin;
let not_after = now + t;
Self {
not_before,
not_after,
}
}
/// Returns true if this lifetime is valid.
pub(crate) fn is_valid(&self) -> bool {
match SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|duration| duration.as_secs())
{
Ok(elapsed) => self.not_before < elapsed && elapsed < self.not_after,
Err(_) => {
log::error!("SystemTime before UNIX EPOCH.");
false
}
}
}
/// ValSem(openmls/annotations#32):
/// Applications MUST define a maximum total lifetime that is acceptable for a LeafNode,
/// and reject any LeafNode where the total lifetime is longer than this duration.
pub fn has_acceptable_range(&self) -> bool {
self.not_after.saturating_sub(self.not_before) <= MAX_LEAF_NODE_LIFETIME_RANGE_SECONDS
}
}
impl Default for Lifetime {
fn default() -> Self {
Lifetime::new(DEFAULT_KEY_PACKAGE_LIFETIME_SECONDS)
}
}
#[cfg(test)]
mod tests {
use tls_codec::{Deserialize, Serialize};
use super::Lifetime;
#[test]
fn lifetime() {
// A freshly created extensions must be valid.
let ext = Lifetime::default();
assert!(ext.is_valid());
// An extension without lifetime is invalid (waiting for 1 second).
let ext = Lifetime::new(0);
std::thread::sleep(std::time::Duration::from_secs(1));
assert!(!ext.is_valid());
// Test (de)serializing invalid extension
let serialized = ext
.tls_serialize_detached()
.expect("error encoding life time extension");
let ext_deserialized = Lifetime::tls_deserialize(&mut serialized.as_slice())
.expect("Error deserializing lifetime");
assert!(!ext_deserialized.is_valid());
}
}