matrix_sdk_crypto/olm/
account.rs

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