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