core_crypto/mls/conversation/
group_info.rs

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