1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use tls_codec::Serialize;
use super::{errors::CreateMessageError, *};
impl MlsGroup {
// === Application messages ===
/// Creates an application message.
/// Returns `CreateMessageError::MlsGroupStateError::UseAfterEviction`
/// if the member is no longer part of the group.
/// Returns `CreateMessageError::MlsGroupStateError::PendingProposal` if pending proposals
/// exist. In that case `.process_pending_proposals()` must be called first
/// and incoming messages from the DS must be processed afterwards.
pub fn create_message(
&mut self,
backend: &impl OpenMlsCryptoProvider,
message: &[u8],
) -> Result<MlsMessageOut, CreateMessageError> {
if !self.is_active() {
return Err(CreateMessageError::GroupStateError(
MlsGroupStateError::UseAfterEviction,
));
}
if !self.proposal_store.is_empty() {
return Err(CreateMessageError::GroupStateError(
MlsGroupStateError::PendingProposal,
));
}
let credential = self
.credential()
// We checked we are in the right group state before
.map_err(|_| LibraryError::custom("Wrong group state"))?;
let credential_bundle: CredentialBundle = backend
.key_store()
.read(
&credential
.signature_key()
.tls_serialize_detached()
.map_err(LibraryError::missing_bound_check)?,
)
.ok_or(CreateMessageError::NoMatchingCredentialBundle)?;
let ciphertext = self
.group
.create_application_message(
&self.aad,
message,
&credential_bundle,
self.configuration().padding_size(),
backend,
)
// We know the application message is wellformed and we have the key material of the current epoch
.map_err(|_| LibraryError::custom("Malformed plaintext"))?;
// Since the state of the group might be changed, arm the state flag
self.flag_state_change();
Ok(MlsMessageOut::from(ciphertext))
}
}