1#[cfg(any(not(feature = "virtual-clients-draft"), feature = "test-utils", test))]
2use commit_builder::CommitMessageBundle;
3use errors::ProposeSelfUpdateError;
4#[cfg(any(not(feature = "virtual-clients-draft"), feature = "test-utils", test))]
5use errors::SelfUpdateError;
6use openmls_traits::signatures::Signer;
7
8use crate::{credentials::NewSignerBundle, storage::OpenMlsProvider, treesync::LeafNodeParameters};
9
10use super::*;
11
12impl MlsGroup {
13 #[cfg(any(not(feature = "virtual-clients-draft"), feature = "test-utils", test))]
32 #[openmls_traits::maybe_async]
33 pub async fn self_update<Provider: OpenMlsProvider>(
34 &mut self,
35 provider: &Provider,
36 signer: &impl Signer,
37 leaf_node_parameters: LeafNodeParameters,
38 ) -> Result<CommitMessageBundle, SelfUpdateError<Provider::StorageError>> {
39 self.is_operational()?;
40
41 let bundle = self
42 .commit_builder()
43 .leaf_node_parameters(leaf_node_parameters)
44 .consume_proposal_store(true)
45 .load_psks(provider.storage())
46 .await?
47 .build(provider.rand(), provider.crypto(), signer, |_| true)?
48 .stage_commit(provider)
49 .await?;
50
51 self.reset_aad();
52
53 Ok(bundle)
54 }
55
56 #[cfg(any(not(feature = "virtual-clients-draft"), feature = "test-utils", test))]
80 #[openmls_traits::maybe_async]
81 pub async fn self_update_with_new_signer<Provider: OpenMlsProvider, S: Signer>(
82 &mut self,
83 provider: &Provider,
84 old_signer: &impl Signer,
85 new_signer: NewSignerBundle<'_, S>,
86 leaf_node_parameters: LeafNodeParameters,
87 ) -> Result<CommitMessageBundle, SelfUpdateError<Provider::StorageError>> {
88 self.is_operational()?;
89
90 let bundle = self
91 .commit_builder()
92 .leaf_node_parameters(leaf_node_parameters)
93 .consume_proposal_store(true)
94 .load_psks(provider.storage())
95 .await?
96 .build_with_new_signer(
97 provider.rand(),
98 provider.crypto(),
99 old_signer,
100 new_signer,
101 |_| true,
102 )?
103 .stage_commit(provider)
104 .await?;
105
106 self.reset_aad();
107
108 Ok(bundle)
109 }
110
111 #[openmls_traits::maybe_async]
115 async fn create_self_update_proposal_internal<Provider: OpenMlsProvider, S: Signer>(
116 &mut self,
117 provider: &Provider,
118 old_signer: &impl Signer,
119 new_signer: Option<NewSignerBundle<'_, S>>,
120 mut leaf_node_parameters: LeafNodeParameters,
121 ) -> Result<AuthenticatedContent, ProposeSelfUpdateError<Provider::StorageError>> {
122 self.is_operational()?;
123
124 let mut own_leaf = self
129 .public_group()
130 .leaf(self.own_leaf_index())
131 .ok_or_else(|| LibraryError::custom("The tree is broken. Couldn't find own leaf."))?
132 .clone();
133 let constraints = self.public_group().leaf_node_constraints();
134
135 if let Some(new_signer) = new_signer {
136 if self.ciphersuite().signature_algorithm() != new_signer.signer.signature_scheme() {
137 return Err(ProposeSelfUpdateError::InvalidSignerCiphersuite);
138 }
139
140 if let Some(ln_cred) = leaf_node_parameters.credential_with_key() {
144 if ln_cred != &new_signer.credential_with_key {
145 return Err(ProposeSelfUpdateError::InvalidLeafNodeParameters);
146 }
147 } else {
148 leaf_node_parameters.set_credential_with_key(new_signer.credential_with_key);
149 }
150
151 own_leaf
152 .update(
153 self.ciphersuite(),
154 provider,
155 new_signer.signer,
156 self.group_id().clone(),
157 self.own_leaf_index(),
158 leaf_node_parameters,
159 &constraints,
160 )
161 .await?;
162 } else {
163 own_leaf
164 .update(
165 self.ciphersuite(),
166 provider,
167 old_signer,
168 self.group_id().clone(),
169 self.own_leaf_index(),
170 leaf_node_parameters,
171 &constraints,
172 )
173 .await?;
174 }
175
176 let aad = self.outgoing_authenticated_data()?;
177 let framing_parameters = FramingParameters::new(&aad, self.outgoing_wire_format());
178 let update_proposal =
179 self.create_update_proposal(framing_parameters, own_leaf.clone(), old_signer)?;
180
181 provider
182 .storage()
183 .append_own_leaf_node(self.group_id(), &own_leaf)
184 .await
185 .map_err(ProposeSelfUpdateError::StorageError)?;
186 self.own_leaf_nodes.push(own_leaf);
187
188 Ok(update_proposal)
189 }
190
191 #[openmls_traits::maybe_async]
192 pub(crate) async fn propose_self_update_internal<Provider: OpenMlsProvider, S: Signer>(
193 &mut self,
194 provider: &Provider,
195 old_signer: &impl Signer,
196 new_signer: Option<NewSignerBundle<'_, S>>,
197 leaf_node_parameters: LeafNodeParameters,
198 ) -> Result<(HandshakeFramingOutput, ProposalRef), ProposeSelfUpdateError<Provider::StorageError>>
199 {
200 let update_proposal = self
201 .create_self_update_proposal_internal(
202 provider,
203 old_signer,
204 new_signer,
205 leaf_node_parameters,
206 )
207 .await?;
208 let proposal = QueuedProposal::from_authenticated_content_by_ref(
209 self.ciphersuite(),
210 provider.crypto(),
211 update_proposal.clone(),
212 )?;
213 let proposal_ref = proposal.proposal_reference();
214 provider
215 .storage()
216 .queue_proposal(self.group_id(), &proposal_ref, &proposal)
217 .await
218 .map_err(ProposeSelfUpdateError::StorageError)?;
219 self.proposal_store_mut().add(proposal);
220
221 let framing = self
222 .content_to_mls_message(update_proposal, provider)
223 .await?;
224
225 self.reset_aad();
226 Ok((framing, proposal_ref))
227 }
228
229 #[cfg(any(not(feature = "virtual-clients-draft"), feature = "test-utils", test))]
238 #[openmls_traits::maybe_async]
239 pub async fn propose_self_update<Provider: OpenMlsProvider, S: Signer>(
240 &mut self,
241 provider: &Provider,
242 signer: &S,
243 leaf_node_parameters: LeafNodeParameters,
244 ) -> Result<(MlsMessageOut, ProposalRef), ProposeSelfUpdateError<Provider::StorageError>> {
245 let (framing, proposal_ref) = self
246 .propose_self_update_internal(
247 provider,
248 signer,
249 None::<NewSignerBundle<'_, S>>,
250 leaf_node_parameters,
251 )
252 .await?;
253 Ok((framing.message, proposal_ref))
254 }
255
256 #[cfg(any(not(feature = "virtual-clients-draft"), feature = "test-utils", test))]
276 #[openmls_traits::maybe_async]
277 pub async fn propose_self_update_with_new_signer<Provider: OpenMlsProvider, S: Signer>(
278 &mut self,
279 provider: &Provider,
280 old_signer: &impl Signer,
281 new_signer: NewSignerBundle<'_, S>,
282 leaf_node_parameters: LeafNodeParameters,
283 ) -> Result<(MlsMessageOut, ProposalRef), ProposeSelfUpdateError<Provider::StorageError>> {
284 let (framing, proposal_ref) = self
285 .propose_self_update_internal(
286 provider,
287 old_signer,
288 Some(new_signer),
289 leaf_node_parameters,
290 )
291 .await?;
292 Ok((framing.message, proposal_ref))
293 }
294
295 #[cfg(feature = "virtual-clients-draft")]
304 #[openmls_traits::maybe_async]
305 pub async fn propose_self_update_with_new_signer_unconfirmed<
306 Provider: OpenMlsProvider,
307 S: Signer,
308 >(
309 &mut self,
310 provider: &Provider,
311 old_signer: &impl Signer,
312 new_signer: NewSignerBundle<'_, S>,
313 leaf_node_parameters: LeafNodeParameters,
314 ) -> Result<
315 (
316 MlsMessageOut,
317 ProposalRef,
318 Option<HandshakeConfirmationData>,
319 ),
320 ProposeSelfUpdateError<Provider::StorageError>,
321 > {
322 let (framing, proposal_ref) = self
323 .propose_self_update_internal(
324 provider,
325 old_signer,
326 Some(new_signer),
327 leaf_node_parameters,
328 )
329 .await?;
330 Ok((framing.message, proposal_ref, framing.confirmation))
331 }
332}