@@ -19,15 +19,20 @@ use futures_core::Stream;
1919use futures_util:: { FutureExt , StreamExt } ;
2020use matrix_sdk_common:: deserialized_responses:: ProcessedToDeviceEvent ;
2121use matrix_sdk_test:: async_test;
22- use ruma:: { RoomId , TransactionId , UserId , room_id, user_id} ;
22+ use ruma:: {
23+ DeviceKeyId , RoomId , TransactionId , UserId , canonical_json:: to_canonical_value, owned_user_id,
24+ room_id, user_id,
25+ } ;
2326use serde:: Serialize ;
2427use serde_json:: json;
2528use tokio_stream:: wrappers:: errors:: BroadcastStreamRecvError ;
29+ use vodozemac:: Curve25519SecretKey ;
2630
2731use crate :: {
28- DecryptionSettings , DeviceData , EncryptionSettings , EncryptionSyncChanges , OlmMachine , Session ,
29- TrustRequirement ,
32+ Account , DecryptionSettings , DeviceData , EncryptionSettings , EncryptionSyncChanges , EventError ,
33+ OlmError , OlmMachine , Session , TrustRequirement ,
3034 machine:: {
35+ DeviceKeyAlgorithm ,
3136 test_helpers:: {
3237 bootstrap_requests_to_keys_query_response,
3338 get_machine_pair_with_setup_sessions_test_helper,
@@ -36,7 +41,10 @@ use crate::{
3641 } ,
3742 olm:: { InboundGroupSession , SenderData } ,
3843 store:: types:: RoomKeyInfo ,
39- types:: events:: { EventType , ToDeviceEvent , room:: encrypted:: ToDeviceEncryptedEventContent } ,
44+ types:: {
45+ DeviceKey , DeviceKeys ,
46+ events:: { EventType , ToDeviceEvent , room:: encrypted:: ToDeviceEncryptedEventContent } ,
47+ } ,
4048} ;
4149
4250/// Test the behaviour when a megolm session is received from an unknown device,
@@ -54,7 +62,7 @@ async fn test_receive_megolm_session_from_unknown_device() {
5462 // When Alice starts a megolm session and shares the key with Bob, *without*
5563 // sending the sender data.
5664 let room_id = room_id ! ( "!test:example.org" ) ;
57- let event = create_and_share_session_without_sender_data ( & alice, & bob, room_id) . await ;
65+ let event = create_and_share_session_with_custom_sender_data ( & alice, & bob, room_id, None ) . await ;
5866
5967 let decryption_settings =
6068 DecryptionSettings { sender_device_trust_requirement : TrustRequirement :: Untrusted } ;
@@ -76,6 +84,112 @@ async fn test_receive_megolm_session_from_unknown_device() {
7684 ) ;
7785}
7886
87+ /// Test the behaviour when a megolm session is received, and the device keys in
88+ /// the to-device message are incorrect.
89+ #[ async_test]
90+ async fn test_receive_megolm_session_with_bad_device_keys ( ) {
91+ // In this test, Alice sends Bob several encrypted events, with various
92+ // contents for the device keys embedded in the encrypted data.
93+ let ( alice, bob) = get_machine_pair ( ) . await ;
94+
95+ let room_id = room_id ! ( "!test:example.org" ) ;
96+ let decryption_settings =
97+ DecryptionSettings { sender_device_trust_requirement : TrustRequirement :: Untrusted } ;
98+
99+ let alice_account = alice. store ( ) . load_account ( ) . await . unwrap ( ) . unwrap ( ) ;
100+ let alice_device_keys = alice_account. device_keys ( ) ;
101+ let alice_unsigned_device_keys = {
102+ let mut device_keys = alice_device_keys. clone ( ) ;
103+ device_keys. signatures . clear ( ) ;
104+ device_keys
105+ } ;
106+ let bob_store = bob. store ( ) ;
107+ let mut bob_account = bob_store. load_account ( ) . await . unwrap ( ) . unwrap ( ) ;
108+
109+ // Using Alice's correct device keys should succeed
110+ let sender_device_keys = serde_json:: to_value ( & alice_device_keys) . unwrap ( ) ;
111+ let event = create_and_share_session_with_custom_sender_data (
112+ & alice,
113+ & bob,
114+ room_id,
115+ Some ( sender_device_keys) ,
116+ )
117+ . await ;
118+ bob_account
119+ . decrypt_to_device_event ( bob_store, & event, & decryption_settings)
120+ . await
121+ . expect ( "using Alice's correct device keys should succeed" ) ;
122+
123+ // An unsigned device key should error.
124+ let sender_device_keys = serde_json:: to_value ( & alice_unsigned_device_keys) . unwrap ( ) ;
125+ let event = create_and_share_session_with_custom_sender_data (
126+ & alice,
127+ & bob,
128+ room_id,
129+ Some ( sender_device_keys) ,
130+ )
131+ . await ;
132+ assert_matches ! (
133+ bob_account. decrypt_to_device_event( bob_store, & event, & decryption_settings) . await ,
134+ Err ( OlmError :: EventError ( EventError :: InvalidSenderDeviceKeys ) )
135+ ) ;
136+
137+ // Having the wrong user ID in the device key should error.
138+ let wrong_user_device_keys = {
139+ let mut device_keys = alice_unsigned_device_keys. clone ( ) ;
140+ device_keys. user_id = owned_user_id ! ( "@wrong_user:example.org" ) ;
141+ sign_device_keys ( & alice_account, & mut device_keys) ;
142+ device_keys
143+ } ;
144+ let sender_device_keys = serde_json:: to_value ( & wrong_user_device_keys) . unwrap ( ) ;
145+ let event = create_and_share_session_with_custom_sender_data (
146+ & alice,
147+ & bob,
148+ room_id,
149+ Some ( sender_device_keys) ,
150+ )
151+ . await ;
152+ assert_matches ! (
153+ bob_account. decrypt_to_device_event( bob_store, & event, & decryption_settings) . await ,
154+ Err ( OlmError :: EventError ( EventError :: InvalidSenderDeviceKeys ) )
155+ ) ;
156+
157+ // Having the wrong ed25519 key in the device key should error.
158+ let wrong_ed25519_device_keys = {
159+ let mut device_keys = alice_unsigned_device_keys. clone ( ) ;
160+ let secret_key = Curve25519SecretKey :: new ( ) ;
161+ device_keys. keys . insert (
162+ DeviceKeyId :: from_parts ( DeviceKeyAlgorithm :: Curve25519 , & device_keys. device_id ) ,
163+ DeviceKey :: Curve25519 ( ( & secret_key) . into ( ) ) ,
164+ ) ;
165+ sign_device_keys ( & alice_account, & mut device_keys) ;
166+ device_keys
167+ } ;
168+ let sender_device_keys = serde_json:: to_value ( & wrong_ed25519_device_keys) . unwrap ( ) ;
169+ let event = create_and_share_session_with_custom_sender_data (
170+ & alice,
171+ & bob,
172+ room_id,
173+ Some ( sender_device_keys) ,
174+ )
175+ . await ;
176+ assert_matches ! (
177+ bob_account. decrypt_to_device_event( bob_store, & event, & decryption_settings) . await ,
178+ Err ( OlmError :: EventError ( EventError :: InvalidSenderDeviceKeys ) )
179+ ) ;
180+ }
181+
182+ fn sign_device_keys ( account : & Account , device_keys : & mut DeviceKeys ) {
183+ let json_device_keys = to_canonical_value ( & device_keys) . unwrap ( ) ;
184+ let signature = account. sign_json ( json_device_keys) . unwrap ( ) ;
185+
186+ device_keys. signatures . add_signature (
187+ device_keys. user_id . to_owned ( ) ,
188+ DeviceKeyId :: from_parts ( DeviceKeyAlgorithm :: Ed25519 , & device_keys. device_id ) ,
189+ signature,
190+ ) ;
191+ }
192+
79193/// Test the behaviour when a megolm session is received from a known, but
80194/// unsigned, device.
81195#[ async_test]
@@ -131,7 +245,7 @@ async fn test_update_unknown_device_senderdata_on_keys_query() {
131245 // Alice starts a megolm session and shares the key with Bob, *without* sending
132246 // the sender data.
133247 let room_id = room_id ! ( "!test:example.org" ) ;
134- let event = create_and_share_session_without_sender_data ( & alice, & bob, room_id) . await ;
248+ let event = create_and_share_session_with_custom_sender_data ( & alice, & bob, room_id, None ) . await ;
135249
136250 let decryption_settings =
137251 DecryptionSettings { sender_device_trust_requirement : TrustRequirement :: Untrusted } ;
@@ -241,17 +355,20 @@ async fn forget_devices_for_user(machine: &OlmMachine, other_user: &UserId) {
241355}
242356
243357/// Create a new [`OutboundGroupSession`], and build a to-device event to share
244- /// it with another [`OlmMachine`], *without* sending the MSC4147 sender data.
358+ /// it with another [`OlmMachine`], using custom MSC4147 sender data.
245359///
246360/// # Arguments
247361///
248362/// * `alice` - sending device.
249363/// * `bob` - receiving device.
250364/// * `room_id` - room to create a session for.
251- async fn create_and_share_session_without_sender_data (
365+ /// * `sender_device_keys` - the MSC4147 sender data to include, or `None` to
366+ /// omit the sender data
367+ async fn create_and_share_session_with_custom_sender_data (
252368 alice : & OlmMachine ,
253369 bob : & OlmMachine ,
254370 room_id : & RoomId ,
371+ sender_device_keys : Option < serde_json:: Value > ,
255372) -> ToDeviceEvent < ToDeviceEncryptedEventContent > {
256373 let ( outbound_session, _) = alice
257374 . inner
@@ -277,7 +394,7 @@ async fn create_and_share_session_without_sender_data(
277394 let mut olm_session: Session = olm_sessions. lock ( ) . await [ 0 ] . clone ( ) ;
278395
279396 let room_key_content = outbound_session. as_content ( ) . await ;
280- let plaintext = serde_json :: to_string ( & json ! ( {
397+ let mut plaintext_value = json ! ( {
281398 "sender" : alice. user_id( ) ,
282399 "sender_device" : alice. device_id( ) ,
283400 "keys" : { "ed25519" : alice. identity_keys( ) . ed25519. to_base64( ) } ,
@@ -287,8 +404,14 @@ async fn create_and_share_session_without_sender_data(
287404 "recipient_keys" : { "ed25519" : bob. identity_keys( ) . ed25519. to_base64( ) } ,
288405 "type" : room_key_content. event_type( ) ,
289406 "content" : room_key_content,
290- } ) )
291- . unwrap ( ) ;
407+ } ) ;
408+ if let Some ( sender_device_keys) = sender_device_keys {
409+ plaintext_value
410+ . as_object_mut ( )
411+ . unwrap ( )
412+ . insert ( "org.matrix.msc4147.device_keys" . to_owned ( ) , sender_device_keys) ;
413+ }
414+ let plaintext = serde_json:: to_string ( & plaintext_value) . unwrap ( ) ;
292415
293416 let ciphertext = olm_session. encrypt_helper ( & plaintext) . await . unwrap ( ) ;
294417 ToDeviceEvent :: new (
0 commit comments