1006 lines
30 KiB
Rust
1006 lines
30 KiB
Rust
|
//
|
||
|
// Copyright 2020-2021 Signal Messenger, LLC.
|
||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||
|
//
|
||
|
|
||
|
mod support;
|
||
|
use support::*;
|
||
|
|
||
|
use futures_util::FutureExt;
|
||
|
use libsignal_protocol::*;
|
||
|
use rand::rngs::OsRng;
|
||
|
use std::convert::TryFrom;
|
||
|
use uuid::Uuid;
|
||
|
|
||
|
#[test]
|
||
|
fn test_server_cert() -> Result<(), SignalProtocolError> {
|
||
|
let mut rng = OsRng;
|
||
|
let trust_root = KeyPair::generate(&mut rng);
|
||
|
let server_key = KeyPair::generate(&mut rng);
|
||
|
|
||
|
let server_cert =
|
||
|
ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng)?;
|
||
|
|
||
|
let serialized = server_cert.serialized()?.to_vec();
|
||
|
|
||
|
let recovered = ServerCertificate::deserialize(&serialized)?;
|
||
|
|
||
|
assert!(recovered.validate(&trust_root.public_key)?);
|
||
|
|
||
|
let mut cert_data = serialized;
|
||
|
let cert_bits = cert_data.len() * 8;
|
||
|
|
||
|
for b in 0..cert_bits {
|
||
|
cert_data[b / 8] ^= 1u8 << (b % 8); // flip a bit
|
||
|
let cert = ServerCertificate::deserialize(&cert_data);
|
||
|
cert_data[b / 8] ^= 1u8 << (b % 8); // flip the bit back
|
||
|
|
||
|
match cert {
|
||
|
Ok(cert) => {
|
||
|
assert!(!cert.validate(&trust_root.public_key)?);
|
||
|
}
|
||
|
Err(e) => match e {
|
||
|
SignalProtocolError::InvalidProtobufEncoding
|
||
|
| SignalProtocolError::ProtobufDecodingError(_)
|
||
|
| SignalProtocolError::BadKeyType(_)
|
||
|
| SignalProtocolError::BadKeyLength(_, _) => {}
|
||
|
|
||
|
unexpected_err => {
|
||
|
panic!("unexpected error {:?}", unexpected_err)
|
||
|
}
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_revoked_server_cert() -> Result<(), SignalProtocolError> {
|
||
|
let mut rng = OsRng;
|
||
|
let trust_root = KeyPair::generate(&mut rng);
|
||
|
let server_key = KeyPair::generate(&mut rng);
|
||
|
|
||
|
let revoked_id = 0xDEADC357;
|
||
|
|
||
|
let server_cert = ServerCertificate::new(
|
||
|
revoked_id,
|
||
|
server_key.public_key,
|
||
|
&trust_root.private_key,
|
||
|
&mut rng,
|
||
|
)?;
|
||
|
|
||
|
let serialized = server_cert.serialized()?.to_vec();
|
||
|
|
||
|
let recovered = ServerCertificate::deserialize(&serialized)?;
|
||
|
|
||
|
assert!(!recovered.validate(&trust_root.public_key)?);
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_sender_cert() -> Result<(), SignalProtocolError> {
|
||
|
let mut rng = OsRng;
|
||
|
let trust_root = KeyPair::generate(&mut rng);
|
||
|
let server_key = KeyPair::generate(&mut rng);
|
||
|
let key = KeyPair::generate(&mut rng);
|
||
|
|
||
|
let server_cert =
|
||
|
ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng)?;
|
||
|
|
||
|
let device_id = 42;
|
||
|
let expires = 1605722925;
|
||
|
|
||
|
let sender_cert = SenderCertificate::new(
|
||
|
"9d0652a3-dcc3-4d11-975f-74d61598733f".to_string(),
|
||
|
Some("+14152222222".to_string()),
|
||
|
key.public_key,
|
||
|
device_id,
|
||
|
expires,
|
||
|
server_cert,
|
||
|
&server_key.private_key,
|
||
|
&mut rng,
|
||
|
)?;
|
||
|
|
||
|
assert!(sender_cert.validate(&trust_root.public_key, expires)?);
|
||
|
assert!(!sender_cert.validate(&trust_root.public_key, expires + 1)?); // expired
|
||
|
|
||
|
let mut sender_cert_data = sender_cert.serialized()?.to_vec();
|
||
|
let sender_cert_bits = sender_cert_data.len() * 8;
|
||
|
|
||
|
for b in 0..sender_cert_bits {
|
||
|
sender_cert_data[b / 8] ^= 1u8 << (b % 8); // flip a bit
|
||
|
let cert = SenderCertificate::deserialize(&sender_cert_data);
|
||
|
sender_cert_data[b / 8] ^= 1u8 << (b % 8); // flip the bit back
|
||
|
|
||
|
match cert {
|
||
|
Ok(cert) => {
|
||
|
assert!(!cert.validate(&trust_root.public_key, expires)?);
|
||
|
}
|
||
|
Err(e) => match e {
|
||
|
SignalProtocolError::InvalidProtobufEncoding
|
||
|
| SignalProtocolError::ProtobufDecodingError(_)
|
||
|
| SignalProtocolError::BadKeyLength(_, _)
|
||
|
| SignalProtocolError::BadKeyType(_) => {}
|
||
|
|
||
|
unexpected_err => {
|
||
|
panic!("unexpected error {:?}", unexpected_err)
|
||
|
}
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_sealed_sender() -> Result<(), SignalProtocolError> {
|
||
|
async {
|
||
|
let mut rng = OsRng;
|
||
|
|
||
|
let alice_device_id = 23;
|
||
|
let bob_device_id = 42;
|
||
|
|
||
|
let alice_e164 = "+14151111111".to_owned();
|
||
|
let bob_e164 = "+14151114444".to_owned();
|
||
|
|
||
|
let alice_uuid = "9d0652a3-dcc3-4d11-975f-74d61598733f".to_string();
|
||
|
let bob_uuid = "796abedb-ca4e-4f18-8803-1fde5b921f9f".to_string();
|
||
|
|
||
|
let bob_uuid_address = ProtocolAddress::new(bob_uuid.clone(), bob_device_id);
|
||
|
|
||
|
let mut alice_store = support::test_in_memory_protocol_store()?;
|
||
|
let mut bob_store = support::test_in_memory_protocol_store()?;
|
||
|
|
||
|
let alice_pubkey = *alice_store.get_identity_key_pair(None).await?.public_key();
|
||
|
|
||
|
let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut rng).await?;
|
||
|
|
||
|
process_prekey_bundle(
|
||
|
&bob_uuid_address,
|
||
|
&mut alice_store.session_store,
|
||
|
&mut alice_store.identity_store,
|
||
|
&bob_pre_key_bundle,
|
||
|
&mut rng,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let trust_root = KeyPair::generate(&mut rng);
|
||
|
let server_key = KeyPair::generate(&mut rng);
|
||
|
|
||
|
let server_cert =
|
||
|
ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng)?;
|
||
|
|
||
|
let expires = 1605722925;
|
||
|
|
||
|
let sender_cert = SenderCertificate::new(
|
||
|
alice_uuid.clone(),
|
||
|
Some(alice_e164.clone()),
|
||
|
alice_pubkey,
|
||
|
alice_device_id,
|
||
|
expires,
|
||
|
server_cert,
|
||
|
&server_key.private_key,
|
||
|
&mut rng,
|
||
|
)?;
|
||
|
|
||
|
let alice_ptext = vec![1, 2, 3, 23, 99];
|
||
|
let alice_ctext = sealed_sender_encrypt(
|
||
|
&bob_uuid_address,
|
||
|
&sender_cert,
|
||
|
&alice_ptext,
|
||
|
&mut alice_store.session_store,
|
||
|
&mut alice_store.identity_store,
|
||
|
None,
|
||
|
&mut rng,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let bob_ptext = sealed_sender_decrypt(
|
||
|
&alice_ctext,
|
||
|
&trust_root.public_key,
|
||
|
expires - 1,
|
||
|
Some(bob_e164.clone()),
|
||
|
bob_uuid.clone(),
|
||
|
bob_device_id,
|
||
|
&mut bob_store.identity_store,
|
||
|
&mut bob_store.session_store,
|
||
|
&mut bob_store.pre_key_store,
|
||
|
&mut bob_store.signed_pre_key_store,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
assert_eq!(bob_ptext.message, alice_ptext);
|
||
|
assert_eq!(bob_ptext.sender_uuid, alice_uuid);
|
||
|
assert_eq!(bob_ptext.sender_e164, Some(alice_e164));
|
||
|
assert_eq!(bob_ptext.device_id, alice_device_id);
|
||
|
|
||
|
// Now test but with an expired cert:
|
||
|
|
||
|
let alice_ctext = sealed_sender_encrypt(
|
||
|
&bob_uuid_address,
|
||
|
&sender_cert,
|
||
|
&alice_ptext,
|
||
|
&mut alice_store.session_store,
|
||
|
&mut alice_store.identity_store,
|
||
|
None,
|
||
|
&mut rng,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let bob_ptext = sealed_sender_decrypt(
|
||
|
&alice_ctext,
|
||
|
&trust_root.public_key,
|
||
|
expires + 11,
|
||
|
Some(bob_e164.clone()),
|
||
|
bob_uuid.clone(),
|
||
|
bob_device_id,
|
||
|
&mut bob_store.identity_store,
|
||
|
&mut bob_store.session_store,
|
||
|
&mut bob_store.pre_key_store,
|
||
|
&mut bob_store.signed_pre_key_store,
|
||
|
None,
|
||
|
)
|
||
|
.await;
|
||
|
|
||
|
match bob_ptext {
|
||
|
Err(SignalProtocolError::InvalidSealedSenderMessage(_)) => { /* ok */ }
|
||
|
Err(err) => {
|
||
|
panic!("Unexpected error {}", err)
|
||
|
}
|
||
|
Ok(_) => {
|
||
|
panic!("Shouldn't have decrypted")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Now test but try to verify using some other trust root
|
||
|
|
||
|
let alice_ctext = sealed_sender_encrypt(
|
||
|
&bob_uuid_address,
|
||
|
&sender_cert,
|
||
|
&alice_ptext,
|
||
|
&mut alice_store.session_store,
|
||
|
&mut alice_store.identity_store,
|
||
|
None,
|
||
|
&mut rng,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let wrong_trust_root = KeyPair::generate(&mut rng);
|
||
|
|
||
|
let bob_ptext = sealed_sender_decrypt(
|
||
|
&alice_ctext,
|
||
|
&wrong_trust_root.public_key,
|
||
|
expires - 1,
|
||
|
Some(bob_e164.clone()),
|
||
|
bob_uuid.clone(),
|
||
|
bob_device_id,
|
||
|
&mut bob_store.identity_store,
|
||
|
&mut bob_store.session_store,
|
||
|
&mut bob_store.pre_key_store,
|
||
|
&mut bob_store.signed_pre_key_store,
|
||
|
None,
|
||
|
)
|
||
|
.await;
|
||
|
|
||
|
match bob_ptext {
|
||
|
Err(SignalProtocolError::InvalidSealedSenderMessage(_)) => { /* ok */ }
|
||
|
Err(err) => {
|
||
|
panic!("Unexpected error {}", err)
|
||
|
}
|
||
|
Ok(_) => {
|
||
|
panic!("Shouldn't have decrypted")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
.now_or_never()
|
||
|
.expect("sync")
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_sender_key_in_sealed_sender() -> Result<(), SignalProtocolError> {
|
||
|
async {
|
||
|
let mut rng = OsRng;
|
||
|
|
||
|
let alice_device_id = 23;
|
||
|
let bob_device_id = 42;
|
||
|
|
||
|
let alice_e164 = "+14151111111".to_owned();
|
||
|
|
||
|
let alice_uuid = "9d0652a3-dcc3-4d11-975f-74d61598733f".to_string();
|
||
|
let bob_uuid = "796abedb-ca4e-4f18-8803-1fde5b921f9f".to_string();
|
||
|
|
||
|
let distribution_id = Uuid::from_u128(0xd1d1d1d1_7000_11eb_b32a_33b8a8a487a6);
|
||
|
|
||
|
let alice_uuid_address = ProtocolAddress::new(alice_uuid.clone(), 1);
|
||
|
let bob_uuid_address = ProtocolAddress::new(bob_uuid.clone(), bob_device_id);
|
||
|
|
||
|
let mut alice_store = support::test_in_memory_protocol_store()?;
|
||
|
let mut bob_store = support::test_in_memory_protocol_store()?;
|
||
|
|
||
|
let alice_pubkey = *alice_store.get_identity_key_pair(None).await?.public_key();
|
||
|
|
||
|
let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut rng).await?;
|
||
|
|
||
|
process_prekey_bundle(
|
||
|
&bob_uuid_address,
|
||
|
&mut alice_store.session_store,
|
||
|
&mut alice_store.identity_store,
|
||
|
&bob_pre_key_bundle,
|
||
|
&mut rng,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let trust_root = KeyPair::generate(&mut rng);
|
||
|
let server_key = KeyPair::generate(&mut rng);
|
||
|
|
||
|
let server_cert =
|
||
|
ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng)?;
|
||
|
|
||
|
let expires = 1605722925;
|
||
|
|
||
|
let sender_cert = SenderCertificate::new(
|
||
|
alice_uuid.clone(),
|
||
|
Some(alice_e164.clone()),
|
||
|
alice_pubkey,
|
||
|
alice_device_id,
|
||
|
expires,
|
||
|
server_cert,
|
||
|
&server_key.private_key,
|
||
|
&mut rng,
|
||
|
)?;
|
||
|
|
||
|
let distribution_message = create_sender_key_distribution_message(
|
||
|
&alice_uuid_address,
|
||
|
distribution_id,
|
||
|
&mut alice_store,
|
||
|
&mut rng,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
process_sender_key_distribution_message(
|
||
|
&alice_uuid_address,
|
||
|
&distribution_message,
|
||
|
&mut bob_store,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let alice_message = group_encrypt(
|
||
|
&mut alice_store,
|
||
|
&alice_uuid_address,
|
||
|
distribution_id,
|
||
|
"swim camp".as_bytes(),
|
||
|
&mut rng,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
let alice_usmc = UnidentifiedSenderMessageContent::new(
|
||
|
CiphertextMessageType::SenderKey,
|
||
|
sender_cert.clone(),
|
||
|
alice_message.serialized().to_vec(),
|
||
|
ContentHint::Default,
|
||
|
None,
|
||
|
)?;
|
||
|
|
||
|
let alice_ctext = sealed_sender_encrypt_from_usmc(
|
||
|
&bob_uuid_address,
|
||
|
&alice_usmc,
|
||
|
&mut alice_store.identity_store,
|
||
|
None,
|
||
|
&mut rng,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let bob_usmc =
|
||
|
sealed_sender_decrypt_to_usmc(&alice_ctext, &mut bob_store.identity_store, None)
|
||
|
.await?;
|
||
|
|
||
|
assert!(matches!(
|
||
|
bob_usmc.msg_type()?,
|
||
|
CiphertextMessageType::SenderKey,
|
||
|
));
|
||
|
|
||
|
let bob_plaintext = group_decrypt(
|
||
|
bob_usmc.contents()?,
|
||
|
&mut bob_store,
|
||
|
&alice_uuid_address,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
assert_eq!(
|
||
|
String::from_utf8(bob_plaintext).expect("valid UTF-8"),
|
||
|
"swim camp"
|
||
|
);
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
.now_or_never()
|
||
|
.expect("sync")
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_sealed_sender_multi_recipient() -> Result<(), SignalProtocolError> {
|
||
|
async {
|
||
|
let mut rng = OsRng;
|
||
|
|
||
|
let alice_device_id = 23;
|
||
|
let bob_device_id = 42;
|
||
|
|
||
|
let alice_e164 = "+14151111111".to_owned();
|
||
|
let bob_e164 = "+14151114444".to_owned();
|
||
|
|
||
|
let alice_uuid = "9d0652a3-dcc3-4d11-975f-74d61598733f".to_string();
|
||
|
let bob_uuid = "796abedb-ca4e-4f18-8803-1fde5b921f9f".to_string();
|
||
|
|
||
|
let bob_uuid_address = ProtocolAddress::new(bob_uuid.clone(), bob_device_id);
|
||
|
|
||
|
let mut alice_store = support::test_in_memory_protocol_store()?;
|
||
|
let mut bob_store = support::test_in_memory_protocol_store()?;
|
||
|
|
||
|
let alice_pubkey = *alice_store.get_identity_key_pair(None).await?.public_key();
|
||
|
|
||
|
let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut rng).await?;
|
||
|
|
||
|
process_prekey_bundle(
|
||
|
&bob_uuid_address,
|
||
|
&mut alice_store.session_store,
|
||
|
&mut alice_store.identity_store,
|
||
|
&bob_pre_key_bundle,
|
||
|
&mut rng,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let trust_root = KeyPair::generate(&mut rng);
|
||
|
let server_key = KeyPair::generate(&mut rng);
|
||
|
|
||
|
let server_cert =
|
||
|
ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng)?;
|
||
|
|
||
|
let expires = 1605722925;
|
||
|
|
||
|
let sender_cert = SenderCertificate::new(
|
||
|
alice_uuid.clone(),
|
||
|
Some(alice_e164.clone()),
|
||
|
alice_pubkey,
|
||
|
alice_device_id,
|
||
|
expires,
|
||
|
server_cert,
|
||
|
&server_key.private_key,
|
||
|
&mut rng,
|
||
|
)?;
|
||
|
|
||
|
let alice_ptext = vec![1, 2, 3, 23, 99];
|
||
|
let alice_message = message_encrypt(
|
||
|
&alice_ptext,
|
||
|
&bob_uuid_address,
|
||
|
&mut alice_store.session_store,
|
||
|
&mut alice_store.identity_store,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let alice_usmc = UnidentifiedSenderMessageContent::new(
|
||
|
alice_message.message_type(),
|
||
|
sender_cert.clone(),
|
||
|
alice_message.serialize().to_vec(),
|
||
|
ContentHint::Default,
|
||
|
None,
|
||
|
)?;
|
||
|
|
||
|
let recipients = [&bob_uuid_address];
|
||
|
let alice_ctext = sealed_sender_multi_recipient_encrypt(
|
||
|
&recipients,
|
||
|
&alice_store
|
||
|
.session_store
|
||
|
.load_existing_sessions(&recipients)?,
|
||
|
&alice_usmc,
|
||
|
&mut alice_store.identity_store,
|
||
|
None,
|
||
|
&mut rng,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let [bob_ctext] = <[_; 1]>::try_from(sealed_sender_multi_recipient_fan_out(&alice_ctext)?)
|
||
|
.expect("only one recipient");
|
||
|
|
||
|
let bob_ptext = sealed_sender_decrypt(
|
||
|
&bob_ctext,
|
||
|
&trust_root.public_key,
|
||
|
expires - 1,
|
||
|
Some(bob_e164.clone()),
|
||
|
bob_uuid.clone(),
|
||
|
bob_device_id,
|
||
|
&mut bob_store.identity_store,
|
||
|
&mut bob_store.session_store,
|
||
|
&mut bob_store.pre_key_store,
|
||
|
&mut bob_store.signed_pre_key_store,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
assert_eq!(bob_ptext.message, alice_ptext);
|
||
|
assert_eq!(bob_ptext.sender_uuid, alice_uuid);
|
||
|
assert_eq!(bob_ptext.sender_e164, Some(alice_e164));
|
||
|
assert_eq!(bob_ptext.device_id, alice_device_id);
|
||
|
|
||
|
// Now test but with an expired cert:
|
||
|
let alice_message = message_encrypt(
|
||
|
&alice_ptext,
|
||
|
&bob_uuid_address,
|
||
|
&mut alice_store.session_store,
|
||
|
&mut alice_store.identity_store,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let alice_usmc = UnidentifiedSenderMessageContent::new(
|
||
|
alice_message.message_type(),
|
||
|
sender_cert.clone(),
|
||
|
alice_message.serialize().to_vec(),
|
||
|
ContentHint::Default,
|
||
|
None,
|
||
|
)?;
|
||
|
|
||
|
let recipients = [&bob_uuid_address];
|
||
|
let alice_ctext = sealed_sender_multi_recipient_encrypt(
|
||
|
&recipients,
|
||
|
&alice_store
|
||
|
.session_store
|
||
|
.load_existing_sessions(&recipients)?,
|
||
|
&alice_usmc,
|
||
|
&mut alice_store.identity_store,
|
||
|
None,
|
||
|
&mut rng,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let [bob_ctext] = <[_; 1]>::try_from(sealed_sender_multi_recipient_fan_out(&alice_ctext)?)
|
||
|
.expect("only one recipient");
|
||
|
|
||
|
let bob_ptext = sealed_sender_decrypt(
|
||
|
&bob_ctext,
|
||
|
&trust_root.public_key,
|
||
|
expires + 11,
|
||
|
Some(bob_e164.clone()),
|
||
|
bob_uuid.clone(),
|
||
|
bob_device_id,
|
||
|
&mut bob_store.identity_store,
|
||
|
&mut bob_store.session_store,
|
||
|
&mut bob_store.pre_key_store,
|
||
|
&mut bob_store.signed_pre_key_store,
|
||
|
None,
|
||
|
)
|
||
|
.await;
|
||
|
|
||
|
match bob_ptext {
|
||
|
Err(SignalProtocolError::InvalidSealedSenderMessage(_)) => { /* ok */ }
|
||
|
Err(err) => {
|
||
|
panic!("Unexpected error {}", err)
|
||
|
}
|
||
|
Ok(_) => {
|
||
|
panic!("Shouldn't have decrypted")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Now test but try to verify using some other trust root
|
||
|
|
||
|
let alice_message = message_encrypt(
|
||
|
&alice_ptext,
|
||
|
&bob_uuid_address,
|
||
|
&mut alice_store.session_store,
|
||
|
&mut alice_store.identity_store,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let alice_usmc = UnidentifiedSenderMessageContent::new(
|
||
|
alice_message.message_type(),
|
||
|
sender_cert.clone(),
|
||
|
alice_message.serialize().to_vec(),
|
||
|
ContentHint::Default,
|
||
|
None,
|
||
|
)?;
|
||
|
|
||
|
let recipients = [&bob_uuid_address];
|
||
|
let alice_ctext = sealed_sender_multi_recipient_encrypt(
|
||
|
&recipients,
|
||
|
&alice_store
|
||
|
.session_store
|
||
|
.load_existing_sessions(&recipients)?,
|
||
|
&alice_usmc,
|
||
|
&mut alice_store.identity_store,
|
||
|
None,
|
||
|
&mut rng,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let wrong_trust_root = KeyPair::generate(&mut rng);
|
||
|
|
||
|
let [bob_ctext] = <[_; 1]>::try_from(sealed_sender_multi_recipient_fan_out(&alice_ctext)?)
|
||
|
.expect("only one recipient");
|
||
|
|
||
|
let bob_ptext = sealed_sender_decrypt(
|
||
|
&bob_ctext,
|
||
|
&wrong_trust_root.public_key,
|
||
|
expires - 1,
|
||
|
Some(bob_e164.clone()),
|
||
|
bob_uuid.clone(),
|
||
|
bob_device_id,
|
||
|
&mut bob_store.identity_store,
|
||
|
&mut bob_store.session_store,
|
||
|
&mut bob_store.pre_key_store,
|
||
|
&mut bob_store.signed_pre_key_store,
|
||
|
None,
|
||
|
)
|
||
|
.await;
|
||
|
|
||
|
match bob_ptext {
|
||
|
Err(SignalProtocolError::InvalidSealedSenderMessage(_)) => { /* ok */ }
|
||
|
Err(err) => {
|
||
|
panic!("Unexpected error {}", err)
|
||
|
}
|
||
|
Ok(_) => {
|
||
|
panic!("Shouldn't have decrypted")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
.now_or_never()
|
||
|
.expect("sync")
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_sealed_sender_multi_recipient_encrypt_with_archived_session(
|
||
|
) -> Result<(), SignalProtocolError> {
|
||
|
async {
|
||
|
let mut rng = OsRng;
|
||
|
|
||
|
let alice_device_id = 23;
|
||
|
let bob_device_id = 42;
|
||
|
|
||
|
let alice_e164 = "+14151111111".to_owned();
|
||
|
|
||
|
let alice_uuid = "9d0652a3-dcc3-4d11-975f-74d61598733f".to_string();
|
||
|
let bob_uuid = "796abedb-ca4e-4f18-8803-1fde5b921f9f".to_string();
|
||
|
|
||
|
let bob_uuid_address = ProtocolAddress::new(bob_uuid.clone(), bob_device_id);
|
||
|
|
||
|
let mut alice_store = support::test_in_memory_protocol_store()?;
|
||
|
let mut bob_store = support::test_in_memory_protocol_store()?;
|
||
|
|
||
|
let alice_pubkey = *alice_store.get_identity_key_pair(None).await?.public_key();
|
||
|
|
||
|
let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut rng).await?;
|
||
|
|
||
|
process_prekey_bundle(
|
||
|
&bob_uuid_address,
|
||
|
&mut alice_store.session_store,
|
||
|
&mut alice_store.identity_store,
|
||
|
&bob_pre_key_bundle,
|
||
|
&mut rng,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let trust_root = KeyPair::generate(&mut rng);
|
||
|
let server_key = KeyPair::generate(&mut rng);
|
||
|
|
||
|
let server_cert =
|
||
|
ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng)?;
|
||
|
|
||
|
let expires = 1605722925;
|
||
|
|
||
|
let sender_cert = SenderCertificate::new(
|
||
|
alice_uuid.clone(),
|
||
|
Some(alice_e164.clone()),
|
||
|
alice_pubkey,
|
||
|
alice_device_id,
|
||
|
expires,
|
||
|
server_cert,
|
||
|
&server_key.private_key,
|
||
|
&mut rng,
|
||
|
)?;
|
||
|
|
||
|
let alice_ptext = vec![1, 2, 3, 23, 99];
|
||
|
let alice_message = message_encrypt(
|
||
|
&alice_ptext,
|
||
|
&bob_uuid_address,
|
||
|
&mut alice_store.session_store,
|
||
|
&mut alice_store.identity_store,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let alice_usmc = UnidentifiedSenderMessageContent::new(
|
||
|
alice_message.message_type(),
|
||
|
sender_cert.clone(),
|
||
|
alice_message.serialize().to_vec(),
|
||
|
ContentHint::Default,
|
||
|
None,
|
||
|
)?;
|
||
|
|
||
|
let recipients = [&bob_uuid_address];
|
||
|
let mut session = alice_store
|
||
|
.session_store
|
||
|
.load_session(&bob_uuid_address, None)
|
||
|
.await?
|
||
|
.expect("present");
|
||
|
session.archive_current_state()?;
|
||
|
match sealed_sender_multi_recipient_encrypt(
|
||
|
&recipients,
|
||
|
&[&session],
|
||
|
&alice_usmc,
|
||
|
&mut alice_store.identity_store,
|
||
|
None,
|
||
|
&mut rng,
|
||
|
)
|
||
|
.await
|
||
|
{
|
||
|
Ok(_) => panic!("should have failed"),
|
||
|
Err(e) => {
|
||
|
// Make sure we mention *which* recipient's session failed.
|
||
|
let description = e.to_string();
|
||
|
assert!(
|
||
|
description.contains(&bob_uuid_address.to_string()),
|
||
|
"should mention recipient in message \"{}\"",
|
||
|
description
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
.now_or_never()
|
||
|
.expect("sync")
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_sealed_sender_multi_recipient_encrypt_with_bad_registration_id(
|
||
|
) -> Result<(), SignalProtocolError> {
|
||
|
async {
|
||
|
let mut rng = OsRng;
|
||
|
|
||
|
let alice_device_id = 23;
|
||
|
let bob_device_id = 42;
|
||
|
|
||
|
let alice_e164 = "+14151111111".to_owned();
|
||
|
|
||
|
let alice_uuid = "9d0652a3-dcc3-4d11-975f-74d61598733f".to_string();
|
||
|
let bob_uuid = "796abedb-ca4e-4f18-8803-1fde5b921f9f".to_string();
|
||
|
|
||
|
let bob_uuid_address = ProtocolAddress::new(bob_uuid.clone(), bob_device_id);
|
||
|
|
||
|
let mut alice_store = support::test_in_memory_protocol_store()?;
|
||
|
let mut bob_store =
|
||
|
InMemSignalProtocolStore::new(IdentityKeyPair::generate(&mut rng), 0x4000)?;
|
||
|
|
||
|
let alice_pubkey = *alice_store.get_identity_key_pair(None).await?.public_key();
|
||
|
|
||
|
let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut rng).await?;
|
||
|
|
||
|
process_prekey_bundle(
|
||
|
&bob_uuid_address,
|
||
|
&mut alice_store.session_store,
|
||
|
&mut alice_store.identity_store,
|
||
|
&bob_pre_key_bundle,
|
||
|
&mut rng,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let trust_root = KeyPair::generate(&mut rng);
|
||
|
let server_key = KeyPair::generate(&mut rng);
|
||
|
|
||
|
let server_cert =
|
||
|
ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng)?;
|
||
|
|
||
|
let expires = 1605722925;
|
||
|
|
||
|
let sender_cert = SenderCertificate::new(
|
||
|
alice_uuid.clone(),
|
||
|
Some(alice_e164.clone()),
|
||
|
alice_pubkey,
|
||
|
alice_device_id,
|
||
|
expires,
|
||
|
server_cert,
|
||
|
&server_key.private_key,
|
||
|
&mut rng,
|
||
|
)?;
|
||
|
|
||
|
let alice_ptext = vec![1, 2, 3, 23, 99];
|
||
|
let alice_message = message_encrypt(
|
||
|
&alice_ptext,
|
||
|
&bob_uuid_address,
|
||
|
&mut alice_store.session_store,
|
||
|
&mut alice_store.identity_store,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let alice_usmc = UnidentifiedSenderMessageContent::new(
|
||
|
alice_message.message_type(),
|
||
|
sender_cert.clone(),
|
||
|
alice_message.serialize().to_vec(),
|
||
|
ContentHint::Default,
|
||
|
None,
|
||
|
)?;
|
||
|
|
||
|
let recipients = [&bob_uuid_address];
|
||
|
match sealed_sender_multi_recipient_encrypt(
|
||
|
&recipients,
|
||
|
&alice_store
|
||
|
.session_store
|
||
|
.load_existing_sessions(&recipients)?,
|
||
|
&alice_usmc,
|
||
|
&mut alice_store.identity_store,
|
||
|
None,
|
||
|
&mut rng,
|
||
|
)
|
||
|
.await
|
||
|
{
|
||
|
Ok(_) => panic!("should have failed"),
|
||
|
Err(SignalProtocolError::InvalidRegistrationId(address, _id)) => {
|
||
|
assert_eq!(address, bob_uuid_address);
|
||
|
}
|
||
|
Err(e) => panic!("wrong error: {}", e),
|
||
|
}
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
.now_or_never()
|
||
|
.expect("sync")
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_decryption_error_in_sealed_sender() -> Result<(), SignalProtocolError> {
|
||
|
async {
|
||
|
let mut rng = OsRng;
|
||
|
|
||
|
let alice_device_id = 23;
|
||
|
let bob_device_id = 42;
|
||
|
|
||
|
let alice_e164 = "+14151111111".to_owned();
|
||
|
|
||
|
let alice_uuid = "9d0652a3-dcc3-4d11-975f-74d61598733f".to_string();
|
||
|
let bob_uuid = "796abedb-ca4e-4f18-8803-1fde5b921f9f".to_string();
|
||
|
|
||
|
let alice_uuid_address = ProtocolAddress::new(alice_uuid.clone(), 1);
|
||
|
let bob_uuid_address = ProtocolAddress::new(bob_uuid.clone(), bob_device_id);
|
||
|
|
||
|
let mut alice_store = support::test_in_memory_protocol_store()?;
|
||
|
let mut bob_store = support::test_in_memory_protocol_store()?;
|
||
|
|
||
|
let alice_pubkey = *alice_store.get_identity_key_pair(None).await?.public_key();
|
||
|
|
||
|
let alice_pre_key_bundle = create_pre_key_bundle(&mut alice_store, &mut rng).await?;
|
||
|
|
||
|
process_prekey_bundle(
|
||
|
&alice_uuid_address,
|
||
|
&mut bob_store.session_store,
|
||
|
&mut bob_store.identity_store,
|
||
|
&alice_pre_key_bundle,
|
||
|
&mut rng,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
// Send one message to establish a session.
|
||
|
|
||
|
let bob_first_message = message_encrypt(
|
||
|
b"swim camp",
|
||
|
&alice_uuid_address,
|
||
|
&mut bob_store.session_store,
|
||
|
&mut bob_store.identity_store,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
message_decrypt(
|
||
|
&bob_first_message,
|
||
|
&bob_uuid_address,
|
||
|
&mut alice_store.session_store,
|
||
|
&mut alice_store.identity_store,
|
||
|
&mut alice_store.pre_key_store,
|
||
|
&mut alice_store.signed_pre_key_store,
|
||
|
&mut rng,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
// Pretend the second message fails to decrypt.
|
||
|
|
||
|
let bob_message = message_encrypt(
|
||
|
b"space camp",
|
||
|
&alice_uuid_address,
|
||
|
&mut bob_store.session_store,
|
||
|
&mut bob_store.identity_store,
|
||
|
None,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let original_ratchet_key = match bob_message {
|
||
|
CiphertextMessage::PreKeySignalMessage(ref m) => m.message().sender_ratchet_key(),
|
||
|
_ => panic!("without ACKs, every message should be a PreKeySignalMessage"),
|
||
|
};
|
||
|
|
||
|
// Skip over the part where Bob sends this to Alice and Alice fails to decrypt it,
|
||
|
// for whatever reason.
|
||
|
|
||
|
let trust_root = KeyPair::generate(&mut rng);
|
||
|
let server_key = KeyPair::generate(&mut rng);
|
||
|
|
||
|
let server_cert =
|
||
|
ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng)?;
|
||
|
|
||
|
let expires = 1605722925;
|
||
|
|
||
|
let sender_cert = SenderCertificate::new(
|
||
|
alice_uuid.clone(),
|
||
|
Some(alice_e164.clone()),
|
||
|
alice_pubkey,
|
||
|
alice_device_id,
|
||
|
expires,
|
||
|
server_cert,
|
||
|
&server_key.private_key,
|
||
|
&mut rng,
|
||
|
)?;
|
||
|
|
||
|
let error_message = DecryptionErrorMessage::for_original(
|
||
|
bob_message.serialize(),
|
||
|
bob_message.message_type(),
|
||
|
408,
|
||
|
5,
|
||
|
)?;
|
||
|
let error_message_content = PlaintextContent::from(error_message);
|
||
|
let error_message_usmc = UnidentifiedSenderMessageContent::new(
|
||
|
CiphertextMessageType::Plaintext,
|
||
|
sender_cert.clone(),
|
||
|
error_message_content.serialized().to_vec(),
|
||
|
ContentHint::Default,
|
||
|
None,
|
||
|
)?;
|
||
|
|
||
|
let alice_ctext = sealed_sender_encrypt_from_usmc(
|
||
|
&bob_uuid_address,
|
||
|
&error_message_usmc,
|
||
|
&mut alice_store.identity_store,
|
||
|
None,
|
||
|
&mut rng,
|
||
|
)
|
||
|
.await?;
|
||
|
|
||
|
let bob_usmc =
|
||
|
sealed_sender_decrypt_to_usmc(&alice_ctext, &mut bob_store.identity_store, None)
|
||
|
.await?;
|
||
|
|
||
|
assert!(matches!(
|
||
|
bob_usmc.msg_type()?,
|
||
|
CiphertextMessageType::Plaintext,
|
||
|
));
|
||
|
|
||
|
let bob_plaintext = PlaintextContent::try_from(bob_usmc.contents()?)?;
|
||
|
let bob_error_message =
|
||
|
extract_decryption_error_message_from_serialized_content(bob_plaintext.body())
|
||
|
.expect("present");
|
||
|
|
||
|
assert_eq!(bob_error_message.ratchet_key(), Some(original_ratchet_key));
|
||
|
assert_eq!(bob_error_message.timestamp(), 408);
|
||
|
assert_eq!(bob_error_message.device_id(), 5);
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
.now_or_never()
|
||
|
.expect("sync")
|
||
|
}
|