openmls/framing/mod.rs
1//! # Message framing
2//!
3//! This module contains framing-related operations for MLS messages, including
4//! validation logic.
5//!
6//! The general structure of the framing process in OpenMLS closely follows the
7//! design described in Section 7 of the MLS specification. It can be visualized
8//! as follows:
9//!
10//! ```text
11//! Proposal Commit Application Data
12//! | | |
13//! +--------------+--------------+
14//! |
15//! V
16//! FramedContent
17//! | | -.
18//! | | |
19//! +--------+ | |
20//! | | |
21//! V | +-- Asymmetric
22//! FramedContentAuthData | | Sign / Verify
23//! | | |
24//! +--------+ | |
25//! | | |
26//! V V -'
27//! AuthenticatedContent
28//! | -.
29//! | |
30//! | |
31//! +--------+--------+ +-- Symmetric
32//! | | | Protect / Unprotect
33//! V V |
34//! Welcome KeyPackage GroupInfo PublicMessage PrivateMessage -'
35//! | | | | |
36//! | | | | |
37//! +----------+----------+----+--------+-----------------+
38//! |
39//! V
40//! MLSMessage
41//! ```
42//!
43//! - [`MlsMessageIn`]/[`MlsMessageOut`]: Unified message type for incoming & outgoing MLS messages
44//! - [`ApplicationMessage`]: Application message received through a [`ProcessedMessage`]
45
46use serde::{Deserialize, Serialize};
47use tls_codec::*;
48
49use crate::{
50 ciphersuite::*,
51 credentials::*,
52 group::*,
53 messages::{proposals::*, *},
54 schedule::{message_secrets::*, *},
55};
56
57pub(crate) mod codec;
58
59pub(crate) mod message_in;
60pub(crate) mod message_out;
61pub(crate) mod mls_auth_content;
62pub(crate) mod mls_auth_content_in;
63pub(crate) mod mls_content;
64pub(crate) mod mls_content_in;
65pub(crate) mod private_message;
66pub(crate) mod private_message_in;
67pub(crate) mod public_message;
68pub(crate) mod public_message_in;
69#[cfg(feature = "extensions-draft-08")]
70pub(crate) mod safe_aad;
71pub(crate) mod sender;
72pub(crate) mod validation;
73pub(crate) use errors::*;
74
75#[cfg(test)]
76pub(crate) use mls_auth_content::*;
77#[cfg(test)]
78pub(crate) use mls_auth_content_in::*;
79
80#[cfg(test)]
81pub(crate) use mls_content::*;
82#[cfg(test)]
83pub(crate) use mls_content_in::*;
84
85// Crate
86#[cfg(feature = "virtual-clients-draft")]
87pub(crate) use private_message::EmulatorReuseGuardCtx;
88pub(crate) use sender::*;
89
90// Public
91pub mod errors;
92
93pub use message_in::*;
94pub use message_out::*;
95pub use private_message::*;
96pub use private_message_in::*;
97pub use public_message::*;
98pub use public_message_in::*;
99#[cfg(feature = "extensions-draft-08")]
100pub use safe_aad::{SafeAad, SafeAadError, SafeAadItem};
101pub use sender::*;
102pub use validation::*;
103
104// Tests
105#[cfg(test)]
106pub(crate) mod tests;
107
108/// Wire format of MLS messages.
109///
110/// // draft-ietf-mls-protocol-17
111/// | Value | Name | Recommended | Reference |
112/// |-----------------|--------------------------|-------------|-----------|
113/// | 0x0000 | RESERVED | N/A | RFC XXXX |
114/// | 0x0001 | mls_plaintext | Y | RFC XXXX |
115/// | 0x0002 | mls_ciphertext | Y | RFC XXXX |
116/// | 0x0003 | mls_welcome | Y | RFC XXXX |
117/// | 0x0004 | mls_group_info | Y | RFC XXXX |
118/// | 0x0005 | mls_key_package | Y | RFC XXXX |
119/// | 0xf000 - 0xffff | Reserved for Private Use | N/A | RFC XXXX |
120#[derive(
121 PartialEq,
122 Eq,
123 Clone,
124 Copy,
125 Debug,
126 Serialize,
127 Deserialize,
128 TlsDeserialize,
129 TlsDeserializeBytes,
130 TlsSerialize,
131 TlsSize,
132)]
133#[repr(u16)]
134pub enum WireFormat {
135 /// Plaintext message
136 PublicMessage = 1,
137 /// Encrypted message
138 PrivateMessage = 2,
139 /// Welcome message
140 Welcome = 3,
141 /// Group information
142 GroupInfo = 4,
143 /// KeyPackage
144 KeyPackage = 5,
145}
146
147/// This struct is used to group common framing parameters
148/// in order to reduce the number of arguments in function calls.
149#[derive(Clone, Copy, PartialEq, Debug)]
150pub(crate) struct FramingParameters<'a> {
151 aad: &'a [u8],
152 wire_format: WireFormat,
153}
154
155impl<'a> FramingParameters<'a> {
156 pub(crate) fn new(aad: &'a [u8], wire_format: impl Into<WireFormat>) -> Self {
157 Self {
158 aad,
159 wire_format: wire_format.into(),
160 }
161 }
162
163 pub(crate) fn aad(&self) -> &'a [u8] {
164 self.aad
165 }
166 pub(crate) fn wire_format(&self) -> WireFormat {
167 self.wire_format
168 }
169}
170
171/// ```c
172/// // draft-ietf-mls-protocol-17
173/// enum {
174/// reserved(0),
175/// application(1),
176/// proposal(2),
177/// commit(3),
178/// (255)
179/// } ContentType;
180/// ```
181#[derive(
182 PartialEq,
183 Eq,
184 Clone,
185 Copy,
186 Debug,
187 Serialize,
188 Deserialize,
189 TlsDeserialize,
190 TlsDeserializeBytes,
191 TlsSerialize,
192 TlsSize,
193)]
194#[repr(u8)]
195pub enum ContentType {
196 /// Application message
197 Application = 1,
198 /// Proposal
199 Proposal = 2,
200 /// Commit
201 Commit = 3,
202}
203
204impl TryFrom<u8> for ContentType {
205 type Error = tls_codec::Error;
206 fn try_from(value: u8) -> Result<Self, tls_codec::Error> {
207 match value {
208 1 => Ok(ContentType::Application),
209 2 => Ok(ContentType::Proposal),
210 3 => Ok(ContentType::Commit),
211 _ => Err(tls_codec::Error::DecodingError(format!(
212 "{value} is not a valid content type"
213 ))),
214 }
215 }
216}
217
218impl ContentType {
219 /// Returns `true` if this is a handshake message and `false` otherwise.
220 pub(crate) fn is_handshake_message(&self) -> bool {
221 self == &ContentType::Proposal || self == &ContentType::Commit
222 }
223}