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(
204 &self,
205 room_id: &RoomId,
206 settings: EncryptionSettings,
207 own_sender_data: SenderData,
208 ) -> Result<(OutboundGroupSession, InboundGroupSession), MegolmSessionCreationError> {
209 trace!(?room_id, algorithm = settings.algorithm.as_str(), "Creating a new room key");
210
211 let visibility = settings.history_visibility.clone();
212 let algorithm = settings.algorithm.to_owned();
213
214 let outbound = OutboundGroupSession::new(
215 self.device_id.clone(),
216 self.identity_keys.clone(),
217 room_id,
218 settings,
219 )?;
220
221 let identity_keys = &self.identity_keys;
222
223 let sender_key = identity_keys.curve25519;
224 let signing_key = identity_keys.ed25519;
225 let shared_history = shared_history_from_history_visibility(&visibility);
226
227 let inbound = InboundGroupSession::new(
228 sender_key,
229 signing_key,
230 room_id,
231 &outbound.session_key().await,
232 own_sender_data,
233 None,
234 algorithm,
235 Some(visibility),
236 shared_history,
237 )?;
238
239 Ok((outbound, inbound))
240 }
241
242 #[cfg(any(test, feature = "testing"))]
243 #[allow(dead_code)]
244 pub async fn create_group_session_pair_with_defaults(
247 &self,
248 room_id: &RoomId,
249 ) -> (OutboundGroupSession, InboundGroupSession) {
250 self.create_group_session_pair(
251 room_id,
252 EncryptionSettings::default(),
253 SenderData::unknown(),
254 )
255 .await
256 .expect("Can't create default group session pair")
257 }
258
259 pub fn signing_key_id(&self) -> OwnedDeviceKeyId {
261 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id())
262 }
263
264 pub fn has_signed_raw(
274 &self,
275 signatures: &crate::types::Signatures,
276 canonical_json: &str,
277 ) -> Result<(), SignatureError> {
278 use crate::olm::utility::VerifyJson;
279
280 let signing_key = self.identity_keys.ed25519;
281
282 signing_key.verify_canonicalized_json(
283 &self.user_id,
284 &DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
285 signatures,
286 canonical_json,
287 )
288 }
289
290 pub fn unsigned_device_keys(&self) -> DeviceKeys {
292 let identity_keys = self.identity_keys();
293 let keys = BTreeMap::from([
294 (
295 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Curve25519, &self.device_id),
296 identity_keys.curve25519.into(),
297 ),
298 (
299 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, &self.device_id),
300 identity_keys.ed25519.into(),
301 ),
302 ]);
303
304 let mut ret = DeviceKeys::new(
305 self.user_id.clone(),
306 self.device_id.clone(),
307 Self::ALGORITHMS.iter().map(|a| (**a).clone()).collect(),
308 keys,
309 Default::default(),
310 );
311 if self.dehydrated {
312 ret.dehydrated = JsOption::Some(true);
313 }
314 ret
315 }
316
317 pub fn user_id(&self) -> &UserId {
319 &self.user_id
320 }
321
322 pub fn device_id(&self) -> &DeviceId {
324 &self.device_id
325 }
326
327 pub fn identity_keys(&self) -> IdentityKeys {
329 *self.identity_keys
330 }
331
332 pub fn creation_local_time(&self) -> MilliSecondsSinceUnixEpoch {
334 self.creation_local_time
335 }
336}
337
338pub struct Account {
343 pub(crate) static_data: StaticAccountData,
344 inner: Box<InnerAccount>,
346 shared: bool,
349 uploaded_signed_key_count: u64,
354 fallback_creation_timestamp: Option<MilliSecondsSinceUnixEpoch>,
362}
363
364impl Deref for Account {
365 type Target = StaticAccountData;
366
367 fn deref(&self) -> &Self::Target {
368 &self.static_data
369 }
370}
371
372#[derive(Serialize, Deserialize)]
377#[allow(missing_debug_implementations)]
378pub struct PickledAccount {
379 pub user_id: OwnedUserId,
381 pub device_id: OwnedDeviceId,
383 pub pickle: AccountPickle,
385 pub shared: bool,
387 #[serde(default)]
389 pub dehydrated: bool,
390 pub uploaded_signed_key_count: u64,
392 #[serde(default = "default_account_creation_time")]
395 pub creation_local_time: MilliSecondsSinceUnixEpoch,
396 #[serde(default)]
398 pub fallback_key_creation_timestamp: Option<MilliSecondsSinceUnixEpoch>,
399}
400
401fn default_account_creation_time() -> MilliSecondsSinceUnixEpoch {
402 MilliSecondsSinceUnixEpoch(UInt::default())
403}
404
405#[cfg(not(tarpaulin_include))]
406impl fmt::Debug for Account {
407 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
408 f.debug_struct("Account")
409 .field("identity_keys", &self.identity_keys())
410 .field("shared", &self.shared())
411 .finish()
412 }
413}
414
415pub type OneTimeKeys = BTreeMap<OwnedOneTimeKeyId, Raw<ruma::encryption::OneTimeKey>>;
416pub type FallbackKeys = OneTimeKeys;
417
418impl Account {
419 pub(crate) fn new_helper(
420 mut account: InnerAccount,
421 user_id: &UserId,
422 device_id: &DeviceId,
423 ) -> Self {
424 let identity_keys = account.identity_keys();
425
426 account.generate_one_time_keys(account.max_number_of_one_time_keys());
438
439 Self {
440 static_data: StaticAccountData {
441 user_id: user_id.into(),
442 device_id: device_id.into(),
443 identity_keys: Arc::new(identity_keys),
444 dehydrated: false,
445 creation_local_time: MilliSecondsSinceUnixEpoch::now(),
446 },
447 inner: Box::new(account),
448 shared: false,
449 uploaded_signed_key_count: 0,
450 fallback_creation_timestamp: None,
451 }
452 }
453
454 pub fn with_device_id(user_id: &UserId, device_id: &DeviceId) -> Self {
456 let account = InnerAccount::new();
457
458 Self::new_helper(account, user_id, device_id)
459 }
460
461 pub fn new(user_id: &UserId) -> Self {
464 let account = InnerAccount::new();
465 let device_id: OwnedDeviceId =
466 base64_encode(account.identity_keys().curve25519.as_bytes()).into();
467
468 Self::new_helper(account, user_id, &device_id)
469 }
470
471 pub fn new_dehydrated(user_id: &UserId) -> Self {
473 let account = InnerAccount::new();
474 let device_id: OwnedDeviceId =
475 base64_encode(account.identity_keys().curve25519.as_bytes()).into();
476
477 let mut ret = Self::new_helper(account, user_id, &device_id);
478 ret.static_data.dehydrated = true;
479 ret
480 }
481
482 pub fn static_data(&self) -> &StaticAccountData {
484 &self.static_data
485 }
486
487 pub fn update_uploaded_key_count(&mut self, new_count: u64) {
493 self.uploaded_signed_key_count = new_count;
494 }
495
496 pub fn uploaded_key_count(&self) -> u64 {
498 self.uploaded_signed_key_count
499 }
500
501 pub fn shared(&self) -> bool {
503 self.shared
504 }
505
506 pub fn mark_as_shared(&mut self) {
511 self.shared = true;
512 }
513
514 pub fn one_time_keys(&self) -> HashMap<KeyId, Curve25519PublicKey> {
518 self.inner.one_time_keys()
519 }
520
521 pub fn generate_one_time_keys(&mut self, count: usize) -> OneTimeKeyGenerationResult {
523 self.inner.generate_one_time_keys(count)
524 }
525
526 pub fn max_one_time_keys(&self) -> usize {
528 self.inner.max_number_of_one_time_keys()
529 }
530
531 pub(crate) fn update_key_counts(
548 &mut self,
549 one_time_key_counts: &BTreeMap<OneTimeKeyAlgorithm, UInt>,
550 unused_fallback_keys: Option<&[OneTimeKeyAlgorithm]>,
551 is_missing_count_zero: bool,
552 ) {
553 let count = if is_missing_count_zero {
554 Some(
555 one_time_key_counts
556 .get(&OneTimeKeyAlgorithm::SignedCurve25519)
557 .copied()
558 .unwrap_or(uint!(0)),
559 )
560 } else {
561 one_time_key_counts.get(&OneTimeKeyAlgorithm::SignedCurve25519).copied()
562 };
563
564 if let Some(count) = count.map(Into::into) {
565 let old_count = self.uploaded_key_count();
566
567 if count != old_count {
571 debug!(
572 "Updated uploaded one-time key count {} -> {count}.",
573 self.uploaded_key_count(),
574 );
575 }
576
577 self.update_uploaded_key_count(count);
578 self.generate_one_time_keys_if_needed();
579 }
580
581 if unused_fallback_keys.is_some() || self.fallback_creation_timestamp.is_some() {
585 self.generate_fallback_key_if_needed();
586 }
587 }
588
589 #[instrument(skip_all)]
598 pub fn generate_one_time_keys_if_needed(&mut self) -> Option<u64> {
599 if !self.one_time_keys().is_empty() {
603 return Some(0);
604 }
605
606 let count = self.uploaded_key_count();
607 let max_keys = self.max_one_time_keys();
608
609 if count >= max_keys as u64 {
610 return None;
611 }
612
613 let key_count = (max_keys as u64) - count;
614 let key_count: usize = key_count.try_into().unwrap_or(max_keys);
615
616 let result = self.generate_one_time_keys(key_count);
617
618 debug!(
619 count = key_count,
620 discarded_keys = ?result.removed,
621 created_keys = ?result.created,
622 "Generated new one-time keys"
623 );
624
625 Some(key_count as u64)
626 }
627
628 pub(crate) fn generate_fallback_key_if_needed(&mut self) {
635 if self.inner.fallback_key().is_empty() && self.fallback_key_expired() {
636 let removed_fallback_key = self.inner.generate_fallback_key();
637 self.fallback_creation_timestamp = Some(MilliSecondsSinceUnixEpoch::now());
638
639 debug!(
640 ?removed_fallback_key,
641 "The fallback key either expired or we didn't have one: generated a new fallback key.",
642 );
643 }
644 }
645
646 fn fallback_key_expired(&self) -> bool {
654 const FALLBACK_KEY_MAX_AGE: Duration = Duration::from_secs(3600 * 24 * 7);
655
656 if let Some(time) = self.fallback_creation_timestamp {
657 let Some(system_time) = time.to_system_time() else {
661 return true;
662 };
663
664 let Ok(elapsed) = system_time.elapsed() else {
668 return true;
669 };
670
671 elapsed > FALLBACK_KEY_MAX_AGE
676 } else {
677 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> {
794 let account: vodozemac::olm::Account = pickle.pickle.into();
795 let identity_keys = account.identity_keys();
796
797 Ok(Self {
798 static_data: StaticAccountData {
799 user_id: pickle.user_id.clone(),
800 device_id: pickle.device_id.clone(),
801 identity_keys: Arc::new(identity_keys),
802 dehydrated: pickle.dehydrated,
803 creation_local_time: pickle.creation_local_time,
804 },
805 inner: Box::new(account),
806 shared: pickle.shared,
807 uploaded_signed_key_count: pickle.uploaded_signed_key_count,
808 fallback_creation_timestamp: pickle.fallback_key_creation_timestamp,
809 })
810 }
811
812 pub fn device_keys(&self) -> DeviceKeys {
815 let mut device_keys = self.unsigned_device_keys();
816
817 let json_device_keys =
820 to_canonical_value(&device_keys).expect("device key is always safe to serialize");
821 let signature = self
822 .sign_json(json_device_keys)
823 .expect("Newly created device keys can always be signed");
824
825 device_keys.signatures.add_signature(
826 self.user_id().to_owned(),
827 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, &self.static_data.device_id),
828 signature,
829 );
830
831 device_keys
832 }
833
834 pub async fn bootstrap_cross_signing(
846 &self,
847 #[cfg(feature = "experimental-x509-identity-verification")] x509_signer: Option<
848 Arc<dyn RawX509Signer>,
849 >,
850 ) -> Result<
851 (PrivateCrossSigningIdentity, UploadSigningKeysRequest, SignatureUploadRequest),
852 SignatureError,
853 > {
854 #[cfg(feature = "experimental-x509-identity-verification")]
855 let x509_signer = x509_signer.map(X509Signer::new);
856
857 let identity = PrivateCrossSigningIdentity::for_account(
858 self,
859 #[cfg(feature = "experimental-x509-identity-verification")]
860 x509_signer.as_ref(),
861 )?;
862
863 let signature_request = identity.sign_account(self.static_data()).await?;
864
865 let upload_request = identity.as_upload_request().await;
866
867 Ok((identity, upload_request, signature_request))
868 }
869
870 pub fn sign_cross_signing_key(
872 &self,
873 cross_signing_key: &mut CrossSigningKey,
874 ) -> Result<(), SignatureError> {
875 let signature = self.sign_json(to_canonical_value(&cross_signing_key)?)?;
876
877 cross_signing_key.signatures.add_signature(
878 self.user_id().to_owned(),
879 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
880 signature,
881 );
882
883 Ok(())
884 }
885
886 pub fn sign_json(&self, json: CanonicalJsonValue) -> Result<Ed25519Signature, SignatureError> {
894 self.inner.sign_json(json)
895 }
896
897 pub fn signed_one_time_keys(&self) -> OneTimeKeys {
901 let one_time_keys = self.one_time_keys();
902
903 if one_time_keys.is_empty() {
904 BTreeMap::new()
905 } else {
906 self.signed_keys(one_time_keys, false)
907 }
908 }
909
910 pub fn signed_fallback_keys(&self) -> FallbackKeys {
914 let fallback_key = self.fallback_key();
915
916 if fallback_key.is_empty() { BTreeMap::new() } else { self.signed_keys(fallback_key, true) }
917 }
918
919 fn signed_keys(
920 &self,
921 keys: HashMap<KeyId, Curve25519PublicKey>,
922 fallback: bool,
923 ) -> OneTimeKeys {
924 let mut keys_map = BTreeMap::new();
925
926 for (key_id, key) in keys {
927 let signed_key = self.sign_key(key, fallback);
928
929 keys_map.insert(
930 OneTimeKeyId::from_parts(
931 OneTimeKeyAlgorithm::SignedCurve25519,
932 key_id.to_base64().as_str().into(),
933 ),
934 signed_key.into_raw(),
935 );
936 }
937
938 keys_map
939 }
940
941 fn sign_key(&self, key: Curve25519PublicKey, fallback: bool) -> SignedKey {
942 let mut key = if fallback {
943 SignedKey::new_fallback(key.to_owned())
944 } else {
945 SignedKey::new(key.to_owned())
946 };
947
948 let signature = self
949 .sign_json(to_canonical_value(&key).expect("Can't serialize a signed key"))
950 .expect("Newly created one-time keys can always be signed");
951
952 key.signatures_mut().add_signature(
953 self.user_id().to_owned(),
954 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
955 signature,
956 );
957
958 key
959 }
960
961 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(
1107 &mut self,
1108 their_identity_key: Curve25519PublicKey,
1109 our_device_keys: DeviceKeys,
1110 message: &PreKeyMessage,
1111 ) -> Result<InboundCreationResult, SessionCreationError> {
1112 Span::current().record("session_id", debug(message.session_id()));
1113 trace!("Creating a new Olm session from a pre-key message");
1114
1115 #[cfg(not(feature = "experimental-algorithms"))]
1116 let config = SessionConfig::version_1();
1117
1118 #[cfg(feature = "experimental-algorithms")]
1119 let config = SessionConfig::version_2();
1120
1121 let result = self.inner.create_inbound_session(config, their_identity_key, message)?;
1122 let now = SecondsSinceUnixEpoch::now();
1123 let session_id = result.session.session_id();
1124
1125 debug!(session=?result.session, "Decrypted an Olm message from a new Olm session");
1126
1127 let session = Session {
1128 inner: Arc::new(Mutex::new(result.session)),
1129 session_id: session_id.into(),
1130 sender_key: their_identity_key,
1131 our_device_keys,
1132 created_using_fallback_key: false,
1133 creation_time: now,
1134 last_use_time: now,
1135 };
1136
1137 let plaintext = String::from_utf8_lossy(&result.plaintext).to_string();
1138
1139 Ok(InboundCreationResult { session, plaintext })
1140 }
1141
1142 #[cfg(any(test, feature = "testing"))]
1143 #[allow(dead_code)]
1144 pub async fn create_session_for_test_helper(
1146 &mut self,
1147 other: &mut Account,
1148 ) -> (Session, Session) {
1149 use ruma::events::dummy::ToDeviceDummyEventContent;
1150
1151 other.generate_one_time_keys(1);
1152 let one_time_map = other.signed_one_time_keys();
1153 let device = DeviceData::from_account(other);
1154
1155 let mut our_session =
1156 self.create_outbound_session(&device, &one_time_map, self.device_keys()).unwrap();
1157
1158 other.mark_keys_as_published();
1159
1160 let message = our_session
1161 .encrypt(&device, "m.dummy", ToDeviceDummyEventContent::new(), None)
1162 .await
1163 .unwrap()
1164 .deserialize()
1165 .unwrap();
1166
1167 #[cfg(feature = "experimental-algorithms")]
1168 let content = if let ToDeviceEncryptedEventContent::OlmV2Curve25519AesSha2(c) = message {
1169 c
1170 } else {
1171 panic!("Invalid encrypted event algorithm {}", message.algorithm());
1172 };
1173
1174 #[cfg(not(feature = "experimental-algorithms"))]
1175 let ToDeviceEncryptedEventContent::OlmV1Curve25519AesSha2(content) = message else {
1176 panic!("Invalid encrypted event algorithm {}", message.algorithm());
1177 };
1178
1179 let OlmMessage::PreKey(prekey) = content.ciphertext else {
1180 panic!("Wrong Olm message type");
1181 };
1182
1183 let our_device = DeviceData::from_account(self);
1184 let other_session = other
1185 .create_inbound_session(
1186 our_device.curve25519_key().unwrap(),
1187 other.device_keys(),
1188 &prekey,
1189 )
1190 .unwrap();
1191
1192 (our_session, other_session.session)
1193 }
1194
1195 async fn decrypt_olm_helper(
1196 &mut self,
1197 store: &Store,
1198 sender: &UserId,
1199 sender_key: Curve25519PublicKey,
1200 ciphertext: &OlmMessage,
1201 decryption_settings: &DecryptionSettings,
1202 ) -> OlmResult<OlmDecryptionInfo> {
1203 let message_hash = OlmMessageHash::new(sender_key, ciphertext);
1204
1205 match self
1206 .decrypt_and_parse_olm_message(
1207 store,
1208 sender,
1209 sender_key,
1210 ciphertext,
1211 decryption_settings,
1212 )
1213 .await
1214 {
1215 Ok((session, result)) => {
1216 Ok(OlmDecryptionInfo { session, message_hash, result, inbound_group_session: None })
1217 }
1218 Err(OlmError::SessionWedged(user_id, sender_key)) => {
1219 if store.is_message_known(&message_hash).await? {
1220 info!(?sender_key, "An Olm message got replayed, decryption failed");
1221 Err(OlmError::ReplayedMessage(user_id, sender_key))
1222 } else {
1223 Err(OlmError::SessionWedged(user_id, sender_key))
1224 }
1225 }
1226 Err(e) => Err(e),
1227 }
1228 }
1229
1230 #[cfg(feature = "experimental-algorithms")]
1231 async fn decrypt_olm_v2(
1232 &mut self,
1233 store: &Store,
1234 sender: &UserId,
1235 content: &OlmV2Curve25519AesSha2Content,
1236 decryption_settings: &DecryptionSettings,
1237 ) -> OlmResult<OlmDecryptionInfo> {
1238 self.decrypt_olm_helper(
1239 store,
1240 sender,
1241 content.sender_key,
1242 &content.ciphertext,
1243 decryption_settings,
1244 )
1245 .await
1246 }
1247
1248 #[instrument(skip_all, fields(sender, sender_key = ?content.sender_key))]
1249 async fn decrypt_olm_v1(
1250 &mut self,
1251 store: &Store,
1252 sender: &UserId,
1253 content: &OlmV1Curve25519AesSha2Content,
1254 decryption_settings: &DecryptionSettings,
1255 ) -> OlmResult<OlmDecryptionInfo> {
1256 if content.recipient_key != self.static_data.identity_keys.curve25519 {
1257 warn!("Olm event doesn't contain a ciphertext for our key");
1258
1259 Err(EventError::MissingCiphertext.into())
1260 } else {
1261 Box::pin(self.decrypt_olm_helper(
1262 store,
1263 sender,
1264 content.sender_key,
1265 &content.ciphertext,
1266 decryption_settings,
1267 ))
1268 .await
1269 }
1270 }
1271
1272 #[instrument(skip_all, fields(algorithm = ?event.content.algorithm()))]
1273 pub(crate) async fn decrypt_to_device_event(
1274 &mut self,
1275 store: &Store,
1276 event: &EncryptedToDeviceEvent,
1277 decryption_settings: &DecryptionSettings,
1278 ) -> OlmResult<OlmDecryptionInfo> {
1279 trace!("Decrypting a to-device event");
1280
1281 match &event.content {
1282 ToDeviceEncryptedEventContent::OlmV1Curve25519AesSha2(c) => {
1283 self.decrypt_olm_v1(store, &event.sender, c, decryption_settings).await
1284 }
1285 #[cfg(feature = "experimental-algorithms")]
1286 ToDeviceEncryptedEventContent::OlmV2Curve25519AesSha2(c) => {
1287 self.decrypt_olm_v2(store, &event.sender, c, decryption_settings).await
1288 }
1289 ToDeviceEncryptedEventContent::Unknown(_) => {
1290 warn!(
1291 "Error decrypting an to-device event, unsupported \
1292 encryption algorithm"
1293 );
1294
1295 Err(EventError::UnsupportedAlgorithm.into())
1296 }
1297 }
1298 }
1299
1300 pub fn receive_keys_upload_response(
1302 &mut self,
1303 response: &upload_keys::v3::Response,
1304 ) -> OlmResult<()> {
1305 if !self.shared() {
1306 debug!("Marking account as shared");
1307 }
1308 self.mark_as_shared();
1309
1310 debug!("Marking one-time keys as published");
1311 self.mark_keys_as_published();
1314 self.update_key_counts(&response.one_time_key_counts, None, false);
1315
1316 Ok(())
1317 }
1318
1319 async fn decrypt_olm_message(
1321 &mut self,
1322 store: &Store,
1323 sender: &UserId,
1324 sender_key: Curve25519PublicKey,
1325 message: &OlmMessage,
1326 ) -> Result<(SessionType, String), OlmError> {
1327 let existing_sessions = store.get_sessions(&sender_key.to_base64()).await?;
1328
1329 match message {
1330 OlmMessage::Normal(_) => {
1331 let mut errors_by_olm_session = Vec::new();
1332
1333 if let Some(sessions) = existing_sessions {
1334 for session in sessions.lock().await.iter_mut() {
1337 match session.decrypt(message).await {
1338 Ok(p) => {
1339 return Ok((SessionType::Existing(session.clone()), p));
1341 }
1342
1343 Err(e) => {
1344 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!(
1389 session_id = session.session_id(),
1390 "Failed to decrypt a pre-key message with the corresponding session"
1391 );
1392
1393 return Err(OlmError::SessionWedged(
1394 session.our_device_keys.user_id.to_owned(),
1395 session.sender_key(),
1396 ));
1397 }
1398 }
1399
1400 let device_keys = store.get_own_device().await?.as_device_keys().clone();
1401 let result =
1402 match self.create_inbound_session(sender_key, device_keys, prekey_message) {
1403 Ok(r) => r,
1404 Err(e) => {
1405 warn!(
1406 "Failed to create a new Olm session from a pre-key message: {e:?}"
1407 );
1408 return Err(OlmError::SessionWedged(sender.to_owned(), sender_key));
1409 }
1410 };
1411
1412 let mut changes =
1417 Changes { sessions: vec![result.session.clone()], ..Default::default() };
1418
1419 if let Some(device) = store.get_device_from_curve_key(sender, sender_key).await? {
1426 let mut device_data = device.inner;
1427 device_data.olm_wedging_index.increment();
1428
1429 changes.devices =
1430 DeviceChanges { changed: vec![device_data], ..Default::default() };
1431 }
1432
1433 store.save_changes(changes).await?;
1434
1435 Ok((SessionType::New(result.session), result.plaintext))
1436 }
1437 }
1438 }
1439
1440 #[instrument(skip(self, store), fields(session, session_id))]
1443 async fn decrypt_and_parse_olm_message(
1444 &mut self,
1445 store: &Store,
1446 sender: &UserId,
1447 sender_key: Curve25519PublicKey,
1448 message: &OlmMessage,
1449 decryption_settings: &DecryptionSettings,
1450 ) -> OlmResult<(SessionType, DecryptionResult)> {
1451 let (session, plaintext) =
1452 self.decrypt_olm_message(store, sender, sender_key, message).await?;
1453
1454 trace!("Successfully decrypted an Olm message");
1455
1456 match self
1457 .parse_decrypted_to_device_event(
1458 store,
1459 sender,
1460 sender_key,
1461 plaintext,
1462 decryption_settings,
1463 )
1464 .await
1465 {
1466 Ok(result) => Ok((session, result)),
1467 Err(e) => {
1468 match session {
1472 SessionType::New(s) | SessionType::Existing(s) => {
1473 store.save_sessions(&[s]).await?;
1474 }
1475 }
1476
1477 warn!(
1478 error = ?e,
1479 "A to-device message was successfully decrypted but \
1480 parsing and checking the event fields failed"
1481 );
1482
1483 Err(e)
1484 }
1485 }
1486 }
1487
1488 async fn parse_decrypted_to_device_event(
1509 &self,
1510 store: &Store,
1511 sender: &UserId,
1512 sender_key: Curve25519PublicKey,
1513 plaintext: String,
1514 decryption_settings: &DecryptionSettings,
1515 ) -> OlmResult<DecryptionResult> {
1516 let event: Box<AnyDecryptedOlmEvent> = serde_json::from_str(&plaintext)?;
1517 let identity_keys = &self.static_data.identity_keys;
1518
1519 if event.recipient() != self.static_data.user_id {
1520 Err(EventError::MismatchedSender(
1521 event.recipient().to_owned(),
1522 self.static_data.user_id.clone(),
1523 )
1524 .into())
1525 }
1526 else if event.sender() != sender {
1529 Err(EventError::MismatchedSender(event.sender().to_owned(), sender.to_owned()).into())
1530 } else if identity_keys.ed25519 != event.recipient_keys().ed25519 {
1531 Err(EventError::MismatchedKeys(
1532 identity_keys.ed25519.into(),
1533 event.recipient_keys().ed25519.into(),
1534 )
1535 .into())
1536 } else {
1537 let sender_device = Self::get_event_sender_device(store, sender_key, &event).await?;
1538 let encryption_info = Self::get_olm_encryption_info(sender_key, sender, &sender_device);
1539
1540 let result = DecryptionResult {
1541 event,
1542 raw_event: Raw::from_json(RawJsonValue::from_string(plaintext)?),
1543 sender_key,
1544 encryption_info,
1545 };
1546
1547 if !self.is_from_verified_device_or_allowed_type(decryption_settings, &result) {
1549 Err(OlmError::UnverifiedSenderDevice)
1550 } else {
1551 Ok(result)
1553 }
1554 }
1555 }
1556
1557 async fn get_event_sender_device(
1571 store: &Store,
1572 sender_key: Curve25519PublicKey,
1573 event: &AnyDecryptedOlmEvent,
1574 ) -> OlmResult<Option<Device>> {
1575 let sender_device_keys = Self::check_sender_device_keys(event, sender_key)?;
1580 if let AnyDecryptedOlmEvent::RoomKey(_) = event {
1581 return Ok(None);
1586 }
1587
1588 if let AnyDecryptedOlmEvent::RoomKeyBundle(_) = event {
1591 sender_device_keys.ok_or(EventError::MissingSigningKey).inspect_err(|_| {
1592 warn!("The room key bundle was missing the sender device keys in the event")
1593 })?;
1594 }
1595
1596 let store_device = store.get_device_from_curve_key(event.sender(), sender_key).await?;
1601
1602 match (store_device, sender_device_keys) {
1603 (Some(device), _) => {
1606 let key = device.ed25519_key().ok_or(EventError::MissingSigningKey)?;
1607 if key != event.keys().ed25519 {
1608 return Err(EventError::MismatchedKeys(
1609 key.into(),
1610 event.keys().ed25519.into(),
1611 )
1612 .into());
1613 }
1614 Ok(Some(device))
1615 }
1616
1617 (None, Some(sender_device_keys)) => {
1618 let sender_device_data = sender_device_keys.try_into().expect("Conversion of DeviceKeys to DeviceData failed despite the signature already having been checked");
1621 Ok(Some(store.wrap_device_data(sender_device_data).await?))
1622 }
1623
1624 (None, None) => Err(OlmError::EventError(EventError::MissingSigningKey)),
1625 }
1626 }
1627
1628 fn is_from_verified_device_or_allowed_type(
1641 &self,
1642 decryption_settings: &DecryptionSettings,
1643 result: &DecryptionResult,
1644 ) -> bool {
1645 let event_type = result.event.event_type();
1646
1647 match event_type {
1659 "m.room_key"
1660 | "m.room_key.withheld"
1661 | "m.room_key_request"
1662 | "m.secret.request"
1663 | "m.key.verification.key"
1664 | "m.key.verification.mac"
1665 | "m.key.verification.done"
1666 | "m.key.verification.ready"
1667 | "m.key.verification.start"
1668 | "m.key.verification.accept"
1669 | "m.key.verification.cancel"
1670 | "m.key.verification.request" => {
1671 true
1674 }
1675 _ => {
1676 satisfies_sender_trust_requirement(
1679 &result.encryption_info,
1680 &decryption_settings.sender_device_trust_requirement,
1681 )
1682 }
1683 }
1684 }
1685
1686 fn get_olm_encryption_info(
1693 sender_key: Curve25519PublicKey,
1694 sender_id: &UserId,
1695 sender_device: &Option<Device>,
1696 ) -> EncryptionInfo {
1697 let verification_state = sender_device
1698 .as_ref()
1699 .map(|device| {
1700 if device.is_verified() {
1701 VerificationState::Verified
1703 } else if device.is_cross_signed_by_owner() {
1704 if device
1706 .device_owner_identity
1707 .as_ref()
1708 .expect("A device cross-signed by the owner must have an owner identity")
1709 .was_previously_verified()
1710 {
1711 VerificationState::Unverified(VerificationLevel::VerificationViolation)
1712 } else {
1713 VerificationState::Unverified(VerificationLevel::UnverifiedIdentity)
1714 }
1715 } else {
1716 VerificationState::Unverified(VerificationLevel::UnsignedDevice)
1718 }
1719 })
1720 .unwrap_or(VerificationState::Unverified(VerificationLevel::None(
1721 DeviceLinkProblem::MissingDevice,
1722 )));
1723
1724 EncryptionInfo {
1725 sender: sender_id.to_owned(),
1726 sender_device: sender_device.as_ref().map(|d| d.device_id().to_owned()),
1727 forwarder: None,
1728 algorithm_info: AlgorithmInfo::OlmV1Curve25519AesSha2 {
1729 curve25519_public_key_base64: sender_key.to_base64(),
1730 },
1731 verification_state,
1732 }
1733 }
1734
1735 fn check_sender_device_keys(
1783 event: &AnyDecryptedOlmEvent,
1784 sender_key: Curve25519PublicKey,
1785 ) -> OlmResult<Option<&DeviceKeys>> {
1786 let Some(sender_device_keys) = event.sender_device_keys() else {
1787 return Ok(None);
1788 };
1789
1790 if sender_device_keys.user_id != event.sender() {
1791 warn!(
1792 "Received a to-device message with sender_device_keys with incorrect user_id: expected {:?}, got {:?}",
1793 event.sender(),
1794 sender_device_keys.user_id
1795 );
1796 return Err(OlmError::EventError(EventError::InvalidSenderDeviceKeys));
1797 }
1798
1799 sender_device_keys.check_self_signature().map_err(|err| {
1801 warn!(
1802 "Received a to-device message with sender_device_keys with \
1803 invalid signature: {err:?}",
1804 );
1805 OlmError::EventError(EventError::InvalidSenderDeviceKeys)
1806 })?;
1807
1808 if sender_device_keys.ed25519_key() != Some(event.keys().ed25519) {
1811 warn!(
1812 "Received a to-device message with sender_device_keys with incorrect \
1813 ed25519 key: expected {:?}, got {:?}",
1814 event.keys().ed25519,
1815 sender_device_keys.ed25519_key(),
1816 );
1817 return Err(OlmError::EventError(EventError::InvalidSenderDeviceKeys));
1818 }
1819
1820 if sender_device_keys.curve25519_key() != Some(sender_key) {
1823 warn!(
1824 "Received a to-device message with sender_device_keys with incorrect \
1825 curve25519 key: expected {sender_key:?}, got {:?}",
1826 sender_device_keys.curve25519_key(),
1827 );
1828 return Err(OlmError::EventError(EventError::InvalidSenderDeviceKeys));
1829 }
1830
1831 Ok(Some(sender_device_keys))
1832 }
1833
1834 #[doc(hidden)]
1839 pub fn deep_clone(&self) -> Self {
1840 Self::from_pickle(self.pickle()).unwrap()
1842 }
1843}
1844
1845impl PartialEq for Account {
1846 fn eq(&self, other: &Self) -> bool {
1847 self.identity_keys() == other.identity_keys() && self.shared() == other.shared()
1848 }
1849}
1850
1851pub(crate) fn shared_history_from_history_visibility(
1871 history_visibility: &HistoryVisibility,
1872) -> bool {
1873 match history_visibility {
1874 HistoryVisibility::Shared | HistoryVisibility::WorldReadable => true,
1875 HistoryVisibility::Invited | HistoryVisibility::Joined | _ => false,
1876 }
1877}
1878
1879fn expand_legacy_pickle_key(key: &[u8; 32], device_id: &DeviceId) -> Box<[u8; 32]> {
1898 let kdf: Hkdf<Sha256> = Hkdf::new(Some(device_id.as_bytes()), key);
1899 let mut key = Box::new([0u8; 32]);
1900
1901 kdf.expand(b"dehydrated-device-pickle-key", key.as_mut_slice())
1902 .expect("We should be able to expand the 32 byte pickle key");
1903
1904 key
1905}
1906
1907fn satisfies_sender_trust_requirement(
1910 encryption_info: &EncryptionInfo,
1911 trust_requirement: &TrustRequirement,
1912) -> bool {
1913 trace!(
1914 verification_state = ?encryption_info.verification_state,
1915 ?trust_requirement, "check_to_device_sender_trust_requirement",
1916 );
1917
1918 match (&encryption_info.verification_state, trust_requirement) {
1919 (_, TrustRequirement::Untrusted) => true,
1921
1922 (VerificationState::Verified, _) => true,
1924
1925 (
1928 VerificationState::Unverified(verification_level),
1929 TrustRequirement::CrossSignedOrLegacy | TrustRequirement::CrossSigned,
1930 ) => match verification_level {
1931 VerificationLevel::UnverifiedIdentity => true,
1933
1934 VerificationLevel::UnsignedDevice
1937 | VerificationLevel::None(_)
1938 | VerificationLevel::VerificationViolation
1939 | VerificationLevel::MismatchedSender => false,
1940 },
1941 }
1942}
1943
1944#[cfg(test)]
1945mod tests {
1946 use std::{
1947 collections::{BTreeMap, BTreeSet},
1948 ops::Deref,
1949 time::Duration,
1950 };
1951
1952 use anyhow::Result;
1953 use matrix_sdk_test::async_test;
1954 use ruma::{
1955 DeviceId, MilliSecondsSinceUnixEpoch, OneTimeKeyAlgorithm, OneTimeKeyId, UserId, device_id,
1956 events::room::history_visibility::HistoryVisibility, room_id, user_id,
1957 };
1958 use serde_json::json;
1959
1960 use super::Account;
1961 use crate::{
1962 DeviceData, EncryptionSettings,
1963 olm::{SignedJsonObject, account::shared_history_from_history_visibility},
1964 types::{DeviceKeys, SignedKey},
1965 };
1966
1967 fn user_id() -> &'static UserId {
1968 user_id!("@alice:localhost")
1969 }
1970
1971 fn device_id() -> &'static DeviceId {
1972 device_id!("DEVICEID")
1973 }
1974
1975 #[test]
1976 fn test_one_time_key_creation() -> Result<()> {
1977 let mut account = Account::with_device_id(user_id(), device_id());
1978
1979 let (_, one_time_keys, _) = account.keys_for_upload();
1980 assert!(!one_time_keys.is_empty());
1981
1982 let (_, second_one_time_keys, _) = account.keys_for_upload();
1983 assert!(!second_one_time_keys.is_empty());
1984
1985 let one_time_key_ids: BTreeSet<&OneTimeKeyId> =
1986 one_time_keys.keys().map(Deref::deref).collect();
1987 let second_one_time_key_ids: BTreeSet<&OneTimeKeyId> =
1988 second_one_time_keys.keys().map(Deref::deref).collect();
1989
1990 assert_eq!(one_time_key_ids, second_one_time_key_ids);
1991
1992 account.mark_keys_as_published();
1993 account.update_uploaded_key_count(50);
1994 account.generate_one_time_keys_if_needed();
1995
1996 let (_, third_one_time_keys, _) = account.keys_for_upload();
1997 assert!(third_one_time_keys.is_empty());
1998
1999 account.update_uploaded_key_count(0);
2000 account.generate_one_time_keys_if_needed();
2001
2002 let (_, fourth_one_time_keys, _) = account.keys_for_upload();
2003 assert!(!fourth_one_time_keys.is_empty());
2004
2005 let fourth_one_time_key_ids: BTreeSet<&OneTimeKeyId> =
2006 fourth_one_time_keys.keys().map(Deref::deref).collect();
2007
2008 assert_ne!(one_time_key_ids, fourth_one_time_key_ids);
2009 Ok(())
2010 }
2011
2012 #[test]
2013 fn test_fallback_key_creation() -> Result<()> {
2014 let mut account = Account::with_device_id(user_id(), device_id());
2015
2016 let (_, _, fallback_keys) = account.keys_for_upload();
2017
2018 assert!(
2022 fallback_keys.is_empty(),
2023 "We should not upload fallback keys until we know if the server supports them."
2024 );
2025
2026 let one_time_keys = BTreeMap::from([(OneTimeKeyAlgorithm::SignedCurve25519, 50u8.into())]);
2027
2028 account.update_key_counts(&one_time_keys, None, false);
2031 let (_, _, fallback_keys) = account.keys_for_upload();
2032 assert!(
2033 fallback_keys.is_empty(),
2034 "We should not upload a fallback key if we're certain that the server doesn't support \
2035 them."
2036 );
2037
2038 let unused_fallback_keys = &[];
2042 account.update_key_counts(&one_time_keys, Some(unused_fallback_keys.as_ref()), false);
2043 let (_, _, fallback_keys) = account.keys_for_upload();
2044 assert!(
2045 !fallback_keys.is_empty(),
2046 "We should upload the initial fallback key if the server supports them."
2047 );
2048 account.mark_keys_as_published();
2049
2050 let unused_fallback_keys = &[];
2053 account.update_key_counts(&one_time_keys, Some(unused_fallback_keys.as_ref()), false);
2054 let (_, _, fallback_keys) = account.keys_for_upload();
2055 assert!(
2056 fallback_keys.is_empty(),
2057 "We should not upload new fallback keys unless our current fallback key expires."
2058 );
2059
2060 let fallback_key_timestamp =
2061 account.fallback_creation_timestamp.unwrap().to_system_time().unwrap()
2062 - Duration::from_secs(3600 * 24 * 30);
2063
2064 account.fallback_creation_timestamp =
2065 Some(MilliSecondsSinceUnixEpoch::from_system_time(fallback_key_timestamp).unwrap());
2066
2067 account.update_key_counts(&one_time_keys, None, false);
2068 let (_, _, fallback_keys) = account.keys_for_upload();
2069 assert!(
2070 !fallback_keys.is_empty(),
2071 "Now that our fallback key has expired, we should try to upload a new one, even if the \
2072 server supposedly doesn't support fallback keys anymore"
2073 );
2074
2075 Ok(())
2076 }
2077
2078 #[test]
2079 fn test_fallback_key_signing() -> Result<()> {
2080 let key = vodozemac::Curve25519PublicKey::from_base64(
2081 "7PUPP6Ijt5R8qLwK2c8uK5hqCNF9tOzWYgGaAay5JBs",
2082 )?;
2083 let account = Account::with_device_id(user_id(), device_id());
2084
2085 let key = account.sign_key(key, true);
2086
2087 let canonical_key = key.to_canonical_json()?;
2088
2089 assert_eq!(
2090 canonical_key,
2091 "{\"fallback\":true,\"key\":\"7PUPP6Ijt5R8qLwK2c8uK5hqCNF9tOzWYgGaAay5JBs\"}"
2092 );
2093
2094 account
2095 .has_signed_raw(key.signatures(), &canonical_key)
2096 .expect("Couldn't verify signature");
2097
2098 let device = DeviceData::from_account(&account);
2099 device.verify_one_time_key(&key).expect("The device can verify its own signature");
2100
2101 Ok(())
2102 }
2103
2104 #[test]
2105 fn test_account_and_device_creation_timestamp() -> Result<()> {
2106 let now = MilliSecondsSinceUnixEpoch::now();
2107 let account = Account::with_device_id(user_id(), device_id());
2108 let then = MilliSecondsSinceUnixEpoch::now();
2109
2110 assert!(account.creation_local_time() >= now);
2111 assert!(account.creation_local_time() <= then);
2112
2113 let device = DeviceData::from_account(&account);
2114 assert_eq!(account.creation_local_time(), device.first_time_seen_ts());
2115
2116 Ok(())
2117 }
2118
2119 #[async_test]
2120 async fn test_fallback_key_signature_verification() -> Result<()> {
2121 let fallback_key = json!({
2122 "fallback": true,
2123 "key": "XPFqtLvBepBmW6jSAbBuJbhEpprBhQOX1IjUu+cnMF4",
2124 "signatures": {
2125 "@dkasak_c:matrix.org": {
2126 "ed25519:EXPDYDPWZH": "RJCBMJPL5hvjxgq8rmLmqkNOuPsaan7JeL1wsE+gW6R39G894lb2sBmzapHeKCn/KFjmkonPLkICApRDS+zyDw"
2127 }
2128 }
2129 });
2130
2131 let device_keys = json!({
2132 "algorithms": [
2133 "m.olm.v1.curve25519-aes-sha2",
2134 "m.megolm.v1.aes-sha2"
2135 ],
2136 "device_id": "EXPDYDPWZH",
2137 "keys": {
2138 "curve25519:EXPDYDPWZH": "k7f3igo0Vrdm88JSSA5d3OCuUfHYELChB2b57aOROB8",
2139 "ed25519:EXPDYDPWZH": "GdjYI8fxs175gSpYRJkyN6FRfvcyTsNOhJ2OR/Ggp+E"
2140 },
2141 "signatures": {
2142 "@dkasak_c:matrix.org": {
2143 "ed25519:EXPDYDPWZH": "kzrtfQMbJXWXQ1uzhybtwFnGk0JJBS4Mg8VPMusMu6U8MPJccwoHVZKo5+owuHTzIodI+GZYqLmMSzvfvsChAA"
2144 }
2145 },
2146 "user_id": "@dkasak_c:matrix.org",
2147 "unsigned": {}
2148 });
2149
2150 let device_keys: DeviceKeys = serde_json::from_value(device_keys).unwrap();
2151 let device = DeviceData::try_from(&device_keys).unwrap();
2152 let fallback_key: SignedKey = serde_json::from_value(fallback_key).unwrap();
2153
2154 device
2155 .verify_one_time_key(&fallback_key)
2156 .expect("The fallback key should pass the signature verification");
2157
2158 Ok(())
2159 }
2160
2161 #[test]
2162 fn test_shared_history_flag_from_history_visibility() {
2163 assert!(
2164 shared_history_from_history_visibility(&HistoryVisibility::WorldReadable),
2165 "The world readable visibility should set the shared history flag to true"
2166 );
2167
2168 assert!(
2169 shared_history_from_history_visibility(&HistoryVisibility::Shared),
2170 "The shared visibility should set the shared history flag to true"
2171 );
2172
2173 assert!(
2174 !shared_history_from_history_visibility(&HistoryVisibility::Joined),
2175 "The joined visibility should set the shared history flag to false"
2176 );
2177
2178 assert!(
2179 !shared_history_from_history_visibility(&HistoryVisibility::Invited),
2180 "The invited visibility should set the shared history flag to false"
2181 );
2182
2183 let visibility = HistoryVisibility::from("custom_visibility");
2184 assert!(
2185 !shared_history_from_history_visibility(&visibility),
2186 "A custom visibility should set the shared history flag to false"
2187 );
2188 }
2189
2190 #[async_test]
2191 async fn test_shared_history_set_when_creating_group_sessions() {
2192 let account = Account::new(user_id());
2193 let room_id = room_id!("!room:id");
2194 let settings = EncryptionSettings {
2195 history_visibility: HistoryVisibility::Shared,
2196 ..Default::default()
2197 };
2198
2199 let (_, session) = account
2200 .create_group_session_pair(room_id, settings, Default::default())
2201 .await
2202 .expect("We should be able to create a group session pair");
2203
2204 assert!(
2205 session.shared_history(),
2206 "The shared history flag should have been set when we created the new session"
2207 );
2208 }
2209}