use crate::{
ciphersuite::{hash_ref::KeyPackageRef, *},
credentials::*,
framing::*,
group::*,
key_packages::*,
messages::*,
treesync::node::Node,
};
use ::rand::{rngs::OsRng, RngCore};
use openmls_rust_crypto::OpenMlsRustCrypto;
use openmls_traits::{
crypto::OpenMlsCrypto,
key_store::OpenMlsKeyStore,
types::{Ciphersuite, SignatureScheme},
OpenMlsCryptoProvider,
};
use rayon::prelude::*;
use std::{collections::HashMap, sync::RwLock};
use tls_codec::*;
pub mod client;
pub mod errors;
pub mod messages;
use self::client::*;
use self::errors::*;
#[derive(Clone)]
pub struct Group {
pub group_id: GroupId,
pub members: Vec<(usize, Vec<u8>)>,
pub ciphersuite: Ciphersuite,
pub group_config: MlsGroupConfig,
pub public_tree: Vec<Option<Node>>,
pub exporter_secret: Vec<u8>,
}
impl Group {
pub fn random_group_member(&self) -> Vec<u8> {
let index = (OsRng.next_u32() as usize) % self.members.len();
let (_, identity) = self.members[index].clone();
identity
}
}
#[derive(Debug)]
pub enum ActionType {
Commit,
Proposal,
}
#[derive(Debug, PartialEq)]
pub enum CodecUse {
SerializedMessages,
StructMessages,
}
pub struct MlsGroupTestSetup {
pub clients: RwLock<HashMap<Vec<u8>, RwLock<Client>>>,
pub groups: RwLock<HashMap<GroupId, Group>>,
pub waiting_for_welcome: RwLock<HashMap<Vec<u8>, Vec<u8>>>,
pub default_mgc: MlsGroupConfig,
pub use_codec: CodecUse,
}
impl MlsGroupTestSetup {
pub fn new(default_mgc: MlsGroupConfig, number_of_clients: usize, use_codec: CodecUse) -> Self {
let mut clients = HashMap::new();
for i in 0..number_of_clients {
let identity = i.to_be_bytes().to_vec();
let crypto = OpenMlsRustCrypto::default();
let mut credentials = HashMap::new();
for ciphersuite in crypto.crypto().supported_ciphersuites().iter() {
let cb = CredentialBundle::new(
identity.clone(),
CredentialType::Basic,
SignatureScheme::from(*ciphersuite),
&crypto,
)
.expect("An unexpected error occurred.");
let credential = cb.credential().clone();
crypto
.key_store()
.store(
&cb.credential()
.signature_key()
.tls_serialize_detached()
.expect("Error serializing signature key."),
&cb,
)
.expect("An unexpected error occurred.");
credentials.insert(*ciphersuite, credential);
}
let client = Client {
identity: identity.clone(),
credentials,
crypto,
groups: RwLock::new(HashMap::new()),
};
clients.insert(identity, RwLock::new(client));
}
let groups = RwLock::new(HashMap::new());
let waiting_for_welcome = RwLock::new(HashMap::new());
MlsGroupTestSetup {
clients: RwLock::new(clients),
groups,
waiting_for_welcome,
default_mgc,
use_codec,
}
}
pub fn get_fresh_key_package(
&self,
client: &Client,
ciphersuite: Ciphersuite,
) -> Result<KeyPackage, SetupError> {
let key_package = client.get_fresh_key_package(&[ciphersuite])?;
self.waiting_for_welcome
.write()
.expect("An unexpected error occurred.")
.insert(
key_package
.hash_ref(client.crypto.crypto())?
.value()
.to_vec(),
client.identity.clone(),
);
Ok(key_package)
}
pub fn key_package_ref_by_index(&self, index: usize, group: &Group) -> Option<KeyPackageRef> {
let (_, id) = group
.members
.iter()
.find(|(leaf_index, _)| index == *leaf_index)
.expect("Couldn't find member at leaf index");
let clients = self.clients.read().expect("An unexpected error occurred.");
let client = clients
.get(id)
.expect("An unexpected error occurred.")
.read()
.expect("An unexpected error occurred.");
client.key_package_ref(&group.group_id)
}
pub fn key_package_ref_by_id(&self, id: &[u8], group: &Group) -> Option<KeyPackageRef> {
let (_, id) = group
.members
.iter()
.find(|(_, leaf_id)| id == leaf_id)
.expect("Couldn't find member at leaf index");
let clients = self.clients.read().expect("An unexpected error occurred.");
let client = clients
.get(id)
.expect("An unexpected error occurred.")
.read()
.expect("An unexpected error occurred.");
client.key_package_ref(&group.group_id)
}
pub fn deliver_welcome(&self, welcome: Welcome, group: &Group) -> Result<(), SetupError> {
let welcome = match self.use_codec {
CodecUse::SerializedMessages => {
let serialized_welcome = welcome
.tls_serialize_detached()
.map_err(ClientError::TlsCodecError)?;
Welcome::tls_deserialize(&mut serialized_welcome.as_slice())
.map_err(ClientError::TlsCodecError)?
}
CodecUse::StructMessages => welcome,
};
if self.use_codec == CodecUse::SerializedMessages {}
let clients = self.clients.read().expect("An unexpected error occurred.");
for egs in welcome.secrets() {
let client_id = self
.waiting_for_welcome
.write()
.expect("An unexpected error occurred.")
.remove(egs.new_member().as_slice())
.ok_or(SetupError::NoFreshKeyPackage)?;
let client = clients
.get(&client_id)
.expect("An unexpected error occurred.")
.read()
.expect("An unexpected error occurred.");
client.join_group(
group.group_config.clone(),
welcome.clone(),
Some(group.public_tree.clone()),
)?;
}
Ok(())
}
pub fn distribute_to_members(
&self,
sender_id: &[u8],
group: &mut Group,
message: &MlsMessageOut,
) -> Result<(), ClientError> {
let message = match self.use_codec {
CodecUse::SerializedMessages => {
let serialized_message =
MlsMessageIn::from(message.clone()).tls_serialize_detached()?;
MlsMessageIn::tls_deserialize(&mut serialized_message.as_slice())?
}
CodecUse::StructMessages => MlsMessageIn::from(message.clone()),
};
let clients = self.clients.read().expect("An unexpected error occurred.");
let results: Result<Vec<_>, _> = group
.members
.par_iter()
.filter_map(|(_index, member_id)| {
if message.content_type() == ContentType::Application && member_id == sender_id {
None
} else {
Some(member_id)
}
})
.map(|member_id| {
let member = clients
.get(member_id)
.expect("An unexpected error occurred.")
.read()
.expect("An unexpected error occurred.");
member.receive_messages_for_group(&message, sender_id)
})
.collect();
results?;
let sender = clients
.get(sender_id)
.expect("An unexpected error occurred.")
.read()
.expect("An unexpected error occurred.");
let sender_groups = sender.groups.read().expect("An unexpected error occurred.");
let sender_group = sender_groups
.get(&group.group_id)
.expect("An unexpected error occurred.");
group.members = sender
.get_members_of_group(&group.group_id)?
.iter()
.map(|(index, cred)| (*index, cred.identity().to_vec()))
.collect();
group.public_tree = sender_group.export_ratchet_tree();
group.exporter_secret = sender_group.export_secret(&sender.crypto, "test", &[], 32)?;
Ok(())
}
pub fn check_group_states(&self, group: &mut Group) {
let clients = self.clients.read().expect("An unexpected error occurred.");
let messages = group
.members
.par_iter()
.filter_map(|(_, m_id)| {
let m = clients
.get(m_id)
.expect("An unexpected error occurred.")
.read()
.expect("An unexpected error occurred.");
let mut group_states = m.groups.write().expect("An unexpected error occurred.");
if let Some(group_state) = group_states.get_mut(&group.group_id) {
assert_eq!(group_state.export_ratchet_tree(), group.public_tree);
assert_eq!(
group_state
.export_secret(&m.crypto, "test", &[], 32)
.expect("An unexpected error occurred."),
group.exporter_secret
);
let message = group_state
.create_message(&m.crypto, "Hello World!".as_bytes())
.expect("Error composing message while checking group states.");
Some((m_id.to_vec(), message))
} else {
None
}
})
.collect::<Vec<(Vec<u8>, MlsMessageOut)>>();
drop(clients);
for (sender_id, message) in messages {
self.distribute_to_members(&sender_id, group, &message)
.expect("Error sending messages to clients while checking group states.");
}
}
pub fn random_new_members_for_group(
&self,
group: &Group,
number_of_members: usize,
) -> Result<Vec<Vec<u8>>, SetupError> {
let clients = self.clients.read().expect("An unexpected error occurred.");
if number_of_members + group.members.len() > clients.len() {
return Err(SetupError::NotEnoughClients);
}
let mut new_member_ids: Vec<Vec<u8>> = Vec::new();
for _ in 0..number_of_members {
let is_in_new_members = |client_id| {
new_member_ids
.iter()
.any(|new_member_id| client_id == new_member_id)
};
let is_in_group = |client_id| {
group
.members
.iter()
.any(|(_, member_id)| client_id == member_id)
};
let new_member_id = clients
.keys()
.find(|&client_id| !is_in_group(client_id) && !is_in_new_members(client_id))
.expect("An unexpected error occurred.");
new_member_ids.push(new_member_id.clone());
}
Ok(new_member_ids)
}
pub fn create_group(&self, ciphersuite: Ciphersuite) -> Result<GroupId, SetupError> {
let clients = self.clients.read().expect("An unexpected error occurred.");
let group_creator_id = ((OsRng.next_u32() as usize) % clients.len())
.to_be_bytes()
.to_vec();
let group_creator = clients
.get(&group_creator_id)
.expect("An unexpected error occurred.")
.read()
.expect("An unexpected error occurred.");
let mut groups = self.groups.write().expect("An unexpected error occurred.");
let group_id = GroupId::from_slice(&groups.len().to_string().into_bytes());
group_creator.create_group(group_id.clone(), self.default_mgc.clone(), ciphersuite)?;
let creator_groups = group_creator
.groups
.read()
.expect("An unexpected error occurred.");
let group = creator_groups
.get(&group_id)
.expect("An unexpected error occurred.");
let public_tree = group.export_ratchet_tree();
let exporter_secret = group.export_secret(&group_creator.crypto, "test", &[], 32)?;
let member_ids = vec![(0, group_creator_id)];
let group = Group {
group_id: group_id.clone(),
members: member_ids,
ciphersuite,
group_config: self.default_mgc.clone(),
public_tree,
exporter_secret,
};
groups.insert(group_id.clone(), group);
Ok(group_id)
}
pub fn create_random_group(
&self,
target_group_size: usize,
ciphersuite: Ciphersuite,
) -> Result<GroupId, SetupError> {
let group_id = self.create_group(ciphersuite)?;
let mut groups = self.groups.write().expect("An unexpected error occurred.");
let group = groups
.get_mut(&group_id)
.expect("An unexpected error occurred.");
let mut new_members = self.random_new_members_for_group(group, target_group_size - 1)?;
while !new_members.is_empty() {
let adder_id = group.random_group_member();
let number_of_adds = ((OsRng.next_u32() as usize) % 5 % new_members.len()) + 1;
let members_to_add = new_members.drain(0..number_of_adds).collect();
self.add_clients(ActionType::Commit, group, &adder_id, members_to_add)?;
}
Ok(group_id)
}
pub fn self_update(
&self,
action_type: ActionType,
group: &mut Group,
client_id: &[u8],
key_package_bundle_option: Option<KeyPackageBundle>,
) -> Result<(), SetupError> {
let clients = self.clients.read().expect("An unexpected error occurred.");
let client = clients
.get(client_id)
.ok_or(SetupError::UnknownClientId)?
.read()
.expect("An unexpected error occurred.");
let (messages, welcome_option) =
client.self_update(action_type, &group.group_id, key_package_bundle_option)?;
self.distribute_to_members(&client.identity, group, &messages)?;
if let Some(welcome) = welcome_option {
self.deliver_welcome(welcome, group)?;
}
Ok(())
}
pub fn add_clients(
&self,
action_type: ActionType,
group: &mut Group,
adder_id: &[u8],
addees: Vec<Vec<u8>>,
) -> Result<(), SetupError> {
let clients = self.clients.read().expect("An unexpected error occurred.");
let adder = clients
.get(adder_id)
.ok_or(SetupError::UnknownClientId)?
.read()
.expect("An unexpected error occurred.");
if group
.members
.iter()
.any(|(_, id)| addees.iter().any(|client_id| client_id == id))
{
return Err(SetupError::ClientAlreadyInGroup);
}
let mut key_packages = Vec::new();
for addee_id in &addees {
let addee = clients
.get(addee_id)
.ok_or(SetupError::UnknownClientId)?
.read()
.expect("An unexpected error occurred.");
let key_package = self.get_fresh_key_package(&addee, group.ciphersuite)?;
key_packages.push(key_package);
}
let (messages, welcome_option) =
adder.add_members(action_type, &group.group_id, &key_packages)?;
for message in &messages {
self.distribute_to_members(adder_id, group, message)?;
}
if let Some(welcome) = welcome_option {
self.deliver_welcome(welcome, group)?;
}
Ok(())
}
pub fn remove_clients(
&self,
action_type: ActionType,
group: &mut Group,
remover_id: &[u8],
target_members: &[hash_ref::KeyPackageRef],
) -> Result<(), SetupError> {
let clients = self.clients.read().expect("An unexpected error occurred.");
let remover = clients
.get(remover_id)
.ok_or(SetupError::UnknownClientId)?
.read()
.expect("An unexpected error occurred.");
let (messages, welcome_option) =
remover.remove_members(action_type, &group.group_id, target_members)?;
for message in &messages {
self.distribute_to_members(remover_id, group, message)?;
}
if let Some(welcome) = welcome_option {
self.deliver_welcome(welcome, group)?;
}
Ok(())
}
pub fn perform_random_operation(&self, group: &mut Group) -> Result<(), SetupError> {
let member_id = group.random_group_member();
println!("Member performing the operation: {:?}", member_id);
let action_type = match (OsRng.next_u32() as usize) % 2 {
0 => ActionType::Proposal,
1 => ActionType::Commit,
_ => return Err(SetupError::Unknown),
};
let operation_type = (OsRng.next_u32() as usize) % 3;
match operation_type {
0 => {
println!(
"Perfoming a self-update with action type: {:?}",
action_type
);
self.self_update(action_type, group, &member_id, None)?;
}
1 => {
if group.members.len() > 1 {
let number_of_removals =
(((OsRng.next_u32() as usize) % group.members.len()) % 5) + 1;
let (own_index, _) = group
.members
.iter()
.find(|(_, identity)| identity == &member_id)
.expect("An unexpected error occurred.")
.clone();
println!(
"Index of the member performing the {:?}: {:?}",
action_type, own_index
);
let mut target_member_ids = Vec::new();
let mut target_member_identities = Vec::new();
let clients = self.clients.read().expect("An unexpected error occurred.");
println!("Removing members:");
for _ in 0..number_of_removals {
let mut member_list_index =
(OsRng.next_u32() as usize) % group.members.len();
let (mut leaf_index, mut identity) =
group.members[member_list_index].clone();
while leaf_index == own_index
|| target_member_identities.contains(&identity)
{
member_list_index = (OsRng.next_u32() as usize) % group.members.len();
let (new_leaf_index, new_identity) =
group.members[member_list_index].clone();
leaf_index = new_leaf_index;
identity = new_identity;
}
let client = clients
.get(&identity)
.expect("An unexpected error occurred.")
.read()
.expect("An unexpected error occurred.");
let client_group =
client.groups.read().expect("An unexpected error occurred.");
let client_group = client_group
.get(&group.group_id)
.expect("An unexpected error occurred.");
target_member_ids.push(
*client_group
.key_package_ref()
.expect("An unexpected error occurred."),
);
target_member_identities.push(identity);
}
self.remove_clients(action_type, group, &member_id, &target_member_ids)?
};
}
2 => {
let clients_left = self
.clients
.read()
.expect("An unexpected error occurred.")
.len()
- group.members.len();
if clients_left > 0 {
let number_of_adds = (((OsRng.next_u32() as usize) % clients_left) % 5) + 1;
let new_member_ids = self
.random_new_members_for_group(group, number_of_adds)
.expect("An unexpected error occurred.");
println!(
"{:?}: Adding new clients: {:?}",
action_type, new_member_ids
);
self.add_clients(action_type, group, &member_id, new_member_ids)?;
}
}
_ => return Err(SetupError::Unknown),
};
Ok(())
}
}