matrix_sdk_crypto/olm/
account.rs

1// Copyright 2020 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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};
28#[cfg(test)]
29use ruma::api::client::dehydrated_device::DehydratedDeviceV1;
30use ruma::{
31    DeviceId, DeviceKeyAlgorithm, DeviceKeyId, MilliSecondsSinceUnixEpoch, OneTimeKeyAlgorithm,
32    OneTimeKeyId, OwnedDeviceId, OwnedDeviceKeyId, OwnedOneTimeKeyId, OwnedUserId, RoomId,
33    SecondsSinceUnixEpoch, UInt, UserId,
34    api::client::{
35        dehydrated_device::{DehydratedDeviceData, DehydratedDeviceV2},
36        keys::{
37            upload_keys,
38            upload_signatures::v3::{Request as SignatureUploadRequest, SignedKeys},
39        },
40    },
41    events::{AnyToDeviceEvent, room::history_visibility::HistoryVisibility},
42    serde::Raw,
43};
44use serde::{Deserialize, Serialize, de::Error};
45use serde_json::{
46    Value,
47    value::{RawValue as RawJsonValue, to_raw_value},
48};
49use sha2::{Digest, Sha256};
50use tokio::sync::Mutex;
51use tracing::{Span, debug, field::debug, info, instrument, trace, warn};
52use vodozemac::{
53    Curve25519PublicKey, Ed25519Signature, KeyId, PickleError, base64_encode,
54    olm::{
55        Account as InnerAccount, AccountPickle, IdentityKeys, OlmMessage,
56        OneTimeKeyGenerationResult, PreKeyMessage, SessionConfig,
57    },
58};
59
60use super::{
61    EncryptionSettings, InboundGroupSession, OutboundGroupSession, PrivateCrossSigningIdentity,
62    Session, SessionCreationError as MegolmSessionCreationError, utility::SignJson,
63};
64#[cfg(feature = "experimental-algorithms")]
65use crate::types::events::room::encrypted::OlmV2Curve25519AesSha2Content;
66use crate::{
67    DecryptionSettings, Device, OlmError, SignatureError, TrustRequirement,
68    dehydrated_devices::DehydrationError,
69    error::{EventError, OlmResult, SessionCreationError},
70    identities::DeviceData,
71    olm::SenderData,
72    store::{
73        Store,
74        types::{Changes, DeviceChanges},
75    },
76    types::{
77        CrossSigningKey, DeviceKeys, EventEncryptionAlgorithm, MasterPubkey, OneTimeKey, SignedKey,
78        events::{
79            olm_v1::AnyDecryptedOlmEvent,
80            room::encrypted::{
81                EncryptedToDeviceEvent, OlmV1Curve25519AesSha2Content,
82                ToDeviceEncryptedEventContent,
83            },
84        },
85        requests::UploadSigningKeysRequest,
86    },
87};
88
89#[derive(Debug)]
90enum PrekeyBundle {
91    Olm3DH { key: SignedKey },
92}
93
94#[derive(Debug, Clone)]
95pub(crate) enum SessionType {
96    New(Session),
97    Existing(Session),
98}
99
100#[derive(Debug)]
101pub struct InboundCreationResult {
102    pub session: Session,
103    pub plaintext: String,
104}
105
106impl SessionType {
107    #[cfg(test)]
108    pub fn session(self) -> Session {
109        match self {
110            SessionType::New(s) => s,
111            SessionType::Existing(s) => s,
112        }
113    }
114}
115
116/// A struct witnessing a successful decryption of an Olm-encrypted to-device
117/// event.
118///
119/// Contains the decrypted event plaintext along with some associated metadata,
120/// such as the identity (Curve25519) key of the to-device event sender.
121#[derive(Debug)]
122pub(crate) struct OlmDecryptionInfo {
123    pub session: SessionType,
124    pub message_hash: OlmMessageHash,
125    pub inbound_group_session: Option<InboundGroupSession>,
126    pub result: DecryptionResult,
127}
128
129#[derive(Debug)]
130pub(crate) struct DecryptionResult {
131    // AnyDecryptedOlmEvent is pretty big at 512 bytes, box it to reduce stack size
132    pub event: Box<AnyDecryptedOlmEvent>,
133    pub raw_event: Raw<AnyToDeviceEvent>,
134    pub sender_key: Curve25519PublicKey,
135    pub encryption_info: EncryptionInfo,
136}
137
138/// A hash of a successfully decrypted Olm message.
139///
140/// Can be used to check if a message has been replayed to us.
141#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct OlmMessageHash {
143    /// The curve25519 key of the sender that sent us the Olm message.
144    pub sender_key: String,
145    /// The hash of the message.
146    pub hash: String,
147}
148
149impl OlmMessageHash {
150    fn new(sender_key: Curve25519PublicKey, ciphertext: &OlmMessage) -> Self {
151        let (message_type, ciphertext) = ciphertext.clone().to_parts();
152        let sender_key = sender_key.to_base64();
153
154        let sha = Sha256::new()
155            .chain_update(sender_key.as_bytes())
156            .chain_update([message_type as u8])
157            .chain_update(ciphertext)
158            .finalize();
159
160        Self { sender_key, hash: base64_encode(sha.as_slice()) }
161    }
162}
163
164/// Account data that's static for the lifetime of a Client.
165///
166/// This data never changes once it's set, so it can be freely passed and cloned
167/// everywhere.
168#[derive(Clone)]
169#[cfg_attr(not(tarpaulin_include), derive(Debug))]
170pub struct StaticAccountData {
171    /// The user_id this account belongs to.
172    pub user_id: OwnedUserId,
173    /// The device_id of this entry.
174    pub device_id: OwnedDeviceId,
175    /// The associated identity keys.
176    pub identity_keys: Arc<IdentityKeys>,
177    /// Whether the account is for a dehydrated device.
178    pub dehydrated: bool,
179    // The creation time of the account in milliseconds since epoch.
180    creation_local_time: MilliSecondsSinceUnixEpoch,
181}
182
183impl StaticAccountData {
184    const ALGORITHMS: &'static [&'static EventEncryptionAlgorithm] = &[
185        &EventEncryptionAlgorithm::OlmV1Curve25519AesSha2,
186        #[cfg(feature = "experimental-algorithms")]
187        &EventEncryptionAlgorithm::OlmV2Curve25519AesSha2,
188        &EventEncryptionAlgorithm::MegolmV1AesSha2,
189        #[cfg(feature = "experimental-algorithms")]
190        &EventEncryptionAlgorithm::MegolmV2AesSha2,
191    ];
192
193    /// Create a group session pair.
194    ///
195    /// This session pair can be used to encrypt and decrypt messages meant for
196    /// a large group of participants.
197    ///
198    /// The outbound session is used to encrypt messages while the inbound one
199    /// is used to decrypt messages encrypted by the outbound one.
200    ///
201    /// # Arguments
202    ///
203    /// * `room_id` - The ID of the room where the group session will be used.
204    ///
205    /// * `settings` - Settings determining the algorithm and rotation period of
206    ///   the outbound group session.
207    pub async fn create_group_session_pair(
208        &self,
209        room_id: &RoomId,
210        settings: EncryptionSettings,
211        own_sender_data: SenderData,
212    ) -> Result<(OutboundGroupSession, InboundGroupSession), MegolmSessionCreationError> {
213        trace!(?room_id, algorithm = settings.algorithm.as_str(), "Creating a new room key");
214
215        let visibility = settings.history_visibility.clone();
216        let algorithm = settings.algorithm.to_owned();
217
218        let outbound = OutboundGroupSession::new(
219            self.device_id.clone(),
220            self.identity_keys.clone(),
221            room_id,
222            settings,
223        )?;
224
225        let identity_keys = &self.identity_keys;
226
227        let sender_key = identity_keys.curve25519;
228        let signing_key = identity_keys.ed25519;
229        let shared_history = shared_history_from_history_visibility(&visibility);
230
231        let inbound = InboundGroupSession::new(
232            sender_key,
233            signing_key,
234            room_id,
235            &outbound.session_key().await,
236            own_sender_data,
237            algorithm,
238            Some(visibility),
239            shared_history,
240        )?;
241
242        Ok((outbound, inbound))
243    }
244
245    #[cfg(any(test, feature = "testing"))]
246    #[allow(dead_code)]
247    /// Testing only facility to create a group session pair with default
248    /// settings.
249    pub async fn create_group_session_pair_with_defaults(
250        &self,
251        room_id: &RoomId,
252    ) -> (OutboundGroupSession, InboundGroupSession) {
253        self.create_group_session_pair(
254            room_id,
255            EncryptionSettings::default(),
256            SenderData::unknown(),
257        )
258        .await
259        .expect("Can't create default group session pair")
260    }
261
262    /// Get the key ID of our Ed25519 signing key.
263    pub fn signing_key_id(&self) -> OwnedDeviceKeyId {
264        DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id())
265    }
266
267    /// Check if the given JSON is signed by this Account key.
268    ///
269    /// This method should only be used if an object's signature needs to be
270    /// checked multiple times, and you'd like to avoid performing the
271    /// canonicalization step each time.
272    ///
273    /// **Note**: Use this method with caution, the `canonical_json` needs to be
274    /// correctly canonicalized and make sure that the object you are checking
275    /// the signature for is allowed to be signed by our own device.
276    pub fn has_signed_raw(
277        &self,
278        signatures: &crate::types::Signatures,
279        canonical_json: &str,
280    ) -> Result<(), SignatureError> {
281        use crate::olm::utility::VerifyJson;
282
283        let signing_key = self.identity_keys.ed25519;
284
285        signing_key.verify_canonicalized_json(
286            &self.user_id,
287            &DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
288            signatures,
289            canonical_json,
290        )
291    }
292
293    /// Generate the unsigned `DeviceKeys` from this `StaticAccountData`.
294    pub fn unsigned_device_keys(&self) -> DeviceKeys {
295        let identity_keys = self.identity_keys();
296        let keys = BTreeMap::from([
297            (
298                DeviceKeyId::from_parts(DeviceKeyAlgorithm::Curve25519, &self.device_id),
299                identity_keys.curve25519.into(),
300            ),
301            (
302                DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, &self.device_id),
303                identity_keys.ed25519.into(),
304            ),
305        ]);
306
307        let mut ret = DeviceKeys::new(
308            (*self.user_id).to_owned(),
309            (*self.device_id).to_owned(),
310            Self::ALGORITHMS.iter().map(|a| (**a).clone()).collect(),
311            keys,
312            Default::default(),
313        );
314        if self.dehydrated {
315            ret.dehydrated = JsOption::Some(true);
316        }
317        ret
318    }
319
320    /// Get the user id of the owner of the account.
321    pub fn user_id(&self) -> &UserId {
322        &self.user_id
323    }
324
325    /// Get the device ID that owns this account.
326    pub fn device_id(&self) -> &DeviceId {
327        &self.device_id
328    }
329
330    /// Get the public parts of the identity keys for the account.
331    pub fn identity_keys(&self) -> IdentityKeys {
332        *self.identity_keys
333    }
334
335    /// Get the local timestamp creation of the account in secs since epoch.
336    pub fn creation_local_time(&self) -> MilliSecondsSinceUnixEpoch {
337        self.creation_local_time
338    }
339}
340
341/// Account holding identity keys for which sessions can be created.
342///
343/// An account is the central identity for encrypted communication between two
344/// devices.
345pub struct Account {
346    pub(crate) static_data: StaticAccountData,
347    /// `vodozemac` account.
348    inner: Box<InnerAccount>,
349    /// Is this account ready to encrypt messages? (i.e. has it shared keys with
350    /// a homeserver)
351    shared: bool,
352    /// The number of signed one-time keys we have uploaded to the server. If
353    /// this is None, no action will be taken. After a sync request the client
354    /// needs to set this for us, depending on the count we will suggest the
355    /// client to upload new keys.
356    uploaded_signed_key_count: u64,
357    /// The timestamp of the last time we generated a fallback key. Fallback
358    /// keys are rotated in a time-based manner. This field records when we
359    /// either generated our first fallback key or rotated one.
360    ///
361    /// Will be `None` if we never created a fallback key, or if we're migrating
362    /// from a `AccountPickle` that didn't use time-based fallback key
363    /// rotation.
364    fallback_creation_timestamp: Option<MilliSecondsSinceUnixEpoch>,
365}
366
367impl Deref for Account {
368    type Target = StaticAccountData;
369
370    fn deref(&self) -> &Self::Target {
371        &self.static_data
372    }
373}
374
375/// A pickled version of an `Account`.
376///
377/// Holds all the information that needs to be stored in a database to restore
378/// an account.
379#[derive(Serialize, Deserialize)]
380#[allow(missing_debug_implementations)]
381pub struct PickledAccount {
382    /// The user id of the account owner.
383    pub user_id: OwnedUserId,
384    /// The device ID of the account owner.
385    pub device_id: OwnedDeviceId,
386    /// The pickled version of the Olm account.
387    pub pickle: AccountPickle,
388    /// Was the account shared.
389    pub shared: bool,
390    /// Whether this is for a dehydrated device
391    #[serde(default)]
392    pub dehydrated: bool,
393    /// The number of uploaded one-time keys we have on the server.
394    pub uploaded_signed_key_count: u64,
395    /// The local time creation of this account (milliseconds since epoch), used
396    /// as creation time of own device
397    #[serde(default = "default_account_creation_time")]
398    pub creation_local_time: MilliSecondsSinceUnixEpoch,
399    /// The timestamp of the last time we generated a fallback key.
400    #[serde(default)]
401    pub fallback_key_creation_timestamp: Option<MilliSecondsSinceUnixEpoch>,
402}
403
404fn default_account_creation_time() -> MilliSecondsSinceUnixEpoch {
405    MilliSecondsSinceUnixEpoch(UInt::default())
406}
407
408#[cfg(not(tarpaulin_include))]
409impl fmt::Debug for Account {
410    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
411        f.debug_struct("Account")
412            .field("identity_keys", &self.identity_keys())
413            .field("shared", &self.shared())
414            .finish()
415    }
416}
417
418pub type OneTimeKeys = BTreeMap<OwnedOneTimeKeyId, Raw<ruma::encryption::OneTimeKey>>;
419pub type FallbackKeys = OneTimeKeys;
420
421impl Account {
422    pub(crate) fn new_helper(
423        mut account: InnerAccount,
424        user_id: &UserId,
425        device_id: &DeviceId,
426    ) -> Self {
427        let identity_keys = account.identity_keys();
428
429        // Let's generate some initial one-time keys while we're here. Since we know
430        // that this is a completely new [`Account`] we're certain that the
431        // server does not yet have any one-time keys of ours.
432        //
433        // This ensures we upload one-time keys along with our device keys right
434        // away, rather than waiting for the key counts to be echoed back to us
435        // from the server.
436        //
437        // It would be nice to do this for the fallback key as well but we can't assume
438        // that the server supports fallback keys. Maybe one of these days we
439        // will be able to do so.
440        account.generate_one_time_keys(account.max_number_of_one_time_keys());
441
442        Self {
443            static_data: StaticAccountData {
444                user_id: user_id.into(),
445                device_id: device_id.into(),
446                identity_keys: Arc::new(identity_keys),
447                dehydrated: false,
448                creation_local_time: MilliSecondsSinceUnixEpoch::now(),
449            },
450            inner: Box::new(account),
451            shared: false,
452            uploaded_signed_key_count: 0,
453            fallback_creation_timestamp: None,
454        }
455    }
456
457    /// Create a fresh new account, this will generate the identity key-pair.
458    pub fn with_device_id(user_id: &UserId, device_id: &DeviceId) -> Self {
459        let account = InnerAccount::new();
460
461        Self::new_helper(account, user_id, device_id)
462    }
463
464    /// Create a new random Olm Account, the long-term Curve25519 identity key
465    /// encoded as base64 will be used for the device ID.
466    pub fn new(user_id: &UserId) -> Self {
467        let account = InnerAccount::new();
468        let device_id: OwnedDeviceId =
469            base64_encode(account.identity_keys().curve25519.as_bytes()).into();
470
471        Self::new_helper(account, user_id, &device_id)
472    }
473
474    /// Create a new random Olm Account for a dehydrated device
475    pub fn new_dehydrated(user_id: &UserId) -> Self {
476        let account = InnerAccount::new();
477        let device_id: OwnedDeviceId =
478            base64_encode(account.identity_keys().curve25519.as_bytes()).into();
479
480        let mut ret = Self::new_helper(account, user_id, &device_id);
481        ret.static_data.dehydrated = true;
482        ret
483    }
484
485    /// Get the immutable data for this account.
486    pub fn static_data(&self) -> &StaticAccountData {
487        &self.static_data
488    }
489
490    /// Update the uploaded key count.
491    ///
492    /// # Arguments
493    ///
494    /// * `new_count` - The new count that was reported by the server.
495    pub fn update_uploaded_key_count(&mut self, new_count: u64) {
496        self.uploaded_signed_key_count = new_count;
497    }
498
499    /// Get the currently known uploaded key count.
500    pub fn uploaded_key_count(&self) -> u64 {
501        self.uploaded_signed_key_count
502    }
503
504    /// Has the account been shared with the server.
505    pub fn shared(&self) -> bool {
506        self.shared
507    }
508
509    /// Mark the account as shared.
510    ///
511    /// Messages shouldn't be encrypted with the session before it has been
512    /// shared.
513    pub fn mark_as_shared(&mut self) {
514        self.shared = true;
515    }
516
517    /// Get the one-time keys of the account.
518    ///
519    /// This can be empty, keys need to be generated first.
520    pub fn one_time_keys(&self) -> HashMap<KeyId, Curve25519PublicKey> {
521        self.inner.one_time_keys()
522    }
523
524    /// Generate count number of one-time keys.
525    pub fn generate_one_time_keys(&mut self, count: usize) -> OneTimeKeyGenerationResult {
526        self.inner.generate_one_time_keys(count)
527    }
528
529    /// Get the maximum number of one-time keys the account can hold.
530    pub fn max_one_time_keys(&self) -> usize {
531        self.inner.max_number_of_one_time_keys()
532    }
533
534    pub(crate) fn update_key_counts(
535        &mut self,
536        one_time_key_counts: &BTreeMap<OneTimeKeyAlgorithm, UInt>,
537        unused_fallback_keys: Option<&[OneTimeKeyAlgorithm]>,
538    ) {
539        if let Some(count) = one_time_key_counts.get(&OneTimeKeyAlgorithm::SignedCurve25519) {
540            let count: u64 = (*count).into();
541            let old_count = self.uploaded_key_count();
542
543            // Some servers might always return the key counts in the sync
544            // response, we don't want to the logs with noop changes if they do
545            // so.
546            if count != old_count {
547                debug!(
548                    "Updated uploaded one-time key count {} -> {count}.",
549                    self.uploaded_key_count(),
550                );
551            }
552
553            self.update_uploaded_key_count(count);
554            self.generate_one_time_keys_if_needed();
555        }
556
557        // If the server supports fallback keys or if it did so in the past, shown by
558        // the existence of a fallback creation timestamp, generate a new one if
559        // we don't have one, or if the current fallback key expired.
560        if unused_fallback_keys.is_some() || self.fallback_creation_timestamp.is_some() {
561            self.generate_fallback_key_if_needed();
562        }
563    }
564
565    /// Generate new one-time keys that need to be uploaded to the server.
566    ///
567    /// Returns None if no keys need to be uploaded, otherwise the number of
568    /// newly generated one-time keys. May return 0 if some one-time keys are
569    /// already generated but weren't uploaded.
570    ///
571    /// Generally `Some` means that keys should be uploaded, while `None` means
572    /// that keys should not be uploaded.
573    #[instrument(skip_all)]
574    pub fn generate_one_time_keys_if_needed(&mut self) -> Option<u64> {
575        // Only generate one-time keys if there aren't any, otherwise the caller
576        // might have failed to upload them the last time this method was
577        // called.
578        if !self.one_time_keys().is_empty() {
579            return Some(0);
580        }
581
582        let count = self.uploaded_key_count();
583        let max_keys = self.max_one_time_keys();
584
585        if count >= max_keys as u64 {
586            return None;
587        }
588
589        let key_count = (max_keys as u64) - count;
590        let key_count: usize = key_count.try_into().unwrap_or(max_keys);
591
592        let result = self.generate_one_time_keys(key_count);
593
594        debug!(
595            count = key_count,
596            discarded_keys = ?result.removed,
597            created_keys = ?result.created,
598            "Generated new one-time keys"
599        );
600
601        Some(key_count as u64)
602    }
603
604    /// Generate a new fallback key iff a unpublished one isn't already inside
605    /// of vodozemac and if the currently active one expired.
606    ///
607    /// The former is checked using [`Account::fallback_key().is_empty()`],
608    /// which is a hashmap that gets cleared by the
609    /// [`Account::mark_keys_as_published()`] call.
610    pub(crate) fn generate_fallback_key_if_needed(&mut self) {
611        if self.inner.fallback_key().is_empty() && self.fallback_key_expired() {
612            let removed_fallback_key = self.inner.generate_fallback_key();
613            self.fallback_creation_timestamp = Some(MilliSecondsSinceUnixEpoch::now());
614
615            debug!(
616                ?removed_fallback_key,
617                "The fallback key either expired or we didn't have one: generated a new fallback key.",
618            );
619        }
620    }
621
622    /// Check if our most recent fallback key has expired.
623    ///
624    /// We consider the fallback key to be expired if it's older than a week.
625    /// This is the lower bound for the recommended signed pre-key bundle
626    /// rotation interval in the X3DH spec[1].
627    ///
628    /// [1]: https://signal.org/docs/specifications/x3dh/#publishing-keys
629    fn fallback_key_expired(&self) -> bool {
630        const FALLBACK_KEY_MAX_AGE: Duration = Duration::from_secs(3600 * 24 * 7);
631
632        if let Some(time) = self.fallback_creation_timestamp {
633            // `to_system_time()` returns `None` if the the UNIX_EPOCH + `time` doesn't fit
634            // into a i64. This will likely never happen, but let's rotate the
635            // key in case the values are messed up for some other reason.
636            let Some(system_time) = time.to_system_time() else {
637                return true;
638            };
639
640            // `elapsed()` errors if the `system_time` is in the future, this should mean
641            // that our clock has changed to the past, let's rotate just in case
642            // and then we'll get to a normal time.
643            let Ok(elapsed) = system_time.elapsed() else {
644                return true;
645            };
646
647            // Alright, our times are normal and we know how much time elapsed since the
648            // last time we created/rotated a fallback key.
649            //
650            // If the key is older than a week, then we rotate it.
651            elapsed > FALLBACK_KEY_MAX_AGE
652        } else {
653            // We never created a fallback key, or we're migrating to the time-based
654            // fallback key rotation, so let's generate a new fallback key.
655            true
656        }
657    }
658
659    fn fallback_key(&self) -> HashMap<KeyId, Curve25519PublicKey> {
660        self.inner.fallback_key()
661    }
662
663    /// Get a tuple of device, one-time, and fallback keys that need to be
664    /// uploaded.
665    ///
666    /// If no keys need to be uploaded the `DeviceKeys` will be `None` and the
667    /// one-time and fallback keys maps will be empty.
668    pub fn keys_for_upload(&self) -> (Option<DeviceKeys>, OneTimeKeys, FallbackKeys) {
669        let device_keys = self.shared().not().then(|| self.device_keys());
670
671        let one_time_keys = self.signed_one_time_keys();
672        let fallback_keys = self.signed_fallback_keys();
673
674        (device_keys, one_time_keys, fallback_keys)
675    }
676
677    /// Mark the current set of one-time keys as being published.
678    pub fn mark_keys_as_published(&mut self) {
679        self.inner.mark_keys_as_published();
680    }
681
682    /// Sign the given string using the accounts signing key.
683    ///
684    /// Returns the signature as a base64 encoded string.
685    pub fn sign(&self, string: &str) -> Ed25519Signature {
686        self.inner.sign(string)
687    }
688
689    /// Get a serializable version of the `Account` so it can be persisted.
690    pub fn pickle(&self) -> PickledAccount {
691        let pickle = self.inner.pickle();
692
693        PickledAccount {
694            user_id: self.user_id().to_owned(),
695            device_id: self.device_id().to_owned(),
696            pickle,
697            shared: self.shared(),
698            dehydrated: self.static_data.dehydrated,
699            uploaded_signed_key_count: self.uploaded_key_count(),
700            creation_local_time: self.static_data.creation_local_time,
701            fallback_key_creation_timestamp: self.fallback_creation_timestamp,
702        }
703    }
704
705    pub(crate) fn dehydrate(&self, pickle_key: &[u8; 32]) -> Raw<DehydratedDeviceData> {
706        let dehydration_result = self
707            .inner
708            .to_dehydrated_device(pickle_key)
709            .expect("We should be able to convert a freshly created Account into a libolm pickle");
710
711        let data = DehydratedDeviceData::V2(DehydratedDeviceV2::new(
712            dehydration_result.ciphertext,
713            dehydration_result.nonce,
714        ));
715        Raw::from_json(to_raw_value(&data).expect("Couldn't serialize our dehydrated device data"))
716    }
717
718    pub(crate) fn rehydrate(
719        pickle_key: &[u8; 32],
720        user_id: &UserId,
721        device_id: &DeviceId,
722        device_data: Raw<DehydratedDeviceData>,
723    ) -> Result<Self, DehydrationError> {
724        let data = device_data.deserialize()?;
725
726        match data {
727            DehydratedDeviceData::V1(d) => {
728                let pickle_key = expand_legacy_pickle_key(pickle_key, device_id);
729                let account =
730                    InnerAccount::from_libolm_pickle(&d.device_pickle, pickle_key.as_ref())?;
731                Ok(Self::new_helper(account, user_id, device_id))
732            }
733            DehydratedDeviceData::V2(d) => {
734                let account =
735                    InnerAccount::from_dehydrated_device(&d.device_pickle, &d.nonce, pickle_key)?;
736                Ok(Self::new_helper(account, user_id, device_id))
737            }
738            _ => Err(DehydrationError::Json(serde_json::Error::custom(format!(
739                "Unsupported dehydrated device algorithm {:?}",
740                data.algorithm()
741            )))),
742        }
743    }
744
745    /// Produce a dehydrated device using a format described in an older version
746    /// of MSC3814.
747    #[cfg(test)]
748    pub(crate) fn legacy_dehydrate(&self, pickle_key: &[u8; 32]) -> Raw<DehydratedDeviceData> {
749        let pickle_key = expand_legacy_pickle_key(pickle_key, &self.device_id);
750        let device_pickle = self
751            .inner
752            .to_libolm_pickle(pickle_key.as_ref())
753            .expect("We should be able to convert a freshly created Account into a libolm pickle");
754
755        let data = DehydratedDeviceData::V1(DehydratedDeviceV1::new(device_pickle));
756        Raw::from_json(to_raw_value(&data).expect("Couldn't serialize our dehydrated device data"))
757    }
758
759    /// Restore an account from a previously pickled one.
760    ///
761    /// # Arguments
762    ///
763    /// * `pickle` - The pickled version of the Account.
764    ///
765    /// * `pickle_mode` - The mode that was used to pickle the account, either
766    ///   an unencrypted mode or an encrypted using passphrase.
767    pub fn from_pickle(pickle: PickledAccount) -> Result<Self, PickleError> {
768        let account: vodozemac::olm::Account = pickle.pickle.into();
769        let identity_keys = account.identity_keys();
770
771        Ok(Self {
772            static_data: StaticAccountData {
773                user_id: (*pickle.user_id).into(),
774                device_id: (*pickle.device_id).into(),
775                identity_keys: Arc::new(identity_keys),
776                dehydrated: pickle.dehydrated,
777                creation_local_time: pickle.creation_local_time,
778            },
779            inner: Box::new(account),
780            shared: pickle.shared,
781            uploaded_signed_key_count: pickle.uploaded_signed_key_count,
782            fallback_creation_timestamp: pickle.fallback_key_creation_timestamp,
783        })
784    }
785
786    /// Sign the device keys of the account and return them so they can be
787    /// uploaded.
788    pub fn device_keys(&self) -> DeviceKeys {
789        let mut device_keys = self.unsigned_device_keys();
790
791        // Create a copy of the device keys containing only fields that will
792        // get signed.
793        let json_device_keys =
794            serde_json::to_value(&device_keys).expect("device key is always safe to serialize");
795        let signature = self
796            .sign_json(json_device_keys)
797            .expect("Newly created device keys can always be signed");
798
799        device_keys.signatures.add_signature(
800            self.user_id().to_owned(),
801            DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, &self.static_data.device_id),
802            signature,
803        );
804
805        device_keys
806    }
807
808    /// Bootstraps cross-signing, generating new cross-signing keys and creating
809    /// the necessary upload and signature requests.
810    ///
811    /// # Returns
812    /// A tuple containing:
813    /// - [`PrivateCrossSigningIdentity`]: The newly-generated cross-signing
814    ///   identity (including a signature from this device).
815    /// - [`UploadSigningKeysRequest`]: The request to upload the
816    ///   newly-generated cross-signing keys to the server.
817    /// - [`SignatureUploadRequest`]: The request to upload the signature of
818    ///   this device to the server.
819    pub async fn bootstrap_cross_signing(
820        &self,
821    ) -> (PrivateCrossSigningIdentity, UploadSigningKeysRequest, SignatureUploadRequest) {
822        let identity = PrivateCrossSigningIdentity::for_account(self);
823
824        let signature_request = identity
825            .sign_account(self.static_data())
826            .await
827            .expect("Can't sign own device with new cross signing keys");
828
829        let upload_request = identity.as_upload_request().await;
830
831        (identity, upload_request, signature_request)
832    }
833
834    /// Sign the given CrossSigning Key in place
835    pub fn sign_cross_signing_key(
836        &self,
837        cross_signing_key: &mut CrossSigningKey,
838    ) -> Result<(), SignatureError> {
839        #[allow(clippy::needless_borrows_for_generic_args)]
840        // XXX: false positive, see https://github.com/rust-lang/rust-clippy/issues/12856
841        let signature = self.sign_json(serde_json::to_value(&cross_signing_key)?)?;
842
843        cross_signing_key.signatures.add_signature(
844            self.user_id().to_owned(),
845            DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
846            signature,
847        );
848
849        Ok(())
850    }
851
852    /// Sign the given Master Key
853    pub fn sign_master_key(
854        &self,
855        master_key: &MasterPubkey,
856    ) -> Result<SignatureUploadRequest, SignatureError> {
857        let public_key =
858            master_key.get_first_key().ok_or(SignatureError::MissingSigningKey)?.to_base64().into();
859
860        let mut cross_signing_key: CrossSigningKey = master_key.as_ref().clone();
861        cross_signing_key.signatures.clear();
862        self.sign_cross_signing_key(&mut cross_signing_key)?;
863
864        let mut user_signed_keys = SignedKeys::new();
865        user_signed_keys.add_cross_signing_keys(public_key, cross_signing_key.to_raw());
866
867        let signed_keys = [(self.user_id().to_owned(), user_signed_keys)].into();
868        Ok(SignatureUploadRequest::new(signed_keys))
869    }
870
871    /// Convert a JSON value to the canonical representation and sign the JSON
872    /// string.
873    ///
874    /// # Arguments
875    ///
876    /// * `json` - The value that should be converted into a canonical JSON
877    ///   string.
878    pub fn sign_json(&self, json: Value) -> Result<Ed25519Signature, SignatureError> {
879        self.inner.sign_json(json)
880    }
881
882    /// Sign and prepare one-time keys to be uploaded.
883    ///
884    /// If no one-time keys need to be uploaded, returns an empty `BTreeMap`.
885    pub fn signed_one_time_keys(&self) -> OneTimeKeys {
886        let one_time_keys = self.one_time_keys();
887
888        if one_time_keys.is_empty() {
889            BTreeMap::new()
890        } else {
891            self.signed_keys(one_time_keys, false)
892        }
893    }
894
895    /// Sign and prepare fallback keys to be uploaded.
896    ///
897    /// If no fallback keys need to be uploaded returns an empty BTreeMap.
898    pub fn signed_fallback_keys(&self) -> FallbackKeys {
899        let fallback_key = self.fallback_key();
900
901        if fallback_key.is_empty() { BTreeMap::new() } else { self.signed_keys(fallback_key, true) }
902    }
903
904    fn signed_keys(
905        &self,
906        keys: HashMap<KeyId, Curve25519PublicKey>,
907        fallback: bool,
908    ) -> OneTimeKeys {
909        let mut keys_map = BTreeMap::new();
910
911        for (key_id, key) in keys {
912            let signed_key = self.sign_key(key, fallback);
913
914            keys_map.insert(
915                OneTimeKeyId::from_parts(
916                    OneTimeKeyAlgorithm::SignedCurve25519,
917                    key_id.to_base64().as_str().into(),
918                ),
919                signed_key.into_raw(),
920            );
921        }
922
923        keys_map
924    }
925
926    fn sign_key(&self, key: Curve25519PublicKey, fallback: bool) -> SignedKey {
927        let mut key = if fallback {
928            SignedKey::new_fallback(key.to_owned())
929        } else {
930            SignedKey::new(key.to_owned())
931        };
932
933        let signature = self
934            .sign_json(serde_json::to_value(&key).expect("Can't serialize a signed key"))
935            .expect("Newly created one-time keys can always be signed");
936
937        key.signatures_mut().add_signature(
938            self.user_id().to_owned(),
939            DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
940            signature,
941        );
942
943        key
944    }
945
946    /// Create a new session with another account given a one-time key.
947    ///
948    /// Returns the newly created session or a `OlmSessionError` if creating a
949    /// session failed.
950    ///
951    /// # Arguments
952    ///
953    /// * `config` - The session config that should be used when creating the
954    ///   Session.
955    ///
956    /// * `identity_key` - The other account's identity/curve25519 key.
957    ///
958    /// * `one_time_key` - A signed one-time key that the other account created
959    ///   and shared with us.
960    ///
961    /// * `fallback_used` - Was the one-time key a fallback key.
962    ///
963    /// * `our_device_keys` - Our own `DeviceKeys`, including cross-signing
964    ///   signatures if applicable, for embedding in encrypted messages.
965    pub fn create_outbound_session_helper(
966        &self,
967        config: SessionConfig,
968        identity_key: Curve25519PublicKey,
969        one_time_key: Curve25519PublicKey,
970        fallback_used: bool,
971        our_device_keys: DeviceKeys,
972    ) -> Session {
973        let session = self.inner.create_outbound_session(config, identity_key, one_time_key);
974
975        let now = SecondsSinceUnixEpoch::now();
976        let session_id = session.session_id();
977
978        Session {
979            inner: Arc::new(Mutex::new(session)),
980            session_id: session_id.into(),
981            sender_key: identity_key,
982            our_device_keys,
983            created_using_fallback_key: fallback_used,
984            creation_time: now,
985            last_use_time: now,
986        }
987    }
988
989    #[instrument(
990        skip_all,
991        fields(
992            user_id = ?device.user_id(),
993            device_id = ?device.device_id(),
994            algorithms = ?device.algorithms()
995        )
996    )]
997    fn find_pre_key_bundle(
998        device: &DeviceData,
999        key_map: &OneTimeKeys,
1000    ) -> Result<PrekeyBundle, SessionCreationError> {
1001        let mut keys = key_map.iter();
1002
1003        let first_key = keys.next().ok_or_else(|| {
1004            SessionCreationError::OneTimeKeyMissing(
1005                device.user_id().to_owned(),
1006                device.device_id().into(),
1007            )
1008        })?;
1009
1010        let first_key_id = first_key.0.to_owned();
1011        let first_key = OneTimeKey::deserialize(first_key_id.algorithm(), first_key.1)?;
1012
1013        let result = match first_key {
1014            OneTimeKey::SignedKey(key) => Ok(PrekeyBundle::Olm3DH { key }),
1015        };
1016
1017        trace!(?result, "Finished searching for a valid pre-key bundle");
1018
1019        result
1020    }
1021
1022    /// Create a new session with another account given a one-time key and a
1023    /// device.
1024    ///
1025    /// Returns the newly created session or a `OlmSessionError` if creating a
1026    /// session failed.
1027    ///
1028    /// # Arguments
1029    /// * `device` - The other account's device.
1030    ///
1031    /// * `key_map` - A map from the algorithm and device ID to the one-time key
1032    ///   that the other account created and shared with us.
1033    ///
1034    /// * `our_device_keys` - Our own `DeviceKeys`, including cross-signing
1035    ///   signatures if applicable, for embedding in encrypted messages.
1036    #[allow(clippy::result_large_err)]
1037    pub fn create_outbound_session(
1038        &self,
1039        device: &DeviceData,
1040        key_map: &OneTimeKeys,
1041        our_device_keys: DeviceKeys,
1042    ) -> Result<Session, SessionCreationError> {
1043        let pre_key_bundle = Self::find_pre_key_bundle(device, key_map)?;
1044
1045        match pre_key_bundle {
1046            PrekeyBundle::Olm3DH { key } => {
1047                device.verify_one_time_key(&key).map_err(|error| {
1048                    SessionCreationError::InvalidSignature {
1049                        signing_key: device.ed25519_key().map(Box::new),
1050                        one_time_key: key.clone().into(),
1051                        error: error.into(),
1052                    }
1053                })?;
1054
1055                let identity_key = device.curve25519_key().ok_or_else(|| {
1056                    SessionCreationError::DeviceMissingCurveKey(
1057                        device.user_id().to_owned(),
1058                        device.device_id().into(),
1059                    )
1060                })?;
1061
1062                let is_fallback = key.fallback();
1063                let one_time_key = key.key();
1064                let config = device.olm_session_config();
1065
1066                Ok(self.create_outbound_session_helper(
1067                    config,
1068                    identity_key,
1069                    one_time_key,
1070                    is_fallback,
1071                    our_device_keys,
1072                ))
1073            }
1074        }
1075    }
1076
1077    /// Create a new session with another account given a pre-key Olm message.
1078    ///
1079    /// Returns the newly created session or a `OlmSessionError` if creating a
1080    /// session failed.
1081    ///
1082    /// # Arguments
1083    ///
1084    /// * `their_identity_key` - The other account's identity/curve25519 key.
1085    ///
1086    /// * `our_device_keys` - Our own `DeviceKeys`, including cross-signing
1087    ///   signatures if applicable, for embedding in encrypted messages.
1088    ///
1089    /// * `message` - A pre-key Olm message that was sent to us by the other
1090    ///   account.
1091    pub fn create_inbound_session(
1092        &mut self,
1093        their_identity_key: Curve25519PublicKey,
1094        our_device_keys: DeviceKeys,
1095        message: &PreKeyMessage,
1096    ) -> Result<InboundCreationResult, SessionCreationError> {
1097        Span::current().record("session_id", debug(message.session_id()));
1098        trace!("Creating a new Olm session from a pre-key message");
1099
1100        let result = self.inner.create_inbound_session(their_identity_key, message)?;
1101        let now = SecondsSinceUnixEpoch::now();
1102        let session_id = result.session.session_id();
1103
1104        debug!(session=?result.session, "Decrypted an Olm message from a new Olm session");
1105
1106        let session = Session {
1107            inner: Arc::new(Mutex::new(result.session)),
1108            session_id: session_id.into(),
1109            sender_key: their_identity_key,
1110            our_device_keys,
1111            created_using_fallback_key: false,
1112            creation_time: now,
1113            last_use_time: now,
1114        };
1115
1116        let plaintext = String::from_utf8_lossy(&result.plaintext).to_string();
1117
1118        Ok(InboundCreationResult { session, plaintext })
1119    }
1120
1121    #[cfg(any(test, feature = "testing"))]
1122    #[allow(dead_code)]
1123    /// Testing only helper to create a session for the given Account
1124    pub async fn create_session_for_test_helper(
1125        &mut self,
1126        other: &mut Account,
1127    ) -> (Session, Session) {
1128        use ruma::events::dummy::ToDeviceDummyEventContent;
1129
1130        other.generate_one_time_keys(1);
1131        let one_time_map = other.signed_one_time_keys();
1132        let device = DeviceData::from_account(other);
1133
1134        let mut our_session =
1135            self.create_outbound_session(&device, &one_time_map, self.device_keys()).unwrap();
1136
1137        other.mark_keys_as_published();
1138
1139        let message = our_session
1140            .encrypt(&device, "m.dummy", ToDeviceDummyEventContent::new(), None)
1141            .await
1142            .unwrap()
1143            .deserialize()
1144            .unwrap();
1145
1146        #[cfg(feature = "experimental-algorithms")]
1147        let content = if let ToDeviceEncryptedEventContent::OlmV2Curve25519AesSha2(c) = message {
1148            c
1149        } else {
1150            panic!("Invalid encrypted event algorithm {}", message.algorithm());
1151        };
1152
1153        #[cfg(not(feature = "experimental-algorithms"))]
1154        let ToDeviceEncryptedEventContent::OlmV1Curve25519AesSha2(content) = message else {
1155            panic!("Invalid encrypted event algorithm {}", message.algorithm());
1156        };
1157
1158        let OlmMessage::PreKey(prekey) = content.ciphertext else {
1159            panic!("Wrong Olm message type");
1160        };
1161
1162        let our_device = DeviceData::from_account(self);
1163        let other_session = other
1164            .create_inbound_session(
1165                our_device.curve25519_key().unwrap(),
1166                other.device_keys(),
1167                &prekey,
1168            )
1169            .unwrap();
1170
1171        (our_session, other_session.session)
1172    }
1173
1174    async fn decrypt_olm_helper(
1175        &mut self,
1176        store: &Store,
1177        sender: &UserId,
1178        sender_key: Curve25519PublicKey,
1179        ciphertext: &OlmMessage,
1180        decryption_settings: &DecryptionSettings,
1181    ) -> OlmResult<OlmDecryptionInfo> {
1182        let message_hash = OlmMessageHash::new(sender_key, ciphertext);
1183
1184        match self
1185            .decrypt_and_parse_olm_message(
1186                store,
1187                sender,
1188                sender_key,
1189                ciphertext,
1190                decryption_settings,
1191            )
1192            .await
1193        {
1194            Ok((session, result)) => {
1195                Ok(OlmDecryptionInfo { session, message_hash, result, inbound_group_session: None })
1196            }
1197            Err(OlmError::SessionWedged(user_id, sender_key)) => {
1198                if store.is_message_known(&message_hash).await? {
1199                    info!(?sender_key, "An Olm message got replayed, decryption failed");
1200                    Err(OlmError::ReplayedMessage(user_id, sender_key))
1201                } else {
1202                    Err(OlmError::SessionWedged(user_id, sender_key))
1203                }
1204            }
1205            Err(e) => Err(e),
1206        }
1207    }
1208
1209    #[cfg(feature = "experimental-algorithms")]
1210    async fn decrypt_olm_v2(
1211        &mut self,
1212        store: &Store,
1213        sender: &UserId,
1214        content: &OlmV2Curve25519AesSha2Content,
1215        decryption_settings: &DecryptionSettings,
1216    ) -> OlmResult<OlmDecryptionInfo> {
1217        self.decrypt_olm_helper(
1218            store,
1219            sender,
1220            content.sender_key,
1221            &content.ciphertext,
1222            decryption_settings,
1223        )
1224        .await
1225    }
1226
1227    #[instrument(skip_all, fields(sender, sender_key = ?content.sender_key))]
1228    async fn decrypt_olm_v1(
1229        &mut self,
1230        store: &Store,
1231        sender: &UserId,
1232        content: &OlmV1Curve25519AesSha2Content,
1233        decryption_settings: &DecryptionSettings,
1234    ) -> OlmResult<OlmDecryptionInfo> {
1235        if content.recipient_key != self.static_data.identity_keys.curve25519 {
1236            warn!("Olm event doesn't contain a ciphertext for our key");
1237
1238            Err(EventError::MissingCiphertext.into())
1239        } else {
1240            Box::pin(self.decrypt_olm_helper(
1241                store,
1242                sender,
1243                content.sender_key,
1244                &content.ciphertext,
1245                decryption_settings,
1246            ))
1247            .await
1248        }
1249    }
1250
1251    #[instrument(skip_all, fields(algorithm = ?event.content.algorithm()))]
1252    pub(crate) async fn decrypt_to_device_event(
1253        &mut self,
1254        store: &Store,
1255        event: &EncryptedToDeviceEvent,
1256        decryption_settings: &DecryptionSettings,
1257    ) -> OlmResult<OlmDecryptionInfo> {
1258        trace!("Decrypting a to-device event");
1259
1260        match &event.content {
1261            ToDeviceEncryptedEventContent::OlmV1Curve25519AesSha2(c) => {
1262                self.decrypt_olm_v1(store, &event.sender, c, decryption_settings).await
1263            }
1264            #[cfg(feature = "experimental-algorithms")]
1265            ToDeviceEncryptedEventContent::OlmV2Curve25519AesSha2(c) => {
1266                self.decrypt_olm_v2(store, &event.sender, c, decryption_settings).await
1267            }
1268            ToDeviceEncryptedEventContent::Unknown(_) => {
1269                warn!(
1270                    "Error decrypting an to-device event, unsupported \
1271                    encryption algorithm"
1272                );
1273
1274                Err(EventError::UnsupportedAlgorithm.into())
1275            }
1276        }
1277    }
1278
1279    /// Handles a response to a /keys/upload request.
1280    pub fn receive_keys_upload_response(
1281        &mut self,
1282        response: &upload_keys::v3::Response,
1283    ) -> OlmResult<()> {
1284        if !self.shared() {
1285            debug!("Marking account as shared");
1286        }
1287        self.mark_as_shared();
1288
1289        debug!("Marking one-time keys as published");
1290        // First mark the current keys as published, as updating the key counts might
1291        // generate some new keys if we're still below the limit.
1292        self.mark_keys_as_published();
1293        self.update_key_counts(&response.one_time_key_counts, None);
1294
1295        Ok(())
1296    }
1297
1298    /// Try to decrypt an olm message, creating a new session if necessary.
1299    async fn decrypt_olm_message(
1300        &mut self,
1301        store: &Store,
1302        sender: &UserId,
1303        sender_key: Curve25519PublicKey,
1304        message: &OlmMessage,
1305    ) -> Result<(SessionType, String), OlmError> {
1306        let existing_sessions = store.get_sessions(&sender_key.to_base64()).await?;
1307
1308        match message {
1309            OlmMessage::Normal(_) => {
1310                let mut errors_by_olm_session = Vec::new();
1311
1312                if let Some(sessions) = existing_sessions {
1313                    // Try to decrypt the message using each Session we share with the
1314                    // given curve25519 sender key.
1315                    for session in sessions.lock().await.iter_mut() {
1316                        match session.decrypt(message).await {
1317                            Ok(p) => {
1318                                // success!
1319                                return Ok((SessionType::Existing(session.clone()), p));
1320                            }
1321
1322                            Err(e) => {
1323                                // An error here is completely normal, after all we don't know
1324                                // which session was used to encrypt a message.
1325                                // We keep hold of the error, so that if *all* sessions fail to
1326                                // decrypt, we can log something useful.
1327                                errors_by_olm_session.push((session.session_id().to_owned(), e));
1328                            }
1329                        }
1330                    }
1331                }
1332
1333                warn!(
1334                    ?errors_by_olm_session,
1335                    "Failed to decrypt a non-pre-key message with all available sessions"
1336                );
1337                Err(OlmError::SessionWedged(sender.to_owned(), sender_key))
1338            }
1339
1340            OlmMessage::PreKey(prekey_message) => {
1341                // First try to decrypt using an existing session.
1342                if let Some(sessions) = existing_sessions {
1343                    for session in sessions.lock().await.iter_mut() {
1344                        if prekey_message.session_id() != session.session_id() {
1345                            // wrong session
1346                            continue;
1347                        }
1348
1349                        if let Ok(p) = session.decrypt(message).await {
1350                            // success!
1351                            return Ok((SessionType::Existing(session.clone()), p));
1352                        }
1353
1354                        // The message was intended for this session, but we weren't able to
1355                        // decrypt it.
1356                        //
1357                        // There's no point trying any other sessions, nor should we try to
1358                        // create a new one since we have already previously created a `Session`
1359                        // with the same keys.
1360                        //
1361                        // (Attempts to create a new session would likely fail anyway since the
1362                        // corresponding one-time key would've been already used up in the
1363                        // previous session creation operation. The one exception where this
1364                        // would not be so is if the fallback key was used for creating the
1365                        // session in lieu of an OTK.)
1366
1367                        warn!(
1368                            session_id = session.session_id(),
1369                            "Failed to decrypt a pre-key message with the corresponding session"
1370                        );
1371
1372                        return Err(OlmError::SessionWedged(
1373                            session.our_device_keys.user_id.to_owned(),
1374                            session.sender_key(),
1375                        ));
1376                    }
1377                }
1378
1379                let device_keys = store.get_own_device().await?.as_device_keys().clone();
1380                let result =
1381                    match self.create_inbound_session(sender_key, device_keys, prekey_message) {
1382                        Ok(r) => r,
1383                        Err(e) => {
1384                            warn!(
1385                                "Failed to create a new Olm session from a pre-key message: {e:?}"
1386                            );
1387                            return Err(OlmError::SessionWedged(sender.to_owned(), sender_key));
1388                        }
1389                    };
1390
1391                // We need to add the new session to the session cache, otherwise
1392                // we might try to create the same session again.
1393                // TODO: separate the session cache from the storage so we only add
1394                // it to the cache but don't store it.
1395                let mut changes =
1396                    Changes { sessions: vec![result.session.clone()], ..Default::default() };
1397
1398                // Any new Olm session will bump the Olm wedging index for the
1399                // sender's device, if we have their device, which will cause us
1400                // to re-send existing Megolm sessions to them the next time we
1401                // use the session.  If we don't have their device, this means
1402                // that we haven't tried to send them any Megolm sessions yet,
1403                // so we don't need to worry about it.
1404                if let Some(device) = store.get_device_from_curve_key(sender, sender_key).await? {
1405                    let mut device_data = device.inner;
1406                    device_data.olm_wedging_index.increment();
1407
1408                    changes.devices =
1409                        DeviceChanges { changed: vec![device_data], ..Default::default() };
1410                }
1411
1412                store.save_changes(changes).await?;
1413
1414                Ok((SessionType::New(result.session), result.plaintext))
1415            }
1416        }
1417    }
1418
1419    /// Decrypt an Olm message, creating a new Olm session if necessary, and
1420    /// parse the result.
1421    #[instrument(skip(self, store), fields(session, session_id))]
1422    async fn decrypt_and_parse_olm_message(
1423        &mut self,
1424        store: &Store,
1425        sender: &UserId,
1426        sender_key: Curve25519PublicKey,
1427        message: &OlmMessage,
1428        decryption_settings: &DecryptionSettings,
1429    ) -> OlmResult<(SessionType, DecryptionResult)> {
1430        let (session, plaintext) =
1431            self.decrypt_olm_message(store, sender, sender_key, message).await?;
1432
1433        trace!("Successfully decrypted an Olm message");
1434
1435        match self
1436            .parse_decrypted_to_device_event(
1437                store,
1438                sender,
1439                sender_key,
1440                plaintext,
1441                decryption_settings,
1442            )
1443            .await
1444        {
1445            Ok(result) => Ok((session, result)),
1446            Err(e) => {
1447                // We might have created a new session but decryption might still
1448                // have failed, store it for the error case here, this is fine
1449                // since we don't expect this to happen often or at all.
1450                match session {
1451                    SessionType::New(s) | SessionType::Existing(s) => {
1452                        store.save_sessions(&[s]).await?;
1453                    }
1454                }
1455
1456                warn!(
1457                    error = ?e,
1458                    "A to-device message was successfully decrypted but \
1459                    parsing and checking the event fields failed"
1460                );
1461
1462                Err(e)
1463            }
1464        }
1465    }
1466
1467    /// Parse the decrypted plaintext as JSON and verify that it wasn't
1468    /// forwarded by a third party.
1469    ///
1470    /// These checks are mandated by the spec[1]:
1471    ///
1472    /// > Other properties are included in order to prevent an attacker from
1473    /// > publishing someone else's Curve25519 keys as their own and
1474    /// > subsequently claiming to have sent messages which they didn't.
1475    /// > sender must correspond to the user who sent the event, recipient to
1476    /// > the local user, and recipient_keys to the local Ed25519 key.
1477    ///
1478    /// # Arguments
1479    ///
1480    /// * `sender` -  The `sender` field from the top level of the received
1481    ///   event.
1482    /// * `sender_key` - The `sender_key` from the cleartext `content` of the
1483    ///   received event (which should also have been used to find or establish
1484    ///   the Olm session that was used to decrypt the event -- so it is
1485    ///   guaranteed to be correct).
1486    /// * `plaintext` - The decrypted content of the event.
1487    async fn parse_decrypted_to_device_event(
1488        &self,
1489        store: &Store,
1490        sender: &UserId,
1491        sender_key: Curve25519PublicKey,
1492        plaintext: String,
1493        decryption_settings: &DecryptionSettings,
1494    ) -> OlmResult<DecryptionResult> {
1495        let event: Box<AnyDecryptedOlmEvent> = serde_json::from_str(&plaintext)?;
1496        let identity_keys = &self.static_data.identity_keys;
1497
1498        if event.recipient() != self.static_data.user_id {
1499            Err(EventError::MismatchedSender(
1500                event.recipient().to_owned(),
1501                self.static_data.user_id.clone(),
1502            )
1503            .into())
1504        }
1505        // Check that the `sender` in the decrypted to-device event matches that at the
1506        // top level of the encrypted event.
1507        else if event.sender() != sender {
1508            Err(EventError::MismatchedSender(event.sender().to_owned(), sender.to_owned()).into())
1509        } else if identity_keys.ed25519 != event.recipient_keys().ed25519 {
1510            Err(EventError::MismatchedKeys(
1511                identity_keys.ed25519.into(),
1512                event.recipient_keys().ed25519.into(),
1513            )
1514            .into())
1515        } else {
1516            let sender_device = Self::get_event_sender_device(store, sender_key, &event).await?;
1517            let encryption_info = Self::get_olm_encryption_info(sender_key, sender, &sender_device);
1518
1519            let result = DecryptionResult {
1520                event,
1521                raw_event: Raw::from_json(RawJsonValue::from_string(plaintext)?),
1522                sender_key,
1523                encryption_info,
1524            };
1525
1526            // Return an error if the sender is unverified (and we care)
1527            if !self.is_from_verified_device_or_allowed_type(decryption_settings, &result) {
1528                Err(OlmError::UnverifiedSenderDevice)
1529            } else {
1530                // Sender is ok - return the decrypted event
1531                Ok(result)
1532            }
1533        }
1534    }
1535
1536    /// Look up the [`Device`] that sent us a successfully-decrypted event.
1537    ///
1538    /// We first look for the sender device in our store; if it is found then we
1539    /// return that (having checked that the keys match). If the device is
1540    /// not found in the store, we return the details
1541    /// from `sender_device_keys`, if present. If the device is not in the
1542    /// store, and the event lacks `sender_device_keys`, an error is returned.
1543    ///
1544    /// Also validates the `sender_device_keys` field, if present, regardless of
1545    /// whether it is used.
1546    ///
1547    /// `m.room_key` events are special-cased and return `None`: we look up
1548    /// their devices later on.
1549    async fn get_event_sender_device(
1550        store: &Store,
1551        sender_key: Curve25519PublicKey,
1552        event: &AnyDecryptedOlmEvent,
1553    ) -> OlmResult<Option<Device>> {
1554        // If the event contained sender_device_keys, check them now.
1555        // WARN: If you move or modify this check, ensure that the code below is still
1556        // valid. The processing of the historic room key bundle depends on this being
1557        // here.
1558        let sender_device_keys = Self::check_sender_device_keys(event, sender_key)?;
1559        if let AnyDecryptedOlmEvent::RoomKey(_) = event {
1560            // If this event is an `m.room_key` event, defer the check for
1561            // the Ed25519 key of the sender until we decrypt room events.
1562            // This ensures that we receive the room key even if we don't
1563            // have access to the device.
1564            return Ok(None);
1565        }
1566
1567        // MSC4268 requires room key bundle events to have a `sender_device_keys` field.
1568        // Enforce that now.
1569        if let AnyDecryptedOlmEvent::RoomKeyBundle(_) = event {
1570            sender_device_keys.ok_or(EventError::MissingSigningKey).inspect_err(|_| {
1571                warn!("The room key bundle was missing the sender device keys in the event")
1572            })?;
1573        }
1574
1575        // For event types other than `m.room_key`, we need to look up the device in the
1576        // database irrespective of whether the `sender_device_keys` field is
1577        // present in the event, because it may have been marked as "locally
1578        // trusted" in the database.
1579        let store_device = store.get_device_from_curve_key(event.sender(), sender_key).await?;
1580
1581        match (store_device, sender_device_keys) {
1582            // If the device is in the database, it had better have an Ed25519 key which
1583            // matches that in the event.
1584            (Some(device), _) => {
1585                let key = device.ed25519_key().ok_or(EventError::MissingSigningKey)?;
1586                if key != event.keys().ed25519 {
1587                    return Err(EventError::MismatchedKeys(
1588                        key.into(),
1589                        event.keys().ed25519.into(),
1590                    )
1591                    .into());
1592                }
1593                Ok(Some(device))
1594            }
1595
1596            (None, Some(sender_device_keys)) => {
1597                // We have already validated the signature on `sender_device_keys`, so this
1598                // try_into cannot fail.
1599                let sender_device_data = sender_device_keys.try_into().expect("Conversion of DeviceKeys to DeviceData failed despite the signature already having been checked");
1600                Ok(Some(store.wrap_device_data(sender_device_data).await?))
1601            }
1602
1603            (None, None) => Err(OlmError::EventError(EventError::MissingSigningKey)),
1604        }
1605    }
1606
1607    /// Return true if:
1608    ///
1609    /// * the sending device is verified, or
1610    /// * the event type is one of those we allow to be sent from unverified
1611    ///   devices, or
1612    /// * we are not in "exclude_insecure_devices" mode, so everything is
1613    ///   allowed.
1614    ///
1615    /// Return false if:
1616    ///
1617    /// * we are in "exclude_insecure_devices" mode AND the sending device is
1618    ///   unverified.
1619    fn is_from_verified_device_or_allowed_type(
1620        &self,
1621        decryption_settings: &DecryptionSettings,
1622        result: &DecryptionResult,
1623    ) -> bool {
1624        let event_type = result.event.event_type();
1625
1626        // If we're in "exclude insecure devices" mode, we prevent most
1627        // to-device events with unverified senders from being allowed
1628        // through here, but there are some exceptions:
1629        //
1630        // * m.room_key - we hold on to these until later, so if the sender becomes
1631        //   verified later we can still use the key.
1632        //
1633        // * m.room_key_request, m.room_key.withheld, m.key.verification.*,
1634        //   m.secret.request - these are allowed as plaintext events, so we also allow
1635        //   them encrypted from insecure devices. Note: the list of allowed types here
1636        //   should match with what is allowed in handle_to_device_event.
1637        match event_type {
1638            "m.room_key"
1639            | "m.room_key.withheld"
1640            | "m.room_key_request"
1641            | "m.secret.request"
1642            | "m.key.verification.key"
1643            | "m.key.verification.mac"
1644            | "m.key.verification.done"
1645            | "m.key.verification.ready"
1646            | "m.key.verification.start"
1647            | "m.key.verification.accept"
1648            | "m.key.verification.cancel"
1649            | "m.key.verification.request" => {
1650                // This is one of the exception types - we allow it even if the sender device is
1651                // not verified.
1652                true
1653            }
1654            _ => {
1655                // This is not an exception type - check for "exclude insecure devices" mode,
1656                // and whether the sender is verified.
1657                satisfies_sender_trust_requirement(
1658                    &result.encryption_info,
1659                    &decryption_settings.sender_device_trust_requirement,
1660                )
1661            }
1662        }
1663    }
1664
1665    /// Gets the EncryptionInfo for a successfully decrypted to-device message
1666    /// that have passed the mismatched sender_key/user_id validation.
1667    ///
1668    /// `sender_device` is optional because for some to-device messages we defer
1669    /// the check for the ed25519 key, in that case the
1670    /// `verification_state` will have a `MissingDevice` link problem.
1671    fn get_olm_encryption_info(
1672        sender_key: Curve25519PublicKey,
1673        sender_id: &UserId,
1674        sender_device: &Option<Device>,
1675    ) -> EncryptionInfo {
1676        let verification_state = sender_device
1677            .as_ref()
1678            .map(|device| {
1679                if device.is_verified() {
1680                    // The device is locally verified or signed by a verified user
1681                    VerificationState::Verified
1682                } else if device.is_cross_signed_by_owner() {
1683                    // The device is not verified, but it is signed by its owner
1684                    if device
1685                        .device_owner_identity
1686                        .as_ref()
1687                        .expect("A device cross-signed by the owner must have an owner identity")
1688                        .was_previously_verified()
1689                    {
1690                        VerificationState::Unverified(VerificationLevel::VerificationViolation)
1691                    } else {
1692                        VerificationState::Unverified(VerificationLevel::UnverifiedIdentity)
1693                    }
1694                } else {
1695                    // No identity or not signed
1696                    VerificationState::Unverified(VerificationLevel::UnsignedDevice)
1697                }
1698            })
1699            .unwrap_or(VerificationState::Unverified(VerificationLevel::None(
1700                DeviceLinkProblem::MissingDevice,
1701            )));
1702
1703        EncryptionInfo {
1704            sender: sender_id.to_owned(),
1705            sender_device: sender_device.as_ref().map(|d| d.device_id().to_owned()),
1706            algorithm_info: AlgorithmInfo::OlmV1Curve25519AesSha2 {
1707                curve25519_public_key_base64: sender_key.to_base64(),
1708            },
1709            verification_state,
1710        }
1711    }
1712
1713    /// If the plaintext of the decrypted message includes a
1714    /// `sender_device_keys` property per [MSC4147], check that it is valid.
1715    ///
1716    /// In particular, we check that:
1717    ///
1718    ///  * The Curve25519 key in the `sender_device_keys` matches that used to
1719    ///    establish the Olm session that was used to decrypt the event.
1720    ///
1721    ///  * The `sender_device_keys` contains a valid self-signature by the
1722    ///    Ed25519 key in the device data.
1723    ///
1724    ///  * The Ed25519 key in the device data matches that in the `keys` field
1725    ///    in the event, for consistency and sanity.
1726    ///
1727    /// The first two checks are sufficient to bind together the Ed25519 and
1728    /// Curve25519 keys:
1729    ///
1730    ///  * Only the holder of the secret part of the Curve25519 key that was
1731    ///    used to construct the Olm session (the 'owner' of that key) can
1732    ///    encrypt the device data in that Olm session. By including the Ed25519
1733    ///    key in the device data, the owner of the Curve25519 key is claiming
1734    ///    ownership of the Ed25519 key.
1735    ///
1736    ///  * Only the owner of the Ed25519 key can construct the self-signature on
1737    ///    the device data. By including the Curve25519 key in the device data
1738    ///    and then signing it, the owner of the Ed25519 key is claiming
1739    ///    ownership of the Curve25519 key.
1740    ///
1741    ///  * Since we now have claims in both directions, the two key owners must
1742    ///    either be the same entity, or working in sufficiently close
1743    ///    collaboration that they can be treated as such.
1744    ///
1745    /// # Arguments
1746    ///
1747    /// * `event` - The decrypted and deserialized plaintext of the event.
1748    /// * `sender_key` - The Curve25519 key that the sender used to establish
1749    ///   the Olm session that was used to decrypt the event.
1750    ///
1751    /// # Returns
1752    ///
1753    /// A reference to the `sender_device_keys` in the event, if it exists and
1754    /// is valid.
1755    ///
1756    /// [MSC4147]: https://github.com/matrix-org/matrix-spec-proposals/pull/4147
1757    fn check_sender_device_keys(
1758        event: &AnyDecryptedOlmEvent,
1759        sender_key: Curve25519PublicKey,
1760    ) -> OlmResult<Option<&DeviceKeys>> {
1761        let Some(sender_device_keys) = event.sender_device_keys() else {
1762            return Ok(None);
1763        };
1764
1765        // Check the signature within the device_keys structure
1766        sender_device_keys.check_self_signature().map_err(|err| {
1767            warn!(
1768                "Received a to-device message with sender_device_keys with \
1769                 invalid signature: {err:?}",
1770            );
1771            OlmError::EventError(EventError::InvalidSenderDeviceKeys)
1772        })?;
1773
1774        // Check that the Ed25519 key in the sender_device_keys matches the `ed25519`
1775        // key in the `keys` field in the event.
1776        if sender_device_keys.ed25519_key() != Some(event.keys().ed25519) {
1777            warn!(
1778                "Received a to-device message with sender_device_keys with incorrect \
1779                 ed25519 key: expected {:?}, got {:?}",
1780                event.keys().ed25519,
1781                sender_device_keys.ed25519_key(),
1782            );
1783            return Err(OlmError::EventError(EventError::InvalidSenderDeviceKeys));
1784        }
1785
1786        // Check that the Curve25519 key in the sender_device_keys matches the key that
1787        // was used for the Olm session.
1788        if sender_device_keys.curve25519_key() != Some(sender_key) {
1789            warn!(
1790                "Received a to-device message with sender_device_keys with incorrect \
1791                 curve25519 key: expected {sender_key:?}, got {:?}",
1792                sender_device_keys.curve25519_key(),
1793            );
1794            return Err(OlmError::EventError(EventError::InvalidSenderDeviceKeys));
1795        }
1796
1797        Ok(Some(sender_device_keys))
1798    }
1799
1800    /// Internal use only.
1801    ///
1802    /// Cloning should only be done for testing purposes or when we are certain
1803    /// that we don't want the inner state to be shared.
1804    #[doc(hidden)]
1805    pub fn deep_clone(&self) -> Self {
1806        // `vodozemac::Account` isn't really cloneable, but... Don't tell anyone.
1807        Self::from_pickle(self.pickle()).unwrap()
1808    }
1809}
1810
1811impl PartialEq for Account {
1812    fn eq(&self, other: &Self) -> bool {
1813        self.identity_keys() == other.identity_keys() && self.shared() == other.shared()
1814    }
1815}
1816
1817/// Calculate the shared history flag from the history visibility as defined in
1818/// [MSC3061]
1819///
1820/// The MSC defines that the shared history flag should be set to true when the
1821/// history visibility setting is set to `shared` or `world_readable`:
1822///
1823/// > A room key is flagged as having been used for shared history when it was
1824/// > used to encrypt a message while the room's history visibility setting
1825/// > was set to world_readable or shared.
1826///
1827/// In all other cases, even if we encounter a custom history visibility, we
1828/// should return false:
1829///
1830/// > If the client does not have an m.room.history_visibility state event for
1831/// > the room, or its value is not understood, the client should treat it as if
1832/// > its value is joined for the purposes of determining whether the key is
1833/// > used for shared history.
1834///
1835/// [MSC3061]: https://github.com/matrix-org/matrix-spec-proposals/pull/3061
1836pub(crate) fn shared_history_from_history_visibility(
1837    history_visibility: &HistoryVisibility,
1838) -> bool {
1839    match history_visibility {
1840        HistoryVisibility::Shared | HistoryVisibility::WorldReadable => true,
1841        HistoryVisibility::Invited | HistoryVisibility::Joined | _ => false,
1842    }
1843}
1844
1845/// Expand the pickle key for an older version of dehydrated devices
1846///
1847/// The `org.matrix.msc3814.v1.olm` variant of dehydrated devices used the
1848/// libolm Account pickle format for the dehydrated device. The libolm pickle
1849/// encryption scheme uses HKDF to deterministically expand an input key
1850/// material, usually 32 bytes, into a AES key, MAC key, and the initialization
1851/// vector (IV).
1852///
1853/// This means that the same input key material will always end up producing the
1854/// same AES key, and IV.
1855///
1856/// This encryption scheme is used in the Olm double ratchet and was designed to
1857/// minimize the size of the ciphertext. As a tradeof, it requires a unique
1858/// input key material for each plaintext that gets encrypted, otherwise IV
1859/// reuse happens.
1860///
1861/// To combat the IV reuse, we're going to create a per-dehydrated-device unique
1862/// pickle key by expanding the key itself with the device ID used as the salt.
1863fn expand_legacy_pickle_key(key: &[u8; 32], device_id: &DeviceId) -> Box<[u8; 32]> {
1864    let kdf: Hkdf<Sha256> = Hkdf::new(Some(device_id.as_bytes()), key);
1865    let mut key = Box::new([0u8; 32]);
1866
1867    kdf.expand(b"dehydrated-device-pickle-key", key.as_mut_slice())
1868        .expect("We should be able to expand the 32 byte pickle key");
1869
1870    key
1871}
1872
1873/// Does the to-device event satisfy the sender trust requirement from the
1874/// decryption settings?
1875fn satisfies_sender_trust_requirement(
1876    encryption_info: &EncryptionInfo,
1877    trust_requirement: &TrustRequirement,
1878) -> bool {
1879    trace!(
1880        verification_state = ?encryption_info.verification_state,
1881        ?trust_requirement, "check_to_device_sender_trust_requirement",
1882    );
1883
1884    match (&encryption_info.verification_state, trust_requirement) {
1885        // If we don't care, everything is OK.
1886        (_, TrustRequirement::Untrusted) => true,
1887
1888        // Verified is OK whatever our requirements are.
1889        (VerificationState::Verified, _) => true,
1890
1891        // We do care, and we are not fully verified: check more deeply.
1892        // (Note that for to-device messages the legacy trust requirement is not relevant.)
1893        (
1894            VerificationState::Unverified(verification_level),
1895            TrustRequirement::CrossSignedOrLegacy | TrustRequirement::CrossSigned,
1896        ) => match verification_level {
1897            // The device is signed but the identity is only pinned - this is fine.
1898            VerificationLevel::UnverifiedIdentity => true,
1899
1900            // The device is unsigned or missing, or the user is in verification violation,
1901            // or the sender is mismatched: this is not fine.
1902            VerificationLevel::UnsignedDevice
1903            | VerificationLevel::None(_)
1904            | VerificationLevel::VerificationViolation
1905            | VerificationLevel::MismatchedSender => false,
1906        },
1907    }
1908}
1909
1910#[cfg(test)]
1911mod tests {
1912    use std::{
1913        collections::{BTreeMap, BTreeSet},
1914        ops::Deref,
1915        time::Duration,
1916    };
1917
1918    use anyhow::Result;
1919    use matrix_sdk_test::async_test;
1920    use ruma::{
1921        DeviceId, MilliSecondsSinceUnixEpoch, OneTimeKeyAlgorithm, OneTimeKeyId, UserId, device_id,
1922        events::room::history_visibility::HistoryVisibility, room_id, user_id,
1923    };
1924    use serde_json::json;
1925
1926    use super::Account;
1927    use crate::{
1928        DeviceData, EncryptionSettings,
1929        olm::{SignedJsonObject, account::shared_history_from_history_visibility},
1930        types::{DeviceKeys, SignedKey},
1931    };
1932
1933    fn user_id() -> &'static UserId {
1934        user_id!("@alice:localhost")
1935    }
1936
1937    fn device_id() -> &'static DeviceId {
1938        device_id!("DEVICEID")
1939    }
1940
1941    #[test]
1942    fn test_one_time_key_creation() -> Result<()> {
1943        let mut account = Account::with_device_id(user_id(), device_id());
1944
1945        let (_, one_time_keys, _) = account.keys_for_upload();
1946        assert!(!one_time_keys.is_empty());
1947
1948        let (_, second_one_time_keys, _) = account.keys_for_upload();
1949        assert!(!second_one_time_keys.is_empty());
1950
1951        let one_time_key_ids: BTreeSet<&OneTimeKeyId> =
1952            one_time_keys.keys().map(Deref::deref).collect();
1953        let second_one_time_key_ids: BTreeSet<&OneTimeKeyId> =
1954            second_one_time_keys.keys().map(Deref::deref).collect();
1955
1956        assert_eq!(one_time_key_ids, second_one_time_key_ids);
1957
1958        account.mark_keys_as_published();
1959        account.update_uploaded_key_count(50);
1960        account.generate_one_time_keys_if_needed();
1961
1962        let (_, third_one_time_keys, _) = account.keys_for_upload();
1963        assert!(third_one_time_keys.is_empty());
1964
1965        account.update_uploaded_key_count(0);
1966        account.generate_one_time_keys_if_needed();
1967
1968        let (_, fourth_one_time_keys, _) = account.keys_for_upload();
1969        assert!(!fourth_one_time_keys.is_empty());
1970
1971        let fourth_one_time_key_ids: BTreeSet<&OneTimeKeyId> =
1972            fourth_one_time_keys.keys().map(Deref::deref).collect();
1973
1974        assert_ne!(one_time_key_ids, fourth_one_time_key_ids);
1975        Ok(())
1976    }
1977
1978    #[test]
1979    fn test_fallback_key_creation() -> Result<()> {
1980        let mut account = Account::with_device_id(user_id(), device_id());
1981
1982        let (_, _, fallback_keys) = account.keys_for_upload();
1983
1984        // We don't create fallback keys since we don't know if the server
1985        // supports them, we need to receive a sync response to decide if we're
1986        // going to create them or not.
1987        assert!(
1988            fallback_keys.is_empty(),
1989            "We should not upload fallback keys until we know if the server supports them."
1990        );
1991
1992        let one_time_keys = BTreeMap::from([(OneTimeKeyAlgorithm::SignedCurve25519, 50u8.into())]);
1993
1994        // A `None` here means that the server doesn't support fallback keys, no
1995        // fallback key gets uploaded.
1996        account.update_key_counts(&one_time_keys, None);
1997        let (_, _, fallback_keys) = account.keys_for_upload();
1998        assert!(
1999            fallback_keys.is_empty(),
2000            "We should not upload a fallback key if we're certain that the server doesn't support \
2001             them."
2002        );
2003
2004        // The empty array means that the server supports fallback keys but
2005        // there isn't a unused fallback key on the server. This time we upload
2006        // a fallback key.
2007        let unused_fallback_keys = &[];
2008        account.update_key_counts(&one_time_keys, Some(unused_fallback_keys.as_ref()));
2009        let (_, _, fallback_keys) = account.keys_for_upload();
2010        assert!(
2011            !fallback_keys.is_empty(),
2012            "We should upload the initial fallback key if the server supports them."
2013        );
2014        account.mark_keys_as_published();
2015
2016        // There's no unused fallback key on the server, but our initial fallback key
2017        // did not yet expire.
2018        let unused_fallback_keys = &[];
2019        account.update_key_counts(&one_time_keys, Some(unused_fallback_keys.as_ref()));
2020        let (_, _, fallback_keys) = account.keys_for_upload();
2021        assert!(
2022            fallback_keys.is_empty(),
2023            "We should not upload new fallback keys unless our current fallback key expires."
2024        );
2025
2026        let fallback_key_timestamp =
2027            account.fallback_creation_timestamp.unwrap().to_system_time().unwrap()
2028                - Duration::from_secs(3600 * 24 * 30);
2029
2030        account.fallback_creation_timestamp =
2031            Some(MilliSecondsSinceUnixEpoch::from_system_time(fallback_key_timestamp).unwrap());
2032
2033        account.update_key_counts(&one_time_keys, None);
2034        let (_, _, fallback_keys) = account.keys_for_upload();
2035        assert!(
2036            !fallback_keys.is_empty(),
2037            "Now that our fallback key has expired, we should try to upload a new one, even if the \
2038             server supposedly doesn't support fallback keys anymore"
2039        );
2040
2041        Ok(())
2042    }
2043
2044    #[test]
2045    fn test_fallback_key_signing() -> Result<()> {
2046        let key = vodozemac::Curve25519PublicKey::from_base64(
2047            "7PUPP6Ijt5R8qLwK2c8uK5hqCNF9tOzWYgGaAay5JBs",
2048        )?;
2049        let account = Account::with_device_id(user_id(), device_id());
2050
2051        let key = account.sign_key(key, true);
2052
2053        let canonical_key = key.to_canonical_json()?;
2054
2055        assert_eq!(
2056            canonical_key,
2057            "{\"fallback\":true,\"key\":\"7PUPP6Ijt5R8qLwK2c8uK5hqCNF9tOzWYgGaAay5JBs\"}"
2058        );
2059
2060        account
2061            .has_signed_raw(key.signatures(), &canonical_key)
2062            .expect("Couldn't verify signature");
2063
2064        let device = DeviceData::from_account(&account);
2065        device.verify_one_time_key(&key).expect("The device can verify its own signature");
2066
2067        Ok(())
2068    }
2069
2070    #[test]
2071    fn test_account_and_device_creation_timestamp() -> Result<()> {
2072        let now = MilliSecondsSinceUnixEpoch::now();
2073        let account = Account::with_device_id(user_id(), device_id());
2074        let then = MilliSecondsSinceUnixEpoch::now();
2075
2076        assert!(account.creation_local_time() >= now);
2077        assert!(account.creation_local_time() <= then);
2078
2079        let device = DeviceData::from_account(&account);
2080        assert_eq!(account.creation_local_time(), device.first_time_seen_ts());
2081
2082        Ok(())
2083    }
2084
2085    #[async_test]
2086    async fn test_fallback_key_signature_verification() -> Result<()> {
2087        let fallback_key = json!({
2088            "fallback": true,
2089            "key": "XPFqtLvBepBmW6jSAbBuJbhEpprBhQOX1IjUu+cnMF4",
2090            "signatures": {
2091                "@dkasak_c:matrix.org": {
2092                    "ed25519:EXPDYDPWZH": "RJCBMJPL5hvjxgq8rmLmqkNOuPsaan7JeL1wsE+gW6R39G894lb2sBmzapHeKCn/KFjmkonPLkICApRDS+zyDw"
2093                }
2094            }
2095        });
2096
2097        let device_keys = json!({
2098            "algorithms": [
2099                "m.olm.v1.curve25519-aes-sha2",
2100                "m.megolm.v1.aes-sha2"
2101            ],
2102            "device_id": "EXPDYDPWZH",
2103            "keys": {
2104                "curve25519:EXPDYDPWZH": "k7f3igo0Vrdm88JSSA5d3OCuUfHYELChB2b57aOROB8",
2105                "ed25519:EXPDYDPWZH": "GdjYI8fxs175gSpYRJkyN6FRfvcyTsNOhJ2OR/Ggp+E"
2106            },
2107            "signatures": {
2108                "@dkasak_c:matrix.org": {
2109                    "ed25519:EXPDYDPWZH": "kzrtfQMbJXWXQ1uzhybtwFnGk0JJBS4Mg8VPMusMu6U8MPJccwoHVZKo5+owuHTzIodI+GZYqLmMSzvfvsChAA"
2110                }
2111            },
2112            "user_id": "@dkasak_c:matrix.org",
2113            "unsigned": {}
2114        });
2115
2116        let device_keys: DeviceKeys = serde_json::from_value(device_keys).unwrap();
2117        let device = DeviceData::try_from(&device_keys).unwrap();
2118        let fallback_key: SignedKey = serde_json::from_value(fallback_key).unwrap();
2119
2120        device
2121            .verify_one_time_key(&fallback_key)
2122            .expect("The fallback key should pass the signature verification");
2123
2124        Ok(())
2125    }
2126
2127    #[test]
2128    fn test_shared_history_flag_from_history_visibility() {
2129        assert!(
2130            shared_history_from_history_visibility(&HistoryVisibility::WorldReadable),
2131            "The world readable visibility should set the shared history flag to true"
2132        );
2133
2134        assert!(
2135            shared_history_from_history_visibility(&HistoryVisibility::Shared),
2136            "The shared visibility should set the shared history flag to true"
2137        );
2138
2139        assert!(
2140            !shared_history_from_history_visibility(&HistoryVisibility::Joined),
2141            "The joined visibility should set the shared history flag to false"
2142        );
2143
2144        assert!(
2145            !shared_history_from_history_visibility(&HistoryVisibility::Invited),
2146            "The invited visibility should set the shared history flag to false"
2147        );
2148
2149        let visibility = HistoryVisibility::from("custom_visibility");
2150        assert!(
2151            !shared_history_from_history_visibility(&visibility),
2152            "A custom visibility should set the shared history flag to false"
2153        );
2154    }
2155
2156    #[async_test]
2157    async fn test_shared_history_set_when_creating_group_sessions() {
2158        let account = Account::new(user_id());
2159        let room_id = room_id!("!room:id");
2160        let settings = EncryptionSettings {
2161            history_visibility: HistoryVisibility::Shared,
2162            ..Default::default()
2163        };
2164
2165        let (_, session) = account
2166            .create_group_session_pair(room_id, settings, Default::default())
2167            .await
2168            .expect("We should be able to create a group session pair");
2169
2170        assert!(
2171            session.shared_history(),
2172            "The shared history flag should have been set when we created the new session"
2173        );
2174    }
2175}