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")]
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")]
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/// | Value | Name | Recommended | Reference |
111/// |-----------------|--------------------------|-------------|----------------------------------------|
112/// | 0x0000 | RESERVED | N/A | RFC 9420 |
113/// | 0x0001 | mls_plaintext | Y | RFC 9420 |
114/// | 0x0002 | mls_ciphertext | Y | RFC 9420 |
115/// | 0x0003 | mls_welcome | Y | RFC 9420 |
116/// | 0x0004 | mls_group_info | Y | RFC 9420 |
117/// | 0x0005 | mls_key_package | Y | RFC 9420 |
118/// | 0x0006 | mls_targeted_message | Y | draft-ietf-mls-targeted-messages |
119/// | 0xf000 - 0xffff | Reserved for Private Use | N/A | RFC 9420 |
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 /// Targeted message (draft-ietf-mls-targeted-messages)
146 #[cfg(feature = "targeted-messages-draft")]
147 #[cfg_attr(docsrs, doc(cfg(feature = "targeted-messages-draft")))]
148 TargetedMessage = 6,
149}
150
151/// This struct is used to group common framing parameters
152/// in order to reduce the number of arguments in function calls.
153#[derive(Clone, Copy, PartialEq, Debug)]
154pub(crate) struct FramingParameters<'a> {
155 aad: &'a [u8],
156 wire_format: WireFormat,
157}
158
159impl<'a> FramingParameters<'a> {
160 pub(crate) fn new(aad: &'a [u8], wire_format: impl Into<WireFormat>) -> Self {
161 Self {
162 aad,
163 wire_format: wire_format.into(),
164 }
165 }
166
167 pub(crate) fn aad(&self) -> &'a [u8] {
168 self.aad
169 }
170 pub(crate) fn wire_format(&self) -> WireFormat {
171 self.wire_format
172 }
173}
174
175/// ```c
176/// enum {
177/// reserved(0),
178/// application(1),
179/// proposal(2),
180/// commit(3),
181/// (255)
182/// } ContentType;
183/// ```
184#[derive(
185 PartialEq,
186 Eq,
187 Clone,
188 Copy,
189 Debug,
190 Serialize,
191 Deserialize,
192 TlsDeserialize,
193 TlsDeserializeBytes,
194 TlsSerialize,
195 TlsSize,
196)]
197#[repr(u8)]
198pub enum ContentType {
199 /// Application message
200 Application = 1,
201 /// Proposal
202 Proposal = 2,
203 /// Commit
204 Commit = 3,
205}
206
207impl TryFrom<u8> for ContentType {
208 type Error = tls_codec::Error;
209 fn try_from(value: u8) -> Result<Self, tls_codec::Error> {
210 match value {
211 1 => Ok(ContentType::Application),
212 2 => Ok(ContentType::Proposal),
213 3 => Ok(ContentType::Commit),
214 _ => Err(tls_codec::Error::DecodingError(format!(
215 "{value} is not a valid content type"
216 ))),
217 }
218 }
219}
220
221impl ContentType {
222 /// Returns `true` if this is a handshake message and `false` otherwise.
223 pub(crate) fn is_handshake_message(&self) -> bool {
224 self == &ContentType::Proposal || self == &ContentType::Commit
225 }
226}