mls_spec/defs/
mod.rs

1use crate::macros::impl_spec_enum;
2
3pub mod labels;
4
5pub type LeafIndex = u32;
6pub type SenderIndex = u32;
7pub type Generation = u32;
8pub type Epoch = u64;
9
10pub const MLS_MIME_TYPE: &str = "message/mls";
11
12/// MLS GREASE values to check implementation robustness
13///
14/// <https://www.rfc-editor.org/rfc/rfc9420.html#section-13.5>
15pub const GREASE_VALUES: [u16; 15] = [
16    0x0A0A, 0x1A1A, 0x2A2A, 0x3A3A, 0x4A4A, 0x5A5A, 0x6A6A, 0x7A7A, 0x8A8A, 0x9A9A, 0xAAAA, 0xBABA,
17    0xCACA, 0xDADA, 0xEAEA,
18];
19
20#[derive(
21    Debug,
22    Clone,
23    Copy,
24    PartialEq,
25    Eq,
26    PartialOrd,
27    Ord,
28    Default,
29    tls_codec::TlsSerialize,
30    tls_codec::TlsDeserialize,
31    tls_codec::TlsSize,
32    strum::IntoStaticStr,
33    strum::Display,
34    strum::EnumString,
35)]
36#[cfg_attr(
37    feature = "serde",
38    derive(serde_repr::Serialize_repr, serde_repr::Deserialize_repr)
39)]
40#[repr(u16)]
41#[non_exhaustive]
42pub enum ProtocolVersion {
43    Reserved = 0x0000,
44    #[strum(serialize = "MLS 1.0")]
45    #[default]
46    Mls10 = 0x0001,
47}
48
49impl ProtocolVersion {
50    #[must_use]
51    pub fn all_without_spec_default() -> Vec<Self> {
52        vec![Self::Mls10]
53    }
54}
55
56impl_spec_enum! {
57    CiphersuiteId(u16);
58    serde_repr "u16";
59    reserved_priv 0xF000..=0xFFFF => crate::MlsSpecError::InvalidPrivateRangeCiphersuite;
60    default_range None;
61    SPEC_RESERVED = 0x0000,
62    MLS_128_DHKEMX25519_AES128GCM_SHA256_ED25519 = 0x0001,
63    MLS_128_DHKEMP256_AES128GCM_SHA256_P256 = 0x0002,
64    MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_ED25519 = 0x0003,
65    MLS_256_DHKEMX448_AES256GCM_SHA512_ED448 = 0x0004,
66    MLS_256_DHKEMP521_AES256GCM_SHA512_P521 = 0x0005,
67    MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_ED448 = 0x0006,
68    MLS_256_DHKEMP384_AES256GCM_SHA384_P384 = 0x0007
69}
70
71impl Default for CiphersuiteId {
72    fn default() -> Self {
73        Self(Self::MLS_128_DHKEMX25519_AES128GCM_SHA256_ED25519)
74    }
75}
76
77impl_spec_enum! {
78    ExtensionType(u16);
79    serde_repr "u16";
80    reserved_priv 0xF000..=0xFFFF => crate::MlsSpecError::InvalidPrivateRangeExtensionType;
81    default_range Some(0x0001..=0x0005);
82    SPEC_RESERVED = 0x0000,
83    APPLICATION_ID = 0x0001,
84    RATCHET_TREE = 0x0002,
85    REQUIRED_CAPABILITIES = 0x0003,
86    EXTERNAL_PUB = 0x0004,
87    EXTERNAL_SENDERS = 0x0005,
88    #[cfg(feature = "draft-ietf-mls-extensions")]
89    APPLICATION_DATA_DICTIONARY = crate::drafts::mls_extensions::EXTENSION_APP_DATA_DICT,
90    #[cfg(feature = "draft-ietf-mls-extensions")]
91    SUPPORTED_WIRE_FORMATS = crate::drafts::mls_extensions::EXTENSION_SUPPORTED_WIRE_FORMATS,
92    #[cfg(feature = "draft-ietf-mls-extensions")]
93    REQUIRED_WIRE_FORMATS = crate::drafts::mls_extensions::EXTENSION_REQUIRED_WIRE_FORMATS,
94    #[cfg(feature = "draft-ietf-mls-extensions")]
95    TARGETED_MESSAGES_CAPABILITY = crate::drafts::mls_extensions::EXTENSION_TARGETED_MESSAGES_CAPABILITY
96}
97
98impl Default for ExtensionType {
99    fn default() -> Self {
100        Self(Self::SPEC_RESERVED)
101    }
102}
103
104impl_spec_enum! {
105    ProposalType(u16);
106    serde_repr "u16";
107    reserved_priv 0xF000..=0xFFFF => crate::MlsSpecError::InvalidPrivateRangeProposalType;
108    default_range Some(0x0001..=0x0007);
109    SPEC_RESERVED = 0x0000,
110    ADD = 0x0001,
111    UPDATE = 0x0002,
112    REMOVE = 0x0003,
113    PSK = 0x0004,
114    REINIT = 0x0005,
115    EXTERNAL_INIT = 0x0006,
116    GROUP_CONTEXT_EXTENSIONS = 0x0007,
117    #[cfg(feature = "draft-ietf-mls-extensions")]
118    APP_DATA_UPDATE = crate::drafts::mls_extensions::PROPOSAL_APP_DATA_UPDATE,
119    #[cfg(feature = "draft-ietf-mls-extensions")]
120    APP_EPHEMERAL = crate::drafts::mls_extensions::PROPOSAL_APP_EPHEMERAL,
121    #[cfg(feature = "draft-ietf-mls-extensions")]
122    SELF_REMOVE = crate::drafts::mls_extensions::PROPOSAL_SELF_REMOVE
123}
124
125impl ProposalType {
126    #[inline]
127    pub fn is_allowed_in_external_proposals(&self) -> bool {
128        #[allow(unused_mut)]
129        let mut allowed = matches!(
130            self.0,
131            Self::ADD | Self::REMOVE | Self::PSK | Self::REINIT | Self::GROUP_CONTEXT_EXTENSIONS
132        );
133
134        #[cfg(feature = "draft-ietf-mls-extensions")]
135        {
136            allowed |= matches!(self.0, Self::APP_DATA_UPDATE | Self::APP_EPHEMERAL);
137        }
138
139        allowed
140    }
141
142    #[inline]
143    pub fn needs_update_path(&self) -> bool {
144        #[allow(unused_mut)]
145        let mut needs_update_path = matches!(
146            self.0,
147            Self::UPDATE | Self::REMOVE | Self::EXTERNAL_INIT | Self::GROUP_CONTEXT_EXTENSIONS
148        );
149
150        #[cfg(feature = "draft-ietf-mls-extensions")]
151        {
152            needs_update_path |= matches!(self.0, Self::SELF_REMOVE);
153        }
154
155        needs_update_path
156    }
157}
158
159impl_spec_enum! {
160    CredentialType(u16);
161    serde_repr "u16";
162    reserved_priv 0xF000..=0xFFFF => crate::MlsSpecError::InvalidPrivateRangeCredentialType;
163    default_range None;
164    SPEC_RESERVED = 0x0000,
165    BASIC = 0x0001,
166    X509 = 0x0002,
167    #[cfg(feature = "draft-ietf-mls-extensions")]
168    MULTI_CREDENTIAL = crate::drafts::mls_extensions::multi_credentials::MULTI_CREDENTIAL,
169    #[cfg(feature = "draft-ietf-mls-extensions")]
170    WEAK_MULTI_CREDENTIAL= crate::drafts::mls_extensions::multi_credentials::WEAK_MULTI_CREDENTIAL,
171    #[cfg(feature = "draft-mahy-mls-sd-cwt-credential")]
172    SD_CWT_CREDENTIAL = crate::drafts::sd_cwt_credential::CREDENTIAL_SD_CWT,
173    #[cfg(feature = "draft-mahy-mls-sd-cwt-credential")]
174    SD_JWT_CREDENTIAL = crate::drafts::sd_cwt_credential::CREDENTIAL_SD_JWT
175}
176
177impl Default for CredentialType {
178    fn default() -> Self {
179        Self(Self::BASIC)
180    }
181}
182
183impl_spec_enum! {
184    WireFormat(u16);
185    serde_repr "u16";
186    reserved_priv 0xF000..=0xFFFF => crate::MlsSpecError::InvalidPrivateRangeWireFormat;
187    default_range None;
188    SPEC_RESERVED = 0x0000,
189    MLS_PUBLIC_MESSAGE = 0x0001,
190    MLS_PRIVATE_MESSAGE = 0x0002,
191    MLS_WELCOME = 0x0003,
192    MLS_GROUP_INFO = 0x0004,
193    MLS_KEY_PACKAGE = 0x0005,
194    #[cfg(feature = "draft-ietf-mls-extensions")]
195    MLS_TARGETED_MESSAGE = crate::drafts::mls_extensions::WIRE_FORMAT_MLS_TARGETED_MESSAGE,
196    #[cfg(feature = "draft-mahy-mls-semiprivatemessage")]
197    MLS_SEMIPRIVATE_MESSAGE = crate::drafts::semiprivate_message::WIRE_FORMAT_MLS_SEMIPRIVATE_MESSAGE,
198    #[cfg(feature = "draft-mularczyk-mls-splitcommit")]
199    MLS_SPLIT_COMMIT = crate::drafts::split_commit::WIRE_FORMAT_MLS_SPLIT_COMMIT,
200    #[cfg(feature = "draft-pham-mls-additional-wire-formats")]
201    MLS_MESSAGE_WITHOUT_AAD = crate::drafts::additional_wire_formats::WIRE_FORMAT_MLS_MESSAGE_WITHOUT_AAD
202}
203
204#[derive(
205    Debug,
206    Clone,
207    PartialEq,
208    Eq,
209    tls_codec::TlsSerialize,
210    tls_codec::TlsDeserialize,
211    tls_codec::TlsSize,
212)]
213#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
214pub struct Capabilities {
215    pub versions: Vec<ProtocolVersion>,
216    pub ciphersuites: Vec<CiphersuiteId>,
217    pub extensions: Vec<ExtensionType>,
218    pub proposals: Vec<ProposalType>,
219    pub credentials: Vec<CredentialType>,
220}