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;
69pub(crate) mod sender;
70pub(crate) mod validation;
71pub(crate) use errors::*;
72
73#[cfg(test)]
74pub(crate) use mls_auth_content::*;
75#[cfg(test)]
76pub(crate) use mls_auth_content_in::*;
77
78#[cfg(test)]
79pub(crate) use mls_content::*;
80#[cfg(test)]
81pub(crate) use mls_content_in::*;
82
83// Crate
84pub(crate) use sender::*;
85
86// Public
87pub mod errors;
88
89pub use message_in::*;
90pub use message_out::*;
91pub use private_message::*;
92pub use private_message_in::*;
93pub use public_message::*;
94pub use public_message_in::*;
95pub use sender::*;
96pub use validation::*;
97
98// Tests
99#[cfg(test)]
100pub(crate) mod tests;
101
102/// Wire format of MLS messages.
103///
104/// // draft-ietf-mls-protocol-17
105/// | Value | Name | Recommended | Reference |
106/// |-----------------|--------------------------|-------------|-----------|
107/// | 0x0000 | RESERVED | N/A | RFC XXXX |
108/// | 0x0001 | mls_plaintext | Y | RFC XXXX |
109/// | 0x0002 | mls_ciphertext | Y | RFC XXXX |
110/// | 0x0003 | mls_welcome | Y | RFC XXXX |
111/// | 0x0004 | mls_group_info | Y | RFC XXXX |
112/// | 0x0005 | mls_key_package | Y | RFC XXXX |
113/// | 0xf000 - 0xffff | Reserved for Private Use | N/A | RFC XXXX |
114#[derive(
115 PartialEq,
116 Eq,
117 Clone,
118 Copy,
119 Debug,
120 Serialize,
121 Deserialize,
122 TlsDeserialize,
123 TlsDeserializeBytes,
124 TlsSerialize,
125 TlsSize,
126)]
127#[repr(u16)]
128pub enum WireFormat {
129 /// Plaintext message
130 PublicMessage = 1,
131 /// Encrypted message
132 PrivateMessage = 2,
133 /// Welcome message
134 Welcome = 3,
135 /// Group information
136 GroupInfo = 4,
137 /// KeyPackage
138 KeyPackage = 5,
139}
140
141/// This struct is used to group common framing parameters
142/// in order to reduce the number of arguments in function calls.
143#[derive(Clone, Copy, PartialEq, Debug)]
144pub(crate) struct FramingParameters<'a> {
145 aad: &'a [u8],
146 wire_format: WireFormat,
147}
148
149impl<'a> FramingParameters<'a> {
150 pub(crate) fn new(aad: &'a [u8], wire_format: impl Into<WireFormat>) -> Self {
151 Self {
152 aad,
153 wire_format: wire_format.into(),
154 }
155 }
156
157 pub(crate) fn aad(&self) -> &'a [u8] {
158 self.aad
159 }
160 pub(crate) fn wire_format(&self) -> WireFormat {
161 self.wire_format
162 }
163}
164
165/// ```c
166/// // draft-ietf-mls-protocol-17
167/// enum {
168/// reserved(0),
169/// application(1),
170/// proposal(2),
171/// commit(3),
172/// (255)
173/// } ContentType;
174/// ```
175#[derive(
176 PartialEq,
177 Eq,
178 Clone,
179 Copy,
180 Debug,
181 Serialize,
182 Deserialize,
183 TlsDeserialize,
184 TlsDeserializeBytes,
185 TlsSerialize,
186 TlsSize,
187)]
188#[repr(u8)]
189pub enum ContentType {
190 /// Application message
191 Application = 1,
192 /// Proposal
193 Proposal = 2,
194 /// Commit
195 Commit = 3,
196}
197
198impl TryFrom<u8> for ContentType {
199 type Error = tls_codec::Error;
200 fn try_from(value: u8) -> Result<Self, tls_codec::Error> {
201 match value {
202 1 => Ok(ContentType::Application),
203 2 => Ok(ContentType::Proposal),
204 3 => Ok(ContentType::Commit),
205 _ => Err(tls_codec::Error::DecodingError(format!(
206 "{value} is not a valid content type"
207 ))),
208 }
209 }
210}
211
212impl ContentType {
213 /// Returns `true` if this is a handshake message and `false` otherwise.
214 pub(crate) fn is_handshake_message(&self) -> bool {
215 self == &ContentType::Proposal || self == &ContentType::Commit
216 }
217}