mls_spec/group/
proposals.rs

1use crate::{
2    SensitiveBytes,
3    defs::{CiphersuiteId, LeafIndex, ProposalType, ProtocolVersion},
4    group::{GroupId, extensions::Extension},
5    key_package::KeyPackage,
6    key_schedule::{GroupContext, PreSharedKeyId},
7    tree::leaf_node::LeafNode,
8};
9
10#[derive(
11    Debug,
12    Clone,
13    PartialEq,
14    Eq,
15    tls_codec::TlsSerialize,
16    tls_codec::TlsDeserialize,
17    tls_codec::TlsSize,
18)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20#[repr(u16)]
21pub enum Proposal {
22    #[tls_codec(discriminant = "ProposalType::ADD")]
23    Add(AddProposal),
24    #[tls_codec(discriminant = "ProposalType::UPDATE")]
25    Update(UpdateProposal),
26    #[tls_codec(discriminant = "ProposalType::REMOVE")]
27    Remove(RemoveProposal),
28    #[tls_codec(discriminant = "ProposalType::PSK")]
29    PreSharedKey(PreSharedKeyProposal),
30    #[tls_codec(discriminant = "ProposalType::REINIT")]
31    ReInit(ReInitProposal),
32    #[tls_codec(discriminant = "ProposalType::EXTERNAL_INIT")]
33    ExternalInit(ExternalInitProposal),
34    #[tls_codec(discriminant = "ProposalType::GROUP_CONTEXT_EXTENSIONS")]
35    GroupContextExtensions(GroupContextExtensionsProposal),
36    #[cfg(feature = "draft-ietf-mls-extensions")]
37    #[tls_codec(discriminant = "ProposalType::APP_DATA_UPDATE")]
38    AppDataUpdate(crate::drafts::mls_extensions::safe_application::AppDataUpdate),
39    #[cfg(feature = "draft-ietf-mls-extensions")]
40    #[tls_codec(discriminant = "ProposalType::APP_EPHEMERAL")]
41    AppEphemeral(crate::drafts::mls_extensions::safe_application::AppEphemeral),
42    #[cfg(feature = "draft-ietf-mls-extensions")]
43    #[tls_codec(discriminant = "ProposalType::SELF_REMOVE")]
44    SelfRemove(crate::drafts::mls_extensions::self_remove::SelfRemoveProposal),
45}
46
47impl Proposal {
48    #[inline(always)]
49    pub fn proposal_type(&self) -> ProposalType {
50        self.into()
51    }
52}
53
54impl From<&Proposal> for ProposalType {
55    fn from(val: &Proposal) -> Self {
56        match val {
57            Proposal::Add(_) => ProposalType::new_unchecked(ProposalType::ADD),
58            Proposal::Update(_) => ProposalType::new_unchecked(ProposalType::UPDATE),
59            Proposal::Remove(_) => ProposalType::new_unchecked(ProposalType::REMOVE),
60            Proposal::PreSharedKey(_) => ProposalType::new_unchecked(ProposalType::PSK),
61            Proposal::ReInit(_) => ProposalType::new_unchecked(ProposalType::REINIT),
62            Proposal::ExternalInit(_) => ProposalType::new_unchecked(ProposalType::EXTERNAL_INIT),
63            Proposal::GroupContextExtensions(_) => {
64                ProposalType::new_unchecked(ProposalType::GROUP_CONTEXT_EXTENSIONS)
65            }
66            #[cfg(feature = "draft-ietf-mls-extensions")]
67            Proposal::AppDataUpdate(_) => {
68                ProposalType::new_unchecked(ProposalType::APP_DATA_UPDATE)
69            }
70            #[cfg(feature = "draft-ietf-mls-extensions")]
71            Proposal::AppEphemeral(_) => ProposalType::new_unchecked(ProposalType::APP_EPHEMERAL),
72            #[cfg(feature = "draft-ietf-mls-extensions")]
73            Proposal::SelfRemove(_) => ProposalType::new_unchecked(ProposalType::SELF_REMOVE),
74        }
75    }
76}
77
78impl Proposal {
79    #[inline]
80    pub fn needs_update_path(&self) -> bool {
81        self.proposal_type().needs_update_path()
82    }
83}
84
85#[derive(
86    Debug,
87    Clone,
88    PartialEq,
89    Eq,
90    tls_codec::TlsSerialize,
91    tls_codec::TlsDeserialize,
92    tls_codec::TlsSize,
93)]
94#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
95pub struct AddProposal {
96    pub key_package: KeyPackage,
97}
98
99#[derive(
100    Debug,
101    Clone,
102    PartialEq,
103    Eq,
104    tls_codec::TlsSerialize,
105    tls_codec::TlsDeserialize,
106    tls_codec::TlsSize,
107)]
108#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
109pub struct UpdateProposal {
110    pub leaf_node: LeafNode,
111}
112
113#[derive(
114    Debug,
115    Clone,
116    PartialEq,
117    Eq,
118    tls_codec::TlsSerialize,
119    tls_codec::TlsDeserialize,
120    tls_codec::TlsSize,
121)]
122#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
123pub struct RemoveProposal {
124    pub removed: LeafIndex,
125}
126
127#[derive(
128    Debug,
129    Clone,
130    PartialEq,
131    Eq,
132    tls_codec::TlsSerialize,
133    tls_codec::TlsDeserialize,
134    tls_codec::TlsSize,
135)]
136#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
137pub struct PreSharedKeyProposal {
138    pub psk: PreSharedKeyId,
139}
140
141#[derive(
142    Debug,
143    Clone,
144    PartialEq,
145    Eq,
146    tls_codec::TlsSerialize,
147    tls_codec::TlsDeserialize,
148    tls_codec::TlsSize,
149)]
150#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
151pub struct ReInitProposal {
152    pub group_id: GroupId,
153    pub version: ProtocolVersion,
154    pub cipher_suite: CiphersuiteId,
155    pub extensions: Vec<Extension>,
156}
157
158impl ReInitProposal {
159    pub fn matches_group_context(&self, ctx: &GroupContext) -> bool {
160        self.group_id == ctx.group_id()
161            && self.version == ctx.version
162            && self.cipher_suite == ctx.cipher_suite
163            && self.extensions == ctx.extensions
164    }
165}
166
167#[derive(
168    Debug,
169    Clone,
170    PartialEq,
171    Eq,
172    tls_codec::TlsSerialize,
173    tls_codec::TlsDeserialize,
174    tls_codec::TlsSize,
175)]
176#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
177pub struct ExternalInitProposal {
178    pub kem_output: SensitiveBytes,
179}
180
181#[derive(
182    Debug,
183    Clone,
184    PartialEq,
185    Eq,
186    tls_codec::TlsSerialize,
187    tls_codec::TlsDeserialize,
188    tls_codec::TlsSize,
189)]
190#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
191pub struct GroupContextExtensionsProposal {
192    pub extensions: Vec<Extension>,
193}