1use std::{
16 collections::{BTreeMap, BTreeSet, HashMap},
17 default::Default,
18};
19
20use itertools::{Either, Itertools};
21use matrix_sdk_common::deserialized_responses::WithheldCode;
22use ruma::{DeviceId, OwnedDeviceId, OwnedUserId, UserId};
23use serde::{Deserialize, Serialize};
24use tracing::{debug, instrument, trace};
25
26use super::OutboundGroupSession;
27#[cfg(feature = "experimental-x509-identity-verification")]
28use crate::x509::X509Verifier;
29#[cfg(doc)]
30use crate::{Device, UserIdentity};
31use crate::{
32 DeviceData, EncryptionSettings, LocalTrust, OlmError, OwnUserIdentityData, UserIdentityData,
33 error::{OlmResult, SessionRecipientCollectionError},
34 olm::ShareInfo,
35 store::Store,
36};
37
38#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
41#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
42#[serde(from = "CollectStrategyDeserializationHelper")]
43pub enum CollectStrategy {
44 #[default]
53 AllDevices,
54
55 ErrorOnVerifiedUserProblem,
74
75 IdentityBasedStrategy,
87
88 OnlyTrustedDevices,
104}
105
106impl CollectStrategy {
107 pub const fn new_identity_based() -> Self {
109 CollectStrategy::IdentityBasedStrategy
110 }
111}
112
113#[derive(Deserialize)]
115enum CollectStrategyDeserializationHelper {
116 DeviceBasedStrategy {
119 #[serde(default)]
120 error_on_verified_user_problem: bool,
121
122 #[serde(default)]
123 only_allow_trusted_devices: bool,
124 },
125
126 AllDevices,
127 ErrorOnVerifiedUserProblem,
128 IdentityBasedStrategy,
129 OnlyTrustedDevices,
130}
131
132impl From<CollectStrategyDeserializationHelper> for CollectStrategy {
133 fn from(value: CollectStrategyDeserializationHelper) -> Self {
134 use CollectStrategyDeserializationHelper::*;
135
136 match value {
137 DeviceBasedStrategy {
138 only_allow_trusted_devices: true,
139 error_on_verified_user_problem: _,
140 } => CollectStrategy::OnlyTrustedDevices,
141 DeviceBasedStrategy {
142 only_allow_trusted_devices: false,
143 error_on_verified_user_problem: true,
144 } => CollectStrategy::ErrorOnVerifiedUserProblem,
145 DeviceBasedStrategy {
146 only_allow_trusted_devices: false,
147 error_on_verified_user_problem: false,
148 } => CollectStrategy::AllDevices,
149
150 AllDevices => CollectStrategy::AllDevices,
151 ErrorOnVerifiedUserProblem => CollectStrategy::ErrorOnVerifiedUserProblem,
152 IdentityBasedStrategy => CollectStrategy::IdentityBasedStrategy,
153 OnlyTrustedDevices => CollectStrategy::OnlyTrustedDevices,
154 }
155 }
156}
157
158#[derive(Debug, Default)]
165pub(crate) struct CollectRecipientsResult {
166 pub should_rotate: bool,
168 pub devices: BTreeMap<OwnedUserId, Vec<DeviceData>>,
170 pub withheld_devices: Vec<(DeviceData, WithheldCode)>,
173}
174
175#[instrument(skip_all)]
182pub(crate) async fn collect_session_recipients(
183 store: &Store,
184 users: impl Iterator<Item = &UserId>,
185 settings: &EncryptionSettings,
186 outbound: &OutboundGroupSession,
187) -> OlmResult<CollectRecipientsResult> {
188 let mut result = collect_recipients_for_share_strategy(
189 store,
190 users,
191 &settings.sharing_strategy,
192 Some(outbound),
193 )
194 .await?;
195
196 let device_removed = result.should_rotate;
206
207 let visibility_changed = outbound.settings().history_visibility != settings.history_visibility;
208 let algorithm_changed = outbound.settings().algorithm != settings.algorithm;
209
210 result.should_rotate = device_removed || visibility_changed || algorithm_changed;
211
212 if result.should_rotate {
213 debug!(
214 device_removed,
215 visibility_changed, algorithm_changed, "Rotating room key to protect room history",
216 );
217 }
218
219 Ok(result)
220}
221
222pub(crate) async fn collect_recipients_for_share_strategy(
232 store: &Store,
233 users: impl Iterator<Item = &UserId>,
234 share_strategy: &CollectStrategy,
235 outbound: Option<&OutboundGroupSession>,
236) -> OlmResult<CollectRecipientsResult> {
237 let users: BTreeSet<&UserId> = users.collect();
238 trace!(?users, ?share_strategy, "Calculating group session recipients");
239
240 let mut result = CollectRecipientsResult::default();
241 let mut verified_users_with_new_identities: Vec<OwnedUserId> = Default::default();
242
243 if let Some(outbound) = outbound {
247 let view = outbound.sharing_view();
248 let users_shared_with = view.shared_with_users().collect::<BTreeSet<_>>();
249 let left_users = users_shared_with.difference(&users).collect::<BTreeSet<_>>();
250 if !left_users.is_empty() {
251 trace!(?left_users, "Some users have left the chat: session must be rotated");
252 result.should_rotate = true;
253 }
254 }
255
256 let own_identity = store.get_user_identity(store.user_id()).await?.and_then(|i| i.into_own());
257
258 match share_strategy {
260 CollectStrategy::AllDevices => {
261 for user_id in users {
262 trace!(?user_id, "CollectStrategy::AllDevices: Considering recipient devices",);
263 let user_devices = store.get_device_data_for_user_filtered(user_id).await?;
264 let device_owner_identity = store.get_user_identity(user_id).await?;
265
266 let recipient_devices = split_devices_for_user_for_all_devices_strategy(
267 user_devices,
268 &own_identity,
269 &device_owner_identity,
270 #[cfg(feature = "experimental-x509-identity-verification")]
271 store.x509_verifier(),
272 );
273 update_recipients_for_user(&mut result, outbound, user_id, recipient_devices);
274 }
275 }
276 CollectStrategy::ErrorOnVerifiedUserProblem => {
277 let mut unsigned_devices_of_verified_users: BTreeMap<OwnedUserId, Vec<OwnedDeviceId>> =
278 Default::default();
279
280 for user_id in users {
281 trace!(
282 ?user_id,
283 "CollectStrategy::ErrorOnVerifiedUserProblem: Considering recipient devices"
284 );
285 let user_devices = store.get_device_data_for_user_filtered(user_id).await?;
286
287 let device_owner_identity = store.get_user_identity(user_id).await?;
288
289 if has_identity_verification_violation(
290 own_identity.as_ref(),
291 device_owner_identity.as_ref(),
292 #[cfg(feature = "experimental-x509-identity-verification")]
293 store.x509_verifier(),
294 ) {
295 verified_users_with_new_identities.push(user_id.to_owned());
296 continue;
298 }
299
300 let recipient_devices =
301 split_devices_for_user_for_error_on_verified_user_problem_strategy(
302 user_devices,
303 &own_identity,
304 &device_owner_identity,
305 #[cfg(feature = "experimental-x509-identity-verification")]
306 store.x509_verifier(),
307 );
308
309 match recipient_devices {
310 ErrorOnVerifiedUserProblemResult::UnsignedDevicesOfVerifiedUser(devices) => {
311 unsigned_devices_of_verified_users.insert(user_id.to_owned(), devices);
312 }
313 ErrorOnVerifiedUserProblemResult::Devices(recipient_devices) => {
314 update_recipients_for_user(
315 &mut result,
316 outbound,
317 user_id,
318 recipient_devices,
319 );
320 }
321 }
322 }
323
324 if !unsigned_devices_of_verified_users.is_empty() {
328 return Err(OlmError::SessionRecipientCollectionError(
329 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
330 unsigned_devices_of_verified_users,
331 ),
332 ));
333 }
334 }
335 CollectStrategy::IdentityBasedStrategy => {
336 match &own_identity {
339 None => {
340 return Err(OlmError::SessionRecipientCollectionError(
341 SessionRecipientCollectionError::CrossSigningNotSetup,
342 ));
343 }
344 Some(identity) if !identity.is_verified() => {
345 return Err(OlmError::SessionRecipientCollectionError(
346 SessionRecipientCollectionError::SendingFromUnverifiedDevice,
347 ));
348 }
349 Some(_) => (),
350 }
351
352 for user_id in users {
353 trace!(
354 ?user_id,
355 "CollectStrategy::IdentityBasedStrategy: Considering recipient devices"
356 );
357 let user_devices = store.get_device_data_for_user_filtered(user_id).await?;
358
359 let device_owner_identity = store.get_user_identity(user_id).await?;
360
361 if has_identity_verification_violation(
362 own_identity.as_ref(),
363 device_owner_identity.as_ref(),
364 #[cfg(feature = "experimental-x509-identity-verification")]
365 store.x509_verifier(),
366 ) {
367 verified_users_with_new_identities.push(user_id.to_owned());
368 continue;
370 }
371
372 let recipient_devices = split_devices_for_user_for_identity_based_strategy(
373 user_devices,
374 &device_owner_identity,
375 );
376
377 update_recipients_for_user(&mut result, outbound, user_id, recipient_devices);
378 }
379 }
380
381 CollectStrategy::OnlyTrustedDevices => {
382 for user_id in users {
383 trace!(
384 ?user_id,
385 "CollectStrategy::OnlyTrustedDevices: Considering recipient devices"
386 );
387 let user_devices = store.get_device_data_for_user_filtered(user_id).await?;
388 let device_owner_identity = store.get_user_identity(user_id).await?;
389
390 let recipient_devices = split_devices_for_user_for_only_trusted_devices(
391 user_devices,
392 &own_identity,
393 &device_owner_identity,
394 #[cfg(feature = "experimental-x509-identity-verification")]
395 store.x509_verifier(),
396 );
397
398 update_recipients_for_user(&mut result, outbound, user_id, recipient_devices);
399 }
400 }
401 }
402
403 if !verified_users_with_new_identities.is_empty() {
406 return Err(OlmError::SessionRecipientCollectionError(
407 SessionRecipientCollectionError::VerifiedUserChangedIdentity(
408 verified_users_with_new_identities,
409 ),
410 ));
411 }
412
413 trace!(result.should_rotate, "Done calculating group session recipients");
414
415 Ok(result)
416}
417
418fn update_recipients_for_user(
421 recipients: &mut CollectRecipientsResult,
422 outbound: Option<&OutboundGroupSession>,
423 user_id: &UserId,
424 recipient_devices: RecipientDevicesForUser,
425) {
426 if let Some(outbound) = outbound
431 && !recipients.should_rotate
432 {
433 recipients.should_rotate =
434 is_session_overshared_for_user(outbound, user_id, &recipient_devices.allowed_devices)
435 }
436
437 recipients
438 .devices
439 .entry(user_id.to_owned())
440 .or_default()
441 .extend(recipient_devices.allowed_devices);
442 recipients.withheld_devices.extend(recipient_devices.denied_devices_with_code);
443}
444
445fn is_session_overshared_for_user(
461 outbound_session: &OutboundGroupSession,
462 user_id: &UserId,
463 recipient_devices: &[DeviceData],
464) -> bool {
465 let recipient_device_ids: BTreeSet<&DeviceId> =
467 recipient_devices.iter().map(|d| d.device_id()).collect();
468
469 let view = outbound_session.sharing_view();
470 let newly_deleted_or_blacklisted: BTreeSet<&DeviceId> = view
471 .iter_shares(Some(user_id), None)
472 .filter_map(|(_user_id, device_id, info)| {
473 if matches!(info, ShareInfo::Shared(_)) && !recipient_device_ids.contains(device_id) {
477 Some(device_id)
478 } else {
479 None
480 }
481 })
482 .collect();
483
484 let should_rotate = !newly_deleted_or_blacklisted.is_empty();
485 if should_rotate {
486 debug!(
487 "Rotating a room key due to these devices being deleted/blacklisted {:?}",
488 newly_deleted_or_blacklisted,
489 );
490 }
491 should_rotate
492}
493
494#[cfg(feature = "experimental-send-custom-to-device")]
495pub(crate) async fn split_devices_for_share_strategy(
497 store: &Store,
498 devices: Vec<DeviceData>,
499 share_strategy: CollectStrategy,
500) -> OlmResult<(Vec<DeviceData>, Vec<(DeviceData, WithheldCode)>)> {
501 let own_identity = store.get_user_identity(store.user_id()).await?.and_then(|i| i.into_own());
502
503 let mut verified_users_with_new_identities: BTreeSet<OwnedUserId> = Default::default();
504
505 let mut allowed_devices: Vec<DeviceData> = Default::default();
506 let mut blocked_devices: Vec<(DeviceData, WithheldCode)> = Default::default();
507
508 let mut user_identities_cache: BTreeMap<OwnedUserId, Option<UserIdentityData>> =
509 Default::default();
510 let mut get_user_identity = async move |user_id| -> OlmResult<_> {
511 match user_identities_cache.get(user_id) {
512 Some(user_identity) => Ok(user_identity.clone()),
513 None => {
514 let user_identity = store.get_user_identity(user_id).await?;
515 user_identities_cache.insert(user_id.to_owned(), user_identity.clone());
516 Ok(user_identity)
517 }
518 }
519 };
520
521 match share_strategy {
522 CollectStrategy::AllDevices => {
523 for device in devices.iter() {
524 let user_id = device.user_id();
525 let device_owner_identity = get_user_identity(user_id).await?;
526
527 if let Some(withheld_code) = withheld_code_for_device_for_all_devices_strategy(
528 device,
529 &own_identity,
530 &device_owner_identity,
531 #[cfg(feature = "experimental-x509-identity-verification")]
532 store.x509_verifier(),
533 ) {
534 blocked_devices.push((device.clone(), withheld_code));
535 } else {
536 allowed_devices.push(device.clone());
537 }
538 }
539 }
540
541 CollectStrategy::ErrorOnVerifiedUserProblem => {
542 let mut unsigned_devices_of_verified_users: BTreeMap<OwnedUserId, Vec<OwnedDeviceId>> =
548 Default::default();
549 let mut add_device_to_unsigned_devices_map = |user_id: &UserId, device: &DeviceData| {
550 let device_id = device.device_id().to_owned();
551 if let Some(devices) = unsigned_devices_of_verified_users.get_mut(user_id) {
552 devices.push(device_id);
553 } else {
554 unsigned_devices_of_verified_users.insert(user_id.to_owned(), vec![device_id]);
555 }
556 };
557
558 for device in devices.iter() {
559 let user_id = device.user_id();
560 let device_owner_identity = get_user_identity(user_id).await?;
561
562 if has_identity_verification_violation(
563 own_identity.as_ref(),
564 device_owner_identity.as_ref(),
565 #[cfg(feature = "experimental-x509-identity-verification")]
566 store.x509_verifier(),
567 ) {
568 verified_users_with_new_identities.insert(user_id.to_owned());
569 } else {
570 match handle_device_for_user_for_error_on_verified_user_problem_strategy(
571 device,
572 own_identity.as_ref(),
573 device_owner_identity.as_ref(),
574 #[cfg(feature = "experimental-x509-identity-verification")]
575 store.x509_verifier(),
576 ) {
577 ErrorOnVerifiedUserProblemDeviceDecision::Ok => {
578 allowed_devices.push(device.clone())
579 }
580 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(code) => {
581 blocked_devices.push((device.clone(), code))
582 }
583 ErrorOnVerifiedUserProblemDeviceDecision::UnsignedOfVerified => {
584 add_device_to_unsigned_devices_map(user_id, device);
585 }
586 }
587 }
588 }
589
590 if !unsigned_devices_of_verified_users.is_empty() {
591 return Err(OlmError::SessionRecipientCollectionError(
592 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
593 unsigned_devices_of_verified_users,
594 ),
595 ));
596 }
597 }
598
599 CollectStrategy::IdentityBasedStrategy => {
600 match &own_identity {
603 None => {
604 return Err(OlmError::SessionRecipientCollectionError(
605 SessionRecipientCollectionError::CrossSigningNotSetup,
606 ));
607 }
608 Some(identity) if !identity.is_verified() => {
609 return Err(OlmError::SessionRecipientCollectionError(
610 SessionRecipientCollectionError::SendingFromUnverifiedDevice,
611 ));
612 }
613 Some(_) => (),
614 }
615
616 for device in devices.iter() {
617 let user_id = device.user_id();
618 let device_owner_identity = get_user_identity(user_id).await?;
619
620 if has_identity_verification_violation(
621 own_identity.as_ref(),
622 device_owner_identity.as_ref(),
623 #[cfg(feature = "experimental-x509-identity-verification")]
624 store.x509_verifier(),
625 ) {
626 verified_users_with_new_identities.insert(user_id.to_owned());
627 } else if let Some(device_owner_identity) = device_owner_identity {
628 if let Some(withheld_code) =
629 withheld_code_for_device_with_owner_for_identity_based_strategy(
630 device,
631 &device_owner_identity,
632 )
633 {
634 blocked_devices.push((device.clone(), withheld_code));
635 } else {
636 allowed_devices.push(device.clone());
637 }
638 } else {
639 blocked_devices.push((device.clone(), WithheldCode::Unverified));
642 }
643 }
644 }
645
646 CollectStrategy::OnlyTrustedDevices => {
647 for device in devices.iter() {
648 let user_id = device.user_id();
649 let device_owner_identity = get_user_identity(user_id).await?;
650
651 if let Some(withheld_code) =
652 withheld_code_for_device_for_only_trusted_devices_strategy(
653 device,
654 &own_identity,
655 &device_owner_identity,
656 #[cfg(feature = "experimental-x509-identity-verification")]
657 store.x509_verifier(),
658 )
659 {
660 blocked_devices.push((device.clone(), withheld_code));
661 } else {
662 allowed_devices.push(device.clone());
663 }
664 }
665 }
666 }
667
668 if !verified_users_with_new_identities.is_empty() {
669 return Err(OlmError::SessionRecipientCollectionError(
670 SessionRecipientCollectionError::VerifiedUserChangedIdentity(
671 verified_users_with_new_identities.into_iter().collect(),
672 ),
673 ));
674 }
675
676 Ok((allowed_devices, blocked_devices))
677}
678
679pub(crate) async fn withheld_code_for_device_for_share_strategy(
680 device: &DeviceData,
681 share_strategy: CollectStrategy,
682 own_identity: &Option<OwnUserIdentityData>,
683 device_owner_identity: &Option<UserIdentityData>,
684 #[cfg(feature = "experimental-x509-identity-verification")] x509_verifier: Option<
685 &X509Verifier,
686 >,
687) -> OlmResult<Option<WithheldCode>> {
688 match share_strategy {
689 CollectStrategy::AllDevices => Ok(withheld_code_for_device_for_all_devices_strategy(
690 device,
691 own_identity,
692 device_owner_identity,
693 #[cfg(feature = "experimental-x509-identity-verification")]
694 x509_verifier,
695 )),
696 CollectStrategy::ErrorOnVerifiedUserProblem => {
697 if has_identity_verification_violation(
698 own_identity.as_ref(),
699 device_owner_identity.as_ref(),
700 #[cfg(feature = "experimental-x509-identity-verification")]
701 x509_verifier,
702 ) {
703 return Err(OlmError::SessionRecipientCollectionError(
704 SessionRecipientCollectionError::VerifiedUserChangedIdentity(vec![
705 device.user_id().to_owned(),
706 ]),
707 ));
708 }
709 match handle_device_for_user_for_error_on_verified_user_problem_strategy(
710 device,
711 own_identity.as_ref(),
712 device_owner_identity.as_ref(),
713 #[cfg(feature = "experimental-x509-identity-verification")]
714 x509_verifier,
715 ) {
716 ErrorOnVerifiedUserProblemDeviceDecision::Ok => Ok(None),
717 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(code) => Ok(Some(code)),
718 ErrorOnVerifiedUserProblemDeviceDecision::UnsignedOfVerified => {
719 Err(OlmError::SessionRecipientCollectionError(
720 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
721 BTreeMap::from([(
722 device.user_id().to_owned(),
723 vec![device.device_id().to_owned()],
724 )]),
725 ),
726 ))
727 }
728 }
729 }
730 CollectStrategy::IdentityBasedStrategy => {
731 match &own_identity {
734 None => {
735 return Err(OlmError::SessionRecipientCollectionError(
736 SessionRecipientCollectionError::CrossSigningNotSetup,
737 ));
738 }
739 Some(identity) if !identity.is_verified() => {
740 return Err(OlmError::SessionRecipientCollectionError(
741 SessionRecipientCollectionError::SendingFromUnverifiedDevice,
742 ));
743 }
744 Some(_) => (),
745 }
746
747 if has_identity_verification_violation(
748 own_identity.as_ref(),
749 device_owner_identity.as_ref(),
750 #[cfg(feature = "experimental-x509-identity-verification")]
751 x509_verifier,
752 ) {
753 Err(OlmError::SessionRecipientCollectionError(
754 SessionRecipientCollectionError::VerifiedUserChangedIdentity(vec![
755 device.user_id().to_owned(),
756 ]),
757 ))
758 } else if let Some(device_owner_identity) = device_owner_identity {
759 Ok(withheld_code_for_device_with_owner_for_identity_based_strategy(
760 device,
761 device_owner_identity,
762 ))
763 } else {
764 Ok(Some(WithheldCode::Unverified))
767 }
768 }
769 CollectStrategy::OnlyTrustedDevices => {
770 Ok(withheld_code_for_device_for_only_trusted_devices_strategy(
771 device,
772 own_identity,
773 device_owner_identity,
774 #[cfg(feature = "experimental-x509-identity-verification")]
775 x509_verifier,
776 ))
777 }
778 }
779}
780
781#[derive(Default)]
788struct RecipientDevicesForUser {
789 allowed_devices: Vec<DeviceData>,
791 denied_devices_with_code: Vec<(DeviceData, WithheldCode)>,
793}
794
795enum ErrorOnVerifiedUserProblemResult {
798 UnsignedDevicesOfVerifiedUser(Vec<OwnedDeviceId>),
802
803 Devices(RecipientDevicesForUser),
805}
806
807fn split_devices_for_user_for_all_devices_strategy(
810 user_devices: HashMap<OwnedDeviceId, DeviceData>,
811 own_identity: &Option<OwnUserIdentityData>,
812 device_owner_identity: &Option<UserIdentityData>,
813 #[cfg(feature = "experimental-x509-identity-verification")] x509_verifier: Option<
814 &X509Verifier,
815 >,
816) -> RecipientDevicesForUser {
817 let (left, right) = user_devices.into_values().partition_map(|d| {
818 if let Some(withheld_code) = withheld_code_for_device_for_all_devices_strategy(
819 &d,
820 own_identity,
821 device_owner_identity,
822 #[cfg(feature = "experimental-x509-identity-verification")]
823 x509_verifier,
824 ) {
825 Either::Right((d, withheld_code))
826 } else {
827 Either::Left(d)
828 }
829 });
830
831 RecipientDevicesForUser { allowed_devices: left, denied_devices_with_code: right }
832}
833
834fn withheld_code_for_device_for_all_devices_strategy(
838 device_data: &DeviceData,
839 own_identity: &Option<OwnUserIdentityData>,
840 device_owner_identity: &Option<UserIdentityData>,
841 #[cfg(feature = "experimental-x509-identity-verification")] x509_verifier: Option<
842 &X509Verifier,
843 >,
844) -> Option<WithheldCode> {
845 if device_data.is_blacklisted() {
846 Some(WithheldCode::Blacklisted)
847 } else if device_data.is_dehydrated()
848 && should_withhold_to_dehydrated_device(
849 device_data,
850 own_identity.as_ref(),
851 device_owner_identity.as_ref(),
852 #[cfg(feature = "experimental-x509-identity-verification")]
853 x509_verifier,
854 )
855 {
856 Some(WithheldCode::Unverified)
857 } else {
858 None
859 }
860}
861
862fn should_withhold_to_dehydrated_device(
871 device: &DeviceData,
872 own_identity: Option<&OwnUserIdentityData>,
873 device_owner_identity: Option<&UserIdentityData>,
874 #[cfg(feature = "experimental-x509-identity-verification")] x509_verifier: Option<
875 &X509Verifier,
876 >,
877) -> bool {
878 device_owner_identity.is_none_or(|owner_id| {
879 !device.is_cross_signed_by_owner(owner_id) ||
881
882 (owner_id.was_previously_verified() && !is_user_verified(
884 own_identity,
885 owner_id,
886 #[cfg(feature = "experimental-x509-identity-verification")]
887 x509_verifier,
888 ))
889 })
890}
891
892fn split_devices_for_user_for_error_on_verified_user_problem_strategy(
905 user_devices: HashMap<OwnedDeviceId, DeviceData>,
906 own_identity: &Option<OwnUserIdentityData>,
907 device_owner_identity: &Option<UserIdentityData>,
908 #[cfg(feature = "experimental-x509-identity-verification")] x509_verifier: Option<
909 &X509Verifier,
910 >,
911) -> ErrorOnVerifiedUserProblemResult {
912 let mut recipient_devices = RecipientDevicesForUser::default();
913
914 let mut unsigned_devices_of_verified_users: Option<Vec<OwnedDeviceId>> = None;
917
918 for d in user_devices.into_values() {
919 match handle_device_for_user_for_error_on_verified_user_problem_strategy(
920 &d,
921 own_identity.as_ref(),
922 device_owner_identity.as_ref(),
923 #[cfg(feature = "experimental-x509-identity-verification")]
924 x509_verifier,
925 ) {
926 ErrorOnVerifiedUserProblemDeviceDecision::Ok => {
927 recipient_devices.allowed_devices.push(d)
928 }
929 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(code) => {
930 recipient_devices.denied_devices_with_code.push((d, code))
931 }
932 ErrorOnVerifiedUserProblemDeviceDecision::UnsignedOfVerified => {
933 unsigned_devices_of_verified_users
934 .get_or_insert_with(Vec::default)
935 .push(d.device_id().to_owned())
936 }
937 }
938 }
939
940 if let Some(devices) = unsigned_devices_of_verified_users {
941 ErrorOnVerifiedUserProblemResult::UnsignedDevicesOfVerifiedUser(devices)
942 } else {
943 ErrorOnVerifiedUserProblemResult::Devices(recipient_devices)
944 }
945}
946
947enum ErrorOnVerifiedUserProblemDeviceDecision {
950 Ok,
951 Withhold(WithheldCode),
952 UnsignedOfVerified,
953}
954
955fn handle_device_for_user_for_error_on_verified_user_problem_strategy(
956 device: &DeviceData,
957 own_identity: Option<&OwnUserIdentityData>,
958 device_owner_identity: Option<&UserIdentityData>,
959 #[cfg(feature = "experimental-x509-identity-verification")] x509_verifier: Option<
960 &X509Verifier,
961 >,
962) -> ErrorOnVerifiedUserProblemDeviceDecision {
963 if device.is_blacklisted() {
964 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(WithheldCode::Blacklisted)
965 } else if device.local_trust_state() == LocalTrust::Ignored {
966 ErrorOnVerifiedUserProblemDeviceDecision::Ok
968 } else if is_unsigned_device_of_verified_user(
969 own_identity,
970 device_owner_identity,
971 device,
972 #[cfg(feature = "experimental-x509-identity-verification")]
973 x509_verifier,
974 ) {
975 ErrorOnVerifiedUserProblemDeviceDecision::UnsignedOfVerified
976 } else if device.is_dehydrated()
977 && device_owner_identity.is_none_or(|owner_id| {
978 !device.is_cross_signed_by_owner(owner_id)
981 })
982 {
983 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(WithheldCode::Unverified)
984 } else {
985 ErrorOnVerifiedUserProblemDeviceDecision::Ok
986 }
987}
988
989fn split_devices_for_user_for_identity_based_strategy(
990 user_devices: HashMap<OwnedDeviceId, DeviceData>,
991 device_owner_identity: &Option<UserIdentityData>,
992) -> RecipientDevicesForUser {
993 match device_owner_identity {
994 None => {
995 RecipientDevicesForUser {
998 allowed_devices: Vec::default(),
999 denied_devices_with_code: user_devices
1000 .into_values()
1001 .map(|d| (d, WithheldCode::Unverified))
1002 .collect(),
1003 }
1004 }
1005 Some(device_owner_identity) => {
1006 let (recipients, withheld_recipients): (
1008 Vec<DeviceData>,
1009 Vec<(DeviceData, WithheldCode)>,
1010 ) = user_devices.into_values().partition_map(|d| {
1011 if let Some(withheld_code) =
1012 withheld_code_for_device_with_owner_for_identity_based_strategy(
1013 &d,
1014 device_owner_identity,
1015 )
1016 {
1017 Either::Right((d, withheld_code))
1018 } else {
1019 Either::Left(d)
1020 }
1021 });
1022 RecipientDevicesForUser {
1023 allowed_devices: recipients,
1024 denied_devices_with_code: withheld_recipients,
1025 }
1026 }
1027 }
1028}
1029
1030fn withheld_code_for_device_with_owner_for_identity_based_strategy(
1034 device_data: &DeviceData,
1035 device_owner_identity: &UserIdentityData,
1036) -> Option<WithheldCode> {
1037 if device_data.is_cross_signed_by_owner(device_owner_identity) {
1038 None
1039 } else {
1040 Some(WithheldCode::Unverified)
1041 }
1042}
1043
1044fn split_devices_for_user_for_only_trusted_devices(
1047 user_devices: HashMap<OwnedDeviceId, DeviceData>,
1048 own_identity: &Option<OwnUserIdentityData>,
1049 device_owner_identity: &Option<UserIdentityData>,
1050 #[cfg(feature = "experimental-x509-identity-verification")] x509_verifier: Option<
1051 &X509Verifier,
1052 >,
1053) -> RecipientDevicesForUser {
1054 let (left, right) = user_devices.into_values().partition_map(|d| {
1055 if let Some(withheld_code) = withheld_code_for_device_for_only_trusted_devices_strategy(
1056 &d,
1057 own_identity,
1058 device_owner_identity,
1059 #[cfg(feature = "experimental-x509-identity-verification")]
1060 x509_verifier,
1061 ) {
1062 Either::Right((d, withheld_code))
1063 } else {
1064 Either::Left(d)
1065 }
1066 });
1067 RecipientDevicesForUser { allowed_devices: left, denied_devices_with_code: right }
1068}
1069
1070fn withheld_code_for_device_for_only_trusted_devices_strategy(
1074 device_data: &DeviceData,
1075 own_identity: &Option<OwnUserIdentityData>,
1076 device_owner_identity: &Option<UserIdentityData>,
1077 #[cfg(feature = "experimental-x509-identity-verification")] x509_verifier: Option<
1078 &X509Verifier,
1079 >,
1080) -> Option<WithheldCode> {
1081 match (
1082 device_data.local_trust_state(),
1083 device_data.is_cross_signing_trusted(
1084 own_identity,
1085 device_owner_identity,
1086 #[cfg(feature = "experimental-x509-identity-verification")]
1087 x509_verifier,
1088 ),
1089 ) {
1090 (LocalTrust::BlackListed, _) => Some(WithheldCode::Blacklisted),
1091 (LocalTrust::Ignored | LocalTrust::Verified, _) => None,
1092 (LocalTrust::Unset, false) => Some(WithheldCode::Unverified),
1093 (LocalTrust::Unset, true) => None,
1094 }
1095}
1096
1097fn is_unsigned_device_of_verified_user(
1098 own_identity: Option<&OwnUserIdentityData>,
1099 device_owner_identity: Option<&UserIdentityData>,
1100 device_data: &DeviceData,
1101 #[cfg(feature = "experimental-x509-identity-verification")] x509_verifier: Option<
1102 &X509Verifier,
1103 >,
1104) -> bool {
1105 device_owner_identity.is_some_and(|device_owner_identity| {
1106 is_user_verified(
1107 own_identity,
1108 device_owner_identity,
1109 #[cfg(feature = "experimental-x509-identity-verification")]
1110 x509_verifier,
1111 ) && !device_data.is_cross_signed_by_owner(device_owner_identity)
1112 })
1113}
1114
1115fn has_identity_verification_violation(
1122 own_identity: Option<&OwnUserIdentityData>,
1123 device_owner_identity: Option<&UserIdentityData>,
1124 #[cfg(feature = "experimental-x509-identity-verification")] x509_verifier: Option<
1125 &X509Verifier,
1126 >,
1127) -> bool {
1128 device_owner_identity.is_some_and(|device_owner_identity| {
1129 device_owner_identity.was_previously_verified()
1130 && !is_user_verified(
1131 own_identity,
1132 device_owner_identity,
1133 #[cfg(feature = "experimental-x509-identity-verification")]
1134 x509_verifier,
1135 )
1136 })
1137}
1138
1139fn is_user_verified(
1140 own_identity: Option<&OwnUserIdentityData>,
1141 user_identity: &UserIdentityData,
1142 #[cfg(feature = "experimental-x509-identity-verification")] x509_verifier: Option<
1143 &X509Verifier,
1144 >,
1145) -> bool {
1146 match user_identity {
1147 UserIdentityData::Own(own_identity) => own_identity.is_verified(),
1148 UserIdentityData::Other(other_identity) => other_identity.is_verified(
1149 own_identity,
1150 #[cfg(feature = "experimental-x509-identity-verification")]
1151 x509_verifier,
1152 ),
1153 }
1154}
1155
1156#[cfg(test)]
1157mod tests {
1158 use std::{collections::BTreeMap, iter, ops::Deref, sync::Arc};
1159
1160 use assert_matches::assert_matches;
1161 use assert_matches2::assert_let;
1162 use insta::{assert_snapshot, with_settings};
1163 use matrix_sdk_common::deserialized_responses::WithheldCode;
1164 use matrix_sdk_test::{
1165 async_test, test_json,
1166 test_json::keys_query_sets::{
1167 IdentityChangeDataSet, KeyDistributionTestData, MaloIdentityChangeDataSet,
1168 VerificationViolationTestData,
1169 },
1170 };
1171 use ruma::{
1172 DeviceId, TransactionId, UserId, device_id,
1173 events::{dummy::ToDeviceDummyEventContent, room::history_visibility::HistoryVisibility},
1174 room_id,
1175 };
1176 use serde_json::json;
1177
1178 #[cfg(feature = "experimental-send-custom-to-device")]
1179 use super::split_devices_for_share_strategy;
1180 use crate::{
1181 CrossSigningKeyExport, DeviceData, EncryptionSettings, LocalTrust, OlmError, OlmMachine,
1182 error::SessionRecipientCollectionError,
1183 olm::{OutboundGroupSession, ShareInfo},
1184 session_manager::{
1185 CollectStrategy,
1186 group_sessions::share_strategy::{
1187 collect_session_recipients, withheld_code_for_device_for_share_strategy,
1188 },
1189 },
1190 store::caches::SequenceNumber,
1191 testing::simulate_key_query_response_for_verification,
1192 types::requests::ToDeviceRequest,
1193 };
1194
1195 async fn test_machine() -> OlmMachine {
1199 use KeyDistributionTestData as DataSet;
1200
1201 let machine = OlmMachine::new(DataSet::me_id(), DataSet::me_device_id()).await;
1203 let keys_query = DataSet::me_keys_query_response();
1204 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
1205
1206 machine
1208 .import_cross_signing_keys(CrossSigningKeyExport {
1209 master_key: DataSet::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(),
1210 self_signing_key: DataSet::SELF_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
1211 user_signing_key: DataSet::USER_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
1212 })
1213 .await
1214 .unwrap();
1215
1216 machine
1217 }
1218
1219 async fn get_device_data(
1221 machine: &OlmMachine,
1222 user_id: &UserId,
1223 device_id: &DeviceId,
1224 ) -> DeviceData {
1225 machine.get_device(user_id, device_id, None).await.unwrap().unwrap().deref().clone()
1226 }
1227
1228 async fn get_own_identity_data(
1229 machine: &OlmMachine,
1230 user_id: &UserId,
1231 ) -> Option<crate::OwnUserIdentityData> {
1232 machine
1233 .get_identity(user_id, None)
1234 .await
1235 .unwrap()
1236 .and_then(|i| i.own())
1237 .map(|i| i.deref().clone())
1238 }
1239
1240 async fn get_user_identity_data(
1241 machine: &OlmMachine,
1242 user_id: &UserId,
1243 ) -> Option<crate::UserIdentityData> {
1244 use crate::{UserIdentity, identities::user::UserIdentityData};
1245 machine.get_identity(user_id, None).await.unwrap().map(|i| match i {
1246 UserIdentity::Own(i) => UserIdentityData::Own(i.deref().clone()),
1247 UserIdentity::Other(i) => UserIdentityData::Other(i.deref().clone()),
1248 })
1249 }
1250
1251 async fn import_known_users_to_test_machine(machine: &OlmMachine) {
1254 let keys_query = KeyDistributionTestData::dan_keys_query_response();
1255 let txn_id = TransactionId::new();
1256 machine.mark_request_as_sent(&txn_id, &keys_query).await.unwrap();
1257
1258 let txn_id_dave = TransactionId::new();
1259 let keys_query_dave = KeyDistributionTestData::dave_keys_query_response();
1260 machine.mark_request_as_sent(&txn_id_dave, &keys_query_dave).await.unwrap();
1261
1262 let txn_id_good = TransactionId::new();
1263 let keys_query_good = KeyDistributionTestData::good_keys_query_response();
1264 machine.mark_request_as_sent(&txn_id_good, &keys_query_good).await.unwrap();
1265 }
1266
1267 #[test]
1270 #[cfg(not(feature = "experimental-encrypted-state-events"))]
1271 fn test_serialize_device_based_strategy() {
1272 let encryption_settings = all_devices_strategy_settings();
1273 let serialized = serde_json::to_string(&encryption_settings).unwrap();
1274 with_settings!({prepend_module_to_snapshot => false}, {
1275 assert_snapshot!(serialized)
1276 });
1277 }
1278
1279 #[test]
1283 #[cfg(feature = "experimental-encrypted-state-events")]
1284 fn test_serialize_strategy_with_encrypted_state() {
1285 let encryption_settings = all_devices_strategy_settings();
1286 let serialized = serde_json::to_string(&encryption_settings).unwrap();
1287 with_settings!({prepend_module_to_snapshot => false}, {
1288 assert_snapshot!(serialized)
1289 });
1290 }
1291
1292 #[test]
1296 fn test_deserialize_old_device_based_strategy() {
1297 let settings: EncryptionSettings = serde_json::from_value(json!({
1298 "algorithm": "m.megolm.v1.aes-sha2",
1299 "rotation_period":{"secs":604800,"nanos":0},
1300 "rotation_period_msgs":100,
1301 "history_visibility":"shared",
1302 "sharing_strategy":{"DeviceBasedStrategy":{"only_allow_trusted_devices":false,"error_on_verified_user_problem":false}},
1303 })).unwrap();
1304 assert_matches!(settings.sharing_strategy, CollectStrategy::AllDevices);
1305 }
1306
1307 #[test]
1311 fn test_deserialize_old_error_on_verified_user_problem() {
1312 let settings: EncryptionSettings = serde_json::from_value(json!({
1313 "algorithm": "m.megolm.v1.aes-sha2",
1314 "rotation_period":{"secs":604800,"nanos":0},
1315 "rotation_period_msgs":100,
1316 "history_visibility":"shared",
1317 "sharing_strategy":{"DeviceBasedStrategy":{"only_allow_trusted_devices":false,"error_on_verified_user_problem":true}},
1318 })).unwrap();
1319 assert_matches!(settings.sharing_strategy, CollectStrategy::ErrorOnVerifiedUserProblem);
1320 }
1321
1322 #[test]
1326 fn test_deserialize_old_only_trusted_devices_strategy() {
1327 let settings: EncryptionSettings = serde_json::from_value(json!({
1328 "algorithm": "m.megolm.v1.aes-sha2",
1329 "rotation_period":{"secs":604800,"nanos":0},
1330 "rotation_period_msgs":100,
1331 "history_visibility":"shared",
1332 "sharing_strategy":{"DeviceBasedStrategy":{"only_allow_trusted_devices":true,"error_on_verified_user_problem":false}},
1333 })).unwrap();
1334 assert_matches!(settings.sharing_strategy, CollectStrategy::OnlyTrustedDevices);
1335 }
1336
1337 #[async_test]
1338 async fn test_share_with_per_device_strategy_to_all() {
1339 let machine = test_machine().await;
1340 import_known_users_to_test_machine(&machine).await;
1341
1342 let encryption_settings = all_devices_strategy_settings();
1343
1344 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1345
1346 let share_result = collect_session_recipients(
1347 machine.store(),
1348 vec![
1349 KeyDistributionTestData::dan_id(),
1350 KeyDistributionTestData::dave_id(),
1351 KeyDistributionTestData::good_id(),
1352 ]
1353 .into_iter(),
1354 &encryption_settings,
1355 &group_session,
1356 )
1357 .await
1358 .unwrap();
1359
1360 assert!(!share_result.should_rotate);
1361
1362 let dan_devices_shared =
1363 share_result.devices.get(KeyDistributionTestData::dan_id()).unwrap();
1364 let dave_devices_shared =
1365 share_result.devices.get(KeyDistributionTestData::dave_id()).unwrap();
1366 let good_devices_shared =
1367 share_result.devices.get(KeyDistributionTestData::good_id()).unwrap();
1368
1369 assert_eq!(dan_devices_shared.len(), 2);
1371 assert_eq!(dave_devices_shared.len(), 1);
1372 assert_eq!(good_devices_shared.len(), 2);
1373
1374 #[cfg(feature = "experimental-send-custom-to-device")]
1375 {
1376 let mut all_devices = dan_devices_shared.clone();
1380 all_devices.append(&mut dave_devices_shared.clone());
1381 all_devices.append(&mut good_devices_shared.clone());
1382
1383 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1384 machine.store(),
1385 all_devices,
1386 CollectStrategy::AllDevices,
1387 )
1388 .await
1389 .unwrap();
1390
1391 assert_eq!(shared_devices.len(), 5);
1392 assert_eq!(withheld_devices.len(), 0);
1393 }
1394
1395 let own_identity_data =
1396 get_own_identity_data(&machine, KeyDistributionTestData::me_id()).await;
1397 let dan_identity_data =
1398 get_user_identity_data(&machine, KeyDistributionTestData::dan_id()).await;
1399
1400 assert_eq!(
1401 withheld_code_for_device_for_share_strategy(
1402 &get_device_data(
1403 &machine,
1404 KeyDistributionTestData::dan_id(),
1405 KeyDistributionTestData::dan_signed_device_id()
1406 )
1407 .await,
1408 CollectStrategy::AllDevices,
1409 &own_identity_data,
1410 &dan_identity_data,
1411 #[cfg(feature = "experimental-x509-identity-verification")]
1412 None,
1413 )
1414 .await
1415 .unwrap(),
1416 None,
1417 );
1418 }
1419
1420 #[async_test]
1421 async fn test_share_with_only_trusted_strategy() {
1422 let machine = test_machine().await;
1423 import_known_users_to_test_machine(&machine).await;
1424
1425 let encryption_settings = EncryptionSettings {
1426 sharing_strategy: CollectStrategy::OnlyTrustedDevices,
1427 ..Default::default()
1428 };
1429
1430 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1431
1432 let share_result = collect_session_recipients(
1433 machine.store(),
1434 vec![
1435 KeyDistributionTestData::dan_id(),
1436 KeyDistributionTestData::dave_id(),
1437 KeyDistributionTestData::good_id(),
1438 ]
1439 .into_iter(),
1440 &encryption_settings,
1441 &group_session,
1442 )
1443 .await
1444 .unwrap();
1445
1446 assert!(!share_result.should_rotate);
1447
1448 let dave_devices_shared = share_result.devices.get(KeyDistributionTestData::dave_id());
1449 let good_devices_shared = share_result.devices.get(KeyDistributionTestData::good_id());
1450 assert!(dave_devices_shared.unwrap().is_empty());
1452 assert!(good_devices_shared.unwrap().is_empty());
1453
1454 let dan_devices_shared =
1457 share_result.devices.get(KeyDistributionTestData::dan_id()).unwrap();
1458
1459 assert_eq!(dan_devices_shared.len(), 1);
1460 let dan_device_that_will_get_the_key = &dan_devices_shared[0];
1461 assert_eq!(
1462 dan_device_that_will_get_the_key.device_id().as_str(),
1463 KeyDistributionTestData::dan_signed_device_id()
1464 );
1465
1466 let (_, code) = share_result
1468 .withheld_devices
1469 .iter()
1470 .find(|(d, _)| d.device_id() == KeyDistributionTestData::dan_unsigned_device_id())
1471 .expect("This dan's device should receive a withheld code");
1472
1473 assert_eq!(code, &WithheldCode::Unverified);
1474
1475 let (_, code) = share_result
1476 .withheld_devices
1477 .iter()
1478 .find(|(d, _)| d.device_id() == KeyDistributionTestData::dave_device_id())
1479 .expect("This daves's device should receive a withheld code");
1480
1481 assert_eq!(code, &WithheldCode::Unverified);
1482
1483 #[cfg(feature = "experimental-send-custom-to-device")]
1484 {
1485 let all_devices: Vec<DeviceData> = vec![
1486 get_device_data(
1487 &machine,
1488 KeyDistributionTestData::dan_id(),
1489 KeyDistributionTestData::dan_unsigned_device_id(),
1490 )
1491 .await,
1492 get_device_data(
1493 &machine,
1494 KeyDistributionTestData::dan_id(),
1495 KeyDistributionTestData::dan_signed_device_id(),
1496 )
1497 .await,
1498 get_device_data(
1499 &machine,
1500 KeyDistributionTestData::dave_id(),
1501 KeyDistributionTestData::dave_device_id(),
1502 )
1503 .await,
1504 get_device_data(
1505 &machine,
1506 KeyDistributionTestData::good_id(),
1507 KeyDistributionTestData::good_device_1_id(),
1508 )
1509 .await,
1510 get_device_data(
1511 &machine,
1512 KeyDistributionTestData::good_id(),
1513 KeyDistributionTestData::good_device_2_id(),
1514 )
1515 .await,
1516 ];
1517
1518 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1519 machine.store(),
1520 all_devices,
1521 CollectStrategy::OnlyTrustedDevices,
1522 )
1523 .await
1524 .unwrap();
1525
1526 assert_eq!(shared_devices.len(), 1);
1527 assert_eq!(
1528 shared_devices[0].device_id().as_str(),
1529 KeyDistributionTestData::dan_signed_device_id()
1530 );
1531
1532 assert_eq!(withheld_devices.len(), 4);
1533 assert_eq!(
1534 withheld_devices[0].0.device_id().as_str(),
1535 KeyDistributionTestData::dan_unsigned_device_id()
1536 );
1537 assert_eq!(withheld_devices[0].1, WithheldCode::Unverified);
1538 assert_eq!(
1539 withheld_devices[1].0.device_id().as_str(),
1540 KeyDistributionTestData::dave_device_id()
1541 );
1542 assert_eq!(withheld_devices[1].1, WithheldCode::Unverified);
1543 }
1544
1545 let own_identity_data =
1546 get_own_identity_data(&machine, KeyDistributionTestData::me_id()).await;
1547 let dan_identity_data =
1548 get_user_identity_data(&machine, KeyDistributionTestData::dan_id()).await;
1549 let dave_identity_data =
1550 get_user_identity_data(&machine, KeyDistributionTestData::dave_id()).await;
1551
1552 assert_eq!(
1553 withheld_code_for_device_for_share_strategy(
1554 &get_device_data(
1555 &machine,
1556 KeyDistributionTestData::dan_id(),
1557 KeyDistributionTestData::dan_signed_device_id()
1558 )
1559 .await,
1560 CollectStrategy::OnlyTrustedDevices,
1561 &own_identity_data,
1562 &dan_identity_data,
1563 #[cfg(feature = "experimental-x509-identity-verification")]
1564 None,
1565 )
1566 .await
1567 .unwrap(),
1568 None,
1569 );
1570 assert_eq!(
1571 withheld_code_for_device_for_share_strategy(
1572 &get_device_data(
1573 &machine,
1574 KeyDistributionTestData::dan_id(),
1575 KeyDistributionTestData::dan_unsigned_device_id()
1576 )
1577 .await,
1578 CollectStrategy::OnlyTrustedDevices,
1579 &own_identity_data,
1580 &dan_identity_data,
1581 #[cfg(feature = "experimental-x509-identity-verification")]
1582 None,
1583 )
1584 .await
1585 .unwrap(),
1586 Some(WithheldCode::Unverified),
1587 );
1588 assert_eq!(
1589 withheld_code_for_device_for_share_strategy(
1590 &get_device_data(
1591 &machine,
1592 KeyDistributionTestData::dave_id(),
1593 KeyDistributionTestData::dave_device_id()
1594 )
1595 .await,
1596 CollectStrategy::OnlyTrustedDevices,
1597 &own_identity_data,
1598 &dave_identity_data,
1599 #[cfg(feature = "experimental-x509-identity-verification")]
1600 None,
1601 )
1602 .await
1603 .unwrap(),
1604 Some(WithheldCode::Unverified),
1605 );
1606 }
1607
1608 #[async_test]
1612 async fn test_error_on_unsigned_of_verified_users() {
1613 use VerificationViolationTestData as DataSet;
1614
1615 let machine = unsigned_of_verified_setup().await;
1617
1618 let carol_keys = DataSet::carol_keys_query_response_signed();
1620 machine.mark_request_as_sent(&TransactionId::new(), &carol_keys).await.unwrap();
1621
1622 let carol_identity =
1624 machine.get_identity(DataSet::carol_id(), None).await.unwrap().unwrap();
1625 assert!(carol_identity.other().unwrap().is_verified());
1626
1627 let carol_unsigned_device = machine
1628 .get_device(DataSet::carol_id(), DataSet::carol_unsigned_device_id(), None)
1629 .await
1630 .unwrap()
1631 .unwrap();
1632 assert!(!carol_unsigned_device.is_verified());
1633
1634 let encryption_settings = error_on_verification_problem_encryption_settings();
1636 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1637 let share_result = collect_session_recipients(
1638 machine.store(),
1639 vec![DataSet::bob_id(), DataSet::carol_id()].into_iter(),
1640 &encryption_settings,
1641 &group_session,
1642 )
1643 .await;
1644
1645 assert_let!(
1646 Err(OlmError::SessionRecipientCollectionError(
1647 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(unverified_devices)
1648 )) = share_result
1649 );
1650
1651 assert_eq!(
1653 unverified_devices,
1654 BTreeMap::from([
1655 (DataSet::bob_id().to_owned(), vec![DataSet::bob_device_2_id().to_owned()]),
1656 (
1657 DataSet::carol_id().to_owned(),
1658 vec![DataSet::carol_unsigned_device_id().to_owned()]
1659 ),
1660 ])
1661 );
1662
1663 #[cfg(feature = "experimental-send-custom-to-device")]
1664 {
1665 let all_devices = vec![
1666 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
1667 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1668 get_device_data(&machine, DataSet::carol_id(), DataSet::carol_signed_device_id())
1669 .await,
1670 get_device_data(&machine, DataSet::carol_id(), DataSet::carol_unsigned_device_id())
1671 .await,
1672 ];
1673
1674 let split_result = split_devices_for_share_strategy(
1675 machine.store(),
1676 all_devices,
1677 CollectStrategy::ErrorOnVerifiedUserProblem,
1678 )
1679 .await;
1680
1681 assert_let!(
1682 Err(OlmError::SessionRecipientCollectionError(
1683 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
1684 unverified_devices
1685 )
1686 )) = split_result
1687 );
1688
1689 assert_eq!(
1691 unverified_devices,
1692 BTreeMap::from([
1693 (DataSet::bob_id().to_owned(), vec![DataSet::bob_device_2_id().to_owned()]),
1694 (
1695 DataSet::carol_id().to_owned(),
1696 vec![DataSet::carol_unsigned_device_id().to_owned()]
1697 ),
1698 ])
1699 );
1700 }
1701
1702 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1703 let carol_identity_data = get_user_identity_data(&machine, DataSet::carol_id()).await;
1704
1705 assert_eq!(
1706 withheld_code_for_device_for_share_strategy(
1707 &get_device_data(&machine, DataSet::carol_id(), DataSet::carol_signed_device_id())
1708 .await,
1709 CollectStrategy::ErrorOnVerifiedUserProblem,
1710 &own_identity_data,
1711 &carol_identity_data,
1712 #[cfg(feature = "experimental-x509-identity-verification")]
1713 None,
1714 )
1715 .await
1716 .unwrap(),
1717 None,
1718 );
1719 assert_let!(
1720 Err(OlmError::SessionRecipientCollectionError(
1721 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(_)
1722 )) = withheld_code_for_device_for_share_strategy(
1723 &get_device_data(
1724 &machine,
1725 DataSet::carol_id(),
1726 DataSet::carol_unsigned_device_id()
1727 )
1728 .await,
1729 CollectStrategy::ErrorOnVerifiedUserProblem,
1730 &own_identity_data,
1731 &carol_identity_data,
1732 #[cfg(feature = "experimental-x509-identity-verification")]
1733 None,
1734 )
1735 .await
1736 );
1737 }
1738
1739 #[async_test]
1743 async fn test_error_on_unsigned_of_verified_resolve_by_whitelisting() {
1744 use VerificationViolationTestData as DataSet;
1745
1746 let machine = unsigned_of_verified_setup().await;
1747
1748 machine
1750 .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None)
1751 .await
1752 .unwrap()
1753 .unwrap()
1754 .set_local_trust(LocalTrust::Ignored)
1755 .await
1756 .unwrap();
1757
1758 let encryption_settings = error_on_verification_problem_encryption_settings();
1759 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1760
1761 let share_result = collect_session_recipients(
1763 machine.store(),
1764 iter::once(DataSet::bob_id()),
1765 &encryption_settings,
1766 &group_session,
1767 )
1768 .await
1769 .unwrap();
1770
1771 assert_eq!(2, share_result.devices.get(DataSet::bob_id()).unwrap().len());
1772 assert_eq!(0, share_result.withheld_devices.len());
1773
1774 #[cfg(feature = "experimental-send-custom-to-device")]
1775 {
1776 let all_devices = vec![
1777 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
1778 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1779 ];
1780
1781 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1782 machine.store(),
1783 all_devices,
1784 CollectStrategy::ErrorOnVerifiedUserProblem,
1785 )
1786 .await
1787 .unwrap();
1788
1789 assert_eq!(shared_devices.len(), 2);
1790 assert_eq!(withheld_devices.len(), 0);
1791 }
1792
1793 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1794 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
1795
1796 assert_eq!(
1797 withheld_code_for_device_for_share_strategy(
1798 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1799 CollectStrategy::ErrorOnVerifiedUserProblem,
1800 &own_identity_data,
1801 &bob_identity_data,
1802 #[cfg(feature = "experimental-x509-identity-verification")]
1803 None,
1804 )
1805 .await
1806 .unwrap(),
1807 None,
1808 );
1809 }
1810
1811 #[async_test]
1815 async fn test_error_on_unsigned_of_verified_resolve_by_blacklisting() {
1816 use VerificationViolationTestData as DataSet;
1817
1818 let machine = unsigned_of_verified_setup().await;
1819
1820 machine
1822 .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None)
1823 .await
1824 .unwrap()
1825 .unwrap()
1826 .set_local_trust(LocalTrust::BlackListed)
1827 .await
1828 .unwrap();
1829
1830 let encryption_settings = error_on_verification_problem_encryption_settings();
1831 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1832
1833 let share_result = collect_session_recipients(
1835 machine.store(),
1836 iter::once(DataSet::bob_id()),
1837 &encryption_settings,
1838 &group_session,
1839 )
1840 .await
1841 .unwrap();
1842
1843 assert_eq!(1, share_result.devices.get(DataSet::bob_id()).unwrap().len());
1844 let withheld_list: Vec<_> = share_result
1845 .withheld_devices
1846 .iter()
1847 .map(|(d, code)| (d.device_id().to_owned(), code.clone()))
1848 .collect();
1849 assert_eq!(
1850 withheld_list,
1851 vec![(DataSet::bob_device_2_id().to_owned(), WithheldCode::Blacklisted)]
1852 );
1853
1854 let bob_device_2 =
1855 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await;
1856 #[cfg(feature = "experimental-send-custom-to-device")]
1857 {
1858 let bob_device_1 =
1859 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await;
1860 let all_devices = vec![bob_device_1.clone(), bob_device_2.clone()];
1861
1862 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1863 machine.store(),
1864 all_devices,
1865 CollectStrategy::ErrorOnVerifiedUserProblem,
1866 )
1867 .await
1868 .unwrap();
1869
1870 assert_eq!(shared_devices, vec![bob_device_1.clone()]);
1871 assert_eq!(withheld_devices, vec![(bob_device_2.clone(), WithheldCode::Blacklisted)]);
1872 }
1873
1874 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1875 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
1876
1877 assert_eq!(
1878 withheld_code_for_device_for_share_strategy(
1879 &bob_device_2,
1880 CollectStrategy::ErrorOnVerifiedUserProblem,
1881 &own_identity_data,
1882 &bob_identity_data,
1883 #[cfg(feature = "experimental-x509-identity-verification")]
1884 None,
1885 )
1886 .await
1887 .unwrap(),
1888 Some(WithheldCode::Blacklisted),
1889 );
1890 }
1891
1892 #[async_test]
1896 async fn test_error_on_unsigned_of_verified_owner_is_us() {
1897 use VerificationViolationTestData as DataSet;
1898
1899 let machine = unsigned_of_verified_setup().await;
1900
1901 let mut own_keys = DataSet::own_keys_query_response_1().clone();
1903 own_keys.device_keys.insert(
1904 DataSet::own_id().to_owned(),
1905 BTreeMap::from([
1906 DataSet::own_signed_device_keys(),
1907 DataSet::own_unsigned_device_keys(),
1908 ]),
1909 );
1910 machine.mark_request_as_sent(&TransactionId::new(), &own_keys).await.unwrap();
1911
1912 let encryption_settings = error_on_verification_problem_encryption_settings();
1913 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1914 let share_result = collect_session_recipients(
1915 machine.store(),
1916 iter::once(DataSet::own_id()),
1917 &encryption_settings,
1918 &group_session,
1919 )
1920 .await;
1921
1922 assert_let!(
1923 Err(OlmError::SessionRecipientCollectionError(
1924 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(unverified_devices)
1925 )) = share_result
1926 );
1927
1928 assert_eq!(
1930 unverified_devices,
1931 BTreeMap::from([(
1932 DataSet::own_id().to_owned(),
1933 vec![DataSet::own_unsigned_device_id()]
1934 ),])
1935 );
1936
1937 #[cfg(feature = "experimental-send-custom-to-device")]
1938 {
1939 let all_devices = vec![
1940 get_device_data(&machine, DataSet::own_id(), &DataSet::own_signed_device_id())
1941 .await,
1942 get_device_data(&machine, DataSet::own_id(), &DataSet::own_unsigned_device_id())
1943 .await,
1944 ];
1945
1946 let split_result = split_devices_for_share_strategy(
1947 machine.store(),
1948 all_devices,
1949 CollectStrategy::ErrorOnVerifiedUserProblem,
1950 )
1951 .await;
1952 assert_let!(
1953 Err(OlmError::SessionRecipientCollectionError(
1954 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
1955 unverified_devices
1956 )
1957 )) = split_result
1958 );
1959
1960 assert_eq!(
1962 unverified_devices,
1963 BTreeMap::from([(
1964 DataSet::own_id().to_owned(),
1965 vec![DataSet::own_unsigned_device_id()]
1966 ),])
1967 );
1968 }
1969
1970 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1971 let own_user_identity_data = get_user_identity_data(&machine, DataSet::own_id()).await;
1972
1973 assert_let!(
1974 Err(OlmError::SessionRecipientCollectionError(
1975 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(_)
1976 )) = withheld_code_for_device_for_share_strategy(
1977 &get_device_data(&machine, DataSet::own_id(), &DataSet::own_unsigned_device_id())
1978 .await,
1979 CollectStrategy::ErrorOnVerifiedUserProblem,
1980 &own_identity_data,
1981 &own_user_identity_data,
1982 #[cfg(feature = "experimental-x509-identity-verification")]
1983 None,
1984 )
1985 .await
1986 );
1987 }
1988
1989 #[async_test]
1992 async fn test_should_not_error_on_unsigned_of_unverified() {
1993 use VerificationViolationTestData as DataSet;
1994
1995 let machine = OlmMachine::new(DataSet::own_id(), device_id!("LOCAL")).await;
1996
1997 let own_keys = DataSet::own_keys_query_response_1();
1999 machine.mark_request_as_sent(&TransactionId::new(), &own_keys).await.unwrap();
2000
2001 machine
2003 .import_cross_signing_keys(CrossSigningKeyExport {
2004 master_key: DataSet::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(),
2005 self_signing_key: DataSet::SELF_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
2006 user_signing_key: DataSet::USER_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
2007 })
2008 .await
2009 .unwrap();
2010
2011 let bob_keys = DataSet::bob_keys_query_response_rotated();
2013 machine.mark_request_as_sent(&TransactionId::new(), &bob_keys).await.unwrap();
2014
2015 let bob_identity = machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap();
2018 assert!(!bob_identity.other().unwrap().is_verified());
2019
2020 let bob_unsigned_device = machine
2021 .get_device(DataSet::bob_id(), DataSet::bob_device_1_id(), None)
2022 .await
2023 .unwrap()
2024 .unwrap();
2025 assert!(!bob_unsigned_device.is_cross_signed_by_owner());
2026
2027 let encryption_settings = error_on_verification_problem_encryption_settings();
2028 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
2029 collect_session_recipients(
2030 machine.store(),
2031 iter::once(DataSet::bob_id()),
2032 &encryption_settings,
2033 &group_session,
2034 )
2035 .await
2036 .unwrap();
2037
2038 #[cfg(feature = "experimental-send-custom-to-device")]
2039 {
2040 let all_devices = vec![
2041 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2042 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
2043 ];
2044
2045 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
2046 machine.store(),
2047 all_devices,
2048 CollectStrategy::ErrorOnVerifiedUserProblem,
2049 )
2050 .await
2051 .unwrap();
2052
2053 assert_eq!(shared_devices.len(), 2);
2054 assert_eq!(withheld_devices.len(), 0);
2055 }
2056
2057 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2058 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
2059
2060 assert_eq!(
2061 withheld_code_for_device_for_share_strategy(
2062 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
2063 CollectStrategy::ErrorOnVerifiedUserProblem,
2064 &own_identity_data,
2065 &bob_identity_data,
2066 #[cfg(feature = "experimental-x509-identity-verification")]
2067 None,
2068 )
2069 .await
2070 .unwrap(),
2071 None,
2072 );
2073 }
2074
2075 #[async_test]
2078 async fn test_should_not_error_on_unsigned_of_signed_but_unverified() {
2079 use VerificationViolationTestData as DataSet;
2080
2081 let machine = OlmMachine::new(DataSet::own_id(), device_id!("LOCAL")).await;
2082
2083 let keys_query = DataSet::own_keys_query_response_1();
2085 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2086
2087 let keys_query = DataSet::bob_keys_query_response_signed();
2089 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2090
2091 let bob_identity =
2094 machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap().other().unwrap();
2095 assert!(
2096 bob_identity.own_identity.as_ref().unwrap().is_identity_signed(&bob_identity.inner)
2097 );
2098 assert!(!bob_identity.is_verified());
2099
2100 let bob_unsigned_device = machine
2101 .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None)
2102 .await
2103 .unwrap()
2104 .unwrap();
2105 assert!(!bob_unsigned_device.is_cross_signed_by_owner());
2106
2107 let encryption_settings = error_on_verification_problem_encryption_settings();
2109 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
2110 collect_session_recipients(
2111 machine.store(),
2112 iter::once(DataSet::bob_id()),
2113 &encryption_settings,
2114 &group_session,
2115 )
2116 .await
2117 .unwrap();
2118
2119 #[cfg(feature = "experimental-send-custom-to-device")]
2120 {
2121 let all_devices = vec![
2122 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2123 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
2124 ];
2125
2126 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
2127 machine.store(),
2128 all_devices,
2129 CollectStrategy::ErrorOnVerifiedUserProblem,
2130 )
2131 .await
2132 .unwrap();
2133
2134 assert_eq!(shared_devices.len(), 2);
2135 assert_eq!(withheld_devices.len(), 0);
2136 }
2137
2138 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2139 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
2140
2141 assert_eq!(
2142 withheld_code_for_device_for_share_strategy(
2143 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
2144 CollectStrategy::ErrorOnVerifiedUserProblem,
2145 &own_identity_data,
2146 &bob_identity_data,
2147 #[cfg(feature = "experimental-x509-identity-verification")]
2148 None,
2149 )
2150 .await
2151 .unwrap(),
2152 None,
2153 );
2154 }
2155
2156 #[async_test]
2160 async fn test_verified_user_changed_identity() {
2161 use test_json::keys_query_sets::VerificationViolationTestData as DataSet;
2162
2163 let machine = unsigned_of_verified_setup().await;
2166
2167 let bob_keys = DataSet::bob_keys_query_response_rotated();
2169 machine.mark_request_as_sent(&TransactionId::new(), &bob_keys).await.unwrap();
2170
2171 let bob_identity = machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap();
2173 assert!(bob_identity.has_verification_violation());
2174
2175 let encryption_settings = error_on_verification_problem_encryption_settings();
2177 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
2178 let share_result = collect_session_recipients(
2179 machine.store(),
2180 iter::once(DataSet::bob_id()),
2181 &encryption_settings,
2182 &group_session,
2183 )
2184 .await;
2185
2186 assert_let!(
2187 Err(OlmError::SessionRecipientCollectionError(
2188 SessionRecipientCollectionError::VerifiedUserChangedIdentity(violating_users)
2189 )) = share_result
2190 );
2191 assert_eq!(violating_users, vec![DataSet::bob_id()]);
2192
2193 #[cfg(feature = "experimental-send-custom-to-device")]
2194 {
2195 let all_devices = vec![
2196 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2197 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
2198 ];
2199
2200 let split_result = split_devices_for_share_strategy(
2201 machine.store(),
2202 all_devices,
2203 CollectStrategy::ErrorOnVerifiedUserProblem,
2204 )
2205 .await;
2206 assert_let!(
2207 Err(OlmError::SessionRecipientCollectionError(
2208 SessionRecipientCollectionError::VerifiedUserChangedIdentity(violating_users)
2209 )) = split_result
2210 );
2211 assert_eq!(violating_users, vec![DataSet::bob_id()]);
2212 }
2213
2214 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2215 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
2216
2217 assert_let!(
2218 Err(OlmError::SessionRecipientCollectionError(
2219 SessionRecipientCollectionError::VerifiedUserChangedIdentity(_)
2220 )) = withheld_code_for_device_for_share_strategy(
2221 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2222 CollectStrategy::ErrorOnVerifiedUserProblem,
2223 &own_identity_data,
2224 &bob_identity_data,
2225 #[cfg(feature = "experimental-x509-identity-verification")]
2226 None,
2227 )
2228 .await
2229 );
2230
2231 bob_identity.withdraw_verification().await.unwrap();
2233
2234 collect_session_recipients(
2235 machine.store(),
2236 iter::once(DataSet::bob_id()),
2237 &encryption_settings,
2238 &group_session,
2239 )
2240 .await
2241 .unwrap();
2242
2243 #[cfg(feature = "experimental-send-custom-to-device")]
2244 {
2245 let all_devices = vec![
2246 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2247 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
2248 ];
2249
2250 split_devices_for_share_strategy(
2251 machine.store(),
2252 all_devices,
2253 CollectStrategy::ErrorOnVerifiedUserProblem,
2254 )
2255 .await
2256 .unwrap();
2257 }
2258
2259 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2260 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
2261
2262 assert_eq!(
2263 withheld_code_for_device_for_share_strategy(
2264 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2265 CollectStrategy::ErrorOnVerifiedUserProblem,
2266 &own_identity_data,
2267 &bob_identity_data,
2268 #[cfg(feature = "experimental-x509-identity-verification")]
2269 None,
2270 )
2271 .await
2272 .unwrap(),
2273 None,
2274 );
2275 }
2276
2277 #[async_test]
2281 async fn test_own_verified_identity_changed() {
2282 use test_json::keys_query_sets::VerificationViolationTestData as DataSet;
2283
2284 let machine = unsigned_of_verified_setup().await;
2286 let own_identity = machine.get_identity(DataSet::own_id(), None).await.unwrap().unwrap();
2287 assert!(own_identity.own().unwrap().is_verified());
2288
2289 let own_keys = DataSet::own_keys_query_response_2();
2291 machine.mark_request_as_sent(&TransactionId::new(), &own_keys).await.unwrap();
2292
2293 let own_identity = machine.get_identity(DataSet::own_id(), None).await.unwrap().unwrap();
2294 assert!(!own_identity.is_verified());
2295
2296 let encryption_settings = error_on_verification_problem_encryption_settings();
2298 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
2299 let share_result = collect_session_recipients(
2300 machine.store(),
2301 iter::once(DataSet::own_id()),
2302 &encryption_settings,
2303 &group_session,
2304 )
2305 .await;
2306
2307 assert_let!(
2308 Err(OlmError::SessionRecipientCollectionError(
2309 SessionRecipientCollectionError::VerifiedUserChangedIdentity(violating_users)
2310 )) = share_result
2311 );
2312 assert_eq!(violating_users, vec![DataSet::own_id()]);
2313
2314 #[cfg(feature = "experimental-send-custom-to-device")]
2315 {
2316 let all_devices: Vec<DeviceData> =
2317 vec![get_device_data(&machine, DataSet::own_id(), machine.device_id()).await];
2318
2319 let split_result = split_devices_for_share_strategy(
2320 machine.store(),
2321 all_devices,
2322 CollectStrategy::ErrorOnVerifiedUserProblem,
2323 )
2324 .await;
2325
2326 assert_let!(
2327 Err(OlmError::SessionRecipientCollectionError(
2328 SessionRecipientCollectionError::VerifiedUserChangedIdentity(violating_users)
2329 )) = split_result
2330 );
2331 assert_eq!(violating_users, vec![DataSet::own_id()]);
2332 }
2333
2334 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2335 let own_user_identity_data = get_user_identity_data(&machine, DataSet::own_id()).await;
2336
2337 assert_let!(
2338 Err(OlmError::SessionRecipientCollectionError(
2339 SessionRecipientCollectionError::VerifiedUserChangedIdentity(_)
2340 )) = withheld_code_for_device_for_share_strategy(
2341 &get_device_data(&machine, DataSet::own_id(), machine.device_id()).await,
2342 CollectStrategy::ErrorOnVerifiedUserProblem,
2343 &own_identity_data,
2344 &own_user_identity_data,
2345 #[cfg(feature = "experimental-x509-identity-verification")]
2346 None,
2347 )
2348 .await
2349 );
2350
2351 own_identity.withdraw_verification().await.unwrap();
2353
2354 collect_session_recipients(
2355 machine.store(),
2356 iter::once(DataSet::own_id()),
2357 &encryption_settings,
2358 &group_session,
2359 )
2360 .await
2361 .unwrap();
2362
2363 #[cfg(feature = "experimental-send-custom-to-device")]
2364 {
2365 let all_devices: Vec<DeviceData> =
2366 vec![get_device_data(&machine, DataSet::own_id(), machine.device_id()).await];
2367
2368 split_devices_for_share_strategy(
2369 machine.store(),
2370 all_devices,
2371 CollectStrategy::ErrorOnVerifiedUserProblem,
2372 )
2373 .await
2374 .unwrap();
2375 }
2376
2377 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2378 let own_user_identity_data = get_user_identity_data(&machine, DataSet::own_id()).await;
2379
2380 withheld_code_for_device_for_share_strategy(
2381 &get_device_data(&machine, DataSet::own_id(), machine.device_id()).await,
2382 CollectStrategy::ErrorOnVerifiedUserProblem,
2383 &own_identity_data,
2384 &own_user_identity_data,
2385 #[cfg(feature = "experimental-x509-identity-verification")]
2386 None,
2387 )
2388 .await
2389 .unwrap();
2390 }
2391
2392 mod dehydrated_device {
2395 use std::{collections::HashSet, iter};
2396
2397 use insta::{allow_duplicates, assert_json_snapshot, with_settings};
2398 use matrix_sdk_common::deserialized_responses::WithheldCode;
2399 use matrix_sdk_test::{
2400 async_test, ruma_response_to_json,
2401 test_json::keys_query_sets::{
2402 KeyDistributionTestData, KeyQueryResponseTemplate,
2403 KeyQueryResponseTemplateDeviceOptions,
2404 },
2405 };
2406 use ruma::{DeviceId, TransactionId, UserId, device_id, user_id};
2407 use vodozemac::{Curve25519PublicKey, Ed25519SecretKey};
2408
2409 use super::{
2410 all_devices_strategy_settings, create_test_outbound_group_session,
2411 error_on_verification_problem_encryption_settings, identity_based_strategy_settings,
2412 test_machine,
2413 };
2414 use crate::{
2415 EncryptionSettings, OlmMachine,
2416 session_manager::group_sessions::{
2417 CollectRecipientsResult, share_strategy::collect_session_recipients,
2418 },
2419 };
2420
2421 #[async_test]
2422 async fn test_all_devices_strategy_should_share_with_verified_dehydrated_device() {
2423 should_share_with_verified_dehydrated_device(&all_devices_strategy_settings()).await
2424 }
2425
2426 #[async_test]
2427 async fn test_error_on_verification_problem_strategy_should_share_with_verified_dehydrated_device()
2428 {
2429 should_share_with_verified_dehydrated_device(
2430 &error_on_verification_problem_encryption_settings(),
2431 )
2432 .await
2433 }
2434
2435 #[async_test]
2436 async fn test_identity_based_strategy_should_share_with_verified_dehydrated_device() {
2437 should_share_with_verified_dehydrated_device(&identity_based_strategy_settings()).await
2438 }
2439
2440 async fn should_share_with_verified_dehydrated_device(
2445 encryption_settings: &EncryptionSettings,
2446 ) {
2447 let machine = test_machine().await;
2448
2449 let bob_user_id = user_id!("@bob:localhost");
2452 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2453 let keys_query = key_query_response_template_with_cross_signing(bob_user_id)
2454 .with_dehydrated_device(bob_dehydrated_device_id, true)
2455 .build_response();
2456 allow_duplicates! {
2457 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
2458 assert_json_snapshot!(ruma_response_to_json(keys_query.clone()));
2459 });
2460 }
2461 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2462
2463 let recips = share_test_session_and_collect_recipients(
2465 &machine,
2466 bob_user_id,
2467 encryption_settings,
2468 )
2469 .await;
2470
2471 assert_shared_with(recips, bob_user_id, [bob_dehydrated_device_id].into());
2473 }
2474
2475 #[async_test]
2476 async fn test_all_devices_strategy_should_not_share_with_unverified_dehydrated_device() {
2477 should_not_share_with_unverified_dehydrated_device(&all_devices_strategy_settings())
2478 .await
2479 }
2480
2481 #[async_test]
2482 async fn test_error_on_verification_problem_strategy_should_not_share_with_unverified_dehydrated_device()
2483 {
2484 should_not_share_with_unverified_dehydrated_device(
2485 &error_on_verification_problem_encryption_settings(),
2486 )
2487 .await
2488 }
2489
2490 #[async_test]
2491 async fn test_identity_based_strategy_should_not_share_with_unverified_dehydrated_device() {
2492 should_not_share_with_unverified_dehydrated_device(&identity_based_strategy_settings())
2493 .await
2494 }
2495
2496 async fn should_not_share_with_unverified_dehydrated_device(
2501 encryption_settings: &EncryptionSettings,
2502 ) {
2503 let machine = test_machine().await;
2504
2505 let bob_user_id = user_id!("@bob:localhost");
2508 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2509 let keys_query = key_query_response_template_with_cross_signing(bob_user_id)
2510 .with_dehydrated_device(bob_dehydrated_device_id, false)
2511 .build_response();
2512 allow_duplicates! {
2513 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
2514 assert_json_snapshot!(ruma_response_to_json(keys_query.clone()));
2515 });
2516 }
2517 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2518
2519 let recips = share_test_session_and_collect_recipients(
2521 &machine,
2522 bob_user_id,
2523 encryption_settings,
2524 )
2525 .await;
2526
2527 assert_withheld_to(recips, bob_user_id, bob_dehydrated_device_id);
2530 }
2531
2532 #[async_test]
2533 async fn test_all_devices_strategy_should_share_with_verified_device_of_pin_violation_user()
2534 {
2535 should_share_with_verified_device_of_pin_violation_user(
2536 &all_devices_strategy_settings(),
2537 )
2538 .await
2539 }
2540
2541 #[async_test]
2542 async fn test_error_on_verification_problem_strategy_should_share_with_verified_device_of_pin_violation_user()
2543 {
2544 should_share_with_verified_device_of_pin_violation_user(
2545 &error_on_verification_problem_encryption_settings(),
2546 )
2547 .await
2548 }
2549
2550 #[async_test]
2551 async fn test_identity_based_strategy_should_share_with_verified_device_of_pin_violation_user()
2552 {
2553 should_share_with_verified_device_of_pin_violation_user(
2554 &identity_based_strategy_settings(),
2555 )
2556 .await
2557 }
2558
2559 async fn should_share_with_verified_device_of_pin_violation_user(
2564 encryption_settings: &EncryptionSettings,
2565 ) {
2566 let machine = test_machine().await;
2567
2568 let bob_user_id = user_id!("@bob:localhost");
2570 let keys_query =
2571 key_query_response_template_with_cross_signing(bob_user_id).build_response();
2572 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2573
2574 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2577 let keys_query = key_query_response_template_with_changed_cross_signing(bob_user_id)
2578 .with_dehydrated_device(bob_dehydrated_device_id, true)
2579 .build_response();
2580 allow_duplicates! {
2581 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
2582 assert_json_snapshot!(ruma_response_to_json(keys_query.clone()));
2583 });
2584 }
2585 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2586
2587 let recips = share_test_session_and_collect_recipients(
2589 &machine,
2590 bob_user_id,
2591 encryption_settings,
2592 )
2593 .await;
2594
2595 assert_shared_with(recips, bob_user_id, [bob_dehydrated_device_id].into());
2597 }
2598
2599 #[async_test]
2600 async fn test_all_devices_strategy_should_not_share_with_dehydrated_device_of_verification_violation_user()
2601 {
2602 should_not_share_with_dehydrated_device_of_verification_violation_user(
2603 &all_devices_strategy_settings(),
2604 )
2605 .await
2606 }
2607
2608 async fn should_not_share_with_dehydrated_device_of_verification_violation_user(
2611 encryption_settings: &EncryptionSettings,
2612 ) {
2613 let bob_user_id = user_id!("@bob:localhost");
2614 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2615 let machine = prepare_machine_with_dehydrated_device_of_verification_violation_user(
2616 bob_user_id,
2617 bob_dehydrated_device_id,
2618 )
2619 .await;
2620
2621 let recips = share_test_session_and_collect_recipients(
2623 &machine,
2624 bob_user_id,
2625 encryption_settings,
2626 )
2627 .await;
2628
2629 assert_withheld_to(recips, bob_user_id, bob_dehydrated_device_id);
2632 }
2633
2634 #[async_test]
2635 async fn test_error_on_verification_problem_strategy_should_give_error_for_dehydrated_device_of_verification_violation_user()
2636 {
2637 should_give_error_for_dehydrated_device_of_verification_violation_user(
2638 &error_on_verification_problem_encryption_settings(),
2639 )
2640 .await
2641 }
2642
2643 #[async_test]
2644 async fn test_identity_based_strategy_should_give_error_for_dehydrated_device_of_verification_violation_user()
2645 {
2646 should_give_error_for_dehydrated_device_of_verification_violation_user(
2650 &identity_based_strategy_settings(),
2651 )
2652 .await
2653 }
2654
2655 async fn should_give_error_for_dehydrated_device_of_verification_violation_user(
2659 encryption_settings: &EncryptionSettings,
2660 ) {
2661 let bob_user_id = user_id!("@bob:localhost");
2662 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2663 let machine = prepare_machine_with_dehydrated_device_of_verification_violation_user(
2664 bob_user_id,
2665 bob_dehydrated_device_id,
2666 )
2667 .await;
2668
2669 let group_session = create_test_outbound_group_session(&machine, encryption_settings);
2670 let share_result = collect_session_recipients(
2671 machine.store(),
2672 iter::once(bob_user_id),
2673 encryption_settings,
2674 &group_session,
2675 )
2676 .await;
2677
2678 assert_matches::assert_matches!(
2681 share_result,
2682 Err(crate::OlmError::SessionRecipientCollectionError(
2683 crate::SessionRecipientCollectionError::VerifiedUserChangedIdentity(_)
2684 ))
2685 );
2686 }
2687
2688 async fn prepare_machine_with_dehydrated_device_of_verification_violation_user(
2692 bob_user_id: &UserId,
2693 bob_dehydrated_device_id: &DeviceId,
2694 ) -> OlmMachine {
2695 let machine = test_machine().await;
2696
2697 let keys_query = key_query_response_template_with_cross_signing(bob_user_id)
2699 .with_user_verification_signature(
2700 KeyDistributionTestData::me_id(),
2701 &KeyDistributionTestData::me_private_user_signing_key(),
2702 )
2703 .build_response();
2704 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2705
2706 let keys_query = key_query_response_template_with_changed_cross_signing(bob_user_id)
2709 .with_dehydrated_device(bob_dehydrated_device_id, true)
2710 .build_response();
2711 allow_duplicates! {
2712 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
2713 assert_json_snapshot!(ruma_response_to_json(keys_query.clone()));
2714 });
2715 }
2716 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2717
2718 machine
2719 }
2720
2721 async fn share_test_session_and_collect_recipients(
2724 machine: &OlmMachine,
2725 target_user_id: &UserId,
2726 encryption_settings: &EncryptionSettings,
2727 ) -> CollectRecipientsResult {
2728 let group_session = create_test_outbound_group_session(machine, encryption_settings);
2729 collect_session_recipients(
2730 machine.store(),
2731 iter::once(target_user_id),
2732 encryption_settings,
2733 &group_session,
2734 )
2735 .await
2736 .unwrap()
2737 }
2738
2739 fn assert_shared_with(
2742 recips: CollectRecipientsResult,
2743 user_id: &UserId,
2744 device_ids: HashSet<&DeviceId>,
2745 ) {
2746 let bob_devices_shared: HashSet<_> = recips
2747 .devices
2748 .get(user_id)
2749 .unwrap_or_else(|| panic!("session not shared with {user_id}"))
2750 .iter()
2751 .map(|d| d.device_id())
2752 .collect();
2753 assert_eq!(bob_devices_shared, device_ids);
2754
2755 assert!(recips.withheld_devices.is_empty(), "Unexpected withheld messages");
2756 }
2757
2758 fn assert_withheld_to(
2761 recips: CollectRecipientsResult,
2762 bob_user_id: &UserId,
2763 bob_dehydrated_device_id: &DeviceId,
2764 ) {
2765 for (user, device_list) in recips.devices {
2767 assert_eq!(device_list.len(), 0, "session unexpectedly shared with {user}");
2768 }
2769
2770 assert_eq!(recips.withheld_devices.len(), 1);
2772 assert_eq!(recips.withheld_devices[0].0.user_id(), bob_user_id);
2773 assert_eq!(recips.withheld_devices[0].0.device_id(), bob_dehydrated_device_id);
2774 assert_eq!(recips.withheld_devices[0].1, WithheldCode::Unverified);
2775 }
2776
2777 fn key_query_response_template_with_cross_signing(
2780 user_id: &UserId,
2781 ) -> KeyQueryResponseTemplate {
2782 KeyQueryResponseTemplate::new(user_id.to_owned()).with_cross_signing_keys(
2783 Ed25519SecretKey::from_slice(b"master12master12master12master12"),
2784 Ed25519SecretKey::from_slice(b"self1234self1234self1234self1234"),
2785 Ed25519SecretKey::from_slice(b"user1234user1234user1234user1234"),
2786 )
2787 }
2788
2789 fn key_query_response_template_with_changed_cross_signing(
2793 bob_user_id: &UserId,
2794 ) -> KeyQueryResponseTemplate {
2795 KeyQueryResponseTemplate::new(bob_user_id.to_owned()).with_cross_signing_keys(
2796 Ed25519SecretKey::from_slice(b"newmaster__newmaster__newmaster_"),
2797 Ed25519SecretKey::from_slice(b"self1234self1234self1234self1234"),
2798 Ed25519SecretKey::from_slice(b"user1234user1234user1234user1234"),
2799 )
2800 }
2801
2802 trait KeyQueryResponseTemplateExt {
2803 fn with_dehydrated_device(
2804 self,
2805 device_id: &DeviceId,
2806 verified: bool,
2807 ) -> KeyQueryResponseTemplate;
2808 }
2809
2810 impl KeyQueryResponseTemplateExt for KeyQueryResponseTemplate {
2811 fn with_dehydrated_device(
2813 self,
2814 device_id: &DeviceId,
2815 verified: bool,
2816 ) -> KeyQueryResponseTemplate {
2817 self.with_device(
2818 device_id,
2819 &Curve25519PublicKey::from(b"curvepubcurvepubcurvepubcurvepub".to_owned()),
2820 &Ed25519SecretKey::from_slice(b"device12device12device12device12"),
2821 KeyQueryResponseTemplateDeviceOptions::new()
2822 .dehydrated(true)
2823 .verified(verified),
2824 )
2825 }
2826 }
2827 }
2828
2829 #[async_test]
2830 async fn test_share_with_identity_strategy() {
2831 let machine = test_machine().await;
2832 import_known_users_to_test_machine(&machine).await;
2833
2834 let encryption_settings = identity_based_strategy_settings();
2835
2836 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
2837
2838 let share_result = collect_session_recipients(
2839 machine.store(),
2840 vec![
2841 KeyDistributionTestData::dan_id(),
2842 KeyDistributionTestData::dave_id(),
2843 KeyDistributionTestData::good_id(),
2844 ]
2845 .into_iter(),
2846 &encryption_settings,
2847 &group_session,
2848 )
2849 .await
2850 .unwrap();
2851
2852 assert!(!share_result.should_rotate);
2853
2854 let dave_devices_shared = share_result.devices.get(KeyDistributionTestData::dave_id());
2855 let good_devices_shared = share_result.devices.get(KeyDistributionTestData::good_id());
2856 assert!(dave_devices_shared.unwrap().is_empty());
2858
2859 assert_eq!(good_devices_shared.unwrap().len(), 2);
2861
2862 let dan_devices_shared =
2865 share_result.devices.get(KeyDistributionTestData::dan_id()).unwrap();
2866
2867 assert_eq!(dan_devices_shared.len(), 1);
2868 let dan_device_that_will_get_the_key = &dan_devices_shared[0];
2869 assert_eq!(
2870 dan_device_that_will_get_the_key.device_id().as_str(),
2871 KeyDistributionTestData::dan_signed_device_id()
2872 );
2873
2874 let (_, code) = share_result
2876 .withheld_devices
2877 .iter()
2878 .find(|(d, _)| d.device_id() == KeyDistributionTestData::dan_unsigned_device_id())
2879 .expect("This dan's device should receive a withheld code");
2880
2881 assert_eq!(code, &WithheldCode::Unverified);
2882
2883 let (_, code) = share_result
2885 .withheld_devices
2886 .iter()
2887 .find(|(d, _)| d.device_id() == KeyDistributionTestData::dave_device_id())
2888 .expect("This dave device should receive a withheld code");
2889
2890 assert_eq!(code, &WithheldCode::Unverified);
2891 }
2892
2893 #[async_test]
2896 async fn test_share_identity_strategy_no_cross_signing() {
2897 let machine: OlmMachine = OlmMachine::new(
2900 KeyDistributionTestData::me_id(),
2901 KeyDistributionTestData::me_device_id(),
2902 )
2903 .await;
2904
2905 let keys_query = KeyDistributionTestData::dan_keys_query_response();
2906 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2907
2908 let fake_room_id = room_id!("!roomid:localhost");
2909
2910 let encryption_settings = identity_based_strategy_settings();
2911
2912 let request_result = machine
2913 .share_room_key(
2914 fake_room_id,
2915 iter::once(KeyDistributionTestData::dan_id()),
2916 encryption_settings.clone(),
2917 )
2918 .await;
2919
2920 assert_matches!(
2921 request_result,
2922 Err(OlmError::SessionRecipientCollectionError(
2923 SessionRecipientCollectionError::CrossSigningNotSetup
2924 ))
2925 );
2926
2927 let keys_query = KeyDistributionTestData::me_keys_query_response();
2931 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2932
2933 let request_result = machine
2934 .share_room_key(
2935 fake_room_id,
2936 iter::once(KeyDistributionTestData::dan_id()),
2937 encryption_settings.clone(),
2938 )
2939 .await;
2940
2941 assert_matches!(
2942 request_result,
2943 Err(OlmError::SessionRecipientCollectionError(
2944 SessionRecipientCollectionError::SendingFromUnverifiedDevice
2945 ))
2946 );
2947
2948 machine
2951 .import_cross_signing_keys(CrossSigningKeyExport {
2952 master_key: KeyDistributionTestData::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(),
2953 self_signing_key: KeyDistributionTestData::SELF_SIGNING_KEY_PRIVATE_EXPORT
2954 .to_owned()
2955 .into(),
2956 user_signing_key: KeyDistributionTestData::USER_SIGNING_KEY_PRIVATE_EXPORT
2957 .to_owned()
2958 .into(),
2959 })
2960 .await
2961 .unwrap();
2962
2963 let requests = machine
2964 .share_room_key(
2965 fake_room_id,
2966 iter::once(KeyDistributionTestData::dan_id()),
2967 encryption_settings.clone(),
2968 )
2969 .await
2970 .unwrap();
2971
2972 assert_eq!(requests.len(), 1);
2975 }
2976
2977 #[async_test]
2981 async fn test_share_identity_strategy_report_verification_violation() {
2982 let machine: OlmMachine = OlmMachine::new(
2983 KeyDistributionTestData::me_id(),
2984 KeyDistributionTestData::me_device_id(),
2985 )
2986 .await;
2987
2988 machine.bootstrap_cross_signing(false).await.unwrap();
2989
2990 let user1 = IdentityChangeDataSet::user_id();
2992 let user2 = MaloIdentityChangeDataSet::user_id();
2993
2994 let keys_query = IdentityChangeDataSet::key_query_with_identity_a();
2996 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2997
2998 let keys_query = MaloIdentityChangeDataSet::initial_key_query();
2999 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
3000
3001 let keys_query = IdentityChangeDataSet::key_query_with_identity_b();
3005 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
3006 machine
3007 .get_identity(user1, None)
3008 .await
3009 .unwrap()
3010 .unwrap()
3011 .other()
3012 .unwrap()
3013 .mark_as_previously_verified()
3014 .await
3015 .unwrap();
3016
3017 let keys_query = MaloIdentityChangeDataSet::updated_key_query();
3018 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
3019 machine
3020 .get_identity(user2, None)
3021 .await
3022 .unwrap()
3023 .unwrap()
3024 .other()
3025 .unwrap()
3026 .mark_as_previously_verified()
3027 .await
3028 .unwrap();
3029
3030 let fake_room_id = room_id!("!roomid:localhost");
3031
3032 let encryption_settings = identity_based_strategy_settings();
3034
3035 let request_result = machine
3036 .share_room_key(
3037 fake_room_id,
3038 vec![user1, user2].into_iter(),
3039 encryption_settings.clone(),
3040 )
3041 .await;
3042
3043 assert_let!(
3046 Err(OlmError::SessionRecipientCollectionError(
3047 SessionRecipientCollectionError::VerifiedUserChangedIdentity(affected_users)
3048 )) = request_result
3049 );
3050 assert_eq!(2, affected_users.len());
3052
3053 machine
3055 .get_identity(user1, None)
3056 .await
3057 .unwrap()
3058 .unwrap()
3059 .withdraw_verification()
3060 .await
3061 .unwrap();
3062
3063 let verification_request = machine
3065 .get_identity(user2, None)
3066 .await
3067 .unwrap()
3068 .unwrap()
3069 .other()
3070 .unwrap()
3071 .verify()
3072 .await
3073 .unwrap();
3074
3075 let master_key =
3076 &machine.get_identity(user2, None).await.unwrap().unwrap().other().unwrap().master_key;
3077
3078 let my_identity = machine
3079 .get_identity(KeyDistributionTestData::me_id(), None)
3080 .await
3081 .expect("Should not fail to find own identity")
3082 .expect("Our own identity should not be missing")
3083 .own()
3084 .expect("Our own identity should be of type Own");
3085
3086 let msk = json!({ user2: serde_json::to_value(master_key).expect("Should not fail to serialize")});
3087 let ssk =
3088 serde_json::to_value(&MaloIdentityChangeDataSet::updated_key_query().self_signing_keys)
3089 .expect("Should not fail to serialize");
3090
3091 let kq_response = simulate_key_query_response_for_verification(
3092 verification_request,
3093 my_identity,
3094 KeyDistributionTestData::me_id(),
3095 user2,
3096 msk,
3097 ssk,
3098 );
3099
3100 machine
3101 .mark_request_as_sent(
3102 &TransactionId::new(),
3103 crate::types::requests::AnyIncomingResponse::KeysQuery(&kq_response),
3104 )
3105 .await
3106 .unwrap();
3107
3108 assert!(machine.get_identity(user2, None).await.unwrap().unwrap().is_verified());
3109
3110 machine
3112 .share_room_key(
3113 fake_room_id,
3114 vec![user1, user2].into_iter(),
3115 encryption_settings.clone(),
3116 )
3117 .await
3118 .unwrap();
3119 }
3120
3121 #[async_test]
3122 async fn test_should_rotate_based_on_visibility() {
3123 let machine = test_machine().await;
3124 import_known_users_to_test_machine(&machine).await;
3125
3126 let strategy = CollectStrategy::AllDevices;
3127
3128 let encryption_settings = EncryptionSettings {
3129 sharing_strategy: strategy.clone(),
3130 history_visibility: HistoryVisibility::Invited,
3131 ..Default::default()
3132 };
3133
3134 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
3135
3136 let _ = collect_session_recipients(
3137 machine.store(),
3138 vec![KeyDistributionTestData::dan_id()].into_iter(),
3139 &encryption_settings,
3140 &group_session,
3141 )
3142 .await
3143 .unwrap();
3144
3145 let encryption_settings = EncryptionSettings {
3147 sharing_strategy: strategy.clone(),
3148 history_visibility: HistoryVisibility::Shared,
3149 ..Default::default()
3150 };
3151
3152 let share_result = collect_session_recipients(
3153 machine.store(),
3154 vec![KeyDistributionTestData::dan_id()].into_iter(),
3155 &encryption_settings,
3156 &group_session,
3157 )
3158 .await
3159 .unwrap();
3160
3161 assert!(share_result.should_rotate);
3162 }
3163
3164 #[async_test]
3168 async fn test_should_rotate_based_on_device_excluded() {
3169 let machine = test_machine().await;
3170 import_known_users_to_test_machine(&machine).await;
3171
3172 let encryption_settings = all_devices_strategy_settings();
3173 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
3174 let sender_key = machine.identity_keys().curve25519;
3175
3176 group_session
3177 .mark_shared_with(
3178 KeyDistributionTestData::dan_id(),
3179 KeyDistributionTestData::dan_signed_device_id(),
3180 sender_key,
3181 )
3182 .await;
3183 group_session
3184 .mark_shared_with(
3185 KeyDistributionTestData::dan_id(),
3186 KeyDistributionTestData::dan_unsigned_device_id(),
3187 sender_key,
3188 )
3189 .await;
3190
3191 let keys_query = KeyDistributionTestData::dan_keys_query_response_device_loggedout();
3193 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
3194
3195 let share_result = collect_session_recipients(
3197 machine.store(),
3198 vec![KeyDistributionTestData::dan_id()].into_iter(),
3199 &encryption_settings,
3200 &group_session,
3201 )
3202 .await
3203 .unwrap();
3204
3205 assert!(share_result.should_rotate);
3206 }
3207
3208 #[async_test]
3211 async fn test_should_rotate_based_on_device_with_pending_request_excluded() {
3212 let machine = test_machine().await;
3213 import_known_users_to_test_machine(&machine).await;
3214
3215 let encryption_settings = all_devices_strategy_settings();
3216 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
3217 let sender_key = machine.identity_keys().curve25519;
3218
3219 let dan_user = KeyDistributionTestData::dan_id();
3220 let dan_dev1 = KeyDistributionTestData::dan_signed_device_id();
3221 let dan_dev2 = KeyDistributionTestData::dan_unsigned_device_id();
3222
3223 group_session.mark_shared_with(dan_user, dan_dev1, sender_key).await;
3225
3226 {
3227 let share_infos = BTreeMap::from([(
3229 dan_user.to_owned(),
3230 BTreeMap::from([(
3231 dan_dev2.to_owned(),
3232 ShareInfo::new_shared(sender_key, 0, SequenceNumber::default()),
3233 )]),
3234 )]);
3235
3236 let txid = TransactionId::new();
3237 let req = Arc::new(ToDeviceRequest::for_recipients(
3238 dan_user,
3239 vec![dan_dev2.to_owned()],
3240 &ruma::events::AnyToDeviceEventContent::Dummy(ToDeviceDummyEventContent),
3241 txid.clone(),
3242 ));
3243 group_session.add_request(txid, req, share_infos);
3244 }
3245
3246 let keys_query = KeyDistributionTestData::dan_keys_query_response_device_loggedout();
3248 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
3249
3250 let share_result = collect_session_recipients(
3252 machine.store(),
3253 vec![KeyDistributionTestData::dan_id()].into_iter(),
3254 &encryption_settings,
3255 &group_session,
3256 )
3257 .await
3258 .unwrap();
3259
3260 assert!(share_result.should_rotate);
3261 }
3262
3263 #[async_test]
3266 async fn test_should_not_rotate_if_keys_were_withheld() {
3267 let machine = test_machine().await;
3268 import_known_users_to_test_machine(&machine).await;
3269
3270 let encryption_settings = all_devices_strategy_settings();
3271 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
3272 let fake_room_id = group_session.room_id();
3273
3274 let requests = machine
3277 .share_room_key(
3278 fake_room_id,
3279 vec![KeyDistributionTestData::dan_id()].into_iter(),
3280 encryption_settings.clone(),
3281 )
3282 .await
3283 .unwrap();
3284
3285 for r in requests {
3286 machine
3287 .inner
3288 .group_session_manager
3289 .mark_request_as_sent(r.as_ref().txn_id.as_ref())
3290 .await
3291 .unwrap();
3292 }
3293
3294 let keys_query = KeyDistributionTestData::dan_keys_query_response_device_loggedout();
3296 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
3297
3298 let share_result = collect_session_recipients(
3300 machine.store(),
3301 vec![KeyDistributionTestData::dan_id()].into_iter(),
3302 &encryption_settings,
3303 &group_session,
3304 )
3305 .await
3306 .unwrap();
3307
3308 assert!(!share_result.should_rotate);
3309 }
3310
3311 async fn unsigned_of_verified_setup() -> OlmMachine {
3319 use test_json::keys_query_sets::VerificationViolationTestData as DataSet;
3320
3321 let machine = OlmMachine::new(DataSet::own_id(), device_id!("LOCAL")).await;
3322
3323 let own_keys = DataSet::own_keys_query_response_1();
3325 machine.mark_request_as_sent(&TransactionId::new(), &own_keys).await.unwrap();
3326
3327 machine
3329 .import_cross_signing_keys(CrossSigningKeyExport {
3330 master_key: DataSet::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(),
3331 self_signing_key: DataSet::SELF_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
3332 user_signing_key: DataSet::USER_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
3333 })
3334 .await
3335 .unwrap();
3336
3337 let bob_keys = DataSet::bob_keys_query_response_signed();
3339 machine.mark_request_as_sent(&TransactionId::new(), &bob_keys).await.unwrap();
3340
3341 let bob_identity = machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap();
3344 assert!(bob_identity.other().unwrap().is_verified());
3345
3346 let bob_signed_device = machine
3347 .get_device(DataSet::bob_id(), DataSet::bob_device_1_id(), None)
3348 .await
3349 .unwrap()
3350 .unwrap();
3351 assert!(bob_signed_device.is_verified());
3352 assert!(bob_signed_device.device_owner_identity.is_some());
3353
3354 let bob_unsigned_device = machine
3355 .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None)
3356 .await
3357 .unwrap()
3358 .unwrap();
3359 assert!(!bob_unsigned_device.is_verified());
3360
3361 machine
3362 }
3363
3364 fn all_devices_strategy_settings() -> EncryptionSettings {
3366 EncryptionSettings { sharing_strategy: CollectStrategy::AllDevices, ..Default::default() }
3367 }
3368
3369 fn error_on_verification_problem_encryption_settings() -> EncryptionSettings {
3372 EncryptionSettings {
3373 sharing_strategy: CollectStrategy::ErrorOnVerifiedUserProblem,
3374 ..Default::default()
3375 }
3376 }
3377
3378 fn identity_based_strategy_settings() -> EncryptionSettings {
3380 EncryptionSettings {
3381 sharing_strategy: CollectStrategy::IdentityBasedStrategy,
3382 ..Default::default()
3383 }
3384 }
3385
3386 fn create_test_outbound_group_session(
3389 machine: &OlmMachine,
3390 encryption_settings: &EncryptionSettings,
3391 ) -> OutboundGroupSession {
3392 OutboundGroupSession::new(
3393 machine.device_id().into(),
3394 Arc::new(machine.identity_keys()),
3395 room_id!("!roomid:localhost"),
3396 encryption_settings.clone(),
3397 )
3398 .expect("creating an outbound group session should not fail")
3399 }
3400}