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, storage::StorageProvider as _};
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 pub fn self_update<Provider: OpenMlsProvider>(
33 &mut self,
34 provider: &Provider,
35 signer: &impl Signer,
36 leaf_node_parameters: LeafNodeParameters,
37 ) -> Result<CommitMessageBundle, SelfUpdateError<Provider::StorageError>> {
38 self.is_operational()?;
39
40 let bundle = self
41 .commit_builder()
42 .leaf_node_parameters(leaf_node_parameters)
43 .consume_proposal_store(true)
44 .load_psks(provider.storage())?
45 .build(provider.rand(), provider.crypto(), signer, |_| true)?
46 .stage_commit(provider)?;
47
48 self.reset_aad();
49
50 Ok(bundle)
51 }
52
53 #[cfg(any(not(feature = "virtual-clients-draft"), feature = "test-utils", test))]
77 pub fn self_update_with_new_signer<Provider: OpenMlsProvider, S: Signer>(
78 &mut self,
79 provider: &Provider,
80 old_signer: &impl Signer,
81 new_signer: NewSignerBundle<'_, S>,
82 leaf_node_parameters: LeafNodeParameters,
83 ) -> Result<CommitMessageBundle, SelfUpdateError<Provider::StorageError>> {
84 self.is_operational()?;
85
86 let bundle = self
87 .commit_builder()
88 .leaf_node_parameters(leaf_node_parameters)
89 .consume_proposal_store(true)
90 .load_psks(provider.storage())?
91 .build_with_new_signer(
92 provider.rand(),
93 provider.crypto(),
94 old_signer,
95 new_signer,
96 |_| true,
97 )?
98 .stage_commit(provider)?;
99
100 self.reset_aad();
101
102 Ok(bundle)
103 }
104
105 fn create_self_update_proposal_internal<Provider: OpenMlsProvider, S: Signer>(
109 &mut self,
110 provider: &Provider,
111 old_signer: &impl Signer,
112 new_signer: Option<NewSignerBundle<'_, S>>,
113 mut leaf_node_parameters: LeafNodeParameters,
114 ) -> Result<AuthenticatedContent, ProposeSelfUpdateError<Provider::StorageError>> {
115 self.is_operational()?;
116
117 let mut own_leaf = self
122 .public_group()
123 .leaf(self.own_leaf_index())
124 .ok_or_else(|| LibraryError::custom("The tree is broken. Couldn't find own leaf."))?
125 .clone();
126
127 if let Some(new_signer) = new_signer {
128 if self.ciphersuite().signature_algorithm() != new_signer.signer.signature_scheme() {
129 return Err(ProposeSelfUpdateError::InvalidSignerCiphersuite);
130 }
131
132 if let Some(ln_cred) = leaf_node_parameters.credential_with_key() {
136 if ln_cred != &new_signer.credential_with_key {
137 return Err(ProposeSelfUpdateError::InvalidLeafNodeParameters);
138 }
139 } else {
140 leaf_node_parameters.set_credential_with_key(new_signer.credential_with_key);
141 }
142
143 own_leaf.update(
144 self.ciphersuite(),
145 provider,
146 new_signer.signer,
147 self.group_id().clone(),
148 self.own_leaf_index(),
149 leaf_node_parameters,
150 )?;
151 } else {
152 own_leaf.update(
153 self.ciphersuite(),
154 provider,
155 old_signer,
156 self.group_id().clone(),
157 self.own_leaf_index(),
158 leaf_node_parameters,
159 )?;
160 }
161
162 let leaf_supports_all_extensions = self
165 .public_group()
166 .group_context()
167 .extensions()
168 .iter()
169 .all(|extension| own_leaf.supports_extension(&extension.extension_type()));
170
171 if !leaf_supports_all_extensions {
172 return Err(ProposeSelfUpdateError::UnsupportedGroupContextExtensions);
173 }
174
175 let aad = self.outgoing_authenticated_data()?;
176 let framing_parameters = FramingParameters::new(&aad, self.outgoing_wire_format());
177 let update_proposal =
178 self.create_update_proposal(framing_parameters, own_leaf.clone(), old_signer)?;
179
180 provider
181 .storage()
182 .append_own_leaf_node(self.group_id(), &own_leaf)
183 .map_err(ProposeSelfUpdateError::StorageError)?;
184 self.own_leaf_nodes.push(own_leaf);
185
186 Ok(update_proposal)
187 }
188
189 pub(crate) fn propose_self_update_internal<Provider: OpenMlsProvider, S: Signer>(
190 &mut self,
191 provider: &Provider,
192 old_signer: &impl Signer,
193 new_signer: Option<NewSignerBundle<'_, S>>,
194 leaf_node_parameters: LeafNodeParameters,
195 ) -> Result<(HandshakeFramingOutput, ProposalRef), ProposeSelfUpdateError<Provider::StorageError>>
196 {
197 let update_proposal = self.create_self_update_proposal_internal(
198 provider,
199 old_signer,
200 new_signer,
201 leaf_node_parameters,
202 )?;
203 let proposal = QueuedProposal::from_authenticated_content_by_ref(
204 self.ciphersuite(),
205 provider.crypto(),
206 update_proposal.clone(),
207 )?;
208 let proposal_ref = proposal.proposal_reference();
209 provider
210 .storage()
211 .queue_proposal(self.group_id(), &proposal_ref, &proposal)
212 .map_err(ProposeSelfUpdateError::StorageError)?;
213 self.proposal_store_mut().add(proposal);
214
215 let framing = self.content_to_mls_message(update_proposal, provider)?;
216
217 self.reset_aad();
218 Ok((framing, proposal_ref))
219 }
220
221 #[cfg(any(not(feature = "virtual-clients-draft"), feature = "test-utils", test))]
230 pub fn propose_self_update<Provider: OpenMlsProvider, S: Signer>(
231 &mut self,
232 provider: &Provider,
233 signer: &S,
234 leaf_node_parameters: LeafNodeParameters,
235 ) -> Result<(MlsMessageOut, ProposalRef), ProposeSelfUpdateError<Provider::StorageError>> {
236 let (framing, proposal_ref) = self.propose_self_update_internal(
237 provider,
238 signer,
239 None::<NewSignerBundle<'_, S>>,
240 leaf_node_parameters,
241 )?;
242 Ok((framing.message, proposal_ref))
243 }
244
245 #[cfg(any(not(feature = "virtual-clients-draft"), feature = "test-utils", test))]
265 pub fn propose_self_update_with_new_signer<Provider: OpenMlsProvider, S: Signer>(
266 &mut self,
267 provider: &Provider,
268 old_signer: &impl Signer,
269 new_signer: NewSignerBundle<'_, S>,
270 leaf_node_parameters: LeafNodeParameters,
271 ) -> Result<(MlsMessageOut, ProposalRef), ProposeSelfUpdateError<Provider::StorageError>> {
272 let (framing, proposal_ref) = self.propose_self_update_internal(
273 provider,
274 old_signer,
275 Some(new_signer),
276 leaf_node_parameters,
277 )?;
278 Ok((framing.message, proposal_ref))
279 }
280
281 #[cfg(feature = "virtual-clients-draft")]
290 pub fn propose_self_update_with_new_signer_unconfirmed<Provider: OpenMlsProvider, S: Signer>(
291 &mut self,
292 provider: &Provider,
293 old_signer: &impl Signer,
294 new_signer: NewSignerBundle<'_, S>,
295 leaf_node_parameters: LeafNodeParameters,
296 ) -> Result<
297 (
298 MlsMessageOut,
299 ProposalRef,
300 Option<HandshakeConfirmationData>,
301 ),
302 ProposeSelfUpdateError<Provider::StorageError>,
303 > {
304 let (framing, proposal_ref) = self.propose_self_update_internal(
305 provider,
306 old_signer,
307 Some(new_signer),
308 leaf_node_parameters,
309 )?;
310 Ok((framing.message, proposal_ref, framing.confirmation))
311 }
312}