// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // Copyright by contributors to this project. // SPDX-License-Identifier: (Apache-2.0 OR MIT)
use alloc::vec::Vec;
use mls_rs_core::{
crypto::{CipherSuite, SignatureSecretKey},
extension::ExtensionList,
identity::SigningIdentity,
protocol_version::ProtocolVersion,
};
impl<C> Group<C> where
C: ClientConfig + Clone,
{ /// Create a sub-group from a subset of the current group members. /// /// Membership within the resulting sub-group is indicated by providing a /// key package that produces the same /// [identity](crate::IdentityProvider::identity) value /// as an existing group member. The identity value of each key package /// is determined using the /// [`IdentityProvider`](crate::IdentityProvider) /// that is currently in use by this group instance. #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)] pubasyncfn branch(
&self,
sub_group_id: Vec<u8>,
new_key_packages: Vec<MlsMessage>,
) -> Result<(Group<C>, Vec<MlsMessage>), MlsError> { let new_group_params = ResumptionGroupParameters {
group_id: &sub_group_id,
cipher_suite: self.cipher_suite(),
version: self.protocol_version(),
extensions: &self.group_state().context.extensions,
};
resumption_create_group( self.config.clone(),
new_key_packages,
&new_group_params, // TODO investigate if it's worth updating your own signing identity here self.current_member_signing_identity()?.clone(), self.signer.clone(), #[cfg(any(feature = "private_message", feature = "psk"))] self.resumption_psk_input(ResumptionPSKUsage::Branch)?,
)
.await
}
/// Join a subgroup that was created by [`Group::branch`]. #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)] pubasyncfn join_subgroup(
&self,
welcome: &MlsMessage,
tree_data: Option<ExportedTree<'_>>,
) -> Result<(Group<C>, NewMemberInfo), MlsError> { let expected_new_group_prams = ResumptionGroupParameters {
group_id: &[],
cipher_suite: self.cipher_suite(),
version: self.protocol_version(),
extensions: &self.group_state().context.extensions,
};
/// Generate a [`ReinitClient`] that can be used to create or join a new group /// that is based on properties defined by a [`ReInitProposal`] /// committed in a previously accepted commit. This is the only action available /// after accepting such a commit. The old group can no longer be used according to the RFC. /// /// If the [`ReInitProposal`] changes the ciphersuite, then `new_signer` /// and `new_signer_identity` must be set and match the new ciphersuite, as indicated by /// [`pending_reinit_ciphersuite`](crate::group::StateUpdate::pending_reinit_ciphersuite) /// of the [`StateUpdate`](crate::group::StateUpdate) outputted after processing the /// commit to the reinit proposal. The value of [identity](crate::IdentityProvider::identity) /// must be the same for `new_signing_identity` and the current identity in use by this /// group instance. pubfn get_reinit_client( self,
new_signer: Option<SignatureSecretKey>,
new_signing_identity: Option<SigningIdentity>,
) -> Result<ReinitClient<C>, MlsError> { let psk_input = self.resumption_psk_input(ResumptionPSKUsage::Reinit)?;
let new_signing_identity = new_signing_identity
.map(Ok)
.unwrap_or_else(|| self.current_member_signing_identity().cloned())?;
let reinit = self
.state
.pending_reinit
.ok_or(MlsError::PendingReInitNotFound)?;
let new_signer = match new_signer {
Some(signer) => signer,
None => self.signer,
};
let client = Client::new( self.config,
Some(new_signer),
Some((new_signing_identity, reinit.new_cipher_suite())),
reinit.new_version(),
);
let id = JustPreSharedKeyID::Resumption(ResumptionPsk {
usage,
psk_group_id: PskGroupId(self.group_id().to_vec()),
psk_epoch: self.current_epoch(),
});
let id = PreSharedKeyID::new(id, self.cipher_suite_provider())?;
Ok(PskSecretInput { id, psk })
}
}
/// A [`Client`] that can be used to create or join a new group /// that is based on properties defined by a [`ReInitProposal`] /// committed in a previously accepted commit. impl<C: ClientConfig + Clone> ReinitClient<C> { /// Generate a key package for the new group. The key package can /// be used in [`ReinitClient::commit`]. #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)] pubasyncfn generate_key_package(&self) -> Result<MlsMessage, MlsError> { self.client.generate_key_package_message().await
}
/// Create the new group using new key packages of all group members, possibly /// generated by [`ReinitClient::generate_key_package`]. /// /// # Warning /// /// This function will fail if the number of members in the reinitialized /// group is not the same as the prior group roster. #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)] pubasyncfn commit( self,
new_key_packages: Vec<MlsMessage>,
) -> Result<(Group<C>, Vec<MlsMessage>), MlsError> { let new_group_params = ResumptionGroupParameters {
group_id: self.reinit.group_id(),
cipher_suite: self.reinit.new_cipher_suite(),
version: self.reinit.new_version(),
extensions: self.reinit.new_group_context_extensions(),
};
resumption_create_group( self.client.config.clone(),
new_key_packages,
&new_group_params, // These private fields are created with `Some(x)` by `get_reinit_client` self.client.signing_identity.unwrap().0, self.client.signer.unwrap(), #[cfg(any(feature = "private_message", feature = "psk"))] self.psk_input,
)
.await
}
/// Join a reinitialized group that was created by [`ReinitClient::commit`]. #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)] pubasyncfn join( self,
welcome: &MlsMessage,
tree_data: Option<ExportedTree<'_>>,
) -> Result<(Group<C>, NewMemberInfo), MlsError> { let reinit = self.reinit;
resumption_join_group( self.client.config, // This private field is created with `Some(x)` by `get_reinit_client` self.client.signer.unwrap(),
welcome,
tree_data,
expected_group_params, true, self.psk_input,
)
.await
}
}
#[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)] asyncfn resumption_create_group<C: ClientConfig + Clone>(
config: C,
new_key_packages: Vec<MlsMessage>,
new_group_params: &ResumptionGroupParameters<'_>,
signing_identity: SigningIdentity,
signer: SignatureSecretKey,
psk_input: PskSecretInput,
) -> Result<(Group<C>, Vec<MlsMessage>), MlsError> { // Create a new group with new parameters letmut group = Group::new(
config,
Some(new_group_params.group_id.to_vec()),
new_group_params.cipher_suite,
new_group_params.version,
signing_identity,
new_group_params.extensions.clone(),
signer,
)
.await?;
// Install the resumption psk in the new group
group.previous_psk = Some(psk_input);
// Create a commit that adds new key packages and uses the resumption PSK letmut commit = group.commit_builder();
for kp in new_key_packages.into_iter() {
commit = commit.add_member(kp)?;
}
let commit = commit.build().await?;
group.apply_pending_commit().await?;
// Uninstall the resumption psk on success (in case of failure, the new group is discarded anyway)
group.previous_psk = None;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.