openmls/key_packages/lifetime.rs
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 130 131 132 133 134 135 136 137 138 139
#[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 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
}
/// Returns the "not before" timestamp of the KeyPackage.
pub fn not_before(&self) -> u64 {
self.not_before
}
/// Returns the "not after" timestamp of the KeyPackage.
pub fn not_after(&self) -> u64 {
self.not_after
}
}
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());
}
}