mls_spec/
group.rs

1use crate::{
2    SensitiveBytes,
3    credential::Credential,
4    crypto::SignaturePublicKey,
5    defs::{CredentialType, ExtensionType, ProposalType},
6};
7
8pub mod commits;
9pub mod extensions;
10pub mod group_info;
11pub mod proposals;
12pub mod welcome;
13
14pub type HashReference = SensitiveBytes;
15pub type ProposalRef = HashReference;
16pub type KeyPackageRef = HashReference;
17
18pub type GroupId = Vec<u8>;
19pub type GroupIdRef<'a> = &'a [u8];
20
21#[derive(
22    Debug,
23    Clone,
24    Copy,
25    PartialEq,
26    Eq,
27    tls_codec::TlsSerialize,
28    tls_codec::TlsDeserialize,
29    tls_codec::TlsSize,
30)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32pub struct KeyPackageLifetime {
33    pub not_before: u64,
34    pub not_after: u64,
35}
36
37impl KeyPackageLifetime {
38    // 14h wiggle room for non-NTP-synced clients
39    pub const LIFETIME_WIGGLE_ROOM: u64 = 50_400;
40    #[cfg(not(feature = "test-vectors"))]
41    // 3 months (93 days)
42    pub const MAX_LEAF_NODE_ACCEPTABLE_RANGE: u64 = 8_035_200;
43    #[cfg(feature = "test-vectors")]
44    pub const MAX_LEAF_NODE_ACCEPTABLE_RANGE: u64 = u64::MAX - Self::LIFETIME_WIGGLE_ROOM;
45
46    /// Validate if the range presented by `not_before` and `not_after` is within an acceptable range
47    /// This is currently statically configured to be 3 months as per the spec recommendation
48    // TODO: Make it configurable by providing overriding values
49    pub fn validate_range(&self) -> bool {
50        if self.not_after < self.not_before {
51            return false;
52        }
53
54        let kp_range = self.not_after.saturating_sub(self.not_before);
55        let acceptable_range =
56            Self::MAX_LEAF_NODE_ACCEPTABLE_RANGE.saturating_add(Self::LIFETIME_WIGGLE_ROOM);
57        kp_range <= acceptable_range
58    }
59
60    /// Validate if the [KeyPackageLifetime]'s bounds are around now
61    pub fn validate_expiration(&self) -> bool {
62        let now = now();
63        self.not_before < now && now < self.not_after
64    }
65}
66
67#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
68fn now() -> u64 {
69    let val = js_sys::Date::now();
70    std::time::Duration::from_millis(val as u64).as_secs()
71}
72
73#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
74fn now() -> u64 {
75    let now = std::time::SystemTime::now();
76    now.duration_since(std::time::SystemTime::UNIX_EPOCH)
77        .expect("System clock is before UNIX_EPOCH")
78        .as_secs()
79}
80
81impl Default for KeyPackageLifetime {
82    fn default() -> Self {
83        let now = now();
84        let not_before = now.saturating_sub(Self::LIFETIME_WIGGLE_ROOM);
85        let not_after = now.saturating_add(Self::MAX_LEAF_NODE_ACCEPTABLE_RANGE);
86        Self {
87            not_before,
88            not_after,
89        }
90    }
91}
92
93#[derive(
94    Debug,
95    Clone,
96    PartialEq,
97    Eq,
98    tls_codec::TlsSerialize,
99    tls_codec::TlsDeserialize,
100    tls_codec::TlsSize,
101)]
102#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
103pub struct ExternalSender {
104    pub signature_key: SignaturePublicKey,
105    pub credential: Credential,
106}
107
108#[derive(
109    Debug,
110    Clone,
111    Default,
112    PartialEq,
113    Eq,
114    tls_codec::TlsSerialize,
115    tls_codec::TlsDeserialize,
116    tls_codec::TlsSize,
117)]
118#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
119pub struct RequiredCapabilities {
120    pub extension_types: Vec<ExtensionType>,
121    pub proposal_types: Vec<ProposalType>,
122    pub credential_types: Vec<CredentialType>,
123}