openmls/group/mls_group/
updates.rs

1use commit_builder::CommitMessageBundle;
2use errors::{ProposeSelfUpdateError, SelfUpdateError};
3use openmls_traits::{signatures::Signer, storage::StorageProvider as _};
4
5use crate::{storage::OpenMlsProvider, treesync::LeafNodeParameters};
6
7use super::*;
8
9impl MlsGroup {
10    /// Updates the own leaf node. The application can choose to update the
11    /// credential, the capabilities, and the extensions by buliding the
12    /// [`LeafNodeParameters`].
13    ///
14    /// If successful, it returns a tuple of [`MlsMessageOut`] (containing the
15    /// commit), an optional [`MlsMessageOut`] (containing the [`Welcome`]) and
16    /// the [GroupInfo]. The [`Welcome`] is [Some] when the queue of pending
17    /// proposals contained add proposals The [GroupInfo] is [Some] if the group
18    /// has the `use_ratchet_tree_extension` flag set.
19    ///
20    /// Returns an error if there is a pending commit.
21    ///
22    /// [`Welcome`]: crate::messages::Welcome
23    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    /// Updates the own leaf node. The application can choose to update the
45    /// credential, the capabilities, and the extensions by buliding the
46    /// [`LeafNodeParameters`].
47    ///
48    /// In contrast to `self_update`, this function allows updating the
49    /// signature public key in the senders leaf node. Note that `new_signer`
50    /// MUST be the private key corresponding to the public key set in the
51    /// `leaf_node_parameters`.
52    ///
53    /// If successful, it returns a tuple of [`MlsMessageOut`] (containing the
54    /// commit), an optional [`MlsMessageOut`] (containing the [`Welcome`]) and
55    /// the [GroupInfo]. The [`Welcome`] is [Some] when the queue of pending
56    /// proposals contained add proposals The [GroupInfo] is [Some] if the group
57    /// has the `use_ratchet_tree_extension` flag set.
58    ///
59    /// Returns an error if there is a pending commit.
60    ///
61    /// [`Welcome`]: crate::messages::Welcome
62    pub fn self_update_with_new_signer<Provider: OpenMlsProvider>(
63        &mut self,
64        provider: &Provider,
65        old_signer: &impl Signer,
66        new_signer: &impl Signer,
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    /// Creates a proposal to update the own leaf node. Optionally, a
91    /// [`LeafNode`] can be provided to update the leaf node. Note that its
92    /// private key must be manually added to the key store.
93    fn _propose_self_update<Provider: OpenMlsProvider>(
94        &mut self,
95        provider: &Provider,
96        signer: &impl Signer,
97        leaf_node_parmeters: LeafNodeParameters,
98    ) -> Result<AuthenticatedContent, ProposeSelfUpdateError<Provider::StorageError>> {
99        self.is_operational()?;
100
101        // Here we clone our own leaf to rekey it such that we don't change the
102        // tree.
103        // The new leaf node will be applied later when the proposal is
104        // committed.
105        let mut own_leaf = self
106            .public_group()
107            .leaf(self.own_leaf_index())
108            .ok_or_else(|| LibraryError::custom("The tree is broken. Couldn't find own leaf."))?
109            .clone();
110
111        own_leaf.update(
112            self.ciphersuite(),
113            provider,
114            signer,
115            self.group_id().clone(),
116            self.own_leaf_index(),
117            leaf_node_parmeters,
118        )?;
119
120        let update_proposal =
121            self.create_update_proposal(self.framing_parameters(), own_leaf.clone(), signer)?;
122
123        provider
124            .storage()
125            .append_own_leaf_node(self.group_id(), &own_leaf)
126            .map_err(ProposeSelfUpdateError::StorageError)?;
127        self.own_leaf_nodes.push(own_leaf);
128
129        Ok(update_proposal)
130    }
131
132    /// Creates a proposal to update the own leaf node. The application can
133    /// choose to update the credential, the capabilities, and the extensions by
134    /// building the [`LeafNodeParameters`].
135    pub fn propose_self_update<Provider: OpenMlsProvider>(
136        &mut self,
137        provider: &Provider,
138        signer: &impl Signer,
139        leaf_node_parameters: LeafNodeParameters,
140    ) -> Result<(MlsMessageOut, ProposalRef), ProposeSelfUpdateError<Provider::StorageError>> {
141        let update_proposal = self._propose_self_update(provider, signer, leaf_node_parameters)?;
142        let proposal = QueuedProposal::from_authenticated_content_by_ref(
143            self.ciphersuite(),
144            provider.crypto(),
145            update_proposal.clone(),
146        )?;
147        let proposal_ref = proposal.proposal_reference();
148        provider
149            .storage()
150            .queue_proposal(self.group_id(), &proposal_ref, &proposal)
151            .map_err(ProposeSelfUpdateError::StorageError)?;
152        self.proposal_store_mut().add(proposal);
153
154        let mls_message = self.content_to_mls_message(update_proposal, provider)?;
155
156        self.reset_aad();
157        Ok((mls_message, proposal_ref))
158    }
159}