Skip to main content

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