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