openmls/group/mls_group/
application.rs

1use openmls_traits::signatures::Signer;
2
3use crate::storage::OpenMlsProvider;
4
5use super::{errors::CreateMessageError, *};
6
7impl MlsGroup {
8    // === Application messages ===
9
10    /// Creates an application message.
11    /// Returns `CreateMessageError::MlsGroupStateError::UseAfterEviction`
12    /// if the member is no longer part of the group.
13    /// Returns `CreateMessageError::MlsGroupStateError::PendingProposal` if pending proposals
14    /// exist. In that case `.process_pending_proposals()` must be called first
15    /// and incoming messages from the DS must be processed afterwards.
16    pub fn create_message<Provider: OpenMlsProvider>(
17        &mut self,
18        provider: &Provider,
19        signer: &impl Signer,
20        message: &[u8],
21    ) -> Result<MlsMessageOut, CreateMessageError> {
22        if !self.is_active() {
23            return Err(CreateMessageError::GroupStateError(
24                MlsGroupStateError::UseAfterEviction,
25            ));
26        }
27        if !self.proposal_store().is_empty() {
28            return Err(CreateMessageError::GroupStateError(
29                MlsGroupStateError::PendingProposal,
30            ));
31        }
32
33        let authenticated_content = AuthenticatedContent::new_application(
34            self.own_leaf_index(),
35            &self.aad,
36            message,
37            self.context(),
38            signer,
39        )?;
40        let ciphertext = self
41            .encrypt(authenticated_content, provider)
42            // We know the application message is wellformed and we have the key material of the current epoch
43            .map_err(|_| LibraryError::custom("Malformed plaintext"))?;
44
45        self.reset_aad();
46        Ok(MlsMessageOut::from_private_message(
47            ciphertext,
48            self.version(),
49        ))
50    }
51}