diff --git a/openmls/Cargo.toml b/openmls/Cargo.toml index d2daaeb3e2..9ff3c75193 100644 --- a/openmls/Cargo.toml +++ b/openmls/Cargo.toml @@ -36,6 +36,7 @@ async-lock = { version = "3.3", optional = true } rstest = { version = "0.18.2", optional = true } rstest_reuse = { version = "0.6.0", optional = true } tokio = { version = "1.24", optional = true, features = ["macros", "rt", "rt-multi-thread"] } +futures = "0.3.30" [features] default = [] diff --git a/openmls/src/ciphersuite/hpke.rs b/openmls/src/ciphersuite/hpke.rs index df6418324c..1783e37b7a 100644 --- a/openmls/src/ciphersuite/hpke.rs +++ b/openmls/src/ciphersuite/hpke.rs @@ -90,7 +90,7 @@ impl From<(&str, &[u8])> for EncryptContext { } /// Encrypt to an HPKE key with a label. -pub(crate) fn encrypt_with_label( +pub(crate) async fn encrypt_with_label( public_key: &[u8], label: &str, context: &[u8], @@ -109,13 +109,15 @@ pub(crate) fn encrypt_with_label( log_crypto!(debug, "* public key: {public_key:x?}"); log_crypto!(debug, "* plaintext: {plaintext:x?}"); - let cipher = crypto.hpke_seal( - ciphersuite.hpke_config(), - public_key, - &context, - &[], - plaintext, - )?; + let cipher = crypto + .hpke_seal( + ciphersuite.hpke_config(), + public_key, + &context, + &[], + plaintext, + ) + .await?; log_crypto!(debug, "* ciphertext: {:x?}", cipher); diff --git a/openmls/src/ciphersuite/reuse_guard.rs b/openmls/src/ciphersuite/reuse_guard.rs index d73d3e7dea..914f385f46 100644 --- a/openmls/src/ciphersuite/reuse_guard.rs +++ b/openmls/src/ciphersuite/reuse_guard.rs @@ -11,13 +11,14 @@ pub struct ReuseGuard { impl ReuseGuard { /// Samples a fresh reuse guard uniformly at random. - pub(crate) fn try_from_random( + pub(crate) async fn try_from_random( crypto: &impl OpenMlsCryptoProvider, ) -> Result { Ok(Self { value: crypto .rand() .random_array() + .await .map_err(|_| CryptoError::InsufficientRandomness)?, }) } diff --git a/openmls/src/ciphersuite/secret.rs b/openmls/src/ciphersuite/secret.rs index ce6a910166..9ded76ee7b 100644 --- a/openmls/src/ciphersuite/secret.rs +++ b/openmls/src/ciphersuite/secret.rs @@ -73,7 +73,7 @@ impl Secret { /// Randomly sample a fresh `Secret`. /// This default random initialiser uses the default Secret length of `hash_length`. /// The function can return a [`CryptoError`] if there is insufficient randomness. - pub(crate) fn random( + pub(crate) async fn random( ciphersuite: Ciphersuite, crypto: &impl OpenMlsCryptoProvider, version: impl Into>, @@ -88,6 +88,7 @@ impl Secret { value: crypto .rand() .random_vec(ciphersuite.hash_length()) + .await .map_err(|_| CryptoError::InsufficientRandomness)? .into(), mls_version, diff --git a/openmls/src/ciphersuite/tests/kat_crypto_basics.rs b/openmls/src/ciphersuite/tests/kat_crypto_basics.rs index fffb649528..768321964c 100644 --- a/openmls/src/ciphersuite/tests/kat_crypto_basics.rs +++ b/openmls/src/ciphersuite/tests/kat_crypto_basics.rs @@ -341,14 +341,17 @@ pub fn run_test_vector( assert_eq!(plaintext, decrypted_plaintext); // Check that encryption works. - let my_ciphertext = hpke::encrypt_with_label( - &public, - &label, - &context, - &plaintext, - ciphersuite, - backend.crypto(), - ) + let my_ciphertext = async_std::task::block_on(async { + hpke::encrypt_with_label( + &public, + &label, + &context, + &plaintext, + ciphersuite, + backend.crypto(), + ) + .await + }) .unwrap(); let decrypted_plaintext = hpke::decrypt_with_label( &private, diff --git a/openmls/src/framing/private_message.rs b/openmls/src/framing/private_message.rs index a5010cc8a6..5bdb579408 100644 --- a/openmls/src/framing/private_message.rs +++ b/openmls/src/framing/private_message.rs @@ -69,7 +69,7 @@ impl PrivateMessage { /// /// TODO #1148: Refactor theses constructors to avoid test code in main and /// to avoid validation using a special feature flag. - pub(crate) fn try_from_authenticated_content( + pub(crate) async fn try_from_authenticated_content( public_message: &AuthenticatedContent, ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoProvider, @@ -90,10 +90,11 @@ impl PrivateMessage { message_secrets, padding_size, ) + .await } #[cfg(any(feature = "test-utils", test))] - pub(crate) fn encrypt_without_check( + pub(crate) async fn encrypt_without_check( public_message: &AuthenticatedContent, ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoProvider, @@ -108,10 +109,11 @@ impl PrivateMessage { message_secrets, padding_size, ) + .await } #[cfg(test)] - pub(crate) fn encrypt_with_different_header( + pub(crate) async fn encrypt_with_different_header( public_message: &AuthenticatedContent, ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoProvider, @@ -127,11 +129,12 @@ impl PrivateMessage { message_secrets, padding_size, ) + .await } /// Internal function to encrypt content. The extra message header is only used /// for tests. Otherwise, the data from the given `AuthenticatedContent` is used. - fn encrypt_content( + async fn encrypt_content( test_header: Option, public_message: &AuthenticatedContent, ciphersuite: Ciphersuite, @@ -170,8 +173,9 @@ impl PrivateMessage { // Even in tests we want to use the real sender index, so we have a key to encrypt. .secret_for_encryption(ciphersuite, backend, sender_index, secret_type)?; // Sample reuse guard uniformly at random. - let reuse_guard: ReuseGuard = - ReuseGuard::try_from_random(backend).map_err(LibraryError::unexpected_crypto_error)?; + let reuse_guard: ReuseGuard = ReuseGuard::try_from_random(backend) + .await + .map_err(LibraryError::unexpected_crypto_error)?; // Prepare the nonce by xoring with the reuse guard. let prepared_nonce = ratchet_nonce.xor_with_reuse_guard(&reuse_guard); // Encrypt the payload diff --git a/openmls/src/framing/test_framing.rs b/openmls/src/framing/test_framing.rs index 4bad37dda9..b88ef0d79a 100644 --- a/openmls/src/framing/test_framing.rs +++ b/openmls/src/framing/test_framing.rs @@ -139,6 +139,7 @@ async fn codec_ciphertext(ciphersuite: Ciphersuite, backend: &impl OpenMlsCrypto &mut message_secrets, 0, ) + .await .expect("Could not encrypt PublicMessage."); let enc = orig @@ -200,6 +201,7 @@ async fn wire_format_checks(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryp &mut message_secrets, 0, ) + .await .expect("Could not encrypt PublicMessage.") .into(); @@ -575,6 +577,7 @@ async fn unknown_sender(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoPr group_alice.message_secrets_test_mut(), 0, ) + .await .expect("Encryption error"); let received_message = group_charlie.decrypt(&enc_message.into(), backend, configuration); diff --git a/openmls/src/group/core_group/mod.rs b/openmls/src/group/core_group/mod.rs index 8837eda493..7ce294b53e 100644 --- a/openmls/src/group/core_group/mod.rs +++ b/openmls/src/group/core_group/mod.rs @@ -246,8 +246,10 @@ impl CoreGroupBuilder { backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, ) -> Result> { - let (public_group_builder, commit_secret, leaf_keypair) = - self.public_group_builder.get_secrets(backend, signer)?; + let (public_group_builder, commit_secret, leaf_keypair) = self + .public_group_builder + .get_secrets(backend, signer) + .await?; let ciphersuite = public_group_builder.crypto_config().ciphersuite; let config = self.config.unwrap_or_default(); @@ -267,6 +269,7 @@ impl CoreGroupBuilder { backend, commit_secret, &InitSecret::random(ciphersuite, backend, version) + .await .map_err(LibraryError::unexpected_crypto_error)?, &serialized_group_context, ) @@ -515,7 +518,7 @@ impl CoreGroup { .map_err(|e| e.into()) } // Create application message - pub(crate) fn create_application_message( + pub(crate) async fn create_application_message( &mut self, aad: &[u8], msg: &[u8], @@ -530,11 +533,11 @@ impl CoreGroup { self.context(), signer, )?; - self.encrypt(public_message, padding_size, backend) + self.encrypt(public_message, padding_size, backend).await } // Encrypt an PublicMessage into an PrivateMessage - pub(crate) fn encrypt( + pub(crate) async fn encrypt( &mut self, public_message: AuthenticatedContent, padding_size: usize, @@ -547,6 +550,7 @@ impl CoreGroup { self.message_secrets_store.message_secrets_mut(), padding_size, ) + .await } /// Decrypt an PrivateMessage into an PublicMessage @@ -986,7 +990,7 @@ impl CoreGroup { signer, params.take_credential_with_key(), apply_proposals_values.extensions, - )? + ).await? } else { // If path is not needed, update the group context and return // empty path processing results @@ -1127,15 +1131,17 @@ impl CoreGroup { // Create group secrets for later use, so we can afterwards consume the // `joiner_secret`. - let encrypted_secrets = diff.encrypt_group_secrets( - &joiner_secret, - apply_proposals_values.invitation_list, - path_computation_result.plain_path.as_deref(), - &apply_proposals_values.presharedkeys, - &encrypted_group_info, - backend, - self.own_leaf_index(), - )?; + let encrypted_secrets = diff + .encrypt_group_secrets( + &joiner_secret, + apply_proposals_values.invitation_list, + path_computation_result.plain_path.as_deref(), + &apply_proposals_values.presharedkeys, + &encrypted_group_info, + backend, + self.own_leaf_index(), + ) + .await?; // Create welcome message let welcome = Welcome::new(self.ciphersuite(), encrypted_secrets, encrypted_group_info); diff --git a/openmls/src/group/core_group/new_from_external_init.rs b/openmls/src/group/core_group/new_from_external_init.rs index b996f7cdc4..45007aabac 100644 --- a/openmls/src/group/core_group/new_from_external_init.rs +++ b/openmls/src/group/core_group/new_from_external_init.rs @@ -66,6 +66,7 @@ impl CoreGroup { let (init_secret, kem_output) = InitSecret::from_group_context(backend, group_context, external_pub.as_slice()) + .await .map_err(|_| ExternalCommitError::UnsupportedCiphersuite)?; // The `EpochSecrets` we create here are essentially zero, with the diff --git a/openmls/src/group/mls_group/application.rs b/openmls/src/group/mls_group/application.rs index 5e0e5b16f1..09cf428958 100644 --- a/openmls/src/group/mls_group/application.rs +++ b/openmls/src/group/mls_group/application.rs @@ -11,7 +11,7 @@ impl MlsGroup { /// Returns `CreateMessageError::MlsGroupStateError::PendingProposal` if pending proposals /// exist. In that case `.process_pending_proposals()` must be called first /// and incoming messages from the DS must be processed afterwards. - pub fn create_message( + pub async fn create_message( &mut self, backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, @@ -37,6 +37,7 @@ impl MlsGroup { backend, signer, ) + .await // We know the application message is wellformed and we have the key material of the current epoch .map_err(|_| LibraryError::custom("Malformed plaintext"))?; diff --git a/openmls/src/group/mls_group/creation.rs b/openmls/src/group/mls_group/creation.rs index 534e983984..bc82efdc09 100644 --- a/openmls/src/group/mls_group/creation.rs +++ b/openmls/src/group/mls_group/creation.rs @@ -31,7 +31,7 @@ impl MlsGroup { backend, signer, mls_group_config, - GroupId::random(backend), + GroupId::random(backend).await, credential_with_key, ) .await diff --git a/openmls/src/group/mls_group/extension.rs b/openmls/src/group/mls_group/extension.rs index 541bb170b4..8b55930b64 100644 --- a/openmls/src/group/mls_group/extension.rs +++ b/openmls/src/group/mls_group/extension.rs @@ -19,7 +19,7 @@ impl MlsGroup { /// of the group but does not merge them yet. /// /// Returns an error if there is a pending commit. - pub fn propose_extensions( + pub async fn propose_extensions( &mut self, backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, @@ -43,7 +43,7 @@ impl MlsGroup { self.proposal_store.add(proposal); - let mls_message = self.content_to_mls_message(gce_proposal, backend)?; + let mls_message = self.content_to_mls_message(gce_proposal, backend).await?; // Since the state of the group might be changed, arm the state flag self.flag_state_change(); @@ -84,7 +84,9 @@ impl MlsGroup { // Convert PublicMessage messages to MLSMessage and encrypt them if required by // the configuration - let mls_messages = self.content_to_mls_message(create_commit_result.commit, backend)?; + let mls_messages = self + .content_to_mls_message(create_commit_result.commit, backend) + .await?; // Set the current group state to [`MlsGroupState::PendingCommit`], // storing the current [`StagedCommit`] from the commit results diff --git a/openmls/src/group/mls_group/membership.rs b/openmls/src/group/mls_group/membership.rs index 7f7bcd4ad8..ec7e632a2c 100644 --- a/openmls/src/group/mls_group/membership.rs +++ b/openmls/src/group/mls_group/membership.rs @@ -76,7 +76,9 @@ impl MlsGroup { // Convert PublicMessage messages to MLSMessage and encrypt them if required by // the configuration - let mls_messages = self.content_to_mls_message(create_commit_result.commit, backend)?; + let mls_messages = self + .content_to_mls_message(create_commit_result.commit, backend) + .await?; // Set the current group state to [`MlsGroupState::PendingCommit`], // storing the current [`StagedCommit`] from the commit results @@ -149,7 +151,9 @@ impl MlsGroup { // Convert PublicMessage messages to MLSMessage and encrypt them if required by // the configuration - let mls_message = self.content_to_mls_message(create_commit_result.commit, backend)?; + let mls_message = self + .content_to_mls_message(create_commit_result.commit, backend) + .await?; // Set the current group state to [`MlsGroupState::PendingCommit`], // storing the current [`StagedCommit`] from the commit results @@ -175,7 +179,7 @@ impl MlsGroup { /// The Remove Proposal is returned as a [`MlsMessageOut`]. /// /// Returns an error if there is a pending commit. - pub fn leave_group( + pub async fn leave_group( &mut self, backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, @@ -195,7 +199,9 @@ impl MlsGroup { remove_proposal.clone(), )?); - Ok(self.content_to_mls_message(remove_proposal, backend)?) + Ok(self + .content_to_mls_message(remove_proposal, backend) + .await?) } /// Returns a list of [`Member`]s in the group. diff --git a/openmls/src/group/mls_group/mod.rs b/openmls/src/group/mls_group/mod.rs index 2dea8a478f..5001f183ed 100644 --- a/openmls/src/group/mls_group/mod.rs +++ b/openmls/src/group/mls_group/mod.rs @@ -357,7 +357,7 @@ impl MlsGroup { /// Converts PublicMessage to MlsMessage. Depending on whether handshake /// message should be encrypted, PublicMessage messages are encrypted to /// PrivateMessage first. - fn content_to_mls_message( + async fn content_to_mls_message( &mut self, mls_auth_content: AuthenticatedContent, backend: &impl OpenMlsCryptoProvider, @@ -383,6 +383,7 @@ impl MlsGroup { self.configuration().padding_size(), backend, ) + .await // We can be sure the encryption will work because the plaintext was created by us .map_err(|_| LibraryError::custom("Malformed plaintext"))?; MlsMessageOut::from_private_message(ciphertext, self.group.version()) diff --git a/openmls/src/group/mls_group/processing.rs b/openmls/src/group/mls_group/processing.rs index 82d4b8b900..79371e47c3 100644 --- a/openmls/src/group/mls_group/processing.rs +++ b/openmls/src/group/mls_group/processing.rs @@ -105,7 +105,9 @@ impl MlsGroup { // Convert PublicMessage messages to MLSMessage and encrypt them if required by // the configuration - let mls_message = self.content_to_mls_message(create_commit_result.commit, backend)?; + let mls_message = self + .content_to_mls_message(create_commit_result.commit, backend) + .await?; // Set the current group state to [`MlsGroupState::PendingCommit`], // storing the current [`StagedCommit`] from the commit results diff --git a/openmls/src/group/mls_group/proposal.rs b/openmls/src/group/mls_group/proposal.rs index 2d931ee0aa..90ba211c82 100644 --- a/openmls/src/group/mls_group/proposal.rs +++ b/openmls/src/group/mls_group/proposal.rs @@ -61,7 +61,7 @@ macro_rules! impl_propose_fun { /// Creates proposals to add an external PSK to the key schedule. /// /// Returns an error if there is a pending commit. - pub fn $name( + pub async fn $name( &mut self, backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, @@ -83,7 +83,7 @@ macro_rules! impl_propose_fun { log::trace!("Storing proposal in queue {:?}", queued_proposal); self.proposal_store.add(queued_proposal); - let mls_message = self.content_to_mls_message(proposal, backend)?; + let mls_message = self.content_to_mls_message(proposal, backend).await?; // Since the state of the group might be changed, arm the state flag self.flag_state_change(); @@ -126,7 +126,7 @@ impl MlsGroup { let proposal_ref = queued_proposal.proposal_reference().clone(); self.proposal_store.add(queued_proposal); - let mls_message = self.content_to_mls_message(proposal, backend)?; + let mls_message = self.content_to_mls_message(proposal, backend).await?; self.flag_state_change(); @@ -192,31 +192,38 @@ impl MlsGroup { }, Propose::Remove(leaf_index) => match ref_or_value { - ProposalOrRefType::Proposal => self.propose_remove_member_by_value( - backend, - signer, - LeafNodeIndex::new(leaf_index), - ), + ProposalOrRefType::Proposal => { + self.propose_remove_member_by_value( + backend, + signer, + LeafNodeIndex::new(leaf_index), + ) + .await + } ProposalOrRefType::Reference => self .propose_remove_member(backend, signer, LeafNodeIndex::new(leaf_index)) + .await .map_err(|e| e.into()), }, Propose::RemoveCredential(credential) => match ref_or_value { ProposalOrRefType::Proposal => { self.propose_remove_member_by_credential_by_value(backend, signer, &credential) + .await } ProposalOrRefType::Reference => self .propose_remove_member_by_credential(backend, signer, &credential) + .await .map_err(|e| e.into()), }, Propose::PreSharedKey(psk_id) => match psk_id.psk() { crate::schedule::Psk::External(_) => match ref_or_value { ProposalOrRefType::Proposal => { self.propose_external_psk_by_value(backend, signer, psk_id) + .await } ProposalOrRefType::Reference => { - self.propose_external_psk(backend, signer, psk_id) + self.propose_external_psk(backend, signer, psk_id).await } }, crate::schedule::Psk::Resumption(_) => Err(ProposalError::LibraryError( @@ -271,7 +278,7 @@ impl MlsGroup { let proposal_ref = proposal.proposal_reference().clone(); self.proposal_store.add(proposal); - let mls_message = self.content_to_mls_message(add_proposal, backend)?; + let mls_message = self.content_to_mls_message(add_proposal, backend).await?; // Since the state of the group might be changed, arm the state flag self.flag_state_change(); @@ -283,7 +290,7 @@ impl MlsGroup { /// The `member` has to be the member's leaf index. /// /// Returns an error if there is a pending commit. - pub fn propose_remove_member( + pub async fn propose_remove_member( &mut self, backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, @@ -304,7 +311,9 @@ impl MlsGroup { let proposal_ref = proposal.proposal_reference().clone(); self.proposal_store.add(proposal); - let mls_message = self.content_to_mls_message(remove_proposal, backend)?; + let mls_message = self + .content_to_mls_message(remove_proposal, backend) + .await?; // Since the state of the group might be changed, arm the state flag self.flag_state_change(); @@ -316,7 +325,7 @@ impl MlsGroup { /// The `member` has to be the member's credential. /// /// Returns an error if there is a pending commit. - pub fn propose_remove_member_by_credential( + pub async fn propose_remove_member_by_credential( &mut self, backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, @@ -332,6 +341,7 @@ impl MlsGroup { if let Some(member_index) = member_index { self.propose_remove_member(backend, signer, member_index) + .await } else { Err(ProposeRemoveMemberError::UnknownMember) } @@ -341,7 +351,7 @@ impl MlsGroup { /// The `member` has to be the member's credential. /// /// Returns an error if there is a pending commit. - pub fn propose_remove_member_by_credential_by_value( + pub async fn propose_remove_member_by_credential_by_value( &mut self, backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, @@ -357,6 +367,7 @@ impl MlsGroup { if let Some(member_index) = member_index { self.propose_remove_member_by_value(backend, signer, member_index) + .await } else { Err(ProposalError::ProposeRemoveMemberError( ProposeRemoveMemberError::UnknownMember, diff --git a/openmls/src/group/mls_group/reinit.rs b/openmls/src/group/mls_group/reinit.rs index 86a8996008..2f0456368f 100644 --- a/openmls/src/group/mls_group/reinit.rs +++ b/openmls/src/group/mls_group/reinit.rs @@ -12,7 +12,7 @@ impl MlsGroup { /// /// Returns an error if there is a pending commit, if the new proposed version is older than /// the current or if any member doesn't support the proposed extensions and/or ciphersuite. - pub fn propose_reinit( + pub async fn propose_reinit( &mut self, backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, @@ -40,7 +40,9 @@ impl MlsGroup { self.proposal_store.add(proposal); - let mls_message = self.content_to_mls_message(reinit_proposal, backend)?; + let mls_message = self + .content_to_mls_message(reinit_proposal, backend) + .await?; // Since the state of the group might be changed, arm the state flag self.flag_state_change(); @@ -85,7 +87,9 @@ impl MlsGroup { // Convert PublicMessage messages to MLSMessage and encrypt them if required by // the configuration - let mls_messages = self.content_to_mls_message(create_commit_result.commit, backend)?; + let mls_messages = self + .content_to_mls_message(create_commit_result.commit, backend) + .await?; // Set the current group state to [`MlsGroupState::PendingCommit`], // storing the current [`StagedCommit`] from the commit results diff --git a/openmls/src/group/mls_group/updates.rs b/openmls/src/group/mls_group/updates.rs index db7df5e118..e15766503b 100644 --- a/openmls/src/group/mls_group/updates.rs +++ b/openmls/src/group/mls_group/updates.rs @@ -82,7 +82,9 @@ impl MlsGroup { // Convert PublicMessage messages to MLSMessage and encrypt them if required by // the configuration - let mls_message = self.content_to_mls_message(create_commit_result.commit, backend)?; + let mls_message = self + .content_to_mls_message(create_commit_result.commit, backend) + .await?; // Set the current group state to [`MlsGroupState::PendingCommit`], // storing the current [`StagedCommit`] from the commit results @@ -117,7 +119,9 @@ impl MlsGroup { let proposal_ref = proposal.proposal_reference().clone(); self.proposal_store.add(proposal); - let mls_message = self.content_to_mls_message(update_proposal, backend)?; + let mls_message = self + .content_to_mls_message(update_proposal, backend) + .await?; // Since the state of the group might be changed, arm the state flag self.flag_state_change(); @@ -140,7 +144,9 @@ impl MlsGroup { let proposal_ref = proposal.proposal_reference().clone(); self.proposal_store.add(proposal); - let mls_message = self.content_to_mls_message(update_proposal, backend)?; + let mls_message = self + .content_to_mls_message(update_proposal, backend) + .await?; // Since the state of the group might be changed, arm the state flag self.flag_state_change(); @@ -164,15 +170,17 @@ impl MlsGroup { .own_leaf() .ok_or_else(|| LibraryError::custom("The tree is broken. Couldn't find own leaf."))? .clone(); - let keypair = own_leaf.rekey( - self.group_id(), - self.own_leaf_index(), - None, - self.ciphersuite(), - ProtocolVersion::default(), // XXX: openmls/openmls#1065 - backend, - signer, - )?; + let keypair = own_leaf + .rekey( + self.group_id(), + self.own_leaf_index(), + None, + self.ciphersuite(), + ProtocolVersion::default(), // XXX: openmls/openmls#1065 + backend, + signer, + ) + .await?; keypair .write_to_key_store(backend) @@ -222,7 +230,9 @@ impl MlsGroup { let proposal_ref = proposal.proposal_reference().clone(); self.proposal_store.add(proposal); - let mls_message = self.content_to_mls_message(update_proposal, backend)?; + let mls_message = self + .content_to_mls_message(update_proposal, backend) + .await?; // Since the state of the group might be changed, arm the state flag self.flag_state_change(); @@ -247,15 +257,17 @@ impl MlsGroup { .ok_or_else(|| LibraryError::custom("The tree is broken. Couldn't find own leaf."))? .clone(); - let keypair = own_leaf.rekey( - self.group_id(), - self.own_leaf_index(), - Some(leaf_node), - self.ciphersuite(), - ProtocolVersion::Mls10, - backend, - leaf_node_signer, - )?; + let keypair = own_leaf + .rekey( + self.group_id(), + self.own_leaf_index(), + Some(leaf_node), + self.ciphersuite(), + ProtocolVersion::Mls10, + backend, + leaf_node_signer, + ) + .await?; keypair .write_to_key_store(backend) diff --git a/openmls/src/group/mod.rs b/openmls/src/group/mod.rs index b23cb31e40..752957f50f 100644 --- a/openmls/src/group/mod.rs +++ b/openmls/src/group/mod.rs @@ -61,11 +61,12 @@ impl GroupId { /// Create a new (random) group ID. /// /// Group IDs should be random and not be misused as, e.g., a group name. - pub fn random(backend: &impl OpenMlsCryptoProvider) -> Self { + pub async fn random(backend: &impl OpenMlsCryptoProvider) -> Self { Self { value: backend .rand() .random_vec(16) + .await .expect("Not enough randomness.") .into(), } diff --git a/openmls/src/group/public_group/builder.rs b/openmls/src/group/public_group/builder.rs index c7deec3a67..6b4177de3e 100644 --- a/openmls/src/group/public_group/builder.rs +++ b/openmls/src/group/public_group/builder.rs @@ -76,7 +76,7 @@ impl TempBuilderPG1 { self } - pub(crate) fn get_secrets( + pub(crate) async fn get_secrets( self, backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, @@ -89,7 +89,8 @@ impl TempBuilderPG1 { self.lifetime.unwrap_or_default(), self.leaf_capabilities.unwrap_or_default(), self.leaf_extensions.unwrap_or_default(), - )?; + ) + .await?; let required_capabilities = self.required_capabilities.unwrap_or_default(); required_capabilities.check_support().map_err(|e| match e { ExtensionError::UnsupportedProposalType => { diff --git a/openmls/src/group/public_group/diff.rs b/openmls/src/group/public_group/diff.rs index 20f7f24e9c..99df1a6b23 100644 --- a/openmls/src/group/public_group/diff.rs +++ b/openmls/src/group/public_group/diff.rs @@ -77,7 +77,7 @@ impl<'a> PublicGroupDiff<'a> { /// - the leaf index of a new member is identical to the own leaf index /// - the plain path does not contain the correct secrets #[allow(clippy::too_many_arguments)] - pub(crate) fn encrypt_group_secrets( + pub(crate) async fn encrypt_group_secrets( &self, joiner_secret: &JoinerSecret, invited_members: Vec<(LeafNodeIndex, AddProposal)>, @@ -87,15 +87,17 @@ impl<'a> PublicGroupDiff<'a> { backend: &impl OpenMlsCryptoProvider, leaf_index: LeafNodeIndex, ) -> Result, LibraryError> { - self.diff.encrypt_group_secrets( - joiner_secret, - invited_members, - plain_path_option, - presharedkeys, - encrypted_group_info, - backend, - leaf_index, - ) + self.diff + .encrypt_group_secrets( + joiner_secret, + invited_members, + plain_path_option, + presharedkeys, + encrypted_group_info, + backend, + leaf_index, + ) + .await } /// Returns the tree size diff --git a/openmls/src/group/public_group/diff/compute_path.rs b/openmls/src/group/public_group/diff/compute_path.rs index a86ec16a93..0bba4fdce1 100644 --- a/openmls/src/group/public_group/diff/compute_path.rs +++ b/openmls/src/group/public_group/diff/compute_path.rs @@ -39,7 +39,7 @@ pub(crate) struct PathComputationResult { impl<'a> PublicGroupDiff<'a> { #[allow(clippy::too_many_arguments)] - pub(crate) fn compute_path( + pub(crate) async fn compute_path( &mut self, backend: &impl OpenMlsCryptoProvider, leaf_index: LeafNodeIndex, @@ -89,7 +89,8 @@ impl<'a> PublicGroupDiff<'a> { backend, signer, credential_with_key.ok_or(CreateCommitError::MissingCredential)?, - )?; + ) + .await?; let leaf_node: LeafNode = key_package.into(); self.diff @@ -108,15 +109,17 @@ impl<'a> PublicGroupDiff<'a> { .leaf_mut(leaf_index) .ok_or_else(|| LibraryError::custom("Unable to get own leaf from diff"))?; - let encryption_keypair = own_diff_leaf.rekey( - &group_id, - leaf_index, - None, - ciphersuite, - version, - backend, - signer, - )?; + let encryption_keypair = own_diff_leaf + .rekey( + &group_id, + leaf_index, + None, + ciphersuite, + version, + backend, + signer, + ) + .await?; vec![encryption_keypair] }; @@ -124,7 +127,8 @@ impl<'a> PublicGroupDiff<'a> { // generated new leaf. let (plain_path, mut new_parent_keypairs, commit_secret) = self .diff - .apply_own_update_path(backend, signer, ciphersuite, group_id, leaf_index)?; + .apply_own_update_path(backend, signer, ciphersuite, group_id, leaf_index) + .await?; new_keypairs.append(&mut new_parent_keypairs); @@ -139,14 +143,17 @@ impl<'a> PublicGroupDiff<'a> { .map_err(LibraryError::missing_bound_check)?; // Encrypt the path to the correct recipient nodes. - let encrypted_path = self.diff.encrypt_path( - backend, - ciphersuite, - &plain_path, - &serialized_group_context, - &exclusion_list, - leaf_index, - )?; + let encrypted_path = self + .diff + .encrypt_path( + backend, + ciphersuite, + &plain_path, + &serialized_group_context, + &exclusion_list, + leaf_index, + ) + .await?; let leaf_node = self .diff .leaf(leaf_index) diff --git a/openmls/src/group/tests/test_encoding.rs b/openmls/src/group/tests/test_encoding.rs index b09455aaab..a68a9f0502 100644 --- a/openmls/src/group/tests/test_encoding.rs +++ b/openmls/src/group/tests/test_encoding.rs @@ -82,6 +82,7 @@ async fn test_application_message_encoding(backend: &impl OpenMlsCryptoProvider) backend, &credential_with_key_and_signer.signer, ) + .await .expect("An unexpected error occurred."); let encrypted_message_bytes = encrypted_message .tls_serialize_detached() diff --git a/openmls/src/group/tests/test_framing.rs b/openmls/src/group/tests/test_framing.rs index aaa42ad9d0..321496354c 100644 --- a/openmls/src/group/tests/test_framing.rs +++ b/openmls/src/group/tests/test_framing.rs @@ -80,6 +80,7 @@ async fn padding(backend: &impl OpenMlsCryptoProvider) { backend, &credential.signer, ) + .await .expect("An unexpected error occurred."); let ciphertext = private_message.ciphertext(); let length = ciphertext.len(); diff --git a/openmls/src/group/tests/test_framing_validation.rs b/openmls/src/group/tests/test_framing_validation.rs index 556c5c5f22..dbf9a17aa7 100644 --- a/openmls/src/group/tests/test_framing_validation.rs +++ b/openmls/src/group/tests/test_framing_validation.rs @@ -405,6 +405,7 @@ async fn test_valsem006(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoPr let message = alice_group .create_message(backend, &_alice_credential.signer, &[1, 2, 3]) + .await .expect("An unexpected error occurred."); let serialized_message = message diff --git a/openmls/src/group/tests/test_group.rs b/openmls/src/group/tests/test_group.rs index 43515b228f..e4504de661 100644 --- a/openmls/src/group/tests/test_group.rs +++ b/openmls/src/group/tests/test_group.rs @@ -417,6 +417,7 @@ async fn group_operations(ciphersuite: Ciphersuite, backend: &impl OpenMlsCrypto backend, &alice_credential_with_keys.signer, ) + .await .expect("An unexpected error occurred.") .into(); @@ -775,6 +776,7 @@ async fn group_operations(ciphersuite: Ciphersuite, backend: &impl OpenMlsCrypto backend, &charlie_credential_with_keys.signer, ) + .await .expect("An unexpected error occurred.") .into(); diff --git a/openmls/src/group/tests/test_past_secrets.rs b/openmls/src/group/tests/test_past_secrets.rs index 7d28cb37b9..698ab7b45c 100644 --- a/openmls/src/group/tests/test_past_secrets.rs +++ b/openmls/src/group/tests/test_past_secrets.rs @@ -96,6 +96,7 @@ async fn test_past_secrets_in_group( for _ in 0..max_epochs { let application_message = alice_group .create_message(backend, &alice_credential_with_keys.signer, &[1, 2, 3]) + .await .expect("An unexpected error occurred."); application_messages.push(application_message.into_protocol_message().unwrap()); diff --git a/openmls/src/key_packages/mod.rs b/openmls/src/key_packages/mod.rs index 87c4fe0716..f8939dcce6 100644 --- a/openmls/src/key_packages/mod.rs +++ b/openmls/src/key_packages/mod.rs @@ -198,7 +198,7 @@ impl KeyPackage { #[allow(clippy::too_many_arguments)] /// Create a new key package for the given `ciphersuite` and `identity`. - pub(crate) fn create( + pub(crate) async fn create( config: CryptoConfig, backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, @@ -214,6 +214,7 @@ impl KeyPackage { // Create a new HPKE key pair let ikm = Secret::random(config.ciphersuite, backend, config.version) + .await .map_err(LibraryError::unexpected_crypto_error)?; let init_key = backend .crypto() @@ -229,7 +230,8 @@ impl KeyPackage { leaf_node_capabilities, leaf_node_extensions, init_key.public, - )?; + ) + .await?; Ok(KeyPackageCreationResult { key_package, @@ -248,7 +250,7 @@ impl KeyPackage { /// /// The caller is responsible for storing the new values. #[allow(clippy::too_many_arguments)] - fn new_from_keys( + async fn new_from_keys( config: CryptoConfig, backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, @@ -272,7 +274,7 @@ impl KeyPackage { }; let (leaf_node, encryption_key_pair) = - LeafNode::new(backend, signer, new_leaf_node_params)?; + LeafNode::new(backend, signer, new_leaf_node_params).await?; let key_package_tbs = KeyPackageTbs { protocol_version: config.version, @@ -575,7 +577,7 @@ impl KeyPackageBuilder { self } - pub(crate) fn build_without_key_storage( + pub(crate) async fn build_without_key_storage( self, config: CryptoConfig, backend: &impl OpenMlsCryptoProvider, @@ -592,6 +594,7 @@ impl KeyPackageBuilder { self.leaf_node_capabilities.unwrap_or_default(), self.leaf_node_extensions.unwrap_or_default(), ) + .await } /// Finalize and build the key package. @@ -615,7 +618,8 @@ impl KeyPackageBuilder { self.key_package_extensions.unwrap_or_default(), self.leaf_node_capabilities.unwrap_or_default(), self.leaf_node_extensions.unwrap_or_default(), - )?; + ) + .await?; // Store the key package in the key store with the hash reference as id // for retrieval when parsing welcome messages. diff --git a/openmls/src/messages/mod.rs b/openmls/src/messages/mod.rs index a75c012fbe..31e7e24d02 100644 --- a/openmls/src/messages/mod.rs +++ b/openmls/src/messages/mod.rs @@ -331,19 +331,21 @@ impl PathSecret { /// Encrypt the path secret under the given `HpkePublicKey` using the given /// `group_context`. - pub fn encrypt( + pub async fn encrypt( &self, backend: &impl OpenMlsCryptoProvider, ciphersuite: Ciphersuite, public_key: &EncryptionKey, group_context: &[u8], ) -> Result { - public_key.encrypt( - backend, - ciphersuite, - group_context, - self.path_secret.as_slice(), - ) + public_key + .encrypt( + backend, + ciphersuite, + group_context, + self.path_secret.as_slice(), + ) + .await } /// Consume the `PathSecret`, returning the internal `Secret` value. diff --git a/openmls/src/schedule/mod.rs b/openmls/src/schedule/mod.rs index d1a0026434..01451322d8 100644 --- a/openmls/src/schedule/mod.rs +++ b/openmls/src/schedule/mod.rs @@ -284,31 +284,34 @@ impl InitSecret { } /// Sample a fresh, random `InitSecret` for the creation of a new group. - pub(crate) fn random( + pub(crate) async fn random( ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoProvider, version: ProtocolVersion, ) -> Result { Ok(InitSecret { - secret: Secret::random(ciphersuite, backend, version)?, + secret: Secret::random(ciphersuite, backend, version).await?, }) } /// Create an `InitSecret` and the corresponding `kem_output` from a group info. - pub(crate) fn from_group_context( + pub(crate) async fn from_group_context( backend: &impl OpenMlsCryptoProvider, group_context: &GroupContext, external_pub: &[u8], ) -> Result<(Self, Vec), KeyScheduleError> { let ciphersuite = group_context.ciphersuite(); let version = group_context.protocol_version(); - let (kem_output, raw_init_secret) = backend.crypto().hpke_setup_sender_and_export( - ciphersuite.hpke_config(), - external_pub, - &[], - hpke_info_from_version(version).as_bytes(), - ciphersuite.hash_length(), - )?; + let (kem_output, raw_init_secret) = backend + .crypto() + .hpke_setup_sender_and_export( + ciphersuite.hpke_config(), + external_pub, + &[], + hpke_info_from_version(version).as_bytes(), + ciphersuite.hash_length(), + ) + .await?; Ok(( InitSecret { secret: Secret::from_slice(&raw_init_secret, version, ciphersuite), diff --git a/openmls/src/schedule/psk.rs b/openmls/src/schedule/psk.rs index 2c266b9675..1870c1f137 100644 --- a/openmls/src/schedule/psk.rs +++ b/openmls/src/schedule/psk.rs @@ -235,13 +235,14 @@ pub struct PreSharedKeyId { impl PreSharedKeyId { /// Construct a `PreSharedKeyID` with a random nonce. - pub fn new( + pub async fn new( ciphersuite: Ciphersuite, rand: &impl OpenMlsRand, psk: Psk, ) -> Result { let psk_nonce = rand .random_vec(ciphersuite.hash_length()) + .await .map_err(|_| CryptoError::InsufficientRandomness)? .into(); diff --git a/openmls/src/test_utils/test_framework/mod.rs b/openmls/src/test_utils/test_framework/mod.rs index fafe0bc304..ae7cc57953 100644 --- a/openmls/src/test_utils/test_framework/mod.rs +++ b/openmls/src/test_utils/test_framework/mod.rs @@ -381,6 +381,7 @@ impl MlsGroupTestSetup { .unwrap(); let message = group_state .create_message(&m.crypto, &signer, "Hello World!".as_bytes()) + .await .expect("Error composing message while checking group states."); messages.push((m_id.to_vec(), message)); } diff --git a/openmls/src/tree/tests_and_kats/kats/kat_message_protection.rs b/openmls/src/tree/tests_and_kats/kats/kat_message_protection.rs index 9c1b0a02d1..c728364da3 100644 --- a/openmls/src/tree/tests_and_kats/kats/kat_message_protection.rs +++ b/openmls/src/tree/tests_and_kats/kats/kat_message_protection.rs @@ -478,6 +478,7 @@ pub async fn run_test_vector( .unwrap(); let my_proposal_priv = sender_group .encrypt(proposal_authenticated_content, 0, backend) + .await .unwrap(); let my_proposal_priv_out = MlsMessageOut::from_private_message(my_proposal_priv, group.version()); @@ -643,6 +644,7 @@ pub async fn run_test_vector( })); let my_commit_pub = sender_group .encrypt(commit_authenticated_content, 0, backend) + .await .unwrap(); let my_commit_priv_out = MlsMessageOut::from_private_message(my_commit_pub, group.version()); @@ -736,6 +738,7 @@ pub async fn run_test_vector( let mut sender_group = setup_group(backend, ciphersuite, &test, true).await; let private_message = sender_group .create_application_message(&[], application, 0, backend, &signer) + .await .unwrap(); let my_application_priv_out = MlsMessageOut::from_private_message(private_message, sender_group.version()); diff --git a/openmls/src/treesync/diff.rs b/openmls/src/treesync/diff.rs index 013f04236b..3316bf1315 100644 --- a/openmls/src/treesync/diff.rs +++ b/openmls/src/treesync/diff.rs @@ -263,7 +263,7 @@ impl<'a> TreeSyncDiff<'a> { /// Derive a new direct path for the leaf with the given index. /// /// Returns an error if the leaf is not in the tree - fn derive_path( + async fn derive_path( &self, backend: &impl OpenMlsCryptoProvider, ciphersuite: Ciphersuite, @@ -271,6 +271,7 @@ impl<'a> TreeSyncDiff<'a> { ) -> Result { let path_secret = PathSecret::from( Secret::random(ciphersuite, backend, None) + .await .map_err(LibraryError::unexpected_crypto_error)?, ); @@ -287,7 +288,7 @@ impl<'a> TreeSyncDiff<'a> { /// derivation, as well as the newly derived [`EncryptionKeyPair`]s. /// /// Returns an error if the target leaf is not in the tree. - pub(crate) fn apply_own_update_path( + pub(crate) async fn apply_own_update_path( &mut self, backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, @@ -301,7 +302,7 @@ impl<'a> TreeSyncDiff<'a> { ); let (path, update_path_nodes, keypairs, commit_secret) = - self.derive_path(backend, ciphersuite, leaf_index)?; + self.derive_path(backend, ciphersuite, leaf_index).await?; let parent_hash = self.process_update_path(backend, ciphersuite, leaf_index, path)?; diff --git a/openmls/src/treesync/mod.rs b/openmls/src/treesync/mod.rs index 18a983c5b3..1fdbd9a7dc 100644 --- a/openmls/src/treesync/mod.rs +++ b/openmls/src/treesync/mod.rs @@ -378,7 +378,7 @@ impl TreeSync { /// /// Returns the resulting [`TreeSync`] instance, as well as the /// corresponding [`CommitSecret`]. - pub(crate) fn new( + pub(crate) async fn new( backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, config: CryptoConfig, @@ -396,10 +396,12 @@ impl TreeSync { extensions, tree_info_tbs: TreeInfoTbs::KeyPackage, }; - let (leaf, encryption_key_pair) = LeafNode::new(backend, signer, new_leaf_node_params)?; + let (leaf, encryption_key_pair) = + LeafNode::new(backend, signer, new_leaf_node_params).await?; let node = Node::LeafNode(leaf); let path_secret: PathSecret = Secret::random(config.ciphersuite, backend, None) + .await .map_err(LibraryError::unexpected_crypto_error)? .into(); let commit_secret: CommitSecret = path_secret diff --git a/openmls/src/treesync/node/encryption_keys.rs b/openmls/src/treesync/node/encryption_keys.rs index b9febdd3a9..4b134aa9b1 100644 --- a/openmls/src/treesync/node/encryption_keys.rs +++ b/openmls/src/treesync/node/encryption_keys.rs @@ -38,7 +38,7 @@ impl EncryptionKey { } /// Encrypt to this HPKE public key. - pub(crate) fn encrypt( + pub(crate) async fn encrypt( &self, backend: &impl OpenMlsCryptoProvider, ciphersuite: Ciphersuite, @@ -53,6 +53,7 @@ impl EncryptionKey { ciphersuite, backend.crypto(), ) + .await .map_err(|_| LibraryError::custom("Encryption failed. A serialization issue really")) } } @@ -187,11 +188,12 @@ impl EncryptionKeyPair { &self.private_key } - pub(crate) fn random( + pub(crate) async fn random( backend: &impl OpenMlsCryptoProvider, config: CryptoConfig, ) -> Result { let ikm = Secret::random(config.ciphersuite, backend, config.version) + .await .map_err(LibraryError::unexpected_crypto_error)?; let kp: Self = backend .crypto() diff --git a/openmls/src/treesync/node/leaf_node.rs b/openmls/src/treesync/node/leaf_node.rs index ebcf1f31fc..30a776385c 100644 --- a/openmls/src/treesync/node/leaf_node.rs +++ b/openmls/src/treesync/node/leaf_node.rs @@ -91,7 +91,7 @@ impl LeafNode { /// This function generates a fresh HPKE key pair for the leaf node and /// returns the HPKE key pair along with the new leaf node. /// The caller is responsible for storing the private key. - pub(crate) fn new( + pub(crate) async fn new( backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, new_leaf_node_params: NewLeafNodeParams, @@ -106,7 +106,7 @@ impl LeafNode { } = new_leaf_node_params; // Create a new encryption key pair. - let encryption_key_pair = EncryptionKeyPair::random(backend, config)?; + let encryption_key_pair = EncryptionKeyPair::random(backend, config).await?; let leaf_node = Self::new_with_key( encryption_key_pair.public_key().clone(), @@ -291,7 +291,7 @@ impl LeafNode { /// /// This signs the new leaf node as well. #[allow(clippy::too_many_arguments)] - pub fn rekey( + pub async fn rekey( &mut self, group_id: &GroupId, leaf_index: LeafNodeIndex, @@ -326,7 +326,8 @@ impl LeafNode { ciphersuite, version: protocol_version, }, - )?; + ) + .await?; if let Some(mut leaf_node) = leaf_node { leaf_node.payload.encryption_key = keypair.public_key().clone(); diff --git a/openmls/src/treesync/node/parent_node.rs b/openmls/src/treesync/node/parent_node.rs index 0f74af8ed2..acc5fb9894 100644 --- a/openmls/src/treesync/node/parent_node.rs +++ b/openmls/src/treesync/node/parent_node.rs @@ -1,6 +1,7 @@ //! This module contains the [`ParentNode`] struct, its implementation, as well //! as the [`PlainUpdatePathNode`], a helper struct for the creation of //! [`UpdatePathNode`] instances. +use futures::{stream, StreamExt, TryStreamExt}; use openmls_traits::{ types::{Ciphersuite, HpkeCiphertext}, OpenMlsCryptoProvider, @@ -52,24 +53,25 @@ pub(crate) struct PlainUpdatePathNode { impl PlainUpdatePathNode { /// Encrypt this node and return the resulting [`UpdatePathNode`]. - pub(in crate::treesync) fn encrypt( + pub(in crate::treesync) async fn encrypt( &self, backend: &impl OpenMlsCryptoProvider, ciphersuite: Ciphersuite, public_keys: &[EncryptionKey], group_context: &[u8], ) -> Result { - public_keys - .iter() - .map(|pk| { + let encrypted_path_secrets = stream::iter(public_keys) + .then(|pk| async { self.path_secret .encrypt(backend, ciphersuite, pk, group_context) + .await }) - .collect::, LibraryError>>() - .map(|encrypted_path_secrets| UpdatePathNode { - public_key: self.public_key.clone(), - encrypted_path_secrets, - }) + .try_collect::>() + .await?; + Ok(UpdatePathNode { + public_key: self.public_key.clone(), + encrypted_path_secrets, + }) } /// Return a reference to the `path_secret` of this node. diff --git a/openmls/src/treesync/tests_and_kats/tests.rs b/openmls/src/treesync/tests_and_kats/tests.rs index 3af61bfb1e..75262328e0 100644 --- a/openmls/src/treesync/tests_and_kats/tests.rs +++ b/openmls/src/treesync/tests_and_kats/tests.rs @@ -174,5 +174,6 @@ async fn that_commit_secret_is_derived_from_end_of_update_path_not_root( &charlie.credential_with_key_and_signer.signer, b"Hello, World!".as_slice(), ) + .await .unwrap(); } diff --git a/openmls/src/treesync/treekem.rs b/openmls/src/treesync/treekem.rs index 81af6432b2..5182f45325 100644 --- a/openmls/src/treesync/treekem.rs +++ b/openmls/src/treesync/treekem.rs @@ -4,6 +4,8 @@ //! //! This module contains structs and functions to encrypt and decrypt path //! updates for a [`TreeSyncDiff`] instance. +use futures::StreamExt; +use futures::{stream, TryStreamExt}; use std::collections::HashSet; use openmls_traits::{ @@ -43,7 +45,7 @@ impl<'a> TreeSyncDiff<'a> { /// included in the resulting [`UpdatePath`]. /// /// Returns the encrypted path (i.e. an [`UpdatePath`] instance). - pub(crate) fn encrypt_path( + pub(crate) async fn encrypt_path( &self, backend: &impl OpenMlsCryptoProvider, ciphersuite: Ciphersuite, @@ -71,10 +73,14 @@ impl<'a> TreeSyncDiff<'a> { debug_assert_eq!(copath_resolutions.len(), path.len()); // Encrypt the secrets - path.iter() - .zip(copath_resolutions.iter()) - .map(|(node, resolution)| node.encrypt(backend, ciphersuite, resolution, group_context)) - .collect::, LibraryError>>() + stream::iter(path) + .zip(stream::iter(copath_resolutions)) + .then(|(node, resolution)| async move { + node.encrypt(backend, ciphersuite, resolution.as_slice(), group_context) + .await + }) + .try_collect::>() + .await } /// Decrypt an [`UpdatePath`] originating from the given @@ -165,7 +171,7 @@ impl<'a> TreeSyncDiff<'a> { /// - the leaf index of a new member is identical to the own leaf index /// - the plain path does not contain the correct secrets #[allow(clippy::too_many_arguments)] - pub(crate) fn encrypt_group_secrets( + pub(crate) async fn encrypt_group_secrets( &self, joiner_secret: &JoinerSecret, invited_members: Vec<(LeafNodeIndex, AddProposal)>, @@ -209,6 +215,7 @@ impl<'a> TreeSyncDiff<'a> { key_package.ciphersuite(), backend.crypto(), ) + .await .map_err(|_| { LibraryError::custom( "Error while encrypting group secrets. \ diff --git a/openmls/tests/book_code.rs b/openmls/tests/book_code.rs index 346ddfb7c4..3fb84f9365 100644 --- a/openmls/tests/book_code.rs +++ b/openmls/tests/book_code.rs @@ -259,6 +259,7 @@ async fn book_operations(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoP let message_alice = b"Hi, I'm Alice!"; let mls_message_out = alice_group .create_message(backend, &alice_signature_keys, message_alice) + .await .expect("Error creating application message."); // ANCHOR_END: create_application_message @@ -513,6 +514,7 @@ async fn book_operations(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoP let message_charlie = b"Hi, I'm Charlie!"; let queued_message = charlie_group .create_message(backend, &charlie_signature_keys, message_charlie) + .await .expect("Error creating application message"); let _alice_processed_message = alice_group @@ -781,6 +783,7 @@ async fn book_operations(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoP // Check that Bob can no longer send messages assert!(bob_group .create_message(backend, &bob_signature_keys, b"Should not go through") + .await .is_err()); // === Alice removes Charlie and re-adds Bob === @@ -980,6 +983,7 @@ async fn book_operations(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoP let message_alice = b"Hi, I'm Alice!"; let queued_message = alice_group .create_message(backend, &alice_signature_keys, message_alice) + .await .expect("Error creating application message"); let bob_processed_message = bob_group diff --git a/openmls_rust_crypto/Cargo.toml b/openmls_rust_crypto/Cargo.toml index 13c5aced93..a94424660a 100644 --- a/openmls_rust_crypto/Cargo.toml +++ b/openmls_rust_crypto/Cargo.toml @@ -31,3 +31,4 @@ signature = "2.1" thiserror = "1.0" generic-array = "0.14" hpke = { version = "0.12", features = ["x25519", "p256", "p384", "p521"] } +async-lock = "2.8.0" diff --git a/openmls_rust_crypto/src/provider.rs b/openmls_rust_crypto/src/provider.rs index 7992a4ecef..5aaf0bf08c 100644 --- a/openmls_rust_crypto/src/provider.rs +++ b/openmls_rust_crypto/src/provider.rs @@ -1,5 +1,5 @@ +use async_lock::RwLock; use rand_core::{RngCore, SeedableRng}; -use std::sync::RwLock; use aes_gcm::{ aead::{Aead, Payload}, @@ -89,6 +89,8 @@ fn normalize_p521_secret_key(sk: &[u8]) -> zeroize::Zeroizing<[u8; 66]> { sk_buf } +#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))] +#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)] impl OpenMlsCrypto for RustCrypto { fn supports(&self, ciphersuite: Ciphersuite) -> Result<(), CryptoError> { match ciphersuite { @@ -248,14 +250,11 @@ impl OpenMlsCrypto for RustCrypto { } } - fn signature_key_gen( + async fn signature_key_gen( &self, alg: openmls_traits::types::SignatureScheme, ) -> Result<(Vec, Vec), openmls_traits::types::CryptoError> { - let mut rng = self - .rng - .write() - .map_err(|_| CryptoError::InsufficientRandomness)?; + let mut rng = self.rng.write().await; match alg { SignatureScheme::ECDSA_SECP256R1_SHA256 => { @@ -277,10 +276,7 @@ impl OpenMlsCrypto for RustCrypto { Ok((sk.to_bytes().to_vec(), pk)) } SignatureScheme::ED25519 => { - let mut rng = self - .rng - .write() - .map_err(|_| CryptoError::InsufficientRandomness)?; + let mut rng = self.rng.write().await; let k = ed25519_dalek::SigningKey::generate(&mut *rng); let pk = k.verifying_key(); Ok((k.to_bytes().into(), pk.to_bytes().into())) @@ -422,7 +418,7 @@ impl OpenMlsCrypto for RustCrypto { } } - fn hpke_seal( + async fn hpke_seal( &self, config: HpkeConfig, pk_r: &[u8], @@ -430,10 +426,7 @@ impl OpenMlsCrypto for RustCrypto { aad: &[u8], ptxt: &[u8], ) -> Result { - let mut rng = self - .rng - .write() - .map_err(|_| CryptoError::InsufficientRandomness)?; + let mut rng = self.rng.write().await; match config { HpkeConfig( @@ -575,7 +568,7 @@ impl OpenMlsCrypto for RustCrypto { Ok(plaintext) } - fn hpke_setup_sender_and_export( + async fn hpke_setup_sender_and_export( &self, config: HpkeConfig, pk_r: &[u8], @@ -583,10 +576,7 @@ impl OpenMlsCrypto for RustCrypto { exporter_context: &[u8], exporter_length: usize, ) -> Result<(Vec, ExporterSecret), CryptoError> { - let mut rng = self - .rng - .write() - .map_err(|_| CryptoError::InsufficientRandomness)?; + let mut rng = self.rng.write().await; let (kem_output, export) = match config { HpkeConfig( @@ -859,26 +849,28 @@ mod hpke_core { } } +#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))] +#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)] impl OpenMlsRand for RustCrypto { type Error = RandError; type RandImpl = rand_chacha::ChaCha20Rng; - type BorrowTarget<'a> = std::sync::RwLockWriteGuard<'a, Self::RandImpl>; + type BorrowTarget<'a> = async_lock::RwLockWriteGuard<'a, Self::RandImpl>; - fn borrow_rand(&self) -> Result, Self::Error> { - self.rng.write().map_err(|_| Self::Error::LockPoisoned) + async fn borrow_rand(&self) -> Self::BorrowTarget<'_> { + self.rng.write().await } - fn random_array(&self) -> Result<[u8; N], Self::Error> { - let mut rng = self.borrow_rand()?; + async fn random_array(&self) -> Result<[u8; N], Self::Error> { + let mut rng = self.borrow_rand().await; let mut out = [0u8; N]; rng.try_fill_bytes(&mut out) .map_err(|_| Self::Error::NotEnoughRandomness)?; Ok(out) } - fn random_vec(&self, len: usize) -> Result, Self::Error> { - let mut rng = self.borrow_rand()?; + async fn random_vec(&self, len: usize) -> Result, Self::Error> { + let mut rng = self.borrow_rand().await; let mut out = vec![0u8; len]; rng.try_fill_bytes(&mut out) .map_err(|_| Self::Error::NotEnoughRandomness)?; diff --git a/traits/src/crypto.rs b/traits/src/crypto.rs index 20c69e6f34..68386da3cc 100644 --- a/traits/src/crypto.rs +++ b/traits/src/crypto.rs @@ -9,6 +9,8 @@ use crate::types::{ HpkeKeyPair, KemOutput, SignatureScheme, }; +#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))] +#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)] pub trait OpenMlsCrypto { /// Check whether the [`Ciphersuite`] is supported by the backend or not. /// @@ -75,7 +77,10 @@ pub trait OpenMlsCrypto { /// /// Returns an error if the [`SignatureScheme`] is not supported or the key /// generation fails. - fn signature_key_gen(&self, alg: SignatureScheme) -> Result<(Vec, Vec), CryptoError>; + async fn signature_key_gen( + &self, + alg: SignatureScheme, + ) -> Result<(Vec, Vec), CryptoError>; /// Gives the length of a signature public key, in bytes fn signature_public_key_len(&self, alg: SignatureScheme) -> usize; @@ -109,7 +114,7 @@ pub trait OpenMlsCrypto { // === HPKE === // /// HPKE single-shot encryption of `ptxt` to `pk_r`, using `info` and `aad`. - fn hpke_seal( + async fn hpke_seal( &self, config: HpkeConfig, pk_r: &[u8], @@ -132,7 +137,7 @@ pub trait OpenMlsCrypto { /// HPKE single-shot setup of a sender and immediate export a secret. /// /// The encapsulated secret is returned together with the exported secret. - fn hpke_setup_sender_and_export( + async fn hpke_setup_sender_and_export( &self, config: HpkeConfig, pk_r: &[u8], diff --git a/traits/src/random.rs b/traits/src/random.rs index 5b56c69544..9e0b1e029a 100644 --- a/traits/src/random.rs +++ b/traits/src/random.rs @@ -3,6 +3,8 @@ //! The [`OpenMlsRand`] trait defines the functionality required by OpenMLS to //! source randomness. +#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))] +#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)] pub trait OpenMlsRand { type Error: std::error::Error + std::fmt::Debug; type RandImpl: rand_core::CryptoRngCore; @@ -10,11 +12,11 @@ pub trait OpenMlsRand { where Self: 'a; - fn borrow_rand(&self) -> Result, Self::Error>; + async fn borrow_rand(&self) -> Self::BorrowTarget<'_>; /// Fill an array with random bytes. - fn random_array(&self) -> Result<[u8; N], Self::Error>; + async fn random_array(&self) -> Result<[u8; N], Self::Error>; /// Fill a vector of length `len` with bytes. - fn random_vec(&self, len: usize) -> Result, Self::Error>; + async fn random_vec(&self, len: usize) -> Result, Self::Error>; }