1use commit_builder::CommitMessageBundle;
2use errors::{ProposeSelfUpdateError, SelfUpdateError};
3use openmls_traits::{signatures::Signer, storage::StorageProvider as _};
4
5use crate::{credentials::NewSignerBundle, storage::OpenMlsProvider, treesync::LeafNodeParameters};
6
7use super::*;
8
9impl MlsGroup {
10 pub fn self_update<Provider: OpenMlsProvider>(
24 &mut self,
25 provider: &Provider,
26 signer: &impl Signer,
27 leaf_node_parameters: LeafNodeParameters,
28 ) -> Result<CommitMessageBundle, SelfUpdateError<Provider::StorageError>> {
29 self.is_operational()?;
30
31 let bundle = self
32 .commit_builder()
33 .leaf_node_parameters(leaf_node_parameters)
34 .consume_proposal_store(true)
35 .load_psks(provider.storage())?
36 .build(provider.rand(), provider.crypto(), signer, |_| true)?
37 .stage_commit(provider)?;
38
39 self.reset_aad();
40
41 Ok(bundle)
42 }
43
44 pub fn self_update_with_new_signer<Provider: OpenMlsProvider, S: Signer>(
63 &mut self,
64 provider: &Provider,
65 old_signer: &impl Signer,
66 new_signer: NewSignerBundle<'_, S>,
67 leaf_node_parameters: LeafNodeParameters,
68 ) -> Result<CommitMessageBundle, SelfUpdateError<Provider::StorageError>> {
69 self.is_operational()?;
70
71 let bundle = self
72 .commit_builder()
73 .leaf_node_parameters(leaf_node_parameters)
74 .consume_proposal_store(true)
75 .load_psks(provider.storage())?
76 .build_with_new_signer(
77 provider.rand(),
78 provider.crypto(),
79 old_signer,
80 new_signer,
81 |_| true,
82 )?
83 .stage_commit(provider)?;
84
85 self.reset_aad();
86
87 Ok(bundle)
88 }
89
90 fn create_self_update_proposal_internal<Provider: OpenMlsProvider, S: Signer>(
94 &mut self,
95 provider: &Provider,
96 old_signer: &impl Signer,
97 new_signer: Option<NewSignerBundle<'_, S>>,
98 mut leaf_node_parameters: LeafNodeParameters,
99 ) -> Result<AuthenticatedContent, ProposeSelfUpdateError<Provider::StorageError>> {
100 self.is_operational()?;
101
102 let mut own_leaf = self
107 .public_group()
108 .leaf(self.own_leaf_index())
109 .ok_or_else(|| LibraryError::custom("The tree is broken. Couldn't find own leaf."))?
110 .clone();
111
112 if let Some(new_signer) = new_signer {
113 if self.ciphersuite().signature_algorithm() != new_signer.signer.signature_scheme() {
114 return Err(ProposeSelfUpdateError::InvalidSignerCiphersuite);
115 }
116
117 if let Some(ln_cred) = leaf_node_parameters.credential_with_key() {
121 if ln_cred != &new_signer.credential_with_key {
122 return Err(ProposeSelfUpdateError::InvalidLeafNodeParameters);
123 }
124 } else {
125 leaf_node_parameters.set_credential_with_key(new_signer.credential_with_key);
126 }
127
128 own_leaf.update(
129 self.ciphersuite(),
130 provider,
131 new_signer.signer,
132 self.group_id().clone(),
133 self.own_leaf_index(),
134 leaf_node_parameters,
135 )?;
136 } else {
137 own_leaf.update(
138 self.ciphersuite(),
139 provider,
140 old_signer,
141 self.group_id().clone(),
142 self.own_leaf_index(),
143 leaf_node_parameters,
144 )?;
145 }
146
147 let leaf_supports_all_extensions = self
150 .public_group()
151 .group_context()
152 .extensions()
153 .iter()
154 .all(|extension| own_leaf.supports_extension(&extension.extension_type()));
155
156 if !leaf_supports_all_extensions {
157 return Err(ProposeSelfUpdateError::UnsupportedGroupContextExtensions);
158 }
159
160 let aad = self.outgoing_authenticated_data()?;
161 let framing_parameters = FramingParameters::new(&aad, self.outgoing_wire_format());
162 let update_proposal =
163 self.create_update_proposal(framing_parameters, own_leaf.clone(), old_signer)?;
164
165 provider
166 .storage()
167 .append_own_leaf_node(self.group_id(), &own_leaf)
168 .map_err(ProposeSelfUpdateError::StorageError)?;
169 self.own_leaf_nodes.push(own_leaf);
170
171 Ok(update_proposal)
172 }
173
174 fn propose_self_update_internal<Provider: OpenMlsProvider, S: Signer>(
175 &mut self,
176 provider: &Provider,
177 old_signer: &impl Signer,
178 new_signer: Option<NewSignerBundle<'_, S>>,
179 leaf_node_parameters: LeafNodeParameters,
180 ) -> Result<(MlsMessageOut, ProposalRef), ProposeSelfUpdateError<Provider::StorageError>> {
181 let update_proposal = self.create_self_update_proposal_internal(
182 provider,
183 old_signer,
184 new_signer,
185 leaf_node_parameters,
186 )?;
187 let proposal = QueuedProposal::from_authenticated_content_by_ref(
188 self.ciphersuite(),
189 provider.crypto(),
190 update_proposal.clone(),
191 )?;
192 let proposal_ref = proposal.proposal_reference();
193 provider
194 .storage()
195 .queue_proposal(self.group_id(), &proposal_ref, &proposal)
196 .map_err(ProposeSelfUpdateError::StorageError)?;
197 self.proposal_store_mut().add(proposal);
198
199 let mls_message = self.content_to_mls_message(update_proposal, provider)?;
200
201 self.reset_aad();
202 Ok((mls_message, proposal_ref))
203 }
204
205 pub fn propose_self_update<Provider: OpenMlsProvider, S: Signer>(
209 &mut self,
210 provider: &Provider,
211 signer: &S,
212 leaf_node_parameters: LeafNodeParameters,
213 ) -> Result<(MlsMessageOut, ProposalRef), ProposeSelfUpdateError<Provider::StorageError>> {
214 self.propose_self_update_internal(
215 provider,
216 signer,
217 None::<NewSignerBundle<'_, S>>,
218 leaf_node_parameters,
219 )
220 }
221
222 pub fn propose_self_update_with_new_signer<Provider: OpenMlsProvider, S: Signer>(
238 &mut self,
239 provider: &Provider,
240 old_signer: &impl Signer,
241 new_signer: NewSignerBundle<'_, S>,
242 leaf_node_parameters: LeafNodeParameters,
243 ) -> Result<(MlsMessageOut, ProposalRef), ProposeSelfUpdateError<Provider::StorageError>> {
244 self.propose_self_update_internal(
245 provider,
246 old_signer,
247 Some(new_signer),
248 leaf_node_parameters,
249 )
250 }
251}