From 051f5950a87e11d64daa010915e24ede9e69643f Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 17 Jan 2025 16:38:28 +0000 Subject: [PATCH] crypto: withhold outgoing messages to unsigned dehydrated devices Per https://github.com/matrix-org/matrix-rust-sdk/issues/4313, we should not send outgoing messages to dehydrated devices that are not signed by the current pinned/verified identity. --- .../src/identities/device.rs | 7 +- .../group_sessions/share_strategy.rs | 477 +++++++++++++++++- ...device_of_verification_violation_user.snap | 77 +++ ...are_with_unverified_dehydrated_device.snap | 76 +++ ...share_with_verified_dehydrated_device.snap | 77 +++ ...verified_device_of_pin_violation_user.snap | 77 +++ 6 files changed, 788 insertions(+), 3 deletions(-) create mode 100644 crates/matrix-sdk-crypto/src/session_manager/group_sessions/snapshots/matrix_sdk_crypto__session_manager__group_sessions__share_strategy__tests__dehydrated_device__prepare_machine_with_dehydrated_device_of_verification_violation_user.snap create mode 100644 crates/matrix-sdk-crypto/src/session_manager/group_sessions/snapshots/matrix_sdk_crypto__session_manager__group_sessions__share_strategy__tests__dehydrated_device__should_not_share_with_unverified_dehydrated_device.snap create mode 100644 crates/matrix-sdk-crypto/src/session_manager/group_sessions/snapshots/matrix_sdk_crypto__session_manager__group_sessions__share_strategy__tests__dehydrated_device__should_share_with_verified_dehydrated_device.snap create mode 100644 crates/matrix-sdk-crypto/src/session_manager/group_sessions/snapshots/matrix_sdk_crypto__session_manager__group_sessions__share_strategy__tests__dehydrated_device__should_share_with_verified_device_of_pin_violation_user.snap diff --git a/crates/matrix-sdk-crypto/src/identities/device.rs b/crates/matrix-sdk-crypto/src/identities/device.rs index cea61624e16..f1db16dc1d7 100644 --- a/crates/matrix-sdk-crypto/src/identities/device.rs +++ b/crates/matrix-sdk-crypto/src/identities/device.rs @@ -481,7 +481,7 @@ impl Device { /// Whether or not the device is a dehydrated device. pub fn is_dehydrated(&self) -> bool { - self.inner.device_keys.dehydrated.unwrap_or(false) + self.inner.is_dehydrated() } } @@ -966,6 +966,11 @@ impl DeviceData { pub fn first_time_seen_ts(&self) -> MilliSecondsSinceUnixEpoch { self.first_time_seen_ts } + + /// True if this device is an MSC3814 dehydrated device. + pub fn is_dehydrated(&self) -> bool { + self.device_keys.dehydrated.unwrap_or(false) + } } impl TryFrom<&DeviceKeys> for DeviceData { diff --git a/crates/matrix-sdk-crypto/src/session_manager/group_sessions/share_strategy.rs b/crates/matrix-sdk-crypto/src/session_manager/group_sessions/share_strategy.rs index 58766d1089c..65dbd120eac 100644 --- a/crates/matrix-sdk-crypto/src/session_manager/group_sessions/share_strategy.rs +++ b/crates/matrix-sdk-crypto/src/session_manager/group_sessions/share_strategy.rs @@ -195,9 +195,13 @@ pub(crate) async fn collect_session_recipients( user_id ); let user_devices = store.get_device_data_for_user_filtered(user_id).await?; + let device_owner_identity = store.get_user_identity(user_id).await?; - let recipient_devices = - split_devices_for_user_for_all_devices_strategy(user_devices); + let recipient_devices = split_devices_for_user_for_all_devices_strategy( + user_devices, + &own_identity, + &device_owner_identity, + ); update_recipients_for_user(&mut result, outbound, user_id, recipient_devices); } } @@ -443,10 +447,20 @@ enum ErrorOnVerifiedUserProblemResult { /// receive the key, for [`CollectStrategy::AllDevices`]. fn split_devices_for_user_for_all_devices_strategy( user_devices: HashMap, + own_identity: &Option, + device_owner_identity: &Option, ) -> RecipientDevicesForUser { let (left, right) = user_devices.into_values().partition_map(|d| { if d.is_blacklisted() { Either::Right((d, WithheldCode::Blacklisted)) + } else if d.is_dehydrated() + && should_withhold_to_dehydrated_device( + &d, + own_identity.as_ref(), + device_owner_identity.as_ref(), + ) + { + Either::Right((d, WithheldCode::Unverified)) } else { Either::Left(d) } @@ -455,6 +469,28 @@ fn split_devices_for_user_for_all_devices_strategy( RecipientDevicesForUser { allowed_devices: left, denied_devices_with_code: right } } +/// Helper for [`split_devices_for_user_for_all_devices_strategy`]. +/// +/// Given a dehydrated device `device`, decide if we should withhold the room +/// key from it. +/// +/// Dehydrated devices must be signed by their owners (whether or not we have +/// verified the owner), and, if we previously verified the owner, they must be +/// verified still (i.e., they must not have a verification violation). +fn should_withhold_to_dehydrated_device( + device: &DeviceData, + own_identity: Option<&OwnUserIdentityData>, + device_owner_identity: Option<&UserIdentityData>, +) -> bool { + device_owner_identity.is_none_or(|owner_id| { + // Dehydrated devices must be signed by their owners + !device.is_cross_signed_by_owner(owner_id) || + + // If the user has changed identity since we verified them, withhold the message + (owner_id.was_previously_verified() && !is_user_verified(own_identity, owner_id)) + }) +} + /// Partition the list of a user's devices according to whether they should /// receive the key, for [`CollectStrategy::ErrorOnVerifiedUserProblem`]. /// @@ -525,6 +561,14 @@ fn handle_device_for_user_for_error_on_verified_user_problem_strategy( ErrorOnVerifiedUserProblemDeviceDecision::Ok } else if is_unsigned_device_of_verified_user(own_identity, device_owner_identity, device) { ErrorOnVerifiedUserProblemDeviceDecision::UnsignedOfVerified + } else if device.is_dehydrated() + && device_owner_identity.is_none_or(|owner_id| { + // Dehydrated devices must be signed by their owners, whether or not that + // owner is verified + !device.is_cross_signed_by_owner(owner_id) + }) + { + ErrorOnVerifiedUserProblemDeviceDecision::Withhold(WithheldCode::Unverified) } else { ErrorOnVerifiedUserProblemDeviceDecision::Ok } @@ -1231,6 +1275,435 @@ mod tests { .unwrap(); } + /// A set of tests for the behaviour of [`collect_session_recipients`] with + /// a dehydrated device + mod dehydrated_device { + use std::{collections::HashSet, iter}; + + use insta::{allow_duplicates, assert_json_snapshot, with_settings}; + use matrix_sdk_common::deserialized_responses::WithheldCode; + use matrix_sdk_test::{ + async_test, ruma_response_to_json, + test_json::keys_query_sets::{ + KeyDistributionTestData, KeyQueryResponseTemplate, + KeyQueryResponseTemplateDeviceOptions, + }, + }; + use ruma::{device_id, user_id, DeviceId, TransactionId, UserId}; + use vodozemac::{Curve25519PublicKey, Ed25519SecretKey}; + + use super::{ + all_devices_strategy_settings, create_test_outbound_group_session, + error_on_verification_problem_encryption_settings, identity_based_strategy_settings, + test_machine, + }; + use crate::{ + session_manager::group_sessions::{ + share_strategy::collect_session_recipients, CollectRecipientsResult, + }, + EncryptionSettings, OlmMachine, + }; + + #[async_test] + async fn test_all_devices_strategy_should_share_with_verified_dehydrated_device() { + should_share_with_verified_dehydrated_device(&all_devices_strategy_settings()).await + } + + #[async_test] + async fn test_error_on_verification_problem_strategy_should_share_with_verified_dehydrated_device( + ) { + should_share_with_verified_dehydrated_device( + &error_on_verification_problem_encryption_settings(), + ) + .await + } + + #[async_test] + async fn test_identity_based_strategy_should_share_with_verified_dehydrated_device() { + should_share_with_verified_dehydrated_device(&identity_based_strategy_settings()).await + } + + /// Common helper for + /// [`test_all_devices_strategy_should_share_with_verified_dehydrated_device`], + /// [`test_error_on_verification_problem_strategy_should_share_with_verified_dehydrated_device`] + /// and [`test_identity_based_strategy_should_share_with_verified_dehydrated_device`]. + async fn should_share_with_verified_dehydrated_device( + encryption_settings: &EncryptionSettings, + ) { + let machine = test_machine().await; + + // Bob is a user with cross-signing, who has a single (verified) dehydrated + // device. + let bob_user_id = user_id!("@bob:localhost"); + let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE"); + let keys_query = key_query_response_template_with_cross_signing(bob_user_id) + .with_dehydrated_device(bob_dehydrated_device_id, true) + .build_response(); + allow_duplicates! { + with_settings!({sort_maps => true}, { assert_json_snapshot!(ruma_response_to_json(keys_query.clone())) }); + } + machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap(); + + // When we collect the recipients ... + let recips = share_test_session_and_collect_recipients( + &machine, + bob_user_id, + encryption_settings, + ) + .await; + + // ... then the dehydrated device should be included + assert_shared_with(recips, bob_user_id, [bob_dehydrated_device_id].into()); + } + + #[async_test] + async fn test_all_devices_strategy_should_not_share_with_unverified_dehydrated_device() { + should_not_share_with_unverified_dehydrated_device(&all_devices_strategy_settings()) + .await + } + + #[async_test] + async fn test_error_on_verification_problem_strategy_should_not_share_with_unverified_dehydrated_device( + ) { + should_not_share_with_unverified_dehydrated_device( + &error_on_verification_problem_encryption_settings(), + ) + .await + } + + #[async_test] + async fn test_identity_based_strategy_should_not_share_with_unverified_dehydrated_device() { + should_not_share_with_unverified_dehydrated_device(&identity_based_strategy_settings()) + .await + } + + /// Common helper for + /// [`test_all_devices_strategy_should_not_share_with_unverified_dehydrated_device`], + /// [`test_error_on_verification_problem_strategy_should_not_share_with_unverified_dehydrated_device`] + /// and [`test_identity_based_strategy_should_not_share_with_unverified_dehydrated_device`]. + async fn should_not_share_with_unverified_dehydrated_device( + encryption_settings: &EncryptionSettings, + ) { + let machine = test_machine().await; + + // Bob is a user with cross-signing, who has a single (unverified) dehydrated + // device. + let bob_user_id = user_id!("@bob:localhost"); + let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE"); + let keys_query = key_query_response_template_with_cross_signing(bob_user_id) + .with_dehydrated_device(bob_dehydrated_device_id, false) + .build_response(); + allow_duplicates! { + with_settings!({sort_maps => true}, { assert_json_snapshot!(ruma_response_to_json(keys_query.clone())) }); + } + machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap(); + + // When we collect the recipients ... + let recips = share_test_session_and_collect_recipients( + &machine, + bob_user_id, + encryption_settings, + ) + .await; + + // ... it shouldn't be shared with anyone, and there should be a withheld + // message for the dehydrated device. + assert_withheld_to(recips, bob_user_id, bob_dehydrated_device_id); + } + + #[async_test] + async fn test_all_devices_strategy_should_share_with_verified_device_of_pin_violation_user() + { + should_share_with_verified_device_of_pin_violation_user( + &all_devices_strategy_settings(), + ) + .await + } + + #[async_test] + async fn test_error_on_verification_problem_strategy_should_share_with_verified_device_of_pin_violation_user( + ) { + should_share_with_verified_device_of_pin_violation_user( + &error_on_verification_problem_encryption_settings(), + ) + .await + } + + #[async_test] + async fn test_identity_based_strategy_should_share_with_verified_device_of_pin_violation_user( + ) { + should_share_with_verified_device_of_pin_violation_user( + &identity_based_strategy_settings(), + ) + .await + } + + /// Common helper for + /// [`test_all_devices_strategy_should_share_with_verified_device_of_pin_violation_user`], + /// [`test_error_on_verification_problem_strategy_should_share_with_verified_device_of_pin_violation_user`] + /// and [`test_identity_based_strategy_should_share_with_verified_device_of_pin_violation_user`]. + async fn should_share_with_verified_device_of_pin_violation_user( + encryption_settings: &EncryptionSettings, + ) { + let machine = test_machine().await; + + // Bob starts out with one identity + let bob_user_id = user_id!("@bob:localhost"); + let keys_query = + key_query_response_template_with_cross_signing(bob_user_id).build_response(); + machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap(); + + // He then changes identity, and adds a dehydrated device (signed with his new + // identity) + let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE"); + let keys_query = key_query_response_template_with_changed_cross_signing(bob_user_id) + .with_dehydrated_device(bob_dehydrated_device_id, true) + .build_response(); + allow_duplicates! { + with_settings!({sort_maps => true}, { assert_json_snapshot!(ruma_response_to_json(keys_query.clone())) }); + } + machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap(); + + // When we collect the recipients ... + let recips = share_test_session_and_collect_recipients( + &machine, + bob_user_id, + encryption_settings, + ) + .await; + + // ... then the dehydrated device should be included + assert_shared_with(recips, bob_user_id, [bob_dehydrated_device_id].into()); + } + + #[async_test] + async fn test_all_devices_strategy_should_not_share_with_dehydrated_device_of_verification_violation_user( + ) { + should_not_share_with_dehydrated_device_of_verification_violation_user( + &all_devices_strategy_settings(), + ) + .await + } + + /// Helper function for + /// [`test_all_devices_strategy_should_not_share_with_dehydrated_device_of_verification_violation_user`]. + async fn should_not_share_with_dehydrated_device_of_verification_violation_user( + encryption_settings: &EncryptionSettings, + ) { + let bob_user_id = user_id!("@bob:localhost"); + let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE"); + let machine = prepare_machine_with_dehydrated_device_of_verification_violation_user( + bob_user_id, + bob_dehydrated_device_id, + ) + .await; + + // When we collect the recipients ... + let recips = share_test_session_and_collect_recipients( + &machine, + bob_user_id, + encryption_settings, + ) + .await; + + // ... it shouldn't be shared with anyone, and there should be a withheld + // message for the dehydrated device. + assert_withheld_to(recips, bob_user_id, bob_dehydrated_device_id); + } + + #[async_test] + async fn test_error_on_verification_problem_strategy_should_give_error_for_dehydrated_device_of_verification_violation_user( + ) { + should_give_error_for_dehydrated_device_of_verification_violation_user( + &error_on_verification_problem_encryption_settings(), + ) + .await + } + + #[async_test] + async fn test_identity_based_strategy_should_give_error_for_dehydrated_device_of_verification_violation_user( + ) { + // This hits the same codepath as + // `test_share_identity_strategy_report_verification_violation`, but + // we test dehydrated devices here specifically, for completeness. + should_give_error_for_dehydrated_device_of_verification_violation_user( + &identity_based_strategy_settings(), + ) + .await + } + + /// Common helper for + /// [`test_error_on_verification_problem_strategy_should_give_error_for_dehydrated_device_of_verification_violation_user`] + /// and [`test_identity_based_strategy_should_give_error_for_dehydrated_device_of_verification_violation_user`]. + async fn should_give_error_for_dehydrated_device_of_verification_violation_user( + encryption_settings: &EncryptionSettings, + ) { + let bob_user_id = user_id!("@bob:localhost"); + let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE"); + let machine = prepare_machine_with_dehydrated_device_of_verification_violation_user( + bob_user_id, + bob_dehydrated_device_id, + ) + .await; + + let group_session = create_test_outbound_group_session(&machine, encryption_settings); + let share_result = collect_session_recipients( + machine.store(), + iter::once(bob_user_id), + encryption_settings, + &group_session, + ) + .await; + + // The key share should fail with an error indicating that recipients + // were previously verified. + assert_matches::assert_matches!( + share_result, + Err(crate::OlmError::SessionRecipientCollectionError( + crate::SessionRecipientCollectionError::VerifiedUserChangedIdentity(_) + )) + ); + } + + /// Prepare an OlmMachine which knows about a user `bob_user_id`, who + /// has recently changed identity, and then added a new + /// dehydrated device `bob_dehydrated_device_id`. + async fn prepare_machine_with_dehydrated_device_of_verification_violation_user( + bob_user_id: &UserId, + bob_dehydrated_device_id: &DeviceId, + ) -> OlmMachine { + let machine = test_machine().await; + + // Bob starts out with one identity, which we have verified + let keys_query = key_query_response_template_with_cross_signing(bob_user_id) + .with_user_verification_signature( + KeyDistributionTestData::me_id(), + &KeyDistributionTestData::me_private_user_signing_key(), + ) + .build_response(); + machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap(); + + // He then changes identity, and adds a dehydrated device (signed with his new + // identity) + let keys_query = key_query_response_template_with_changed_cross_signing(bob_user_id) + .with_dehydrated_device(bob_dehydrated_device_id, true) + .build_response(); + allow_duplicates! { + with_settings!({sort_maps => true}, { assert_json_snapshot!(ruma_response_to_json(keys_query.clone())) }); + } + machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap(); + + machine + } + + /// Create a test megolm session and prepare to share it with the given + /// users, using the given sharing strategy. + async fn share_test_session_and_collect_recipients( + machine: &OlmMachine, + target_user_id: &UserId, + encryption_settings: &EncryptionSettings, + ) -> CollectRecipientsResult { + let group_session = create_test_outbound_group_session(machine, encryption_settings); + collect_session_recipients( + machine.store(), + iter::once(target_user_id), + encryption_settings, + &group_session, + ) + .await + .unwrap() + } + + /// Assert that the session is shared with the given devices, and that + /// there are no "withheld" messages + fn assert_shared_with( + recips: CollectRecipientsResult, + user_id: &UserId, + device_ids: HashSet<&DeviceId>, + ) { + let bob_devices_shared: HashSet<_> = recips + .devices + .get(user_id) + .unwrap_or_else(|| panic!("session not shared with {user_id}")) + .iter() + .map(|d| d.device_id()) + .collect(); + assert_eq!(bob_devices_shared, device_ids); + + assert!(recips.withheld_devices.is_empty(), "Unexpected withheld messages"); + } + + /// Assert that the session is not shared with any devices, and that + /// there is a withheld code for the given device. + fn assert_withheld_to( + recips: CollectRecipientsResult, + bob_user_id: &UserId, + bob_dehydrated_device_id: &DeviceId, + ) { + // The share list should be empty + for (user, device_list) in recips.devices { + assert_eq!(device_list.len(), 0, "session unexpectedly shared with {}", user); + } + + // ... and there should be one withheld message + assert_eq!(recips.withheld_devices.len(), 1); + assert_eq!(recips.withheld_devices[0].0.user_id(), bob_user_id); + assert_eq!(recips.withheld_devices[0].0.device_id(), bob_dehydrated_device_id); + assert_eq!(recips.withheld_devices[0].1, WithheldCode::Unverified); + } + + /// Start a [`KeysQueryResponseTemplate`] for the given user, with + /// cross-signing keys. + fn key_query_response_template_with_cross_signing( + user_id: &UserId, + ) -> KeyQueryResponseTemplate { + KeyQueryResponseTemplate::new(user_id.to_owned()).with_cross_signing_keys( + Ed25519SecretKey::from_slice(b"master12master12master12master12"), + Ed25519SecretKey::from_slice(b"self1234self1234self1234self1234"), + Ed25519SecretKey::from_slice(b"user1234user1234user1234user1234"), + ) + } + + /// Start a [`KeysQueryResponseTemplate`] for the given user, with + /// *different* cross signing key to + /// [`key_query_response_template_with_cross_signing`]. + fn key_query_response_template_with_changed_cross_signing( + bob_user_id: &UserId, + ) -> KeyQueryResponseTemplate { + KeyQueryResponseTemplate::new(bob_user_id.to_owned()).with_cross_signing_keys( + Ed25519SecretKey::from_slice(b"newmaster__newmaster__newmaster_"), + Ed25519SecretKey::from_slice(b"self1234self1234self1234self1234"), + Ed25519SecretKey::from_slice(b"user1234user1234user1234user1234"), + ) + } + + trait KeyQueryResponseTemplateExt { + fn with_dehydrated_device( + self, + device_id: &DeviceId, + verified: bool, + ) -> KeyQueryResponseTemplate; + } + + impl KeyQueryResponseTemplateExt for KeyQueryResponseTemplate { + /// Add a dehydrated device to the KeyQueryResponseTemplate + fn with_dehydrated_device( + self, + device_id: &DeviceId, + verified: bool, + ) -> KeyQueryResponseTemplate { + self.with_device( + device_id, + &Curve25519PublicKey::from(b"curvepubcurvepubcurvepubcurvepub".to_owned()), + &Ed25519SecretKey::from_slice(b"device12device12device12device12"), + KeyQueryResponseTemplateDeviceOptions::new() + .dehydrated(true) + .verified(verified), + ) + } + } + } + #[async_test] async fn test_share_with_identity_strategy() { let machine = test_machine().await; diff --git a/crates/matrix-sdk-crypto/src/session_manager/group_sessions/snapshots/matrix_sdk_crypto__session_manager__group_sessions__share_strategy__tests__dehydrated_device__prepare_machine_with_dehydrated_device_of_verification_violation_user.snap b/crates/matrix-sdk-crypto/src/session_manager/group_sessions/snapshots/matrix_sdk_crypto__session_manager__group_sessions__share_strategy__tests__dehydrated_device__prepare_machine_with_dehydrated_device_of_verification_violation_user.snap new file mode 100644 index 00000000000..5eed92a5f5f --- /dev/null +++ b/crates/matrix-sdk-crypto/src/session_manager/group_sessions/snapshots/matrix_sdk_crypto__session_manager__group_sessions__share_strategy__tests__dehydrated_device__prepare_machine_with_dehydrated_device_of_verification_violation_user.snap @@ -0,0 +1,77 @@ +--- +source: crates/matrix-sdk-crypto/src/session_manager/group_sessions/share_strategy.rs +expression: ruma_response_to_json(keys_query.clone()) +--- +{ + "device_keys": { + "@bob:localhost": { + "DEHYDRATED_DEVICE": { + "algorithms": [ + "m.olm.v1.curve25519-aes-sha2", + "m.megolm.v1.aes-sha2" + ], + "dehydrated": true, + "device_id": "DEHYDRATED_DEVICE", + "keys": { + "curve25519:DEHYDRATED_DEVICE": "Y3VydmVwdWJjdXJ2ZXB1YmN1cnZlcHViY3VydmVwdWI", + "ed25519:DEHYDRATED_DEVICE": "aXceGe19ufgBArmAjKeIPEEk0eaA4c3yIB6WjkjvYNE" + }, + "signatures": { + "@bob:localhost": { + "ed25519:DEHYDRATED_DEVICE": "7diDwtxcBHi6gu3fxy3Yau0vtUrvW9r5gBPUQO6qmuOSGfZCJkqhATmruPd7bCu1N5xRCZOd4bEhM/j/yY1vBQ", + "ed25519:hpK1owolWNIVv/CIximGep0a1dYwHWyhkdJ/t6flFeU": "lU1441xv6W4WY1d7trmRbdagAcoWwBrwR8D8Lr4VrWn8V0mlL8qSf/zJQ+nh12WcD3NRTEZ6H7rm6ncaBxbKDQ" + } + }, + "user_id": "@bob:localhost" + } + } + }, + "master_keys": { + "@bob:localhost": { + "keys": { + "ed25519:QK24BHjZnsDxe8rfCBHieNRG3MDNCcCMjBNhKCfNuC0": "QK24BHjZnsDxe8rfCBHieNRG3MDNCcCMjBNhKCfNuC0" + }, + "signatures": { + "@bob:localhost": { + "ed25519:QK24BHjZnsDxe8rfCBHieNRG3MDNCcCMjBNhKCfNuC0": "MalGqUfgScuZcEzFyBaJV0nXP6cBGaDz6LZtwrWmvAtfn3uDVatym+CX+YkKZmflog7XJogdeYtHuyn733tWBA" + } + }, + "usage": [ + "master" + ], + "user_id": "@bob:localhost" + } + }, + "self_signing_keys": { + "@bob:localhost": { + "keys": { + "ed25519:hpK1owolWNIVv/CIximGep0a1dYwHWyhkdJ/t6flFeU": "hpK1owolWNIVv/CIximGep0a1dYwHWyhkdJ/t6flFeU" + }, + "signatures": { + "@bob:localhost": { + "ed25519:QK24BHjZnsDxe8rfCBHieNRG3MDNCcCMjBNhKCfNuC0": "h1sADa7kifsHyzGc0ZTGckzjEE15s2YVR9Tz6pdyOWoHJUUcOjBDz6aGNbDarcs/OY49rF3nNXUMsRXEW6ZCBA" + } + }, + "usage": [ + "self_signing" + ], + "user_id": "@bob:localhost" + } + }, + "user_signing_keys": { + "@bob:localhost": { + "keys": { + "ed25519:AXFeCsS+P7TpZOkiYvzjMvO1+K6q3Ljf5CHRY3e19MM": "AXFeCsS+P7TpZOkiYvzjMvO1+K6q3Ljf5CHRY3e19MM" + }, + "signatures": { + "@bob:localhost": { + "ed25519:QK24BHjZnsDxe8rfCBHieNRG3MDNCcCMjBNhKCfNuC0": "gIfvMruwAbB7l7893w6bR/2dqTGTFM4qfSYWZWJ/i981zZYfTQv+8h91URCMhviKXQlelnVnMRrP6osssS8NAA" + } + }, + "usage": [ + "user_signing" + ], + "user_id": "@bob:localhost" + } + } +} diff --git a/crates/matrix-sdk-crypto/src/session_manager/group_sessions/snapshots/matrix_sdk_crypto__session_manager__group_sessions__share_strategy__tests__dehydrated_device__should_not_share_with_unverified_dehydrated_device.snap b/crates/matrix-sdk-crypto/src/session_manager/group_sessions/snapshots/matrix_sdk_crypto__session_manager__group_sessions__share_strategy__tests__dehydrated_device__should_not_share_with_unverified_dehydrated_device.snap new file mode 100644 index 00000000000..7fbb6b8061c --- /dev/null +++ b/crates/matrix-sdk-crypto/src/session_manager/group_sessions/snapshots/matrix_sdk_crypto__session_manager__group_sessions__share_strategy__tests__dehydrated_device__should_not_share_with_unverified_dehydrated_device.snap @@ -0,0 +1,76 @@ +--- +source: crates/matrix-sdk-crypto/src/session_manager/group_sessions/share_strategy.rs +expression: ruma_response_to_json(keys_query.clone()) +--- +{ + "device_keys": { + "@bob:localhost": { + "DEHYDRATED_DEVICE": { + "algorithms": [ + "m.olm.v1.curve25519-aes-sha2", + "m.megolm.v1.aes-sha2" + ], + "dehydrated": true, + "device_id": "DEHYDRATED_DEVICE", + "keys": { + "curve25519:DEHYDRATED_DEVICE": "Y3VydmVwdWJjdXJ2ZXB1YmN1cnZlcHViY3VydmVwdWI", + "ed25519:DEHYDRATED_DEVICE": "aXceGe19ufgBArmAjKeIPEEk0eaA4c3yIB6WjkjvYNE" + }, + "signatures": { + "@bob:localhost": { + "ed25519:DEHYDRATED_DEVICE": "7diDwtxcBHi6gu3fxy3Yau0vtUrvW9r5gBPUQO6qmuOSGfZCJkqhATmruPd7bCu1N5xRCZOd4bEhM/j/yY1vBQ" + } + }, + "user_id": "@bob:localhost" + } + } + }, + "master_keys": { + "@bob:localhost": { + "keys": { + "ed25519:B2W5RIPXTnKtRhFATxcvrKzIOWVstpdNLkf2uOQNBOY": "B2W5RIPXTnKtRhFATxcvrKzIOWVstpdNLkf2uOQNBOY" + }, + "signatures": { + "@bob:localhost": { + "ed25519:B2W5RIPXTnKtRhFATxcvrKzIOWVstpdNLkf2uOQNBOY": "vgFiLvyxYeiVxhpMV81Z4HTvjRhgmZgWn1ScnsLC+HojFwXckA6+/Aa9L/+sA1hzapNZJ4Vrbstl9c4Ep4nbAA" + } + }, + "usage": [ + "master" + ], + "user_id": "@bob:localhost" + } + }, + "self_signing_keys": { + "@bob:localhost": { + "keys": { + "ed25519:hpK1owolWNIVv/CIximGep0a1dYwHWyhkdJ/t6flFeU": "hpK1owolWNIVv/CIximGep0a1dYwHWyhkdJ/t6flFeU" + }, + "signatures": { + "@bob:localhost": { + "ed25519:B2W5RIPXTnKtRhFATxcvrKzIOWVstpdNLkf2uOQNBOY": "xQhtPoTJilhxKrruKAhrpQ1MJFKsCPh77R2WUrWHIB5Mi4sPbxpeU1MZvV/jCCfHrZ5ID40PG2EcEAPtPLYgAQ" + } + }, + "usage": [ + "self_signing" + ], + "user_id": "@bob:localhost" + } + }, + "user_signing_keys": { + "@bob:localhost": { + "keys": { + "ed25519:AXFeCsS+P7TpZOkiYvzjMvO1+K6q3Ljf5CHRY3e19MM": "AXFeCsS+P7TpZOkiYvzjMvO1+K6q3Ljf5CHRY3e19MM" + }, + "signatures": { + "@bob:localhost": { + "ed25519:B2W5RIPXTnKtRhFATxcvrKzIOWVstpdNLkf2uOQNBOY": "d9lPdE5nqpl1euENWderCnPJRTClAcH11JMAIlKiPIWObL19U26zxuchBMEgVR4U7UN55ykDiWtPUlDCC7yvAg" + } + }, + "usage": [ + "user_signing" + ], + "user_id": "@bob:localhost" + } + } +} diff --git a/crates/matrix-sdk-crypto/src/session_manager/group_sessions/snapshots/matrix_sdk_crypto__session_manager__group_sessions__share_strategy__tests__dehydrated_device__should_share_with_verified_dehydrated_device.snap b/crates/matrix-sdk-crypto/src/session_manager/group_sessions/snapshots/matrix_sdk_crypto__session_manager__group_sessions__share_strategy__tests__dehydrated_device__should_share_with_verified_dehydrated_device.snap new file mode 100644 index 00000000000..2b54d5200a4 --- /dev/null +++ b/crates/matrix-sdk-crypto/src/session_manager/group_sessions/snapshots/matrix_sdk_crypto__session_manager__group_sessions__share_strategy__tests__dehydrated_device__should_share_with_verified_dehydrated_device.snap @@ -0,0 +1,77 @@ +--- +source: crates/matrix-sdk-crypto/src/session_manager/group_sessions/share_strategy.rs +expression: ruma_response_to_json(keys_query.clone()) +--- +{ + "device_keys": { + "@bob:localhost": { + "DEHYDRATED_DEVICE": { + "algorithms": [ + "m.olm.v1.curve25519-aes-sha2", + "m.megolm.v1.aes-sha2" + ], + "dehydrated": true, + "device_id": "DEHYDRATED_DEVICE", + "keys": { + "curve25519:DEHYDRATED_DEVICE": "Y3VydmVwdWJjdXJ2ZXB1YmN1cnZlcHViY3VydmVwdWI", + "ed25519:DEHYDRATED_DEVICE": "aXceGe19ufgBArmAjKeIPEEk0eaA4c3yIB6WjkjvYNE" + }, + "signatures": { + "@bob:localhost": { + "ed25519:DEHYDRATED_DEVICE": "7diDwtxcBHi6gu3fxy3Yau0vtUrvW9r5gBPUQO6qmuOSGfZCJkqhATmruPd7bCu1N5xRCZOd4bEhM/j/yY1vBQ", + "ed25519:hpK1owolWNIVv/CIximGep0a1dYwHWyhkdJ/t6flFeU": "lU1441xv6W4WY1d7trmRbdagAcoWwBrwR8D8Lr4VrWn8V0mlL8qSf/zJQ+nh12WcD3NRTEZ6H7rm6ncaBxbKDQ" + } + }, + "user_id": "@bob:localhost" + } + } + }, + "master_keys": { + "@bob:localhost": { + "keys": { + "ed25519:B2W5RIPXTnKtRhFATxcvrKzIOWVstpdNLkf2uOQNBOY": "B2W5RIPXTnKtRhFATxcvrKzIOWVstpdNLkf2uOQNBOY" + }, + "signatures": { + "@bob:localhost": { + "ed25519:B2W5RIPXTnKtRhFATxcvrKzIOWVstpdNLkf2uOQNBOY": "vgFiLvyxYeiVxhpMV81Z4HTvjRhgmZgWn1ScnsLC+HojFwXckA6+/Aa9L/+sA1hzapNZJ4Vrbstl9c4Ep4nbAA" + } + }, + "usage": [ + "master" + ], + "user_id": "@bob:localhost" + } + }, + "self_signing_keys": { + "@bob:localhost": { + "keys": { + "ed25519:hpK1owolWNIVv/CIximGep0a1dYwHWyhkdJ/t6flFeU": "hpK1owolWNIVv/CIximGep0a1dYwHWyhkdJ/t6flFeU" + }, + "signatures": { + "@bob:localhost": { + "ed25519:B2W5RIPXTnKtRhFATxcvrKzIOWVstpdNLkf2uOQNBOY": "xQhtPoTJilhxKrruKAhrpQ1MJFKsCPh77R2WUrWHIB5Mi4sPbxpeU1MZvV/jCCfHrZ5ID40PG2EcEAPtPLYgAQ" + } + }, + "usage": [ + "self_signing" + ], + "user_id": "@bob:localhost" + } + }, + "user_signing_keys": { + "@bob:localhost": { + "keys": { + "ed25519:AXFeCsS+P7TpZOkiYvzjMvO1+K6q3Ljf5CHRY3e19MM": "AXFeCsS+P7TpZOkiYvzjMvO1+K6q3Ljf5CHRY3e19MM" + }, + "signatures": { + "@bob:localhost": { + "ed25519:B2W5RIPXTnKtRhFATxcvrKzIOWVstpdNLkf2uOQNBOY": "d9lPdE5nqpl1euENWderCnPJRTClAcH11JMAIlKiPIWObL19U26zxuchBMEgVR4U7UN55ykDiWtPUlDCC7yvAg" + } + }, + "usage": [ + "user_signing" + ], + "user_id": "@bob:localhost" + } + } +} diff --git a/crates/matrix-sdk-crypto/src/session_manager/group_sessions/snapshots/matrix_sdk_crypto__session_manager__group_sessions__share_strategy__tests__dehydrated_device__should_share_with_verified_device_of_pin_violation_user.snap b/crates/matrix-sdk-crypto/src/session_manager/group_sessions/snapshots/matrix_sdk_crypto__session_manager__group_sessions__share_strategy__tests__dehydrated_device__should_share_with_verified_device_of_pin_violation_user.snap new file mode 100644 index 00000000000..5eed92a5f5f --- /dev/null +++ b/crates/matrix-sdk-crypto/src/session_manager/group_sessions/snapshots/matrix_sdk_crypto__session_manager__group_sessions__share_strategy__tests__dehydrated_device__should_share_with_verified_device_of_pin_violation_user.snap @@ -0,0 +1,77 @@ +--- +source: crates/matrix-sdk-crypto/src/session_manager/group_sessions/share_strategy.rs +expression: ruma_response_to_json(keys_query.clone()) +--- +{ + "device_keys": { + "@bob:localhost": { + "DEHYDRATED_DEVICE": { + "algorithms": [ + "m.olm.v1.curve25519-aes-sha2", + "m.megolm.v1.aes-sha2" + ], + "dehydrated": true, + "device_id": "DEHYDRATED_DEVICE", + "keys": { + "curve25519:DEHYDRATED_DEVICE": "Y3VydmVwdWJjdXJ2ZXB1YmN1cnZlcHViY3VydmVwdWI", + "ed25519:DEHYDRATED_DEVICE": "aXceGe19ufgBArmAjKeIPEEk0eaA4c3yIB6WjkjvYNE" + }, + "signatures": { + "@bob:localhost": { + "ed25519:DEHYDRATED_DEVICE": "7diDwtxcBHi6gu3fxy3Yau0vtUrvW9r5gBPUQO6qmuOSGfZCJkqhATmruPd7bCu1N5xRCZOd4bEhM/j/yY1vBQ", + "ed25519:hpK1owolWNIVv/CIximGep0a1dYwHWyhkdJ/t6flFeU": "lU1441xv6W4WY1d7trmRbdagAcoWwBrwR8D8Lr4VrWn8V0mlL8qSf/zJQ+nh12WcD3NRTEZ6H7rm6ncaBxbKDQ" + } + }, + "user_id": "@bob:localhost" + } + } + }, + "master_keys": { + "@bob:localhost": { + "keys": { + "ed25519:QK24BHjZnsDxe8rfCBHieNRG3MDNCcCMjBNhKCfNuC0": "QK24BHjZnsDxe8rfCBHieNRG3MDNCcCMjBNhKCfNuC0" + }, + "signatures": { + "@bob:localhost": { + "ed25519:QK24BHjZnsDxe8rfCBHieNRG3MDNCcCMjBNhKCfNuC0": "MalGqUfgScuZcEzFyBaJV0nXP6cBGaDz6LZtwrWmvAtfn3uDVatym+CX+YkKZmflog7XJogdeYtHuyn733tWBA" + } + }, + "usage": [ + "master" + ], + "user_id": "@bob:localhost" + } + }, + "self_signing_keys": { + "@bob:localhost": { + "keys": { + "ed25519:hpK1owolWNIVv/CIximGep0a1dYwHWyhkdJ/t6flFeU": "hpK1owolWNIVv/CIximGep0a1dYwHWyhkdJ/t6flFeU" + }, + "signatures": { + "@bob:localhost": { + "ed25519:QK24BHjZnsDxe8rfCBHieNRG3MDNCcCMjBNhKCfNuC0": "h1sADa7kifsHyzGc0ZTGckzjEE15s2YVR9Tz6pdyOWoHJUUcOjBDz6aGNbDarcs/OY49rF3nNXUMsRXEW6ZCBA" + } + }, + "usage": [ + "self_signing" + ], + "user_id": "@bob:localhost" + } + }, + "user_signing_keys": { + "@bob:localhost": { + "keys": { + "ed25519:AXFeCsS+P7TpZOkiYvzjMvO1+K6q3Ljf5CHRY3e19MM": "AXFeCsS+P7TpZOkiYvzjMvO1+K6q3Ljf5CHRY3e19MM" + }, + "signatures": { + "@bob:localhost": { + "ed25519:QK24BHjZnsDxe8rfCBHieNRG3MDNCcCMjBNhKCfNuC0": "gIfvMruwAbB7l7893w6bR/2dqTGTFM4qfSYWZWJ/i981zZYfTQv+8h91URCMhviKXQlelnVnMRrP6osssS8NAA" + } + }, + "usage": [ + "user_signing" + ], + "user_id": "@bob:localhost" + } + } +}