crypto: Test a key share cycle.
parent
798656dac5
commit
e1c220e2f7
|
@ -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.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue