diff --git a/openmls/src/credentials/errors.rs b/openmls/src/credentials/errors.rs index 8d36c7c4ee..0a7c1bc43a 100644 --- a/openmls/src/credentials/errors.rs +++ b/openmls/src/credentials/errors.rs @@ -7,7 +7,7 @@ use openmls_traits::authentication_service::CredentialAuthenticationStatus; use thiserror::Error; /// An error that occurs in methods of a [`super::Credential`]. -#[derive(Error, Debug, PartialEq, Clone)] +#[derive(Error, Debug, PartialEq, Eq, Clone)] pub enum CredentialError { /// A library error occurred. #[error(transparent)] diff --git a/openmls/src/credentials/mod.rs b/openmls/src/credentials/mod.rs index d2c77e8e3b..e5abf5f441 100644 --- a/openmls/src/credentials/mod.rs +++ b/openmls/src/credentials/mod.rs @@ -312,7 +312,10 @@ impl Credential { .validate_credential(credential_ref) .await; - if credential_authentication != CredentialAuthenticationStatus::Valid { + if !matches!( + credential_authentication, + CredentialAuthenticationStatus::Valid | CredentialAuthenticationStatus::Expired + ) { return Err(CredentialError::AuthenticationServiceValidationFailure( credential_authentication, )); diff --git a/openmls/src/framing/mls_auth_content_in.rs b/openmls/src/framing/mls_auth_content_in.rs index 1492e64bd1..01d7e3908a 100644 --- a/openmls/src/framing/mls_auth_content_in.rs +++ b/openmls/src/framing/mls_auth_content_in.rs @@ -47,7 +47,7 @@ pub struct AuthenticatedContentIn { impl AuthenticatedContentIn { /// Returns a [`AuthenticatedContent`] after successful validation. - pub fn validate( + pub async fn validate( self, ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoProvider, @@ -57,13 +57,16 @@ impl AuthenticatedContentIn { ) -> Result { Ok(AuthenticatedContent { wire_format: self.wire_format, - content: self.content.validate( - ciphersuite, - backend, - sender_context, - protocol_version, - group, - )?, + content: self + .content + .validate( + ciphersuite, + backend, + sender_context, + protocol_version, + group, + ) + .await?, auth: self.auth, }) } diff --git a/openmls/src/framing/mls_content_in.rs b/openmls/src/framing/mls_content_in.rs index 22c06115d6..a300a986ea 100644 --- a/openmls/src/framing/mls_content_in.rs +++ b/openmls/src/framing/mls_content_in.rs @@ -50,7 +50,7 @@ pub struct FramedContentIn { impl FramedContentIn { /// Returns a [`FramedContent`] after successful validation. - pub fn validate( + pub async fn validate( self, ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoProvider, @@ -63,13 +63,16 @@ impl FramedContentIn { epoch: self.epoch, sender: self.sender, authenticated_data: self.authenticated_data, - body: self.body.validate( - ciphersuite, - backend, - sender_context, - protocol_version, - group, - )?, + body: self + .body + .validate( + ciphersuite, + backend, + sender_context, + protocol_version, + group, + ) + .await?, }) } } @@ -135,7 +138,7 @@ impl FramedContentBodyIn { } /// Returns a [`FramedContentBody`] after successful validation. - pub fn validate( + pub async fn validate( self, ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoProvider, @@ -145,25 +148,31 @@ impl FramedContentBodyIn { ) -> Result { Ok(match self { FramedContentBodyIn::Application(bytes) => FramedContentBody::Application(bytes), - FramedContentBodyIn::Proposal(proposal_in) => { - FramedContentBody::Proposal(proposal_in.validate( - backend, - ciphersuite, - sender_context, - protocol_version, - group, - )?) - } + FramedContentBodyIn::Proposal(proposal_in) => FramedContentBody::Proposal( + proposal_in + .validate( + backend, + ciphersuite, + sender_context, + protocol_version, + group, + ) + .await?, + ), FramedContentBodyIn::Commit(commit_in) => { let sender_context = sender_context .ok_or(LibraryError::custom("Forgot the commit sender context"))?; - FramedContentBody::Commit(commit_in.validate( - ciphersuite, - backend, - sender_context, - protocol_version, - group, - )?) + FramedContentBody::Commit( + commit_in + .validate( + ciphersuite, + backend, + sender_context, + protocol_version, + group, + ) + .await?, + ) } }) } diff --git a/openmls/src/framing/validation.rs b/openmls/src/framing/validation.rs index c6b1b73e08..85ddd07deb 100644 --- a/openmls/src/framing/validation.rs +++ b/openmls/src/framing/validation.rs @@ -272,7 +272,7 @@ impl UnverifiedMessage { /// Verify the [`UnverifiedMessage`]. Returns the [`AuthenticatedContent`] /// and the internal [`Credential`]. - pub(crate) fn verify( + pub(crate) async fn verify( self, ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoProvider, @@ -315,13 +315,15 @@ impl UnverifiedMessage { .map_err(|_| ProcessMessageError::InvalidSignature)? } }; - let content = content.validate( - ciphersuite, - backend, - self.sender_context, - protocol_version, - group, - )?; + let content = content + .validate( + ciphersuite, + backend, + self.sender_context, + protocol_version, + group, + ) + .await?; Ok((content, self.credential)) } diff --git a/openmls/src/group/core_group/new_from_welcome.rs b/openmls/src/group/core_group/new_from_welcome.rs index ce6fc6481e..7ce8cbc0be 100644 --- a/openmls/src/group/core_group/new_from_welcome.rs +++ b/openmls/src/group/core_group/new_from_welcome.rs @@ -153,11 +153,9 @@ impl CoreGroup { ProposalStore::new(), )?; - KeyPackageIn::from(key_package.clone()).validate( - backend, - ProtocolVersion::Mls10, - &public_group, - )?; + KeyPackageIn::from(key_package.clone()) + .validate(backend, ProtocolVersion::Mls10, &public_group) + .await?; // Find our own leaf in the tree. let own_leaf_index = public_group diff --git a/openmls/src/group/core_group/process.rs b/openmls/src/group/core_group/process.rs index ab54f56db4..3b3be81c48 100644 --- a/openmls/src/group/core_group/process.rs +++ b/openmls/src/group/core_group/process.rs @@ -49,12 +49,14 @@ impl CoreGroup { // Checks the following semantic validation: // - ValSem010 // - ValSem246 (as part of ValSem010) - let (content, credential) = unverified_message.verify( - self.ciphersuite(), - backend, - self.version(), - self.public_group(), - )?; + let (content, credential) = unverified_message + .verify( + self.ciphersuite(), + backend, + self.version(), + self.public_group(), + ) + .await?; match content.sender() { Sender::Member(_) | Sender::NewMemberCommit | Sender::NewMemberProposal => { diff --git a/openmls/src/group/core_group/test_proposals.rs b/openmls/src/group/core_group/test_proposals.rs index d68959685f..7a6f97407e 100644 --- a/openmls/src/group/core_group/test_proposals.rs +++ b/openmls/src/group/core_group/test_proposals.rs @@ -51,6 +51,7 @@ async fn proposal_queue_functions(ciphersuite: Ciphersuite, backend: &impl OpenM assert!(kpi .standalone_validate(backend, ProtocolVersion::Mls10) + .await .is_ok()); let group_context = GroupContext::new( @@ -197,6 +198,7 @@ async fn proposal_queue_order(ciphersuite: Ciphersuite, backend: &impl OpenMlsCr assert!(kpi .standalone_validate(backend, ProtocolVersion::Mls10) + .await .is_ok()); let group_context = GroupContext::new( diff --git a/openmls/src/group/mls_group/membership.rs b/openmls/src/group/mls_group/membership.rs index a4ab72f9dd..990a4f5c3a 100644 --- a/openmls/src/group/mls_group/membership.rs +++ b/openmls/src/group/mls_group/membership.rs @@ -45,17 +45,13 @@ impl MlsGroup { self.is_operational()?; // Create inline add proposals from key packages - let inline_proposals = key_packages - .into_iter() - .map(|key_package| { - let key_package = key_package.validate( - backend, - ProtocolVersion::Mls10, - self.group().public_group(), - )?; - Ok(Proposal::Add(AddProposal { key_package })) - }) - .collect::, AddMembersError>>()?; + let mut inline_proposals = Vec::with_capacity(key_packages.len()); + for key_package in key_packages.into_iter() { + let key_package = key_package + .validate(backend, ProtocolVersion::Mls10, self.group().public_group()) + .await?; + inline_proposals.push(Proposal::Add(AddProposal { key_package })); + } // Create Commit over all proposals // TODO #751 diff --git a/openmls/src/group/mls_group/proposal.rs b/openmls/src/group/mls_group/proposal.rs index d895d547f5..da9a4a88bf 100644 --- a/openmls/src/group/mls_group/proposal.rs +++ b/openmls/src/group/mls_group/proposal.rs @@ -97,7 +97,7 @@ impl MlsGroup { /// Creates proposals to add an external PSK to the key schedule. /// /// Returns an error if there is a pending commit. - pub fn propose_add_member_by_value( + pub async fn propose_add_member_by_value( &mut self, backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, @@ -105,11 +105,9 @@ impl MlsGroup { ) -> Result<(MlsMessageOut, ProposalRef), ProposalError> { self.is_operational()?; - let key_package = joiner_key_package.validate( - backend, - ProtocolVersion::Mls10, - self.group().public_group(), - )?; + let key_package = joiner_key_package + .validate(backend, ProtocolVersion::Mls10, self.group().public_group()) + .await?; let proposal = self.group .create_add_proposal(self.framing_parameters(), key_package, signer)?; @@ -161,12 +159,12 @@ impl MlsGroup { ) -> Result<(MlsMessageOut, ProposalRef), ProposalError> { match propose { Propose::Add(key_package) => match ref_or_value { - ProposalOrRefType::Proposal => { - self.propose_add_member_by_value(backend, signer, key_package.into()) - } - ProposalOrRefType::Reference => self + ProposalOrRefType::Proposal => Ok(self + .propose_add_member_by_value(backend, signer, key_package.into()) + .await?), + ProposalOrRefType::Reference => Ok(self .propose_add_member(backend, signer, key_package.into()) - .map_err(|e| e.into()), + .await?), }, Propose::Update(leaf_node) => match ref_or_value { @@ -240,7 +238,7 @@ impl MlsGroup { /// Creates proposals to add members to the group. /// /// Returns an error if there is a pending commit. - pub fn propose_add_member( + pub async fn propose_add_member( &mut self, backend: &impl OpenMlsCryptoProvider, signer: &impl Signer, @@ -248,11 +246,9 @@ impl MlsGroup { ) -> Result<(MlsMessageOut, ProposalRef), ProposeAddMemberError> { self.is_operational()?; - let key_package = joiner_key_package.validate( - backend, - ProtocolVersion::Mls10, - self.group().public_group(), - )?; + let key_package = joiner_key_package + .validate(backend, ProtocolVersion::Mls10, self.group().public_group()) + .await?; let add_proposal = self.group .create_add_proposal(self.framing_parameters(), key_package, signer)?; diff --git a/openmls/src/group/mls_group/test_mls_group.rs b/openmls/src/group/mls_group/test_mls_group.rs index 4d343f5de2..b531b50a3e 100644 --- a/openmls/src/group/mls_group/test_mls_group.rs +++ b/openmls/src/group/mls_group/test_mls_group.rs @@ -404,6 +404,7 @@ async fn test_pending_commit_logic(ciphersuite: Ciphersuite, backend: &impl Open // Let's add bob let (proposal, _) = alice_group .propose_add_member(backend, &alice_signer, bob_key_package.clone().into()) + .await .expect("error creating self-update proposal"); let alice_processed_message = alice_group @@ -445,6 +446,7 @@ async fn test_pending_commit_logic(ciphersuite: Ciphersuite, backend: &impl Open )); let error = alice_group .propose_add_member(backend, &alice_signer, bob_key_package.clone().into()) + .await .expect_err("no error creating a proposal while a commit is pending"); assert!(matches!( error, @@ -676,6 +678,7 @@ async fn remove_prosposal_by_ref(ciphersuite: Ciphersuite, backend: &impl OpenMl // alice proposes to add charlie let (_, reference) = alice_group .propose_add_member(backend, &alice_signer, charlie_key_package.clone().into()) + .await .unwrap(); assert_eq!(alice_group.proposal_store.proposals().count(), 1); diff --git a/openmls/src/group/mls_group/updates.rs b/openmls/src/group/mls_group/updates.rs index ff55f1b639..2f08159426 100644 --- a/openmls/src/group/mls_group/updates.rs +++ b/openmls/src/group/mls_group/updates.rs @@ -188,7 +188,9 @@ impl MlsGroup { ) .into()); }; - let own_leaf = own_leaf.validate(self.group().public_group(), backend.crypto())?; + let own_leaf = own_leaf + .validate(self.group().public_group(), backend) + .await?; let update_proposal = self.group.create_update_proposal( self.framing_parameters(), @@ -269,7 +271,9 @@ impl MlsGroup { ) .into()); }; - let own_leaf = own_leaf.validate(self.group().public_group(), backend.crypto())?; + let own_leaf = own_leaf + .validate(self.group().public_group(), backend) + .await?; let update_proposal = self.group.create_update_proposal( self.framing_parameters(), diff --git a/openmls/src/group/public_group/process.rs b/openmls/src/group/public_group/process.rs index 0892be8f70..70be92f0e1 100644 --- a/openmls/src/group/public_group/process.rs +++ b/openmls/src/group/public_group/process.rs @@ -131,7 +131,7 @@ impl PublicGroup { /// - ValSem244 /// - ValSem245 /// - ValSem246 (as part of ValSem010) - pub fn process_message( + pub async fn process_message( &self, backend: &impl OpenMlsCryptoProvider, message: impl Into, @@ -162,6 +162,7 @@ impl PublicGroup { .parse_message(decrypted_message, None) .map_err(ProcessMessageError::from)?; self.process_unverified_message(backend, unverified_message, &self.proposal_store, self) + .await } } @@ -193,7 +194,7 @@ impl PublicGroup { /// - ValSem243 /// - ValSem244 /// - ValSem246 (as part of ValSem010) - pub(crate) fn process_unverified_message( + pub(crate) async fn process_unverified_message( &self, backend: &impl OpenMlsCryptoProvider, unverified_message: UnverifiedMessage, @@ -203,8 +204,9 @@ impl PublicGroup { // Checks the following semantic validation: // - ValSem010 // - ValSem246 (as part of ValSem010) - let (content, credential) = - unverified_message.verify(self.ciphersuite(), backend, self.version(), group)?; + let (content, credential) = unverified_message + .verify(self.ciphersuite(), backend, self.version(), group) + .await?; match content.sender() { Sender::Member(_) | Sender::NewMemberCommit | Sender::NewMemberProposal => { diff --git a/openmls/src/group/public_group/tests.rs b/openmls/src/group/public_group/tests.rs index f12d479fe1..cc3e451bb7 100644 --- a/openmls/src/group/public_group/tests.rs +++ b/openmls/src/group/public_group/tests.rs @@ -84,6 +84,7 @@ async fn public_group(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoProv }; let processed_message = public_group .process_message(backend, public_message) + .await .unwrap(); // Further inspection of the message can take place here ... @@ -145,6 +146,7 @@ async fn public_group(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoProv // The public group processes let ppm = public_group .process_message(backend, into_public_message(queued_messages)) + .await .unwrap(); public_group.merge_commit(extract_staged_commit(ppm)); @@ -183,6 +185,7 @@ async fn public_group(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoProv // The public group processes let ppm = public_group .process_message(backend, into_public_message(queued_messages)) + .await .unwrap(); // We have to add the proposal to the public group's proposal store. match ppm.into_content() { @@ -229,6 +232,7 @@ async fn public_group(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoProv // The public group processes let ppm = public_group .process_message(backend, into_public_message(queued_messages.clone())) + .await .unwrap(); public_group.merge_commit(extract_staged_commit(ppm)); diff --git a/openmls/src/group/tests/test_gce_proposals.rs b/openmls/src/group/tests/test_gce_proposals.rs index c738086f4b..60685767b1 100644 --- a/openmls/src/group/tests/test_gce_proposals.rs +++ b/openmls/src/group/tests/test_gce_proposals.rs @@ -370,6 +370,7 @@ async fn gce_proposal_must_be_applied_first_then_used_to_validate_other_add_prop &alice_signer, charlie_key_package_bundle.key_package().clone().into(), ) + .await .unwrap(); let processed_message = bob_group diff --git a/openmls/src/group/tests/test_proposal_validation.rs b/openmls/src/group/tests/test_proposal_validation.rs index 3865f1c11b..5fbaa3fa3a 100644 --- a/openmls/src/group/tests/test_proposal_validation.rs +++ b/openmls/src/group/tests/test_proposal_validation.rs @@ -1085,6 +1085,7 @@ async fn test_valsem105(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoPr let kpi: KeyPackageIn = charlie_key_package.clone().into(); kpi.standalone_validate(backend, ProtocolVersion::Mls10) + .await .unwrap(); // Let's just pick a ciphersuite that's not the one we're testing right now. @@ -1165,11 +1166,13 @@ async fn test_valsem105(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoPr for proposal_inclusion in [ProposalInclusion::ByReference, ProposalInclusion::ByValue] { match proposal_inclusion { ProposalInclusion::ByReference => { - let proposal_result = alice_group.propose_add_member( - backend, - &alice_credential_with_key_and_signer.signer, - test_kp.clone().into(), - ); + let proposal_result = alice_group + .propose_add_member( + backend, + &alice_credential_with_key_and_signer.signer, + test_kp.clone().into(), + ) + .await; match key_package_version { KeyPackageTestVersion::WrongCiphersuite => { diff --git a/openmls/src/key_packages/key_package_in.rs b/openmls/src/key_packages/key_package_in.rs index 9b35d95be4..f03a7113aa 100644 --- a/openmls/src/key_packages/key_package_in.rs +++ b/openmls/src/key_packages/key_package_in.rs @@ -114,25 +114,25 @@ impl KeyPackageIn { /// /// Returns a [`KeyPackage`] after having verified the signature or a /// [`KeyPackageVerifyError`] otherwise. - pub fn validate( + pub async fn validate( self, backend: &impl OpenMlsCryptoProvider, protocol_version: ProtocolVersion, group: &PublicGroup, ) -> Result { - self._validate(backend, protocol_version, Some(group)) + self._validate(backend, protocol_version, Some(group)).await } /// Verify that this key package is valid disregarding the group it is supposed to be used with. - pub fn standalone_validate( + pub async fn standalone_validate( self, backend: &impl OpenMlsCryptoProvider, protocol_version: ProtocolVersion, ) -> Result { - self._validate(backend, protocol_version, None) + self._validate(backend, protocol_version, None).await } - fn _validate( + async fn _validate( self, backend: &impl OpenMlsCryptoProvider, protocol_version: ProtocolVersion, @@ -154,9 +154,11 @@ impl KeyPackageIn { let leaf_node = match verifiable_leaf_node { VerifiableLeafNode::KeyPackage(leaf_node) => { if let Some(group) = group { - leaf_node.validate(group, backend.crypto())? + leaf_node.validate(group, backend).await? } else { - leaf_node.standalone_validate(backend.crypto(), signature_scheme)? + leaf_node + .standalone_validate(backend, signature_scheme) + .await? } } _ => return Err(KeyPackageVerifyError::InvalidLeafNodeSourceType), diff --git a/openmls/src/key_packages/test_key_packages.rs b/openmls/src/key_packages/test_key_packages.rs index f2458ca8c7..ec0b68d712 100644 --- a/openmls/src/key_packages/test_key_packages.rs +++ b/openmls/src/key_packages/test_key_packages.rs @@ -48,6 +48,7 @@ async fn generate_key_package(ciphersuite: Ciphersuite, backend: &impl OpenMlsCr let kpi = KeyPackageIn::from(key_package); assert!(kpi .standalone_validate(backend, ProtocolVersion::Mls10) + .await .is_ok()); } @@ -101,6 +102,7 @@ async fn application_id_extension(ciphersuite: Ciphersuite, backend: &impl OpenM let kpi = KeyPackageIn::from(key_package.clone()); assert!(kpi .standalone_validate(backend, ProtocolVersion::Mls10) + .await .is_ok()); // Check ID @@ -137,6 +139,7 @@ async fn key_package_validation(ciphersuite: Ciphersuite, backend: &impl OpenMls let err = kpi .standalone_validate(backend, ProtocolVersion::Mls10) + .await .unwrap_err(); // Expect an invalid protocol version error assert_eq!(err, KeyPackageVerifyError::InvalidProtocolVersion); @@ -156,6 +159,7 @@ async fn key_package_validation(ciphersuite: Ciphersuite, backend: &impl OpenMls let err = kpi .standalone_validate(backend, ProtocolVersion::Mls10) + .await .unwrap_err(); // Expect an invalid init/encryption key error assert_eq!(err, KeyPackageVerifyError::InitKeyEqualsEncryptionKey); diff --git a/openmls/src/messages/mod.rs b/openmls/src/messages/mod.rs index 63adb4ac5c..81190cc8e2 100644 --- a/openmls/src/messages/mod.rs +++ b/openmls/src/messages/mod.rs @@ -189,7 +189,7 @@ impl CommitIn { } /// Returns a [`Commit`] after successful validation. - pub fn validate( + pub async fn validate( self, ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoProvider, @@ -197,11 +197,14 @@ impl CommitIn { protocol_version: ProtocolVersion, group: &PublicGroup, ) -> Result { - let proposals = self - .proposals - .into_iter() - .map(|p| p.validate(backend, ciphersuite, protocol_version, group)) - .collect::, _>>()?; + let mut proposals = Vec::with_capacity(self.proposals.len()); + for proposal in self.proposals.into_iter() { + proposals.push( + proposal + .validate(backend, ciphersuite, protocol_version, group) + .await?, + ); + } let path = if let Some(path) = self.path { let tree_position = match sender_context { @@ -234,7 +237,7 @@ impl CommitIn { TreePosition::new(group_id, new_leaf_index) } }; - Some(path.into_verified(backend.crypto(), tree_position, group)?) + Some(path.into_verified(backend, tree_position, group).await?) } else { None }; diff --git a/openmls/src/messages/proposals_in.rs b/openmls/src/messages/proposals_in.rs index c79d948ff9..821703f763 100644 --- a/openmls/src/messages/proposals_in.rs +++ b/openmls/src/messages/proposals_in.rs @@ -17,7 +17,7 @@ use crate::{ use crate::prelude::PublicGroup; use crate::treesync::node::validate::ValidatableLeafNode; -use openmls_traits::{crypto::OpenMlsCrypto, types::Ciphersuite, OpenMlsCryptoProvider}; +use openmls_traits::{types::Ciphersuite, OpenMlsCryptoProvider}; use serde::{Deserialize, Serialize}; use tls_codec::{TlsDeserialize, TlsSerialize, TlsSize}; @@ -95,7 +95,7 @@ impl ProposalIn { } /// Returns a [`Proposal`] after successful validation. - pub(crate) fn validate( + pub(crate) async fn validate( self, backend: &impl OpenMlsCryptoProvider, ciphersuite: Ciphersuite, @@ -104,13 +104,14 @@ impl ProposalIn { group: &PublicGroup, ) -> Result { Ok(match self { - ProposalIn::Add(add) => { - Proposal::Add(add.validate(backend, protocol_version, ciphersuite, group)?) - } + ProposalIn::Add(add) => Proposal::Add( + add.validate(backend, protocol_version, ciphersuite, group) + .await?, + ), ProposalIn::Update(update) => { let sender_context = sender_context.ok_or(ValidationError::CommitterIncludedOwnUpdate)?; - Proposal::Update(update.validate(backend.crypto(), sender_context, group)?) + Proposal::Update(update.validate(backend, sender_context, group).await?) } ProposalIn::Remove(remove) => Proposal::Remove(remove), ProposalIn::PreSharedKey(psk) => Proposal::PreSharedKey(psk), @@ -147,7 +148,7 @@ impl AddProposalIn { } /// Returns a [`AddProposal`] after successful validation. - pub(crate) fn validate( + pub(crate) async fn validate( self, backend: &impl OpenMlsCryptoProvider, protocol_version: ProtocolVersion, @@ -156,7 +157,8 @@ impl AddProposalIn { ) -> Result { let key_package = self .key_package - .validate(backend, protocol_version, group)?; + .validate(backend, protocol_version, group) + .await?; // Verify that the ciphersuite is valid if key_package.ciphersuite() != ciphersuite { return Err(ValidationError::InvalidAddProposalCiphersuite); @@ -185,9 +187,9 @@ pub struct UpdateProposalIn { impl UpdateProposalIn { /// Returns a [`UpdateProposal`] after successful validation. - pub(crate) fn validate( + pub(crate) async fn validate( self, - crypto: &impl OpenMlsCrypto, + backend: &impl OpenMlsCryptoProvider, sender_context: SenderContext, group: &PublicGroup, ) -> Result { @@ -201,7 +203,7 @@ impl UpdateProposalIn { .leaf_node .try_into_verifiable_leaf_node(Some(tree_position))?; let leaf_node = match verifiable_leaf_node { - VerifiableLeafNode::Update(leaf_node) => leaf_node.validate(group, crypto)?, + VerifiableLeafNode::Update(leaf_node) => leaf_node.validate(group, backend).await?, _ => return Err(ValidationError::InvalidLeafNodeSourceType), }; @@ -226,7 +228,7 @@ pub(crate) enum ProposalOrRefIn { impl ProposalOrRefIn { /// Returns a [`ProposalOrRef`] after successful validation. - pub(crate) fn validate( + pub(crate) async fn validate( self, backend: &impl OpenMlsCryptoProvider, ciphersuite: Ciphersuite, @@ -235,7 +237,9 @@ impl ProposalOrRefIn { ) -> Result { Ok(match self { ProposalOrRefIn::Proposal(proposal_in) => ProposalOrRef::Proposal( - proposal_in.validate(backend, ciphersuite, None, protocol_version, group)?, + proposal_in + .validate(backend, ciphersuite, None, protocol_version, group) + .await?, ), ProposalOrRefIn::Reference(reference) => ProposalOrRef::Reference(reference), }) diff --git a/openmls/src/test_utils/test_framework/client.rs b/openmls/src/test_utils/test_framework/client.rs index a956bdda2d..18082cc46f 100644 --- a/openmls/src/test_utils/test_framework/client.rs +++ b/openmls/src/test_utils/test_framework/client.rs @@ -281,6 +281,7 @@ impl Client { for key_package in key_packages { let message = group .propose_add_member(&self.crypto, &signer, key_package.clone()) + .await .map(|(out, _)| out)?; messages.push(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 1349a5d8f3..0fb65fe623 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 @@ -423,6 +423,7 @@ pub async fn run_test_vector( ProtocolVersion::Mls10, group.public_group(), ) + .await .unwrap() .0; match processed_message.content().to_owned() { @@ -538,7 +539,7 @@ pub async fn run_test_vector( let commit_priv = MlsMessageIn::tls_deserialize_exact(hex_to_bytes(&test.commit_priv)).unwrap(); - fn test_commit_pub( + async fn test_commit_pub( mut group: CoreGroup, backend: &impl OpenMlsCryptoProvider, ciphersuite: Ciphersuite, @@ -568,6 +569,7 @@ pub async fn run_test_vector( ProtocolVersion::Mls10, group.public_group(), ) + .await .unwrap() .0; match processed_message.content().to_owned() { @@ -584,9 +586,10 @@ pub async fn run_test_vector( ciphersuite, commit.clone(), commit_pub, - ); + ) + .await; - fn test_commit_priv( + async fn test_commit_priv( mut group: CoreGroup, backend: &impl OpenMlsCryptoProvider, ciphersuite: Ciphersuite, @@ -616,6 +619,7 @@ pub async fn run_test_vector( ProtocolVersion::Mls10, group.public_group(), ) + .await .unwrap() .0; match processed_message.content().to_owned() { @@ -632,7 +636,8 @@ pub async fn run_test_vector( ciphersuite, commit.clone(), commit_priv, - ); + ) + .await; // Wrap `commit` into a `PrivateMessage`. let group = setup_group(backend, ciphersuite, &test, false).await; @@ -660,7 +665,8 @@ pub async fn run_test_vector( ciphersuite, commit.clone(), my_commit_priv_out.into(), - ); + ) + .await; // Wrap `commit` into a `PublicMessage`. let group = setup_group(backend, ciphersuite, &test, false).await; @@ -692,7 +698,8 @@ pub async fn run_test_vector( ciphersuite, commit, my_commit_pub_out.into(), - ); + ) + .await; } // Application diff --git a/openmls/src/treesync/errors.rs b/openmls/src/treesync/errors.rs index d225230bad..8884849726 100644 --- a/openmls/src/treesync/errors.rs +++ b/openmls/src/treesync/errors.rs @@ -7,7 +7,7 @@ use thiserror::Error; use super::*; use crate::{ binary_tree::MlsBinaryTreeDiffError, ciphersuite::signable::SignatureError, - error::LibraryError, extensions::errors::ExtensionError, + credentials::errors::CredentialError, error::LibraryError, extensions::errors::ExtensionError, }; // === Public errors === @@ -262,6 +262,8 @@ pub enum LeafNodeValidationError { /// The credential used by a member is not supported by this leaf node. #[error("The credential used by a member is not supported by this leaf node.")] MemberCredentialNotSupportedByLeafNode, + #[error(transparent)] + InvalidCredential(#[from] CredentialError), /// A library error occurred. #[error(transparent)] LibraryError(#[from] LibraryError), diff --git a/openmls/src/treesync/node/validate.rs b/openmls/src/treesync/node/validate.rs index d0781c2766..66d8ed07e6 100644 --- a/openmls/src/treesync/node/validate.rs +++ b/openmls/src/treesync/node/validate.rs @@ -1,4 +1,5 @@ use crate::{ + credentials::Credential, prelude::{ Capabilities, CredentialType, ExtensionType, Extensions, SignaturePublicKey, Verifiable, }, @@ -13,7 +14,7 @@ use crate::{ }, }; use itertools::Itertools; -use openmls_traits::{crypto::OpenMlsCrypto, types::SignatureScheme}; +use openmls_traits::{crypto::OpenMlsCrypto, types::SignatureScheme, OpenMlsCryptoProvider}; impl ValidatableLeafNode for VerifiableCommitLeafNode { fn signature_key(&self) -> &SignaturePublicKey { @@ -28,19 +29,24 @@ impl ValidatableLeafNode for VerifiableCommitLeafNode { &self.payload.credential.credential_type } + fn credential(&self) -> &Credential { + &self.payload.credential + } + fn extensions(&self) -> &Extensions { &self.payload.extensions } } +#[async_trait::async_trait(?Send)] impl ValidatableLeafNode for VerifiableUpdateLeafNode { - fn validate( + async fn validate( self, group: &PublicGroup, - crypto: &impl OpenMlsCrypto, + backend: &impl OpenMlsCryptoProvider, ) -> Result { self.validate_replaced_encryption_key(group)?; - self.generic_validate(crypto, group) + self.generic_validate(backend, group).await } fn signature_key(&self) -> &SignaturePublicKey { @@ -55,6 +61,10 @@ impl ValidatableLeafNode for VerifiableUpdateLeafNode { &self.payload.credential.credential_type } + fn credential(&self) -> &Credential { + &self.payload.credential + } + fn extensions(&self) -> &Extensions { &self.payload.extensions } @@ -77,14 +87,16 @@ impl VerifiableUpdateLeafNode { } } +#[async_trait::async_trait(?Send)] + impl ValidatableLeafNode for VerifiableKeyPackageLeafNode { - fn validate( + async fn validate( self, group: &PublicGroup, - crypto: &impl OpenMlsCrypto, + backend: &impl OpenMlsCryptoProvider, ) -> Result { self.validate_lifetime()?; - self.generic_validate(crypto, group) + self.generic_validate(backend, group).await } fn signature_key(&self) -> &SignaturePublicKey { @@ -99,6 +111,10 @@ impl ValidatableLeafNode for VerifiableKeyPackageLeafNode { &self.payload.credential.credential_type } + fn credential(&self) -> &Credential { + &self.payload.credential + } + fn extensions(&self) -> &Extensions { &self.payload.extensions } @@ -116,34 +132,37 @@ impl VerifiableKeyPackageLeafNode { } } +#[async_trait::async_trait(?Send)] pub(crate) trait ValidatableLeafNode: Verifiable + Sized where LeafNode: VerifiedStruct, { - fn standalone_validate( + async fn standalone_validate( self, - crypto: &impl OpenMlsCrypto, + backend: &impl OpenMlsCryptoProvider, signature_scheme: SignatureScheme, ) -> Result { let extension_types = self.extension_types(); - let leaf_node = self.verify_signature(crypto, signature_scheme)?; + self.validate_credential(backend).await?; + let leaf_node = self.verify_signature(backend.crypto(), signature_scheme)?; Self::validate_extension_support(&leaf_node, &extension_types[..])?; + Ok(leaf_node) } /// Validate a LeafNode as per https://www.rfc-editor.org/rfc/rfc9420.html#name-leaf-node-validation - fn validate( + async fn validate( self, group: &PublicGroup, - crypto: &impl OpenMlsCrypto, + backend: &impl OpenMlsCryptoProvider, ) -> Result { - self.generic_validate(crypto, group) + self.generic_validate(backend, group).await } /// Validation regardless of [LeafNode]'s source - fn generic_validate( + async fn generic_validate( self, - crypto: &impl OpenMlsCrypto, + backend: &impl OpenMlsCryptoProvider, group: &PublicGroup, ) -> Result { self.validate_capabilities(group)?; @@ -151,17 +170,20 @@ where let tree = group.treesync(); self.validate_signature_key_unique(tree)?; self.validate_encryption_key_unique(tree)?; + self.validate_credential(backend).await?; let extension_types = self.extension_types(); let signature_scheme = group.ciphersuite().signature_algorithm(); - let leaf_node = self.verify_signature(crypto, signature_scheme)?; + let leaf_node = self.verify_signature(backend.crypto(), signature_scheme)?; Self::validate_extension_support(&leaf_node, &extension_types[..])?; + Ok(leaf_node) } fn signature_key(&self) -> &SignaturePublicKey; fn capabilities(&self) -> &Capabilities; fn credential_type(&self) -> &CredentialType; + fn credential(&self) -> &Credential; fn extensions(&self) -> &Extensions; fn extension_types(&self) -> Vec { @@ -201,6 +223,13 @@ where Ok(()) } + async fn validate_credential( + &self, + backend: &impl OpenMlsCryptoProvider, + ) -> Result<(), LeafNodeValidationError> { + Ok(self.credential().validate(backend).await?) + } + /// Verify that the following fields are unique among the members of the group: signature_key fn validate_signature_key_unique( &self, diff --git a/openmls/src/treesync/treekem.rs b/openmls/src/treesync/treekem.rs index 0904ae253a..9a82289aaf 100644 --- a/openmls/src/treesync/treekem.rs +++ b/openmls/src/treesync/treekem.rs @@ -7,7 +7,6 @@ use std::collections::HashSet; use openmls_traits::{ - crypto::OpenMlsCrypto, types::{Ciphersuite, HpkeCiphertext}, OpenMlsCryptoProvider, }; @@ -379,9 +378,9 @@ impl UpdatePathIn { } /// Return a verified [`UpdatePath`]. - pub(crate) fn into_verified( + pub(crate) async fn into_verified( self, - crypto: &impl OpenMlsCrypto, + backend: &impl OpenMlsCryptoProvider, tree_position: TreePosition, group: &PublicGroup, ) -> Result { @@ -390,7 +389,7 @@ impl UpdatePathIn { leaf_node_in.try_into_verifiable_leaf_node(Some(tree_position))?; match verifiable_leaf_node { VerifiableLeafNode::Commit(commit_leaf_node) => { - let leaf_node = commit_leaf_node.validate(group, crypto)?; + let leaf_node = commit_leaf_node.validate(group, backend).await?; Ok(UpdatePath { leaf_node, nodes: self.nodes, diff --git a/openmls/tests/book_code.rs b/openmls/tests/book_code.rs index a0cb7d05be..14bc101595 100644 --- a/openmls/tests/book_code.rs +++ b/openmls/tests/book_code.rs @@ -846,6 +846,7 @@ async fn book_operations(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoP &alice_signature_keys, bob_key_package.clone().into(), ) + .await .expect("Could not create proposal to add Bob"); alice_group .remove_pending_proposal(backend.key_store(), &proposal_ref) @@ -861,6 +862,7 @@ async fn book_operations(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoP &alice_signature_keys, bob_key_package.clone().into(), ) + .await .expect("Could not create proposal to add Bob"); // ANCHOR_END: propose_add diff --git a/openmls/tests/test_mls_group.rs b/openmls/tests/test_mls_group.rs index 06768f0aee..c8f49cf89b 100644 --- a/openmls/tests/test_mls_group.rs +++ b/openmls/tests/test_mls_group.rs @@ -648,6 +648,7 @@ async fn mls_group_operations(ciphersuite: Ciphersuite, backend: &impl OpenMlsCr // Create AddProposal and process it let (queued_message, _) = alice_group .propose_add_member(backend, &alice_signer, bob_key_package.into()) + .await .expect("Could not create proposal to add Bob"); let charlie_processed_message = charlie_group