Skip to main content

core_crypto/mls/conversation/
group_info.rs

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