1use std::{
16 collections::{BTreeMap, HashMap},
17 fmt,
18 ops::{Deref, Not as _},
19 sync::Arc,
20 time::Duration,
21};
22
23use hkdf::Hkdf;
24use js_option::JsOption;
25use matrix_sdk_common::deserialized_responses::{
26 AlgorithmInfo, DeviceLinkProblem, EncryptionInfo, VerificationLevel, VerificationState,
27};
28use ruma::{
29 CanonicalJsonValue, DeviceId, DeviceKeyAlgorithm, DeviceKeyId, MilliSecondsSinceUnixEpoch,
30 OneTimeKeyAlgorithm, OneTimeKeyId, OwnedDeviceId, OwnedDeviceKeyId, OwnedOneTimeKeyId,
31 OwnedUserId, RoomId, SecondsSinceUnixEpoch, UInt, UserId,
32 api::client::{
33 dehydrated_device::{DehydratedDeviceData, DehydratedDeviceV2},
34 keys::{upload_keys, upload_signatures::v3::Request as SignatureUploadRequest},
35 },
36 canonical_json::to_canonical_value,
37 events::{AnyToDeviceEvent, room::history_visibility::HistoryVisibility},
38 serde::Raw,
39 uint,
40};
41use serde::{Deserialize, Serialize, de::Error};
42use serde_json::value::{RawValue as RawJsonValue, to_raw_value};
43use sha2::{Digest, Sha256};
44use tokio::sync::Mutex;
45use tracing::{Span, debug, field::debug, info, instrument, trace, warn};
46use vodozemac::{
47 Curve25519PublicKey, Ed25519Signature, KeyId, PickleError, base64_encode,
48 olm::{
49 Account as InnerAccount, AccountPickle, IdentityKeys, OlmMessage,
50 OneTimeKeyGenerationResult, PreKeyMessage, SessionConfig,
51 },
52};
53
54use super::{
55 EncryptionSettings, InboundGroupSession, OutboundGroupSession, PrivateCrossSigningIdentity,
56 Session, SessionCreationError as MegolmSessionCreationError, utility::SignJson,
57};
58#[cfg(feature = "experimental-algorithms")]
59use crate::types::events::room::encrypted::OlmV2Curve25519AesSha2Content;
60#[cfg(feature = "experimental-x509-identity-verification")]
61use crate::x509::{RawX509Signer, X509Signer};
62use crate::{
63 DecryptionSettings, Device, OlmError, SignatureError, TrustRequirement,
64 dehydrated_devices::DehydrationError,
65 error::{EventError, OlmResult, SessionCreationError},
66 identities::DeviceData,
67 olm::SenderData,
68 store::{
69 Store,
70 types::{Changes, DeviceChanges},
71 },
72 types::{
73 CrossSigningKey, DeviceKeys, EventEncryptionAlgorithm, OneTimeKey, SignedKey,
74 events::{
75 olm_v1::AnyDecryptedOlmEvent,
76 room::encrypted::{
77 EncryptedToDeviceEvent, OlmV1Curve25519AesSha2Content,
78 ToDeviceEncryptedEventContent,
79 },
80 },
81 requests::UploadSigningKeysRequest,
82 },
83};
84
85#[derive(Debug)]
86enum PrekeyBundle {
87 Olm3DH { key: SignedKey },
88}
89
90#[derive(Debug, Clone)]
91pub(crate) enum SessionType {
92 New(Session),
93 Existing(Session),
94}
95
96#[derive(Debug)]
97pub struct InboundCreationResult {
98 pub session: Session,
99 pub plaintext: String,
100}
101
102impl SessionType {
103 #[cfg(test)]
104 pub fn session(self) -> Session {
105 match self {
106 SessionType::New(s) => s,
107 SessionType::Existing(s) => s,
108 }
109 }
110}
111
112#[derive(Debug)]
118pub(crate) struct OlmDecryptionInfo {
119 pub session: SessionType,
120 pub message_hash: OlmMessageHash,
121 pub inbound_group_session: Option<InboundGroupSession>,
122 pub result: DecryptionResult,
123}
124
125#[derive(Debug)]
126pub(crate) struct DecryptionResult {
127 pub event: Box<AnyDecryptedOlmEvent>,
129 pub raw_event: Raw<AnyToDeviceEvent>,
130 pub sender_key: Curve25519PublicKey,
131 pub encryption_info: EncryptionInfo,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct OlmMessageHash {
139 pub sender_key: String,
141 pub hash: String,
143}
144
145impl OlmMessageHash {
146 fn new(sender_key: Curve25519PublicKey, ciphertext: &OlmMessage) -> Self {
147 let (message_type, ciphertext) = ciphertext.clone().to_parts();
148 let sender_key = sender_key.to_base64();
149
150 let sha = Sha256::new()
151 .chain_update(sender_key.as_bytes())
152 .chain_update([message_type as u8])
153 .chain_update(ciphertext)
154 .finalize();
155
156 Self { sender_key, hash: base64_encode(sha.as_slice()) }
157 }
158}
159
160#[derive(Clone)]
165#[cfg_attr(not(tarpaulin_include), derive(Debug))]
166pub struct StaticAccountData {
167 pub user_id: OwnedUserId,
169 pub device_id: OwnedDeviceId,
171 pub identity_keys: Arc<IdentityKeys>,
173 pub dehydrated: bool,
175 creation_local_time: MilliSecondsSinceUnixEpoch,
177}
178
179impl StaticAccountData {
180 const ALGORITHMS: &'static [&'static EventEncryptionAlgorithm] = &[
181 &EventEncryptionAlgorithm::OlmV1Curve25519AesSha2,
182 #[cfg(feature = "experimental-algorithms")]
183 &EventEncryptionAlgorithm::OlmV2Curve25519AesSha2,
184 &EventEncryptionAlgorithm::MegolmV1AesSha2,
185 #[cfg(feature = "experimental-algorithms")]
186 &EventEncryptionAlgorithm::MegolmV2AesSha2,
187 ];
188
189 pub async fn create_group_session_pair(
203 &self,
204 room_id: &RoomId,
205 settings: EncryptionSettings,
206 own_sender_data: SenderData,
207 ) -> Result<(OutboundGroupSession, InboundGroupSession), MegolmSessionCreationError> {
208 trace!(?room_id, algorithm = settings.algorithm.as_str(), "Creating a new room key");
209
210 let visibility = settings.history_visibility.clone();
211 let algorithm = settings.algorithm.to_owned();
212
213 let outbound = OutboundGroupSession::new(
214 self.device_id.clone(),
215 self.identity_keys.clone(),
216 room_id,
217 settings,
218 )?;
219
220 let identity_keys = &self.identity_keys;
221
222 let sender_key = identity_keys.curve25519;
223 let signing_key = identity_keys.ed25519;
224 let shared_history = shared_history_from_history_visibility(&visibility);
225
226 let inbound = InboundGroupSession::new(
227 sender_key,
228 signing_key,
229 room_id,
230 &outbound.session_key().await,
231 own_sender_data,
232 None,
233 algorithm,
234 Some(visibility),
235 shared_history,
236 )?;
237
238 Ok((outbound, inbound))
239 }
240
241 #[cfg(any(test, feature = "testing"))]
242 #[allow(dead_code)]
243 pub async fn create_group_session_pair_with_defaults(
246 &self,
247 room_id: &RoomId,
248 ) -> (OutboundGroupSession, InboundGroupSession) {
249 self.create_group_session_pair(
250 room_id,
251 EncryptionSettings::default(),
252 SenderData::unknown(),
253 )
254 .await
255 .expect("Can't create default group session pair")
256 }
257
258 pub fn signing_key_id(&self) -> OwnedDeviceKeyId {
260 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id())
261 }
262
263 pub fn has_signed_raw(
273 &self,
274 signatures: &crate::types::Signatures,
275 canonical_json: &str,
276 ) -> Result<(), SignatureError> {
277 use crate::olm::utility::VerifyJson;
278
279 let signing_key = self.identity_keys.ed25519;
280
281 signing_key.verify_canonicalized_json(
282 &self.user_id,
283 &DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
284 signatures,
285 canonical_json,
286 )
287 }
288
289 pub fn unsigned_device_keys(&self) -> DeviceKeys {
291 let identity_keys = self.identity_keys();
292 let keys = BTreeMap::from([
293 (
294 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Curve25519, &self.device_id),
295 identity_keys.curve25519.into(),
296 ),
297 (
298 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, &self.device_id),
299 identity_keys.ed25519.into(),
300 ),
301 ]);
302
303 let mut ret = DeviceKeys::new(
304 self.user_id.clone(),
305 self.device_id.clone(),
306 Self::ALGORITHMS.iter().map(|a| (**a).clone()).collect(),
307 keys,
308 Default::default(),
309 );
310 if self.dehydrated {
311 ret.dehydrated = JsOption::Some(true);
312 }
313 ret
314 }
315
316 pub fn user_id(&self) -> &UserId {
318 &self.user_id
319 }
320
321 pub fn device_id(&self) -> &DeviceId {
323 &self.device_id
324 }
325
326 pub fn identity_keys(&self) -> IdentityKeys {
328 *self.identity_keys
329 }
330
331 pub fn creation_local_time(&self) -> MilliSecondsSinceUnixEpoch {
333 self.creation_local_time
334 }
335}
336
337pub struct Account {
342 pub(crate) static_data: StaticAccountData,
343 inner: Box<InnerAccount>,
345 shared: bool,
348 uploaded_signed_key_count: u64,
353 fallback_creation_timestamp: Option<MilliSecondsSinceUnixEpoch>,
360}
361
362impl Deref for Account {
363 type Target = StaticAccountData;
364
365 fn deref(&self) -> &Self::Target {
366 &self.static_data
367 }
368}
369
370#[derive(Serialize, Deserialize)]
375#[allow(missing_debug_implementations)]
376pub struct PickledAccount {
377 pub user_id: OwnedUserId,
379 pub device_id: OwnedDeviceId,
381 pub pickle: AccountPickle,
383 pub shared: bool,
385 #[serde(default)]
387 pub dehydrated: bool,
388 pub uploaded_signed_key_count: u64,
390 #[serde(default = "default_account_creation_time")]
393 pub creation_local_time: MilliSecondsSinceUnixEpoch,
394 #[serde(default)]
396 pub fallback_key_creation_timestamp: Option<MilliSecondsSinceUnixEpoch>,
397}
398
399fn default_account_creation_time() -> MilliSecondsSinceUnixEpoch {
400 MilliSecondsSinceUnixEpoch(UInt::default())
401}
402
403#[cfg(not(tarpaulin_include))]
404impl fmt::Debug for Account {
405 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406 f.debug_struct("Account")
407 .field("identity_keys", &self.identity_keys())
408 .field("shared", &self.shared())
409 .finish()
410 }
411}
412
413pub type OneTimeKeys = BTreeMap<OwnedOneTimeKeyId, Raw<ruma::encryption::OneTimeKey>>;
414pub type FallbackKeys = OneTimeKeys;
415
416impl Account {
417 pub(crate) fn new_helper(
418 mut account: InnerAccount,
419 user_id: &UserId,
420 device_id: &DeviceId,
421 ) -> Self {
422 let identity_keys = account.identity_keys();
423
424 account.generate_one_time_keys(account.max_number_of_one_time_keys());
436
437 Self {
438 static_data: StaticAccountData {
439 user_id: user_id.into(),
440 device_id: device_id.into(),
441 identity_keys: Arc::new(identity_keys),
442 dehydrated: false,
443 creation_local_time: MilliSecondsSinceUnixEpoch::now(),
444 },
445 inner: Box::new(account),
446 shared: false,
447 uploaded_signed_key_count: 0,
448 fallback_creation_timestamp: None,
449 }
450 }
451
452 pub fn with_device_id(user_id: &UserId, device_id: &DeviceId) -> Self {
454 let account = InnerAccount::new();
455
456 Self::new_helper(account, user_id, device_id)
457 }
458
459 pub fn new(user_id: &UserId) -> Self {
462 let account = InnerAccount::new();
463 let device_id: OwnedDeviceId =
464 base64_encode(account.identity_keys().curve25519.as_bytes()).into();
465
466 Self::new_helper(account, user_id, &device_id)
467 }
468
469 pub fn new_dehydrated(user_id: &UserId) -> Self {
471 let account = InnerAccount::new();
472 let device_id: OwnedDeviceId =
473 base64_encode(account.identity_keys().curve25519.as_bytes()).into();
474
475 let mut ret = Self::new_helper(account, user_id, &device_id);
476 ret.static_data.dehydrated = true;
477 ret
478 }
479
480 pub fn static_data(&self) -> &StaticAccountData {
482 &self.static_data
483 }
484
485 pub fn update_uploaded_key_count(&mut self, new_count: u64) {
491 self.uploaded_signed_key_count = new_count;
492 }
493
494 pub fn uploaded_key_count(&self) -> u64 {
496 self.uploaded_signed_key_count
497 }
498
499 pub fn shared(&self) -> bool {
501 self.shared
502 }
503
504 pub fn mark_as_shared(&mut self) {
509 self.shared = true;
510 }
511
512 pub fn one_time_keys(&self) -> HashMap<KeyId, Curve25519PublicKey> {
516 self.inner.one_time_keys()
517 }
518
519 pub fn generate_one_time_keys(&mut self, count: usize) -> OneTimeKeyGenerationResult {
521 self.inner.generate_one_time_keys(count)
522 }
523
524 pub fn max_one_time_keys(&self) -> usize {
526 self.inner.max_number_of_one_time_keys()
527 }
528
529 pub(crate) fn update_key_counts(
546 &mut self,
547 one_time_key_counts: &BTreeMap<OneTimeKeyAlgorithm, UInt>,
548 unused_fallback_keys: Option<&[OneTimeKeyAlgorithm]>,
549 is_missing_count_zero: bool,
550 ) {
551 let count = if is_missing_count_zero {
552 Some(
553 one_time_key_counts
554 .get(&OneTimeKeyAlgorithm::SignedCurve25519)
555 .copied()
556 .unwrap_or(uint!(0)),
557 )
558 } else {
559 one_time_key_counts.get(&OneTimeKeyAlgorithm::SignedCurve25519).copied()
560 };
561
562 if let Some(count) = count.map(Into::into) {
563 let old_count = self.uploaded_key_count();
564
565 if count != old_count {
569 debug!(
570 "Updated uploaded one-time key count {} -> {count}.",
571 self.uploaded_key_count(),
572 );
573 }
574
575 self.update_uploaded_key_count(count);
576 self.generate_one_time_keys_if_needed();
577 }
578
579 if unused_fallback_keys.is_some() || self.fallback_creation_timestamp.is_some() {
583 self.generate_fallback_key_if_needed();
584 }
585 }
586
587 #[instrument(skip_all)]
596 pub fn generate_one_time_keys_if_needed(&mut self) -> Option<u64> {
597 if !self.one_time_keys().is_empty() {
601 return Some(0);
602 }
603
604 let count = self.uploaded_key_count();
605 let max_keys = self.max_one_time_keys();
606
607 if count >= max_keys as u64 {
608 return None;
609 }
610
611 let key_count = (max_keys as u64) - count;
612 let key_count: usize = key_count.try_into().unwrap_or(max_keys);
613
614 let result = self.generate_one_time_keys(key_count);
615
616 debug!(
617 count = key_count,
618 discarded_keys = ?result.removed,
619 created_keys = ?result.created,
620 "Generated new one-time keys"
621 );
622
623 Some(key_count as u64)
624 }
625
626 pub(crate) fn generate_fallback_key_if_needed(&mut self) {
633 if self.inner.fallback_key().is_empty() && self.fallback_key_expired() {
634 let removed_fallback_key = self.inner.generate_fallback_key();
635 self.fallback_creation_timestamp = Some(MilliSecondsSinceUnixEpoch::now());
636
637 debug!(
638 ?removed_fallback_key,
639 "The fallback key either expired or we didn't have one: generated a new fallback key.",
640 );
641 }
642 }
643
644 fn fallback_key_expired(&self) -> bool {
652 const FALLBACK_KEY_MAX_AGE: Duration = Duration::from_secs(3600 * 24 * 7);
653
654 if let Some(time) = self.fallback_creation_timestamp {
655 let Some(system_time) = time.to_system_time() else {
660 return true;
661 };
662
663 let Ok(elapsed) = system_time.elapsed() else {
667 return true;
668 };
669
670 elapsed > FALLBACK_KEY_MAX_AGE
675 } else {
676 true
680 }
681 }
682
683 fn fallback_key(&self) -> HashMap<KeyId, Curve25519PublicKey> {
684 self.inner.fallback_key()
685 }
686
687 pub fn keys_for_upload(&self) -> (Option<DeviceKeys>, OneTimeKeys, FallbackKeys) {
693 let device_keys = self.shared().not().then(|| self.device_keys());
694
695 let one_time_keys = self.signed_one_time_keys();
696 let fallback_keys = self.signed_fallback_keys();
697
698 (device_keys, one_time_keys, fallback_keys)
699 }
700
701 pub fn mark_keys_as_published(&mut self) {
703 self.inner.mark_keys_as_published();
704 }
705
706 pub fn sign(&self, string: &str) -> Ed25519Signature {
710 self.inner.sign(string)
711 }
712
713 pub fn pickle(&self) -> PickledAccount {
715 let pickle = self.inner.pickle();
716
717 PickledAccount {
718 user_id: self.user_id().to_owned(),
719 device_id: self.device_id().to_owned(),
720 pickle,
721 shared: self.shared(),
722 dehydrated: self.static_data.dehydrated,
723 uploaded_signed_key_count: self.uploaded_key_count(),
724 creation_local_time: self.static_data.creation_local_time,
725 fallback_key_creation_timestamp: self.fallback_creation_timestamp,
726 }
727 }
728
729 pub(crate) fn dehydrate(&self, pickle_key: &[u8; 32]) -> Raw<DehydratedDeviceData> {
730 let dehydration_result = self
731 .inner
732 .to_dehydrated_device(pickle_key)
733 .expect("We should be able to convert a freshly created Account into a libolm pickle");
734
735 let data = DehydratedDeviceData::V2(DehydratedDeviceV2::new(
736 dehydration_result.ciphertext,
737 dehydration_result.nonce,
738 ));
739 Raw::from_json(to_raw_value(&data).expect("Couldn't serialize our dehydrated device data"))
740 }
741
742 pub(crate) fn rehydrate(
743 pickle_key: &[u8; 32],
744 user_id: &UserId,
745 device_id: &DeviceId,
746 device_data: Raw<DehydratedDeviceData>,
747 ) -> Result<Self, DehydrationError> {
748 let data = device_data.deserialize()?;
749
750 match data {
751 DehydratedDeviceData::V1(d) => {
752 let pickle_key = expand_legacy_pickle_key(pickle_key, device_id);
753 let account =
754 InnerAccount::from_libolm_pickle(&d.device_pickle, pickle_key.as_ref())?;
755 Ok(Self::new_helper(account, user_id, device_id))
756 }
757 DehydratedDeviceData::V2(d) => {
758 let account =
759 InnerAccount::from_dehydrated_device(&d.device_pickle, &d.nonce, pickle_key)?;
760 Ok(Self::new_helper(account, user_id, device_id))
761 }
762 _ => Err(DehydrationError::Json(serde_json::Error::custom(format!(
763 "Unsupported dehydrated device algorithm {:?}",
764 data.algorithm()
765 )))),
766 }
767 }
768
769 #[cfg(test)]
772 pub(crate) fn legacy_dehydrate(&self, pickle_key: &[u8; 32]) -> Raw<DehydratedDeviceData> {
773 use ruma::api::client::dehydrated_device::DehydratedDeviceV1;
774
775 let pickle_key = expand_legacy_pickle_key(pickle_key, &self.device_id);
776 let device_pickle = self
777 .inner
778 .to_libolm_pickle(pickle_key.as_ref())
779 .expect("We should be able to convert a freshly created Account into a libolm pickle");
780
781 let data = DehydratedDeviceData::V1(DehydratedDeviceV1::new(device_pickle));
782 Raw::from_json(to_raw_value(&data).expect("Couldn't serialize our dehydrated device data"))
783 }
784
785 pub fn from_pickle(pickle: PickledAccount) -> Result<Self, PickleError> {
793 let account: vodozemac::olm::Account = pickle.pickle.into();
794 let identity_keys = account.identity_keys();
795
796 Ok(Self {
797 static_data: StaticAccountData {
798 user_id: pickle.user_id.clone(),
799 device_id: pickle.device_id.clone(),
800 identity_keys: Arc::new(identity_keys),
801 dehydrated: pickle.dehydrated,
802 creation_local_time: pickle.creation_local_time,
803 },
804 inner: Box::new(account),
805 shared: pickle.shared,
806 uploaded_signed_key_count: pickle.uploaded_signed_key_count,
807 fallback_creation_timestamp: pickle.fallback_key_creation_timestamp,
808 })
809 }
810
811 pub fn device_keys(&self) -> DeviceKeys {
814 let mut device_keys = self.unsigned_device_keys();
815
816 let json_device_keys =
819 to_canonical_value(&device_keys).expect("device key is always safe to serialize");
820 let signature = self
821 .sign_json(json_device_keys)
822 .expect("Newly created device keys can always be signed");
823
824 device_keys.signatures.add_signature(
825 self.user_id().to_owned(),
826 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, &self.static_data.device_id),
827 signature,
828 );
829
830 device_keys
831 }
832
833 pub async fn bootstrap_cross_signing(
847 &self,
848 #[cfg(feature = "experimental-x509-identity-verification")] x509_signer: Option<
849 Arc<dyn RawX509Signer>,
850 >,
851 ) -> Result<
852 (PrivateCrossSigningIdentity, UploadSigningKeysRequest, SignatureUploadRequest),
853 SignatureError,
854 > {
855 #[cfg(feature = "experimental-x509-identity-verification")]
856 let x509_signer = x509_signer.map(X509Signer::new);
857
858 let identity = PrivateCrossSigningIdentity::for_account(
859 self,
860 #[cfg(feature = "experimental-x509-identity-verification")]
861 x509_signer.as_ref(),
862 )
863 .await?;
864
865 let signature_request = identity.sign_account(self.static_data()).await?;
866
867 let upload_request = identity.as_upload_request().await;
868
869 Ok((identity, upload_request, signature_request))
870 }
871
872 pub fn sign_cross_signing_key(
874 &self,
875 cross_signing_key: &mut CrossSigningKey,
876 ) -> Result<(), SignatureError> {
877 let signature = self.sign_json(to_canonical_value(&cross_signing_key)?)?;
878
879 cross_signing_key.signatures.add_signature(
880 self.user_id().to_owned(),
881 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
882 signature,
883 );
884
885 Ok(())
886 }
887
888 pub fn sign_json(&self, json: CanonicalJsonValue) -> Result<Ed25519Signature, SignatureError> {
896 self.inner.sign_json(json)
897 }
898
899 pub fn signed_one_time_keys(&self) -> OneTimeKeys {
903 let one_time_keys = self.one_time_keys();
904
905 if one_time_keys.is_empty() {
906 BTreeMap::new()
907 } else {
908 self.signed_keys(one_time_keys, false)
909 }
910 }
911
912 pub fn signed_fallback_keys(&self) -> FallbackKeys {
916 let fallback_key = self.fallback_key();
917
918 if fallback_key.is_empty() { BTreeMap::new() } else { self.signed_keys(fallback_key, true) }
919 }
920
921 fn signed_keys(
922 &self,
923 keys: HashMap<KeyId, Curve25519PublicKey>,
924 fallback: bool,
925 ) -> OneTimeKeys {
926 let mut keys_map = BTreeMap::new();
927
928 for (key_id, key) in keys {
929 let signed_key = self.sign_key(key, fallback);
930
931 keys_map.insert(
932 OneTimeKeyId::from_parts(
933 OneTimeKeyAlgorithm::SignedCurve25519,
934 key_id.to_base64().as_str().into(),
935 ),
936 signed_key.into_raw(),
937 );
938 }
939
940 keys_map
941 }
942
943 fn sign_key(&self, key: Curve25519PublicKey, fallback: bool) -> SignedKey {
944 let mut key = if fallback {
945 SignedKey::new_fallback(key.to_owned())
946 } else {
947 SignedKey::new(key.to_owned())
948 };
949
950 let signature = self
951 .sign_json(to_canonical_value(&key).expect("Can't serialize a signed key"))
952 .expect("Newly created one-time keys can always be signed");
953
954 key.signatures_mut().add_signature(
955 self.user_id().to_owned(),
956 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
957 signature,
958 );
959
960 key
961 }
962
963 pub fn create_outbound_session_helper(
981 &self,
982 config: SessionConfig,
983 identity_key: Curve25519PublicKey,
984 one_time_key: Curve25519PublicKey,
985 fallback_used: bool,
986 our_device_keys: DeviceKeys,
987 ) -> Result<Session, vodozemac::olm::SessionCreationError> {
988 let session = self.inner.create_outbound_session(config, identity_key, one_time_key)?;
989
990 let now = SecondsSinceUnixEpoch::now();
991 let session_id = session.session_id();
992
993 Ok(Session {
994 inner: Arc::new(Mutex::new(session)),
995 session_id: session_id.into(),
996 sender_key: identity_key,
997 our_device_keys,
998 created_using_fallback_key: fallback_used,
999 creation_time: now,
1000 last_use_time: now,
1001 })
1002 }
1003
1004 #[instrument(
1005 skip_all,
1006 fields(
1007 user_id = ?device.user_id(),
1008 device_id = ?device.device_id(),
1009 algorithms = ?device.algorithms()
1010 )
1011 )]
1012 fn find_pre_key_bundle(
1013 device: &DeviceData,
1014 key_map: &OneTimeKeys,
1015 ) -> Result<PrekeyBundle, SessionCreationError> {
1016 let mut keys = key_map.iter();
1017
1018 let first_key = keys.next().ok_or_else(|| {
1019 SessionCreationError::OneTimeKeyMissing(
1020 device.user_id().to_owned(),
1021 device.device_id().into(),
1022 )
1023 })?;
1024
1025 let first_key_id = first_key.0.to_owned();
1026 let first_key = OneTimeKey::deserialize(first_key_id.algorithm(), first_key.1)?;
1027
1028 let result = match first_key {
1029 OneTimeKey::SignedKey(key) => Ok(PrekeyBundle::Olm3DH { key }),
1030 };
1031
1032 trace!(?result, "Finished searching for a valid pre-key bundle");
1033
1034 result
1035 }
1036
1037 #[allow(clippy::result_large_err)]
1052 pub fn create_outbound_session(
1053 &self,
1054 device: &DeviceData,
1055 key_map: &OneTimeKeys,
1056 our_device_keys: DeviceKeys,
1057 ) -> Result<Session, SessionCreationError> {
1058 let pre_key_bundle = Self::find_pre_key_bundle(device, key_map)?;
1059
1060 match pre_key_bundle {
1061 PrekeyBundle::Olm3DH { key } => {
1062 device.verify_one_time_key(&key).map_err(|error| {
1063 SessionCreationError::InvalidSignature {
1064 signing_key: device.ed25519_key().map(Box::new),
1065 one_time_key: key.clone().into(),
1066 error: error.into(),
1067 }
1068 })?;
1069
1070 let identity_key = device.curve25519_key().ok_or_else(|| {
1071 SessionCreationError::DeviceMissingCurveKey(
1072 device.user_id().to_owned(),
1073 device.device_id().into(),
1074 )
1075 })?;
1076
1077 let is_fallback = key.fallback();
1078 let one_time_key = key.key();
1079 let config = device.olm_session_config();
1080
1081 Ok(self.create_outbound_session_helper(
1082 config,
1083 identity_key,
1084 one_time_key,
1085 is_fallback,
1086 our_device_keys,
1087 )?)
1088 }
1089 }
1090 }
1091
1092 pub fn create_inbound_session(
1106 &mut self,
1107 their_identity_key: Curve25519PublicKey,
1108 our_device_keys: DeviceKeys,
1109 message: &PreKeyMessage,
1110 ) -> Result<InboundCreationResult, SessionCreationError> {
1111 Span::current().record("session_id", debug(message.session_id()));
1112 trace!("Creating a new Olm session from a pre-key message");
1113
1114 #[cfg(not(feature = "experimental-algorithms"))]
1115 let config = SessionConfig::version_1();
1116
1117 #[cfg(feature = "experimental-algorithms")]
1118 let config = SessionConfig::version_2();
1119
1120 let result = self.inner.create_inbound_session(config, their_identity_key, message)?;
1121 let now = SecondsSinceUnixEpoch::now();
1122 let session_id = result.session.session_id();
1123
1124 debug!(session=?result.session, "Decrypted an Olm message from a new Olm session");
1125
1126 let session = Session {
1127 inner: Arc::new(Mutex::new(result.session)),
1128 session_id: session_id.into(),
1129 sender_key: their_identity_key,
1130 our_device_keys,
1131 created_using_fallback_key: false,
1132 creation_time: now,
1133 last_use_time: now,
1134 };
1135
1136 let plaintext = String::from_utf8_lossy(&result.plaintext).to_string();
1137
1138 Ok(InboundCreationResult { session, plaintext })
1139 }
1140
1141 #[cfg(any(test, feature = "testing"))]
1142 #[allow(dead_code)]
1143 pub async fn create_session_for_test_helper(
1145 &mut self,
1146 other: &mut Account,
1147 ) -> (Session, Session) {
1148 use ruma::events::dummy::ToDeviceDummyEventContent;
1149
1150 other.generate_one_time_keys(1);
1151 let one_time_map = other.signed_one_time_keys();
1152 let device = DeviceData::from_account(other);
1153
1154 let mut our_session =
1155 self.create_outbound_session(&device, &one_time_map, self.device_keys()).unwrap();
1156
1157 other.mark_keys_as_published();
1158
1159 let message = our_session
1160 .encrypt(&device, "m.dummy", ToDeviceDummyEventContent::new(), None)
1161 .await
1162 .unwrap()
1163 .deserialize()
1164 .unwrap();
1165
1166 #[cfg(feature = "experimental-algorithms")]
1167 let content = if let ToDeviceEncryptedEventContent::OlmV2Curve25519AesSha2(c) = message {
1168 c
1169 } else {
1170 panic!("Invalid encrypted event algorithm {}", message.algorithm());
1171 };
1172
1173 #[cfg(not(feature = "experimental-algorithms"))]
1174 let ToDeviceEncryptedEventContent::OlmV1Curve25519AesSha2(content) = message else {
1175 panic!("Invalid encrypted event algorithm {}", message.algorithm());
1176 };
1177
1178 let OlmMessage::PreKey(prekey) = content.ciphertext else {
1179 panic!("Wrong Olm message type");
1180 };
1181
1182 let our_device = DeviceData::from_account(self);
1183 let other_session = other
1184 .create_inbound_session(
1185 our_device.curve25519_key().unwrap(),
1186 other.device_keys(),
1187 &prekey,
1188 )
1189 .unwrap();
1190
1191 (our_session, other_session.session)
1192 }
1193
1194 async fn decrypt_olm_helper(
1195 &mut self,
1196 store: &Store,
1197 sender: &UserId,
1198 sender_key: Curve25519PublicKey,
1199 ciphertext: &OlmMessage,
1200 decryption_settings: &DecryptionSettings,
1201 ) -> OlmResult<OlmDecryptionInfo> {
1202 let message_hash = OlmMessageHash::new(sender_key, ciphertext);
1203
1204 match self
1205 .decrypt_and_parse_olm_message(
1206 store,
1207 sender,
1208 sender_key,
1209 ciphertext,
1210 decryption_settings,
1211 )
1212 .await
1213 {
1214 Ok((session, result)) => {
1215 Ok(OlmDecryptionInfo { session, message_hash, result, inbound_group_session: None })
1216 }
1217 Err(OlmError::SessionWedged(user_id, sender_key)) => {
1218 if store.is_message_known(&message_hash).await? {
1219 info!(?sender_key, "An Olm message got replayed, decryption failed");
1220 Err(OlmError::ReplayedMessage(user_id, sender_key))
1221 } else {
1222 Err(OlmError::SessionWedged(user_id, sender_key))
1223 }
1224 }
1225 Err(e) => Err(e),
1226 }
1227 }
1228
1229 #[cfg(feature = "experimental-algorithms")]
1230 async fn decrypt_olm_v2(
1231 &mut self,
1232 store: &Store,
1233 sender: &UserId,
1234 content: &OlmV2Curve25519AesSha2Content,
1235 decryption_settings: &DecryptionSettings,
1236 ) -> OlmResult<OlmDecryptionInfo> {
1237 self.decrypt_olm_helper(
1238 store,
1239 sender,
1240 content.sender_key,
1241 &content.ciphertext,
1242 decryption_settings,
1243 )
1244 .await
1245 }
1246
1247 #[instrument(skip_all, fields(sender, sender_key = ?content.sender_key))]
1248 async fn decrypt_olm_v1(
1249 &mut self,
1250 store: &Store,
1251 sender: &UserId,
1252 content: &OlmV1Curve25519AesSha2Content,
1253 decryption_settings: &DecryptionSettings,
1254 ) -> OlmResult<OlmDecryptionInfo> {
1255 if content.recipient_key != self.static_data.identity_keys.curve25519 {
1256 warn!("Olm event doesn't contain a ciphertext for our key");
1257
1258 Err(EventError::MissingCiphertext.into())
1259 } else {
1260 Box::pin(self.decrypt_olm_helper(
1261 store,
1262 sender,
1263 content.sender_key,
1264 &content.ciphertext,
1265 decryption_settings,
1266 ))
1267 .await
1268 }
1269 }
1270
1271 #[instrument(skip_all, fields(algorithm = ?event.content.algorithm()))]
1272 pub(crate) async fn decrypt_to_device_event(
1273 &mut self,
1274 store: &Store,
1275 event: &EncryptedToDeviceEvent,
1276 decryption_settings: &DecryptionSettings,
1277 ) -> OlmResult<OlmDecryptionInfo> {
1278 trace!("Decrypting a to-device event");
1279
1280 match &event.content {
1281 ToDeviceEncryptedEventContent::OlmV1Curve25519AesSha2(c) => {
1282 self.decrypt_olm_v1(store, &event.sender, c, decryption_settings).await
1283 }
1284 #[cfg(feature = "experimental-algorithms")]
1285 ToDeviceEncryptedEventContent::OlmV2Curve25519AesSha2(c) => {
1286 self.decrypt_olm_v2(store, &event.sender, c, decryption_settings).await
1287 }
1288 ToDeviceEncryptedEventContent::Unknown(_) => {
1289 warn!(
1290 "Error decrypting an to-device event, unsupported \
1291 encryption algorithm"
1292 );
1293
1294 Err(EventError::UnsupportedAlgorithm.into())
1295 }
1296 }
1297 }
1298
1299 pub fn receive_keys_upload_response(
1301 &mut self,
1302 response: &upload_keys::v3::Response,
1303 ) -> OlmResult<()> {
1304 if !self.shared() {
1305 debug!("Marking account as shared");
1306 }
1307 self.mark_as_shared();
1308
1309 debug!("Marking one-time keys as published");
1310 self.mark_keys_as_published();
1313 self.update_key_counts(&response.one_time_key_counts, None, false);
1314
1315 Ok(())
1316 }
1317
1318 async fn decrypt_olm_message(
1320 &mut self,
1321 store: &Store,
1322 sender: &UserId,
1323 sender_key: Curve25519PublicKey,
1324 message: &OlmMessage,
1325 ) -> Result<(SessionType, String), OlmError> {
1326 let existing_sessions = store.get_sessions(&sender_key.to_base64()).await?;
1327
1328 match message {
1329 OlmMessage::Normal(_) => {
1330 let mut errors_by_olm_session = Vec::new();
1331
1332 if let Some(sessions) = existing_sessions {
1333 for session in sessions.lock().await.iter_mut() {
1336 match session.decrypt(message).await {
1337 Ok(p) => {
1338 return Ok((SessionType::Existing(session.clone()), p));
1340 }
1341
1342 Err(e) => {
1343 errors_by_olm_session.push((session.session_id().to_owned(), e));
1349 }
1350 }
1351 }
1352 }
1353
1354 warn!(
1355 ?errors_by_olm_session,
1356 "Failed to decrypt a non-pre-key message with all available sessions"
1357 );
1358 Err(OlmError::SessionWedged(sender.to_owned(), sender_key))
1359 }
1360
1361 OlmMessage::PreKey(prekey_message) => {
1362 if let Some(sessions) = existing_sessions {
1364 for session in sessions.lock().await.iter_mut() {
1365 if prekey_message.session_id() != session.session_id() {
1366 continue;
1368 }
1369
1370 if let Ok(p) = session.decrypt(message).await {
1371 return Ok((SessionType::Existing(session.clone()), p));
1373 }
1374
1375 warn!(
1391 session_id = session.session_id(),
1392 "Failed to decrypt a pre-key message with the corresponding session"
1393 );
1394
1395 return Err(OlmError::SessionWedged(
1396 session.our_device_keys.user_id.to_owned(),
1397 session.sender_key(),
1398 ));
1399 }
1400 }
1401
1402 let device_keys = store.get_own_device().await?.as_device_keys().clone();
1403 let result =
1404 match self.create_inbound_session(sender_key, device_keys, prekey_message) {
1405 Ok(r) => r,
1406 Err(e) => {
1407 warn!(
1408 "Failed to create a new Olm session from a pre-key message: {e:?}"
1409 );
1410 return Err(OlmError::SessionWedged(sender.to_owned(), sender_key));
1411 }
1412 };
1413
1414 let mut changes =
1419 Changes { sessions: vec![result.session.clone()], ..Default::default() };
1420
1421 if let Some(device) = store.get_device_from_curve_key(sender, sender_key).await? {
1428 let mut device_data = device.inner;
1429 device_data.olm_wedging_index.increment();
1430
1431 changes.devices =
1432 DeviceChanges { changed: vec![device_data], ..Default::default() };
1433 }
1434
1435 store.save_changes(changes).await?;
1436
1437 Ok((SessionType::New(result.session), result.plaintext))
1438 }
1439 }
1440 }
1441
1442 #[instrument(skip(self, store), fields(session, session_id))]
1445 async fn decrypt_and_parse_olm_message(
1446 &mut self,
1447 store: &Store,
1448 sender: &UserId,
1449 sender_key: Curve25519PublicKey,
1450 message: &OlmMessage,
1451 decryption_settings: &DecryptionSettings,
1452 ) -> OlmResult<(SessionType, DecryptionResult)> {
1453 let (session, plaintext) =
1454 self.decrypt_olm_message(store, sender, sender_key, message).await?;
1455
1456 trace!("Successfully decrypted an Olm message");
1457
1458 match self
1459 .parse_decrypted_to_device_event(
1460 store,
1461 sender,
1462 sender_key,
1463 plaintext,
1464 decryption_settings,
1465 )
1466 .await
1467 {
1468 Ok(result) => Ok((session, result)),
1469 Err(e) => {
1470 match session {
1474 SessionType::New(s) | SessionType::Existing(s) => {
1475 store.save_sessions(&[s]).await?;
1476 }
1477 }
1478
1479 warn!(
1480 error = ?e,
1481 "A to-device message was successfully decrypted but \
1482 parsing and checking the event fields failed"
1483 );
1484
1485 Err(e)
1486 }
1487 }
1488 }
1489
1490 async fn parse_decrypted_to_device_event(
1511 &self,
1512 store: &Store,
1513 sender: &UserId,
1514 sender_key: Curve25519PublicKey,
1515 plaintext: String,
1516 decryption_settings: &DecryptionSettings,
1517 ) -> OlmResult<DecryptionResult> {
1518 let event: Box<AnyDecryptedOlmEvent> = serde_json::from_str(&plaintext)?;
1519 let identity_keys = &self.static_data.identity_keys;
1520
1521 if event.recipient() != self.static_data.user_id {
1522 Err(EventError::MismatchedSender(
1523 event.recipient().to_owned(),
1524 self.static_data.user_id.clone(),
1525 )
1526 .into())
1527 }
1528 else if event.sender() != sender {
1531 Err(EventError::MismatchedSender(event.sender().to_owned(), sender.to_owned()).into())
1532 } else if identity_keys.ed25519 != event.recipient_keys().ed25519 {
1533 Err(EventError::MismatchedKeys(
1534 identity_keys.ed25519.into(),
1535 event.recipient_keys().ed25519.into(),
1536 )
1537 .into())
1538 } else {
1539 let sender_device = Self::get_event_sender_device(store, sender_key, &event).await?;
1540 let encryption_info = Self::get_olm_encryption_info(sender_key, sender, &sender_device);
1541
1542 let result = DecryptionResult {
1543 event,
1544 raw_event: Raw::from_json(RawJsonValue::from_string(plaintext)?),
1545 sender_key,
1546 encryption_info,
1547 };
1548
1549 if !self.is_from_verified_device_or_allowed_type(decryption_settings, &result) {
1551 Err(OlmError::UnverifiedSenderDevice)
1552 } else {
1553 Ok(result)
1555 }
1556 }
1557 }
1558
1559 async fn get_event_sender_device(
1573 store: &Store,
1574 sender_key: Curve25519PublicKey,
1575 event: &AnyDecryptedOlmEvent,
1576 ) -> OlmResult<Option<Device>> {
1577 let sender_device_keys = Self::check_sender_device_keys(event, sender_key)?;
1582 if let AnyDecryptedOlmEvent::RoomKey(_) = event {
1583 return Ok(None);
1588 }
1589
1590 if let AnyDecryptedOlmEvent::RoomKeyBundle(_) = event {
1593 sender_device_keys.ok_or(EventError::MissingSigningKey).inspect_err(|_| {
1594 warn!("The room key bundle was missing the sender device keys in the event")
1595 })?;
1596 }
1597
1598 let store_device = store.get_device_from_curve_key(event.sender(), sender_key).await?;
1603
1604 match (store_device, sender_device_keys) {
1605 (Some(device), _) => {
1608 let key = device.ed25519_key().ok_or(EventError::MissingSigningKey)?;
1609 if key != event.keys().ed25519 {
1610 return Err(EventError::MismatchedKeys(
1611 key.into(),
1612 event.keys().ed25519.into(),
1613 )
1614 .into());
1615 }
1616 Ok(Some(device))
1617 }
1618
1619 (None, Some(sender_device_keys)) => {
1620 let sender_device_data = sender_device_keys.try_into().expect("Conversion of DeviceKeys to DeviceData failed despite the signature already having been checked");
1623 Ok(Some(store.wrap_device_data(sender_device_data).await?))
1624 }
1625
1626 (None, None) => Err(OlmError::EventError(EventError::MissingSigningKey)),
1627 }
1628 }
1629
1630 fn is_from_verified_device_or_allowed_type(
1643 &self,
1644 decryption_settings: &DecryptionSettings,
1645 result: &DecryptionResult,
1646 ) -> bool {
1647 let event_type = result.event.event_type();
1648
1649 match event_type {
1661 "m.room_key"
1662 | "m.room_key.withheld"
1663 | "m.room_key_request"
1664 | "m.secret.request"
1665 | "m.key.verification.key"
1666 | "m.key.verification.mac"
1667 | "m.key.verification.done"
1668 | "m.key.verification.ready"
1669 | "m.key.verification.start"
1670 | "m.key.verification.accept"
1671 | "m.key.verification.cancel"
1672 | "m.key.verification.request" => {
1673 true
1676 }
1677 _ => {
1678 satisfies_sender_trust_requirement(
1681 &result.encryption_info,
1682 &decryption_settings.sender_device_trust_requirement,
1683 )
1684 }
1685 }
1686 }
1687
1688 fn get_olm_encryption_info(
1695 sender_key: Curve25519PublicKey,
1696 sender_id: &UserId,
1697 sender_device: &Option<Device>,
1698 ) -> EncryptionInfo {
1699 let verification_state = sender_device
1700 .as_ref()
1701 .map(|device| {
1702 if device.is_verified() {
1703 VerificationState::Verified
1706 } else if device.is_cross_signed_by_owner() {
1707 if device
1709 .device_owner_identity
1710 .as_ref()
1711 .expect("A device cross-signed by the owner must have an owner identity")
1712 .was_previously_verified()
1713 {
1714 VerificationState::Unverified(VerificationLevel::VerificationViolation)
1715 } else {
1716 VerificationState::Unverified(VerificationLevel::UnverifiedIdentity)
1717 }
1718 } else {
1719 VerificationState::Unverified(VerificationLevel::UnsignedDevice)
1721 }
1722 })
1723 .unwrap_or(VerificationState::Unverified(VerificationLevel::None(
1724 DeviceLinkProblem::MissingDevice,
1725 )));
1726
1727 EncryptionInfo {
1728 sender: sender_id.to_owned(),
1729 sender_device: sender_device.as_ref().map(|d| d.device_id().to_owned()),
1730 forwarder: None,
1731 algorithm_info: AlgorithmInfo::OlmV1Curve25519AesSha2 {
1732 curve25519_public_key_base64: sender_key.to_base64(),
1733 },
1734 verification_state,
1735 }
1736 }
1737
1738 fn check_sender_device_keys(
1786 event: &AnyDecryptedOlmEvent,
1787 sender_key: Curve25519PublicKey,
1788 ) -> OlmResult<Option<&DeviceKeys>> {
1789 let Some(sender_device_keys) = event.sender_device_keys() else {
1790 return Ok(None);
1791 };
1792
1793 if sender_device_keys.user_id != event.sender() {
1794 warn!(
1795 "Received a to-device message with sender_device_keys with incorrect user_id: expected {:?}, got {:?}",
1796 event.sender(),
1797 sender_device_keys.user_id
1798 );
1799 return Err(OlmError::EventError(EventError::InvalidSenderDeviceKeys));
1800 }
1801
1802 sender_device_keys.check_self_signature().map_err(|err| {
1804 warn!(
1805 "Received a to-device message with sender_device_keys with \
1806 invalid signature: {err:?}",
1807 );
1808 OlmError::EventError(EventError::InvalidSenderDeviceKeys)
1809 })?;
1810
1811 if sender_device_keys.ed25519_key() != Some(event.keys().ed25519) {
1814 warn!(
1815 "Received a to-device message with sender_device_keys with incorrect \
1816 ed25519 key: expected {:?}, got {:?}",
1817 event.keys().ed25519,
1818 sender_device_keys.ed25519_key(),
1819 );
1820 return Err(OlmError::EventError(EventError::InvalidSenderDeviceKeys));
1821 }
1822
1823 if sender_device_keys.curve25519_key() != Some(sender_key) {
1826 warn!(
1827 "Received a to-device message with sender_device_keys with incorrect \
1828 curve25519 key: expected {sender_key:?}, got {:?}",
1829 sender_device_keys.curve25519_key(),
1830 );
1831 return Err(OlmError::EventError(EventError::InvalidSenderDeviceKeys));
1832 }
1833
1834 Ok(Some(sender_device_keys))
1835 }
1836
1837 #[doc(hidden)]
1842 pub fn deep_clone(&self) -> Self {
1843 Self::from_pickle(self.pickle()).unwrap()
1846 }
1847}
1848
1849impl PartialEq for Account {
1850 fn eq(&self, other: &Self) -> bool {
1851 self.identity_keys() == other.identity_keys() && self.shared() == other.shared()
1852 }
1853}
1854
1855pub(crate) fn shared_history_from_history_visibility(
1875 history_visibility: &HistoryVisibility,
1876) -> bool {
1877 match history_visibility {
1878 HistoryVisibility::Shared | HistoryVisibility::WorldReadable => true,
1879 HistoryVisibility::Invited | HistoryVisibility::Joined | _ => false,
1880 }
1881}
1882
1883fn expand_legacy_pickle_key(key: &[u8; 32], device_id: &DeviceId) -> Box<[u8; 32]> {
1902 let kdf: Hkdf<Sha256> = Hkdf::new(Some(device_id.as_bytes()), key);
1903 let mut key = Box::new([0u8; 32]);
1904
1905 kdf.expand(b"dehydrated-device-pickle-key", key.as_mut_slice())
1906 .expect("We should be able to expand the 32 byte pickle key");
1907
1908 key
1909}
1910
1911fn satisfies_sender_trust_requirement(
1914 encryption_info: &EncryptionInfo,
1915 trust_requirement: &TrustRequirement,
1916) -> bool {
1917 trace!(
1918 verification_state = ?encryption_info.verification_state,
1919 ?trust_requirement, "check_to_device_sender_trust_requirement",
1920 );
1921
1922 match (&encryption_info.verification_state, trust_requirement) {
1923 (_, TrustRequirement::Untrusted) => true,
1925
1926 (VerificationState::Verified, _) => true,
1928
1929 (
1933 VerificationState::Unverified(verification_level),
1934 TrustRequirement::CrossSignedOrLegacy | TrustRequirement::CrossSigned,
1935 ) => match verification_level {
1936 VerificationLevel::UnverifiedIdentity => true,
1938
1939 VerificationLevel::UnsignedDevice
1942 | VerificationLevel::None(_)
1943 | VerificationLevel::VerificationViolation
1944 | VerificationLevel::MismatchedSender => false,
1945 },
1946 }
1947}
1948
1949#[cfg(test)]
1950mod tests {
1951 use std::{
1952 collections::{BTreeMap, BTreeSet},
1953 ops::Deref,
1954 time::Duration,
1955 };
1956
1957 use anyhow::Result;
1958 use matrix_sdk_test::async_test;
1959 use ruma::{
1960 DeviceId, MilliSecondsSinceUnixEpoch, OneTimeKeyAlgorithm, OneTimeKeyId, UserId, device_id,
1961 events::room::history_visibility::HistoryVisibility, room_id, user_id,
1962 };
1963 use serde_json::json;
1964
1965 use super::Account;
1966 use crate::{
1967 DeviceData, EncryptionSettings,
1968 olm::{SignedJsonObject, account::shared_history_from_history_visibility},
1969 types::{DeviceKeys, SignedKey},
1970 };
1971
1972 fn user_id() -> &'static UserId {
1973 user_id!("@alice:localhost")
1974 }
1975
1976 fn device_id() -> &'static DeviceId {
1977 device_id!("DEVICEID")
1978 }
1979
1980 #[test]
1981 fn test_one_time_key_creation() -> Result<()> {
1982 let mut account = Account::with_device_id(user_id(), device_id());
1983
1984 let (_, one_time_keys, _) = account.keys_for_upload();
1985 assert!(!one_time_keys.is_empty());
1986
1987 let (_, second_one_time_keys, _) = account.keys_for_upload();
1988 assert!(!second_one_time_keys.is_empty());
1989
1990 let one_time_key_ids: BTreeSet<&OneTimeKeyId> =
1991 one_time_keys.keys().map(Deref::deref).collect();
1992 let second_one_time_key_ids: BTreeSet<&OneTimeKeyId> =
1993 second_one_time_keys.keys().map(Deref::deref).collect();
1994
1995 assert_eq!(one_time_key_ids, second_one_time_key_ids);
1996
1997 account.mark_keys_as_published();
1998 account.update_uploaded_key_count(50);
1999 account.generate_one_time_keys_if_needed();
2000
2001 let (_, third_one_time_keys, _) = account.keys_for_upload();
2002 assert!(third_one_time_keys.is_empty());
2003
2004 account.update_uploaded_key_count(0);
2005 account.generate_one_time_keys_if_needed();
2006
2007 let (_, fourth_one_time_keys, _) = account.keys_for_upload();
2008 assert!(!fourth_one_time_keys.is_empty());
2009
2010 let fourth_one_time_key_ids: BTreeSet<&OneTimeKeyId> =
2011 fourth_one_time_keys.keys().map(Deref::deref).collect();
2012
2013 assert_ne!(one_time_key_ids, fourth_one_time_key_ids);
2014 Ok(())
2015 }
2016
2017 #[test]
2018 fn test_fallback_key_creation() -> Result<()> {
2019 let mut account = Account::with_device_id(user_id(), device_id());
2020
2021 let (_, _, fallback_keys) = account.keys_for_upload();
2022
2023 assert!(
2027 fallback_keys.is_empty(),
2028 "We should not upload fallback keys until we know if the server supports them."
2029 );
2030
2031 let one_time_keys = BTreeMap::from([(OneTimeKeyAlgorithm::SignedCurve25519, 50u8.into())]);
2032
2033 account.update_key_counts(&one_time_keys, None, false);
2036 let (_, _, fallback_keys) = account.keys_for_upload();
2037 assert!(
2038 fallback_keys.is_empty(),
2039 "We should not upload a fallback key if we're certain that the server doesn't support \
2040 them."
2041 );
2042
2043 let unused_fallback_keys = &[];
2047 account.update_key_counts(&one_time_keys, Some(unused_fallback_keys.as_ref()), false);
2048 let (_, _, fallback_keys) = account.keys_for_upload();
2049 assert!(
2050 !fallback_keys.is_empty(),
2051 "We should upload the initial fallback key if the server supports them."
2052 );
2053 account.mark_keys_as_published();
2054
2055 let unused_fallback_keys = &[];
2058 account.update_key_counts(&one_time_keys, Some(unused_fallback_keys.as_ref()), false);
2059 let (_, _, fallback_keys) = account.keys_for_upload();
2060 assert!(
2061 fallback_keys.is_empty(),
2062 "We should not upload new fallback keys unless our current fallback key expires."
2063 );
2064
2065 let fallback_key_timestamp =
2066 account.fallback_creation_timestamp.unwrap().to_system_time().unwrap()
2067 - Duration::from_secs(3600 * 24 * 30);
2068
2069 account.fallback_creation_timestamp =
2070 Some(MilliSecondsSinceUnixEpoch::from_system_time(fallback_key_timestamp).unwrap());
2071
2072 account.update_key_counts(&one_time_keys, None, false);
2073 let (_, _, fallback_keys) = account.keys_for_upload();
2074 assert!(
2075 !fallback_keys.is_empty(),
2076 "Now that our fallback key has expired, we should try to upload a new one, even if the \
2077 server supposedly doesn't support fallback keys anymore"
2078 );
2079
2080 Ok(())
2081 }
2082
2083 #[test]
2084 fn test_fallback_key_signing() -> Result<()> {
2085 let key = vodozemac::Curve25519PublicKey::from_base64(
2086 "7PUPP6Ijt5R8qLwK2c8uK5hqCNF9tOzWYgGaAay5JBs",
2087 )?;
2088 let account = Account::with_device_id(user_id(), device_id());
2089
2090 let key = account.sign_key(key, true);
2091
2092 let canonical_key = key.to_canonical_json()?;
2093
2094 assert_eq!(
2095 canonical_key,
2096 "{\"fallback\":true,\"key\":\"7PUPP6Ijt5R8qLwK2c8uK5hqCNF9tOzWYgGaAay5JBs\"}"
2097 );
2098
2099 account
2100 .has_signed_raw(key.signatures(), &canonical_key)
2101 .expect("Couldn't verify signature");
2102
2103 let device = DeviceData::from_account(&account);
2104 device.verify_one_time_key(&key).expect("The device can verify its own signature");
2105
2106 Ok(())
2107 }
2108
2109 #[test]
2110 fn test_account_and_device_creation_timestamp() -> Result<()> {
2111 let now = MilliSecondsSinceUnixEpoch::now();
2112 let account = Account::with_device_id(user_id(), device_id());
2113 let then = MilliSecondsSinceUnixEpoch::now();
2114
2115 assert!(account.creation_local_time() >= now);
2116 assert!(account.creation_local_time() <= then);
2117
2118 let device = DeviceData::from_account(&account);
2119 assert_eq!(account.creation_local_time(), device.first_time_seen_ts());
2120
2121 Ok(())
2122 }
2123
2124 #[async_test]
2125 async fn test_fallback_key_signature_verification() -> Result<()> {
2126 let fallback_key = json!({
2127 "fallback": true,
2128 "key": "XPFqtLvBepBmW6jSAbBuJbhEpprBhQOX1IjUu+cnMF4",
2129 "signatures": {
2130 "@dkasak_c:matrix.org": {
2131 "ed25519:EXPDYDPWZH": "RJCBMJPL5hvjxgq8rmLmqkNOuPsaan7JeL1wsE+gW6R39G894lb2sBmzapHeKCn/KFjmkonPLkICApRDS+zyDw"
2132 }
2133 }
2134 });
2135
2136 let device_keys = json!({
2137 "algorithms": [
2138 "m.olm.v1.curve25519-aes-sha2",
2139 "m.megolm.v1.aes-sha2"
2140 ],
2141 "device_id": "EXPDYDPWZH",
2142 "keys": {
2143 "curve25519:EXPDYDPWZH": "k7f3igo0Vrdm88JSSA5d3OCuUfHYELChB2b57aOROB8",
2144 "ed25519:EXPDYDPWZH": "GdjYI8fxs175gSpYRJkyN6FRfvcyTsNOhJ2OR/Ggp+E"
2145 },
2146 "signatures": {
2147 "@dkasak_c:matrix.org": {
2148 "ed25519:EXPDYDPWZH": "kzrtfQMbJXWXQ1uzhybtwFnGk0JJBS4Mg8VPMusMu6U8MPJccwoHVZKo5+owuHTzIodI+GZYqLmMSzvfvsChAA"
2149 }
2150 },
2151 "user_id": "@dkasak_c:matrix.org",
2152 "unsigned": {}
2153 });
2154
2155 let device_keys: DeviceKeys = serde_json::from_value(device_keys).unwrap();
2156 let device = DeviceData::try_from(&device_keys).unwrap();
2157 let fallback_key: SignedKey = serde_json::from_value(fallback_key).unwrap();
2158
2159 device
2160 .verify_one_time_key(&fallback_key)
2161 .expect("The fallback key should pass the signature verification");
2162
2163 Ok(())
2164 }
2165
2166 #[test]
2167 fn test_shared_history_flag_from_history_visibility() {
2168 assert!(
2169 shared_history_from_history_visibility(&HistoryVisibility::WorldReadable),
2170 "The world readable visibility should set the shared history flag to true"
2171 );
2172
2173 assert!(
2174 shared_history_from_history_visibility(&HistoryVisibility::Shared),
2175 "The shared visibility should set the shared history flag to true"
2176 );
2177
2178 assert!(
2179 !shared_history_from_history_visibility(&HistoryVisibility::Joined),
2180 "The joined visibility should set the shared history flag to false"
2181 );
2182
2183 assert!(
2184 !shared_history_from_history_visibility(&HistoryVisibility::Invited),
2185 "The invited visibility should set the shared history flag to false"
2186 );
2187
2188 let visibility = HistoryVisibility::from("custom_visibility");
2189 assert!(
2190 !shared_history_from_history_visibility(&visibility),
2191 "A custom visibility should set the shared history flag to false"
2192 );
2193 }
2194
2195 #[async_test]
2196 async fn test_shared_history_set_when_creating_group_sessions() {
2197 let account = Account::new(user_id());
2198 let room_id = room_id!("!room:id");
2199 let settings = EncryptionSettings {
2200 history_visibility: HistoryVisibility::Shared,
2201 ..Default::default()
2202 };
2203
2204 let (_, session) = account
2205 .create_group_session_pair(room_id, settings, Default::default())
2206 .await
2207 .expect("We should be able to create a group session pair");
2208
2209 assert!(
2210 session.shared_history(),
2211 "The shared history flag should have been set when we created the new session"
2212 );
2213 }
2214}