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