core_crypto/mls/conversation/
group_info.rs

1use openmls::prelude::{MlsMessageOut, group_info::GroupInfo};
2use serde::{Deserialize, Serialize};
3
4use super::{Error, Result};
5
6/// A [GroupInfo] with metadata
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct MlsGroupInfoBundle {
9    /// Indicates if the `payload` is encrypted or not
10    pub encryption_type: MlsGroupInfoEncryptionType,
11    /// Indicates if the `payload` contains a full, partial or referenced [GroupInfo]
12    pub ratchet_tree_type: MlsRatchetTreeType,
13    /// The [GroupInfo]
14    pub payload: GroupInfoPayload,
15}
16
17impl MlsGroupInfoBundle {
18    /// Creates a new [GroupInfoBundle] with complete and unencrypted [GroupInfo]
19    pub(crate) fn try_new_full_plaintext(gi: GroupInfo) -> Result<Self> {
20        use tls_codec::Serialize as _;
21
22        let payload = MlsMessageOut::from(gi);
23        let payload = payload
24            .tls_serialize_detached()
25            .map_err(Error::tls_serialize("unencrypted mls message"))?;
26        Ok(Self {
27            encryption_type: MlsGroupInfoEncryptionType::Plaintext,
28            ratchet_tree_type: MlsRatchetTreeType::Full,
29            payload: GroupInfoPayload::Plaintext(payload),
30        })
31    }
32}
33
34#[cfg(test)]
35impl MlsGroupInfoBundle {
36    // test functions are not held to the same standard
37    #![allow(missing_docs)]
38
39    pub fn get_group_info(self) -> openmls::prelude::group_info::VerifiableGroupInfo {
40        match self.get_payload().extract() {
41            openmls::prelude::MlsMessageInBody::GroupInfo(vgi) => vgi,
42            _ => panic!("This payload should contain a GroupInfo"),
43        }
44    }
45
46    pub fn get_payload(mut self) -> openmls::prelude::MlsMessageIn {
47        use tls_codec::Deserialize as _;
48        match &mut self.payload {
49            GroupInfoPayload::Plaintext(gi) => {
50                openmls::prelude::MlsMessageIn::tls_deserialize(&mut gi.as_slice()).unwrap()
51            }
52        }
53    }
54}
55
56/// # GroupInfoEncryptionType
57///
58/// In order to guarantee confidentiality of the [GroupInfo] on the wire a domain can
59/// request it to be encrypted when sent to the Delivery Service.
60///
61/// ```text
62/// enum {
63///     plaintext(1),
64///     jwe_encrypted(2),
65///     (255)
66/// } GroupInfoEncryptionType;
67/// ```
68#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
69#[repr(u8)]
70pub enum MlsGroupInfoEncryptionType {
71    /// Unencrypted [GroupInfo]
72    Plaintext = 1,
73    /// [GroupInfo] encrypted in a JWE
74    JweEncrypted = 2,
75}
76
77/// # RatchetTreeType
78///
79/// In order to spare some precious bytes, a [GroupInfo] can have different representations.
80///
81/// ```text
82/// enum {
83///     full(1),
84///     delta(2),
85///     by_ref(3),
86///     (255)
87/// } RatchetTreeType;
88/// ```
89#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
90#[repr(u8)]
91pub enum MlsRatchetTreeType {
92    /// Plain old and complete [GroupInfo]
93    Full = 1,
94    /// Contains [GroupInfo] changes since previous epoch (not yet implemented)
95    /// (see [draft](https://github.com/rohan-wire/ietf-drafts/blob/main/mahy-mls-ratchet-tree-delta/draft-mahy-mls-ratchet-tree-delta.md))
96    Delta = 2,
97    /// Not implemented
98    ByRef = 3,
99}
100
101/// Represents the byte array in [MlsGroupInfoBundle]
102#[derive(Debug, Clone, Serialize, Deserialize)]
103pub enum GroupInfoPayload {
104    /// Unencrypted [GroupInfo]
105    Plaintext(Vec<u8>),
106    // not implemented
107    // Encrypted(Vec<u8>),
108}
109
110impl GroupInfoPayload {
111    /// Returns the internal byte array
112    pub fn bytes(self) -> Vec<u8> {
113        match self {
114            GroupInfoPayload::Plaintext(gi) => gi,
115        }
116    }
117}