crypto: Test a key share cycle.

master
Damir Jelić 2020-09-29 10:24:54 +02:00
parent 798656dac5
commit e1c220e2f7
3 changed files with 221 additions and 1 deletions

View File

@ -586,7 +586,12 @@ impl KeyRequestMachine {
mod test { mod test {
use dashmap::DashMap; use dashmap::DashMap;
use matrix_sdk_common::{ use matrix_sdk_common::{
events::{forwarded_room_key::ForwardedRoomKeyEventContent, ToDeviceEvent}, api::r0::to_device::DeviceIdOrAllDevices,
events::{
forwarded_room_key::ForwardedRoomKeyEventContent,
room::encrypted::EncryptedEventContent, room_key_request::RoomKeyRequestEventContent,
ToDeviceEvent,
},
identifiers::{room_id, user_id, DeviceIdBox, RoomId, UserId}, identifiers::{room_id, user_id, DeviceIdBox, RoomId, UserId},
}; };
use matrix_sdk_test::async_test; use matrix_sdk_test::async_test;
@ -628,6 +633,18 @@ mod test {
Account::new(&bob_id(), &bob_device_id()) Account::new(&bob_id(), &bob_device_id())
} }
fn bob_machine() -> KeyRequestMachine {
let user_id = Arc::new(bob_id());
let store = Store::new(user_id.clone(), Box::new(MemoryStore::new()));
KeyRequestMachine::new(
user_id,
Arc::new(bob_device_id()),
store,
Arc::new(DashMap::new()),
)
}
fn get_machine() -> KeyRequestMachine { fn get_machine() -> KeyRequestMachine {
let user_id = Arc::new(alice_id()); let user_id = Arc::new(alice_id());
let store = Store::new(user_id.clone(), Box::new(MemoryStore::new())); let store = Store::new(user_id.clone(), Box::new(MemoryStore::new()));
@ -884,4 +901,140 @@ mod test {
.should_share_session(&bob_device, Some(&session)) .should_share_session(&bob_device, Some(&session))
.is_ok()); .is_ok());
} }
#[async_test]
async fn key_share_cycle() {
let alice_machine = get_machine();
let alice_account = account();
let bob_machine = bob_machine();
let bob_account = bob_account();
// Create Olm sessions for our two accounts.
let (alice_session, bob_session) = alice_account.create_session_for(&bob_account).await;
let alice_device = ReadOnlyDevice::from_account(&alice_account).await;
let bob_device = ReadOnlyDevice::from_account(&bob_account).await;
// Populate our stores with Olm sessions and a Megolm session.
alice_machine
.store
.save_sessions(&[alice_session])
.await
.unwrap();
alice_machine
.store
.save_devices(&[bob_device])
.await
.unwrap();
bob_machine
.store
.save_sessions(&[bob_session])
.await
.unwrap();
bob_machine
.store
.save_devices(&[alice_device])
.await
.unwrap();
let (group_session, inbound_group_session) = bob_account
.create_group_session_pair_with_defaults(&room_id())
.await
.unwrap();
bob_machine
.store
.save_inbound_group_sessions(&[inbound_group_session])
.await
.unwrap();
// Alice wants to request the outbound group session from bob.
alice_machine
.create_outgoing_key_request(
&room_id(),
bob_account.identity_keys.curve25519(),
group_session.session_id(),
)
.await
.unwrap();
group_session.mark_shared_with(&alice_id(), &alice_device_id());
// Put the outbound session into bobs store.
bob_machine
.outbound_group_sessions
.insert(room_id(), group_session);
// Get the request and convert it into a event.
let request = alice_machine
.outgoing_to_device_requests
.iter()
.next()
.unwrap();
let id = request.request_id;
let content = request
.request
.to_device()
.unwrap()
.messages
.get(&alice_id())
.unwrap()
.get(&DeviceIdOrAllDevices::AllDevices)
.unwrap();
let content: RoomKeyRequestEventContent = serde_json::from_str(content.get()).unwrap();
drop(request);
alice_machine
.mark_outgoing_request_as_sent(&id)
.await
.unwrap();
let event = ToDeviceEvent {
sender: alice_id(),
content,
};
// Bob doesn't have any outgoing requests.
assert!(bob_machine.outgoing_to_device_requests.is_empty());
// Receive the room key request from alice.
bob_machine.receive_incoming_key_request(&event);
bob_machine.collect_incoming_key_requests().await.unwrap();
// Now bob does have an outgoing request.
assert!(!bob_machine.outgoing_to_device_requests.is_empty());
// Get the request and convert it to a encrypted to-device event.
let request = bob_machine
.outgoing_to_device_requests
.iter()
.next()
.unwrap();
let id = request.request_id;
let content = request
.request
.to_device()
.unwrap()
.messages
.get(&alice_id())
.unwrap()
.get(&DeviceIdOrAllDevices::DeviceId(alice_device_id()))
.unwrap();
let content: EncryptedEventContent = serde_json::from_str(content.get()).unwrap();
drop(request);
bob_machine
.mark_outgoing_request_as_sent(&id)
.await
.unwrap();
let _event = ToDeviceEvent {
sender: bob_id(),
content,
};
// TODO test that alice can receive, decrypt and add the requested key
// to the store.
}
} }

View File

@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#[cfg(test)]
use matrix_sdk_common::events::{room::encrypted::EncryptedEventContent, EventType};
use std::{ use std::{
collections::BTreeMap, collections::BTreeMap,
convert::{TryFrom, TryInto}, convert::{TryFrom, TryInto},
@ -617,6 +619,61 @@ impl Account {
self.create_group_session_pair(room_id, EncryptionSettings::default(), [].iter()) self.create_group_session_pair(room_id, EncryptionSettings::default(), [].iter())
.await .await
} }
#[cfg(test)]
pub(crate) async fn create_session_for(&self, other: &Account) -> (Session, Session) {
other.generate_one_time_keys_helper(1).await;
let one_time = other.signed_one_time_keys().await.unwrap();
let device = ReadOnlyDevice::from_account(other).await;
let mut our_session = self
.create_outbound_session(device.clone(), &one_time)
.await
.unwrap();
let message = our_session
.encrypt(&device, EventType::Dummy, json!({}))
.await
.unwrap();
let content = if let EncryptedEventContent::OlmV1Curve25519AesSha2(c) = message {
c
} else {
panic!("Invalid encrypted event algorithm");
};
let own_ciphertext = content
.ciphertext
.get(other.identity_keys.curve25519())
.unwrap();
let message_type: u8 = own_ciphertext.message_type.try_into().unwrap();
let message =
OlmMessage::from_type_and_ciphertext(message_type.into(), own_ciphertext.body.clone())
.unwrap();
let message = if let OlmMessage::PreKey(m) = message {
m
} else {
panic!("Wrong Olm message type");
};
let our_device = ReadOnlyDevice::from_account(self).await;
let other_session = other
.create_inbound_session(
our_device
.keys()
.get(&DeviceKeyId::from_parts(
DeviceKeyAlgorithm::Curve25519,
our_device.device_id(),
))
.unwrap(),
message,
)
.await
.unwrap();
(our_session, other_session)
}
} }
impl PartialEq for Account { impl PartialEq for Account {

View File

@ -99,6 +99,16 @@ pub enum OutgoingRequests {
ToDeviceRequest(ToDeviceRequest), ToDeviceRequest(ToDeviceRequest),
} }
#[cfg(test)]
impl OutgoingRequests {
pub fn to_device(&self) -> Option<&ToDeviceRequest> {
match self {
OutgoingRequests::ToDeviceRequest(r) => Some(r),
_ => None,
}
}
}
impl From<KeysQueryRequest> for OutgoingRequests { impl From<KeysQueryRequest> for OutgoingRequests {
fn from(request: KeysQueryRequest) -> Self { fn from(request: KeysQueryRequest) -> Self {
OutgoingRequests::KeysQuery(request) OutgoingRequests::KeysQuery(request)