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