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}