From 001dcf628e2199da0c0debbc3fe0469113a8179c 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 | 378 +++++++++++++++++- ...are_with_unverified_dehydrated_device.snap | 76 ++++ ...verified_device_of_pin_violation_user.snap | 77 ++++ ...share_with_verified_dehydrated_device.snap | 77 ++++ ...verified_device_of_pin_violation_user.snap | 77 ++++ ...share_with_verified_dehydrated_device.snap | 77 ++++ 7 files changed, 750 insertions(+), 19 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__device_based_strategy_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__device_based_strategy_should_not_share_with_verified_device_of_pin_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__device_based_strategy_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__identity_based_strategy_should_not_share_with_verified_device_of_pin_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__identity_based_strategy_should_share_with_verified_dehydrated_device.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 d1b701fc334..017ae508df9 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 @@ -18,6 +18,7 @@ use std::{ ops::Deref, }; +use as_variant::as_variant; use itertools::{Either, Itertools}; use matrix_sdk_common::deserialized_responses::WithheldCode; use ruma::{DeviceId, OwnedDeviceId, OwnedUserId, UserId}; @@ -160,15 +161,7 @@ pub(crate) async fn collect_session_recipients( for user_id in users { trace!("Considering recipient devices for user {}", user_id); let user_devices = store.get_device_data_for_user_filtered(user_id).await?; - - // We only need the user identity if `only_allow_trusted_devices` or - // `error_on_verified_user_problem` is set. - let device_owner_identity = - if only_allow_trusted_devices || error_on_verified_user_problem { - store.get_user_identity(user_id).await? - } else { - None - }; + let device_owner_identity = store.get_user_identity(user_id).await?; if error_on_verified_user_problem && has_identity_verification_violation( @@ -406,27 +399,88 @@ fn split_devices_for_user( for d in user_devices.into_values() { if d.is_blacklisted() { recipient_devices.denied_devices_with_code.push((d, WithheldCode::Blacklisted)); - } else if d.local_trust_state() == LocalTrust::Ignored { + continue; + } + + if d.local_trust_state() == LocalTrust::Ignored { // Ignore the trust state of that device and share recipient_devices.allowed_devices.push(d); - } else if only_allow_trusted_devices && !d.is_verified(own_identity, device_owner_identity) - { + continue; + } + + if only_allow_trusted_devices && !d.is_verified(own_identity, device_owner_identity) { recipient_devices.denied_devices_with_code.push((d, WithheldCode::Unverified)); - } else if error_on_verified_user_problem + continue; + } + + // If `error_on_verified_user_problem` is set, and the user is verified, but the + // device is not signed, we fail the request by adding an entry to + // `unsigned_of_verified_user`. + if error_on_verified_user_problem && is_unsigned_device_of_verified_user( own_identity.as_ref(), device_owner_identity.as_ref(), &d, ) { - recipient_devices.unsigned_of_verified_user.push(d) - } else { - recipient_devices.allowed_devices.push(d); + recipient_devices.unsigned_of_verified_user.push(d); + continue; } + + // If the device is dehydrated, it must be signed by the user, even if that user + // is not verified; further, that user must not have a pinning or identity + // violation. + if d.is_dehydrated() + && should_withhold_to_verified_device( + own_identity.as_ref(), + device_owner_identity.as_ref(), + &d, + ) + { + recipient_devices.denied_devices_with_code.push((d, WithheldCode::Unverified)); + continue; + } + + recipient_devices.allowed_devices.push(d); } recipient_devices } +fn should_withhold_to_verified_device( + own_identity: Option<&OwnUserIdentityData>, + device_owner_identity: Option<&UserIdentityData>, + d: &DeviceData, +) -> bool { + let Some(owner_id) = device_owner_identity else { + // Dehydrated devices must be signed by their owners, and if we don't have the + // owner's identity, that can't be the case. + return true; + }; + + // If the user has changed identity since we first saw them, withhold. + // + // A pin violation is not well-defined for our own user, and in any case, there + // is no need to check it: such a failure will result in a verification + // violation. + if let UserIdentityData::Other(other) = owner_id { + if other.has_pin_violation() { + return true; + } + } + + // If the user has changed identity since we verified them, withhold the message + if owner_id.was_previously_verified() && !is_user_verified(own_identity, owner_id) { + return true; + } + + // Dehydrated devices must be signed by their owners + if !d.is_cross_signed_by_owner(owner_id) { + return true; + } + + false +} + /// Result type for [`split_recipients_withhelds_for_user_based_on_identity`]. #[derive(Default)] struct IdentityBasedRecipientDevices { @@ -453,12 +507,23 @@ fn split_recipients_withhelds_for_user_based_on_identity( } } Some(device_owner_identity) => { - // Only accept devices signed by the current identity let (recipients, withheld_recipients): ( Vec, Vec<(DeviceData, WithheldCode)>, ) = user_devices.into_values().partition_map(|d| { - if d.is_cross_signed_by_owner(device_owner_identity) { + // If the device is dehydrated, that user must not have a pin violation. + // + // A pin violation is not well-defined for our own user, and in any case, there + // is no need to check it: such a failure will result in a verification + // violation, so we will not get this far. + if d.is_dehydrated() + && as_variant!(device_owner_identity, UserIdentityData::Other) + .is_some_and(|other| other.has_pin_violation()) + { + Either::Right((d, WithheldCode::Unverified)) + } + // Only accept devices signed by the current identity + else if d.is_cross_signed_by_owner(device_owner_identity) { Either::Left(d) } else { Either::Right((d, WithheldCode::Unverified)) @@ -1083,6 +1148,283 @@ 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::{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::{ + KeyQueryResponseTemplate, KeyQueryResponseTemplateDeviceOptions, + }, + }; + use ruma::{device_id, user_id, DeviceId, TransactionId, UserId}; + use vodozemac::{Curve25519PublicKey, Ed25519SecretKey}; + + use super::{ + create_test_outbound_group_session, device_based_strategy_settings, + identity_based_settings, test_machine, + }; + use crate::{ + session_manager::group_sessions::{ + share_strategy::collect_session_recipients, CollectRecipientsResult, + }, + EncryptionSettings, OlmMachine, + }; + + #[async_test] + async fn test_device_based_strategy_should_share_with_verified_dehydrated_device() { + 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(); + 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, + &device_based_strategy_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_device_based_strategy_should_not_share_with_unverified_dehydrated_device() { + 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(); + 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, + &device_based_strategy_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_device_based_strategy_should_not_share_with_verified_device_of_pin_violation_user( + ) { + 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(); + 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, + &device_based_strategy_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_identity_based_strategy_should_share_with_verified_dehydrated_device() { + 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(); + 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, + &identity_based_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_identity_based_strategy_should_not_share_with_verified_device_of_pin_violation_user( + ) { + 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(); + 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, + &identity_based_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); + } + + /// 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. + fn assert_shared_with( + recips: CollectRecipientsResult, + user_id: &UserId, + device_ids: HashSet<&DeviceId>, + ) { + let bob_devices_shared: HashSet<_> = recips + .devices + .get(user_id) + .expect(&format!("session not shared with {user_id}")) + .iter() + .map(|d| d.device_id()) + .collect(); + assert_eq!(bob_devices_shared, device_ids); + } + + /// 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".clone()), + &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__device_based_strategy_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__device_based_strategy_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__device_based_strategy_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__device_based_strategy_should_not_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__device_based_strategy_should_not_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__device_based_strategy_should_not_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" + } + } +} 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__device_based_strategy_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__device_based_strategy_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__device_based_strategy_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__identity_based_strategy_should_not_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__identity_based_strategy_should_not_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__identity_based_strategy_should_not_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" + } + } +} 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__identity_based_strategy_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__identity_based_strategy_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__identity_based_strategy_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" + } + } +}