use openmls_rust_crypto::OpenMlsRustCrypto;
use crate::{
ciphersuite::Secret, test_utils::*, tree::secret_tree::SecretTreeError,
tree::sender_ratchet::*, versions::ProtocolVersion,
};
#[apply(ciphersuites_and_backends)]
fn test_max_forward_distance(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoProvider) {
let configuration = &SenderRatchetConfiguration::default();
let secret = Secret::random(ciphersuite, backend, ProtocolVersion::Mls10)
.expect("Not enough randomness.");
let mut ratchet1 = DecryptionRatchet::new(secret.clone());
let mut ratchet2 = DecryptionRatchet::new(secret);
let _secret = ratchet1
.secret_for_decryption(
ciphersuite,
backend,
configuration.maximum_forward_distance(),
configuration,
)
.expect("Expected decryption secret.");
let err = ratchet2
.secret_for_decryption(
ciphersuite,
backend,
configuration.maximum_forward_distance() + 1,
configuration,
)
.expect_err("Expected error.");
assert_eq!(err, SecretTreeError::TooDistantInTheFuture);
ratchet1.ratchet_secret_mut().set_generation(u32::MAX - 5);
ratchet1
.secret_for_decryption(ciphersuite, backend, u32::MAX - 1, configuration)
.expect("Error ratcheting to very high generation");
}
#[apply(ciphersuites_and_backends)]
fn test_out_of_order_generations(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoProvider) {
let configuration = &SenderRatchetConfiguration::default();
let secret = Secret::random(ciphersuite, backend, ProtocolVersion::Mls10)
.expect("Not enough randomness.");
let mut ratchet1 = DecryptionRatchet::new(secret);
for i in 0..configuration.out_of_order_tolerance() * 2 {
let _secret = ratchet1
.secret_for_decryption(ciphersuite, backend, i, configuration)
.expect("Expected decryption secret.");
}
let err = ratchet1
.secret_for_decryption(
ciphersuite,
backend,
configuration.out_of_order_tolerance() - 1,
configuration,
)
.expect_err("Expected error.");
assert_eq!(err, SecretTreeError::TooDistantInThePast);
for i in configuration.out_of_order_tolerance()..configuration.out_of_order_tolerance() * 2 {
assert_eq!(
ratchet1
.secret_for_decryption(ciphersuite, backend, i, configuration)
.expect_err("Expected decryption secret."),
SecretTreeError::SecretReuseError
);
}
}
#[apply(ciphersuites_and_backends)]
fn test_forward_secrecy(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoProvider) {
let configuration = &SenderRatchetConfiguration::default();
let secret = Secret::random(ciphersuite, backend, ProtocolVersion::Mls10)
.expect("Not enough randomness.");
let mut ratchet = DecryptionRatchet::new(secret);
let _ratchet_secrets = ratchet
.secret_for_decryption(ciphersuite, backend, 0, configuration)
.expect("Error ratcheting forward.");
assert_eq!(ratchet.generation(), 1);
let err = ratchet
.secret_for_decryption(ciphersuite, backend, 0, configuration)
.expect_err("No error when trying to retrieve key outside of tolerance window.");
assert_eq!(err, SecretTreeError::SecretReuseError);
let _ratchet_secrets = ratchet
.secret_for_decryption(ciphersuite, backend, 10, configuration)
.expect("Error ratcheting forward.");
let err = ratchet
.secret_for_decryption(ciphersuite, backend, 5, configuration)
.expect_err("No error when trying to retrieve key outside of tolerance window.");
assert_eq!(err, SecretTreeError::TooDistantInThePast);
for generation in 10 - configuration.out_of_order_tolerance() + 1..10 {
let keys = ratchet.secret_for_decryption(ciphersuite, backend, generation, configuration);
assert!(keys.is_ok());
let err = ratchet
.secret_for_decryption(ciphersuite, backend, generation, configuration)
.expect_err("No error when trying to retrieve deleted key.");
assert_eq!(err, SecretTreeError::SecretReuseError);
}
}
#[test]
fn sender_ratchet_generation_overflow() {
let backend = OpenMlsRustCrypto::default();
let ciphersuite = Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519;
let secret = Secret::random(ciphersuite, &backend, ProtocolVersion::Mls10)
.expect("Not enough randomness.");
let mut ratchet = RatchetSecret::initial_ratchet_secret(secret);
ratchet.set_generation(u32::MAX - 1);
let _ = ratchet
.ratchet_forward(&backend, ciphersuite)
.expect("error ratcheting forward");
let err = ratchet
.ratchet_forward(&backend, ciphersuite)
.expect_err("no error exceeding generation u32::MAX");
assert_eq!(err, SecretTreeError::RatchetTooLong)
}