// 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 assert_matches::assert_matches; use cfg_if::cfg_if; use mls_rs::client_builder::MlsConfig; use mls_rs::error::MlsError; use mls_rs::group::proposal::Proposal; use mls_rs::group::ReceivedMessage; use mls_rs::identity::SigningIdentity; use mls_rs::mls_rules::CommitOptions; use mls_rs::ExtensionList; use mls_rs::MlsMessage; use mls_rs::ProtocolVersion; use mls_rs::{CipherSuite, Group}; use mls_rs::{Client, CryptoProvider}; use mls_rs_core::crypto::CipherSuiteProvider; use rand::prelude::SliceRandom; use rand::RngCore;
use mls_rs::test_utils::{all_process_message, get_test_basic_credential};
#[cfg(mls_build_async)] use futures::Future;
cfg_if! { if#[cfg(target_arch = "wasm32")] { use mls_rs_crypto_webcrypto::WebCryptoProvider as TestCryptoProvider;
} else { use mls_rs_crypto_openssl::OpensslCryptoProvider as TestCryptoProvider;
}
}
#[cfg(target_arch = "wasm32")] use wasm_bindgen_test::wasm_bindgen_test as futures_test;
#[cfg(all(mls_build_async, not(target_arch = "wasm32")))] use futures_test::test as futures_test;
#[cfg(feature = "private_message")] #[cfg(mls_build_async)] asyncfn test_on_all_params<F, Fut>(test: F) where
F: Fn(ProtocolVersion, CipherSuite, usize, bool) -> Fut,
Fut: Future<Output = ()>,
{ for version in ProtocolVersion::all() { for cs in TestCryptoProvider::all_supported_cipher_suites() { for encrypt_controls in [true, false] {
test(version, cs, 10, encrypt_controls).await;
}
}
}
}
#[cfg(feature = "private_message")] #[cfg(not(mls_build_async))] fn test_on_all_params<F>(test: F) where
F: Fn(ProtocolVersion, CipherSuite, usize, bool),
{ for version in ProtocolVersion::all() { for cs in TestCryptoProvider::all_supported_cipher_suites() { for encrypt_controls in [true, false] {
test(version, cs, 10, encrypt_controls);
}
}
}
}
#[cfg(mls_build_async)] asyncfn test_on_all_params_plaintext<F, Fut>(test: F) where
F: Fn(ProtocolVersion, CipherSuite, usize, bool) -> Fut,
Fut: Future<Output = ()>,
{ for version in ProtocolVersion::all() { for cs in TestCryptoProvider::all_supported_cipher_suites() {
test(version, cs, 10, false).await;
}
}
}
#[cfg(not(mls_build_async))] fn test_on_all_params_plaintext<F>(test: F) where
F: Fn(ProtocolVersion, CipherSuite, usize, bool),
{ for version in ProtocolVersion::all() { for cs in TestCryptoProvider::all_supported_cipher_suites() {
test(version, cs, 10, false);
}
}
}
#[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)] asyncfn test_create(
protocol_version: ProtocolVersion,
cipher_suite: CipherSuite,
_n_participants: usize,
encrypt_controls: bool,
) { let alice = generate_client(cipher_suite, protocol_version, 0, encrypt_controls).await; let bob = generate_client(cipher_suite, protocol_version, 1, encrypt_controls).await; let bob_key_pkg = bob.generate_key_package_message().await.unwrap();
// Alice creates a group and adds bob letmut alice_group = alice
.create_group_with_id(b"group".to_vec(), ExtensionList::default())
.await
.unwrap();
// Create an update from the ith member, have the ith + 1 member commit it for i in0..groups.len() - 1 { let update_proposal_msg = groups[i].propose_update(Vec::new()).await.unwrap();
let sender = groups[i].current_member_index() as usize;
all_process_message(&mut groups, &update_proposal_msg, sender, false).await;
// Everyone receives the commit let committer_index = i + 1;
let commit_output = groups[committer_index].commit(Vec::new()).await.unwrap();
// Remove people from the group one at a time while groups.len() > 1 { let removed_and_committer = (0..groups.len()).choose_multiple(&mut rand::thread_rng(), 2);
let to_remove = removed_and_committer[0]; let committer = removed_and_committer[1]; let to_remove_index = groups[to_remove].current_member_index();
let epoch_before_remove = groups[committer].current_epoch();
let commit_output = groups[committer]
.commit_builder()
.remove_member(to_remove_index)
.unwrap()
.build()
.await
.unwrap();
let commit = commit_output.commit_message; let committer_index = groups[committer].current_member_index() as usize;
all_process_message(&mut groups, &commit, committer_index, true).await;
// Check that remove was effective for (i, group) in groups.iter().enumerate() { if i == to_remove {
assert_eq!(group.current_epoch(), epoch_before_remove);
} else {
assert_eq!(group.current_epoch(), epoch_before_remove + 1);
assert!(group.roster().member_with_index(to_remove_index).is_err());
}
}
letmut groups = get_test_groups(
protocol_version,
cipher_suite,
participants,
encrypt_controls,
)
.await;
// Loop through each participant and send application messages for i in0..groups.len() { letmut test_message = vec![0; 1024];
rand::thread_rng().fill_bytes(&mut test_message);
for _ in0..message_count { // Encrypt the application message let ciphertext = groups[i]
.encrypt_application_message(&test_message, Vec::new())
.await
.unwrap();
let sender_index = groups[i].current_member_index();
for g in groups.iter_mut() { if g.current_member_index() != sender_index { let decrypted = g
.process_incoming_message(ciphertext.clone())
.await
.unwrap();
for i in0..groups.len() { let message = groups[i].propose_remove(0, Vec::new()).await.unwrap();
for (_, group) in groups.iter_mut().enumerate().filter(|&(j, _)| i != j) { let processed = group
.process_incoming_message(message.clone())
.await
.unwrap();
let alice1 = generate_client(suite1, version, 1, Default::default()).await; let bob1 = generate_client(suite1, version, 2, Default::default()).await;
// Create a group with 2 parties letmut alice_group = alice1.create_group(ExtensionList::new()).await.unwrap(); let kp = bob1.generate_key_package_message().await.unwrap();
// They can't create new epochs anymore let res = alice_group.commit(Vec::new()).await;
assert!(res.is_err());
let res = bob_group.commit(Vec::new()).await;
assert!(res.is_err());
// Get reinit clients for alice and bob let (secret_key, public_key) = TestCryptoProvider::new()
.cipher_suite_provider(suite2)
.unwrap()
.signature_key_generate()
.await
.unwrap();
let identity = SigningIdentity::new(get_test_basic_credential(b"bob".to_vec()), public_key);
let bob2 = bob_group
.get_reinit_client(Some(secret_key), Some(identity))
.unwrap();
let (secret_key, public_key) = TestCryptoProvider::new()
.cipher_suite_provider(suite2)
.unwrap()
.signature_key_generate()
.await
.unwrap();
let identity = SigningIdentity::new(get_test_basic_credential(b"alice".to_vec()), public_key);
let alice2 = alice_group
.get_reinit_client(Some(secret_key), Some(identity))
.unwrap();
// Bob produces key package, alice commits, bob joins let kp = bob2.generate_key_package().await.unwrap(); let (mut alice_group, welcome) = alice2.commit(vec![kp]).await.unwrap(); let (mut bob_group, _) = bob2.join(&welcome[0], None).await.unwrap();
assert!(bob_group.cipher_suite() == suite2);
// They can talk let carol = generate_client(suite2, version, 3, Default::default()).await;
let kp = carol.generate_key_package_message().await.unwrap();
let commit_output = alice_group
.commit_builder()
.add_member(kp)
.unwrap()
.build()
.await
.unwrap();
// Remove leaf 1 s.t. the external joiner joins in its place let c = groups[0]
.commit_builder()
.remove_member(1)
.unwrap()
.build()
.await
.unwrap();
// New client's sibling proposes an update to blank their common parent let p = groups[0].propose_update(Vec::new()).await.unwrap();
all_process_message(&mut groups, &p, 0, false).await;
group.process_incoming_message(p).await.unwrap();
// Some other member commits let c = groups[1].commit(Vec::new()).await.unwrap().commit_message;
all_process_message(&mut groups, &c, 2, true).await;
group.process_incoming_message(c).await.unwrap();
}
#[maybe_async::test(not(mls_build_async), async(mls_build_async, futures_test))] asyncfn external_info_from_commit_allows_to_join() { let cs = CipherSuite::P256_AES128; let version = ProtocolVersion::MLS_10;
let commit = alice.commit(vec![]).await.unwrap();
alice.apply_pending_commit().await.unwrap(); let bob = generate_client(cs, version, 0xdead, false).await;
let (_bob, commit) = bob
.commit_external(commit.external_commit_group_info.unwrap())
.await
.unwrap();
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.