1use std::{
16 collections::{BTreeMap, HashMap},
17 fmt,
18 ops::{Deref, Not as _},
19 sync::Arc,
20 time::Duration,
21};
22
23use hkdf::Hkdf;
24use js_option::JsOption;
25#[cfg(test)]
26use ruma::api::client::dehydrated_device::DehydratedDeviceV1;
27use ruma::{
28 api::client::{
29 dehydrated_device::{DehydratedDeviceData, DehydratedDeviceV2},
30 keys::{
31 upload_keys,
32 upload_signatures::v3::{Request as SignatureUploadRequest, SignedKeys},
33 },
34 },
35 events::AnyToDeviceEvent,
36 serde::Raw,
37 DeviceId, DeviceKeyAlgorithm, DeviceKeyId, MilliSecondsSinceUnixEpoch, OneTimeKeyAlgorithm,
38 OneTimeKeyId, OwnedDeviceId, OwnedDeviceKeyId, OwnedOneTimeKeyId, OwnedUserId, RoomId,
39 SecondsSinceUnixEpoch, UInt, UserId,
40};
41use serde::{de::Error, Deserialize, Serialize};
42use serde_json::{
43 value::{to_raw_value, RawValue as RawJsonValue},
44 Value,
45};
46use sha2::{Digest, Sha256};
47use tokio::sync::Mutex;
48use tracing::{debug, field::debug, info, instrument, trace, warn, Span};
49use vodozemac::{
50 base64_encode,
51 olm::{
52 Account as InnerAccount, AccountPickle, IdentityKeys, OlmMessage,
53 OneTimeKeyGenerationResult, PreKeyMessage, SessionConfig,
54 },
55 Curve25519PublicKey, Ed25519Signature, KeyId, PickleError,
56};
57
58use super::{
59 utility::SignJson, EncryptionSettings, InboundGroupSession, OutboundGroupSession,
60 PrivateCrossSigningIdentity, Session, SessionCreationError as MegolmSessionCreationError,
61};
62#[cfg(feature = "experimental-algorithms")]
63use crate::types::events::room::encrypted::OlmV2Curve25519AesSha2Content;
64use crate::{
65 dehydrated_devices::DehydrationError,
66 error::{EventError, OlmResult, SessionCreationError},
67 identities::DeviceData,
68 olm::SenderData,
69 store::{Changes, DeviceChanges, Store},
70 types::{
71 events::{
72 olm_v1::AnyDecryptedOlmEvent,
73 room::encrypted::{
74 EncryptedToDeviceEvent, OlmV1Curve25519AesSha2Content,
75 ToDeviceEncryptedEventContent,
76 },
77 },
78 requests::UploadSigningKeysRequest,
79 CrossSigningKey, DeviceKeys, EventEncryptionAlgorithm, MasterPubkey, OneTimeKey, SignedKey,
80 },
81 OlmError, SignatureError,
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#[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 pub event: Box<AnyDecryptedOlmEvent>,
128 pub raw_event: Raw<AnyToDeviceEvent>,
129 pub sender_key: Curve25519PublicKey,
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
136pub struct OlmMessageHash {
137 pub sender_key: String,
139 pub hash: String,
141}
142
143impl OlmMessageHash {
144 fn new(sender_key: Curve25519PublicKey, ciphertext: &OlmMessage) -> Self {
145 let (message_type, ciphertext) = ciphertext.clone().to_parts();
146 let sender_key = sender_key.to_base64();
147
148 let sha = Sha256::new()
149 .chain_update(sender_key.as_bytes())
150 .chain_update([message_type as u8])
151 .chain_update(ciphertext)
152 .finalize();
153
154 Self { sender_key, hash: base64_encode(sha.as_slice()) }
155 }
156}
157
158#[derive(Clone)]
163#[cfg_attr(not(tarpaulin_include), derive(Debug))]
164pub struct StaticAccountData {
165 pub user_id: OwnedUserId,
167 pub device_id: OwnedDeviceId,
169 pub identity_keys: Arc<IdentityKeys>,
171 pub dehydrated: bool,
173 creation_local_time: MilliSecondsSinceUnixEpoch,
175}
176
177impl StaticAccountData {
178 const ALGORITHMS: &'static [&'static EventEncryptionAlgorithm] = &[
179 &EventEncryptionAlgorithm::OlmV1Curve25519AesSha2,
180 #[cfg(feature = "experimental-algorithms")]
181 &EventEncryptionAlgorithm::OlmV2Curve25519AesSha2,
182 &EventEncryptionAlgorithm::MegolmV1AesSha2,
183 #[cfg(feature = "experimental-algorithms")]
184 &EventEncryptionAlgorithm::MegolmV2AesSha2,
185 ];
186
187 pub async fn create_group_session_pair(
202 &self,
203 room_id: &RoomId,
204 settings: EncryptionSettings,
205 own_sender_data: SenderData,
206 ) -> Result<(OutboundGroupSession, InboundGroupSession), MegolmSessionCreationError> {
207 trace!(?room_id, algorithm = settings.algorithm.as_str(), "Creating a new room key");
208
209 let visibility = settings.history_visibility.clone();
210 let algorithm = settings.algorithm.to_owned();
211
212 let outbound = OutboundGroupSession::new(
213 self.device_id.clone(),
214 self.identity_keys.clone(),
215 room_id,
216 settings,
217 )?;
218
219 let identity_keys = &self.identity_keys;
220
221 let sender_key = identity_keys.curve25519;
222 let signing_key = identity_keys.ed25519;
223
224 let inbound = InboundGroupSession::new(
225 sender_key,
226 signing_key,
227 room_id,
228 &outbound.session_key().await,
229 own_sender_data,
230 algorithm,
231 Some(visibility),
232 )?;
233
234 Ok((outbound, inbound))
235 }
236
237 #[cfg(any(test, feature = "testing"))]
238 #[allow(dead_code)]
239 pub async fn create_group_session_pair_with_defaults(
242 &self,
243 room_id: &RoomId,
244 ) -> (OutboundGroupSession, InboundGroupSession) {
245 self.create_group_session_pair(
246 room_id,
247 EncryptionSettings::default(),
248 SenderData::unknown(),
249 )
250 .await
251 .expect("Can't create default group session pair")
252 }
253
254 pub fn signing_key_id(&self) -> OwnedDeviceKeyId {
256 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id())
257 }
258
259 pub fn has_signed_raw(
269 &self,
270 signatures: &crate::types::Signatures,
271 canonical_json: &str,
272 ) -> Result<(), SignatureError> {
273 use crate::olm::utility::VerifyJson;
274
275 let signing_key = self.identity_keys.ed25519;
276
277 signing_key.verify_canonicalized_json(
278 &self.user_id,
279 &DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
280 signatures,
281 canonical_json,
282 )
283 }
284
285 pub fn unsigned_device_keys(&self) -> DeviceKeys {
287 let identity_keys = self.identity_keys();
288 let keys = BTreeMap::from([
289 (
290 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Curve25519, &self.device_id),
291 identity_keys.curve25519.into(),
292 ),
293 (
294 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, &self.device_id),
295 identity_keys.ed25519.into(),
296 ),
297 ]);
298
299 let mut ret = DeviceKeys::new(
300 (*self.user_id).to_owned(),
301 (*self.device_id).to_owned(),
302 Self::ALGORITHMS.iter().map(|a| (**a).clone()).collect(),
303 keys,
304 Default::default(),
305 );
306 if self.dehydrated {
307 ret.dehydrated = JsOption::Some(true);
308 }
309 ret
310 }
311
312 pub fn user_id(&self) -> &UserId {
314 &self.user_id
315 }
316
317 pub fn device_id(&self) -> &DeviceId {
319 &self.device_id
320 }
321
322 pub fn identity_keys(&self) -> IdentityKeys {
324 *self.identity_keys
325 }
326
327 pub fn creation_local_time(&self) -> MilliSecondsSinceUnixEpoch {
329 self.creation_local_time
330 }
331}
332
333pub struct Account {
338 pub(crate) static_data: StaticAccountData,
339 inner: Box<InnerAccount>,
341 shared: bool,
344 uploaded_signed_key_count: u64,
349 fallback_creation_timestamp: Option<MilliSecondsSinceUnixEpoch>,
357}
358
359impl Deref for Account {
360 type Target = StaticAccountData;
361
362 fn deref(&self) -> &Self::Target {
363 &self.static_data
364 }
365}
366
367#[derive(Serialize, Deserialize)]
372#[allow(missing_debug_implementations)]
373pub struct PickledAccount {
374 pub user_id: OwnedUserId,
376 pub device_id: OwnedDeviceId,
378 pub pickle: AccountPickle,
380 pub shared: bool,
382 #[serde(default)]
384 pub dehydrated: bool,
385 pub uploaded_signed_key_count: u64,
387 #[serde(default = "default_account_creation_time")]
390 pub creation_local_time: MilliSecondsSinceUnixEpoch,
391 #[serde(default)]
393 pub fallback_key_creation_timestamp: Option<MilliSecondsSinceUnixEpoch>,
394}
395
396fn default_account_creation_time() -> MilliSecondsSinceUnixEpoch {
397 MilliSecondsSinceUnixEpoch(UInt::default())
398}
399
400#[cfg(not(tarpaulin_include))]
401impl fmt::Debug for Account {
402 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
403 f.debug_struct("Account")
404 .field("identity_keys", &self.identity_keys())
405 .field("shared", &self.shared())
406 .finish()
407 }
408}
409
410pub type OneTimeKeys = BTreeMap<OwnedOneTimeKeyId, Raw<ruma::encryption::OneTimeKey>>;
411pub type FallbackKeys = OneTimeKeys;
412
413impl Account {
414 pub(crate) fn new_helper(
415 mut account: InnerAccount,
416 user_id: &UserId,
417 device_id: &DeviceId,
418 ) -> Self {
419 let identity_keys = account.identity_keys();
420
421 account.generate_one_time_keys(account.max_number_of_one_time_keys());
433
434 Self {
435 static_data: StaticAccountData {
436 user_id: user_id.into(),
437 device_id: device_id.into(),
438 identity_keys: Arc::new(identity_keys),
439 dehydrated: false,
440 creation_local_time: MilliSecondsSinceUnixEpoch::now(),
441 },
442 inner: Box::new(account),
443 shared: false,
444 uploaded_signed_key_count: 0,
445 fallback_creation_timestamp: None,
446 }
447 }
448
449 pub fn with_device_id(user_id: &UserId, device_id: &DeviceId) -> Self {
451 let account = InnerAccount::new();
452
453 Self::new_helper(account, user_id, device_id)
454 }
455
456 pub fn new(user_id: &UserId) -> Self {
459 let account = InnerAccount::new();
460 let device_id: OwnedDeviceId =
461 base64_encode(account.identity_keys().curve25519.as_bytes()).into();
462
463 Self::new_helper(account, user_id, &device_id)
464 }
465
466 pub fn new_dehydrated(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 let mut ret = Self::new_helper(account, user_id, &device_id);
473 ret.static_data.dehydrated = true;
474 ret
475 }
476
477 pub fn static_data(&self) -> &StaticAccountData {
479 &self.static_data
480 }
481
482 pub fn update_uploaded_key_count(&mut self, new_count: u64) {
488 self.uploaded_signed_key_count = new_count;
489 }
490
491 pub fn uploaded_key_count(&self) -> u64 {
493 self.uploaded_signed_key_count
494 }
495
496 pub fn shared(&self) -> bool {
498 self.shared
499 }
500
501 pub fn mark_as_shared(&mut self) {
506 self.shared = true;
507 }
508
509 pub fn one_time_keys(&self) -> HashMap<KeyId, Curve25519PublicKey> {
513 self.inner.one_time_keys()
514 }
515
516 pub fn generate_one_time_keys(&mut self, count: usize) -> OneTimeKeyGenerationResult {
518 self.inner.generate_one_time_keys(count)
519 }
520
521 pub fn max_one_time_keys(&self) -> usize {
523 self.inner.max_number_of_one_time_keys()
524 }
525
526 pub(crate) fn update_key_counts(
527 &mut self,
528 one_time_key_counts: &BTreeMap<OneTimeKeyAlgorithm, UInt>,
529 unused_fallback_keys: Option<&[OneTimeKeyAlgorithm]>,
530 ) {
531 if let Some(count) = one_time_key_counts.get(&OneTimeKeyAlgorithm::SignedCurve25519) {
532 let count: u64 = (*count).into();
533 let old_count = self.uploaded_key_count();
534
535 if count != old_count {
539 debug!(
540 "Updated uploaded one-time key count {} -> {count}.",
541 self.uploaded_key_count(),
542 );
543 }
544
545 self.update_uploaded_key_count(count);
546 self.generate_one_time_keys_if_needed();
547 }
548
549 if unused_fallback_keys.is_some() || self.fallback_creation_timestamp.is_some() {
553 self.generate_fallback_key_if_needed();
554 }
555 }
556
557 #[instrument(skip_all)]
566 pub fn generate_one_time_keys_if_needed(&mut self) -> Option<u64> {
567 if !self.one_time_keys().is_empty() {
571 return Some(0);
572 }
573
574 let count = self.uploaded_key_count();
575 let max_keys = self.max_one_time_keys();
576
577 if count >= max_keys as u64 {
578 return None;
579 }
580
581 let key_count = (max_keys as u64) - count;
582 let key_count: usize = key_count.try_into().unwrap_or(max_keys);
583
584 let result = self.generate_one_time_keys(key_count);
585
586 debug!(
587 count = key_count,
588 discarded_keys = ?result.removed,
589 created_keys = ?result.created,
590 "Generated new one-time keys"
591 );
592
593 Some(key_count as u64)
594 }
595
596 pub(crate) fn generate_fallback_key_if_needed(&mut self) {
603 if self.inner.fallback_key().is_empty() && self.fallback_key_expired() {
604 let removed_fallback_key = self.inner.generate_fallback_key();
605 self.fallback_creation_timestamp = Some(MilliSecondsSinceUnixEpoch::now());
606
607 debug!(
608 ?removed_fallback_key,
609 "The fallback key either expired or we didn't have one: generated a new fallback key.",
610 );
611 }
612 }
613
614 fn fallback_key_expired(&self) -> bool {
622 const FALLBACK_KEY_MAX_AGE: Duration = Duration::from_secs(3600 * 24 * 7);
623
624 if let Some(time) = self.fallback_creation_timestamp {
625 let Some(system_time) = time.to_system_time() else {
629 return true;
630 };
631
632 let Ok(elapsed) = system_time.elapsed() else {
636 return true;
637 };
638
639 elapsed > FALLBACK_KEY_MAX_AGE
644 } else {
645 true
648 }
649 }
650
651 fn fallback_key(&self) -> HashMap<KeyId, Curve25519PublicKey> {
652 self.inner.fallback_key()
653 }
654
655 pub fn keys_for_upload(&self) -> (Option<DeviceKeys>, OneTimeKeys, FallbackKeys) {
661 let device_keys = self.shared().not().then(|| self.device_keys());
662
663 let one_time_keys = self.signed_one_time_keys();
664 let fallback_keys = self.signed_fallback_keys();
665
666 (device_keys, one_time_keys, fallback_keys)
667 }
668
669 pub fn mark_keys_as_published(&mut self) {
671 self.inner.mark_keys_as_published();
672 }
673
674 pub fn sign(&self, string: &str) -> Ed25519Signature {
678 self.inner.sign(string)
679 }
680
681 pub fn pickle(&self) -> PickledAccount {
683 let pickle = self.inner.pickle();
684
685 PickledAccount {
686 user_id: self.user_id().to_owned(),
687 device_id: self.device_id().to_owned(),
688 pickle,
689 shared: self.shared(),
690 dehydrated: self.static_data.dehydrated,
691 uploaded_signed_key_count: self.uploaded_key_count(),
692 creation_local_time: self.static_data.creation_local_time,
693 fallback_key_creation_timestamp: self.fallback_creation_timestamp,
694 }
695 }
696
697 pub(crate) fn dehydrate(&self, pickle_key: &[u8; 32]) -> Raw<DehydratedDeviceData> {
698 let dehydration_result = self
699 .inner
700 .to_dehydrated_device(pickle_key)
701 .expect("We should be able to convert a freshly created Account into a libolm pickle");
702
703 let data = DehydratedDeviceData::V2(DehydratedDeviceV2::new(
704 dehydration_result.ciphertext,
705 dehydration_result.nonce,
706 ));
707 Raw::from_json(to_raw_value(&data).expect("Couldn't serialize our dehydrated device data"))
708 }
709
710 pub(crate) fn rehydrate(
711 pickle_key: &[u8; 32],
712 user_id: &UserId,
713 device_id: &DeviceId,
714 device_data: Raw<DehydratedDeviceData>,
715 ) -> Result<Self, DehydrationError> {
716 let data = device_data.deserialize()?;
717
718 match data {
719 DehydratedDeviceData::V1(d) => {
720 let pickle_key = expand_legacy_pickle_key(pickle_key, device_id);
721 let account =
722 InnerAccount::from_libolm_pickle(&d.device_pickle, pickle_key.as_ref())?;
723 Ok(Self::new_helper(account, user_id, device_id))
724 }
725 DehydratedDeviceData::V2(d) => {
726 let account =
727 InnerAccount::from_dehydrated_device(&d.device_pickle, &d.nonce, pickle_key)?;
728 Ok(Self::new_helper(account, user_id, device_id))
729 }
730 _ => Err(DehydrationError::Json(serde_json::Error::custom(format!(
731 "Unsupported dehydrated device algorithm {:?}",
732 data.algorithm()
733 )))),
734 }
735 }
736
737 #[cfg(test)]
740 pub(crate) fn legacy_dehydrate(&self, pickle_key: &[u8; 32]) -> Raw<DehydratedDeviceData> {
741 let pickle_key = expand_legacy_pickle_key(pickle_key, &self.device_id);
742 let device_pickle = self
743 .inner
744 .to_libolm_pickle(pickle_key.as_ref())
745 .expect("We should be able to convert a freshly created Account into a libolm pickle");
746
747 let data = DehydratedDeviceData::V1(DehydratedDeviceV1::new(device_pickle));
748 Raw::from_json(to_raw_value(&data).expect("Couldn't serialize our dehydrated device data"))
749 }
750
751 pub fn from_pickle(pickle: PickledAccount) -> Result<Self, PickleError> {
760 let account: vodozemac::olm::Account = pickle.pickle.into();
761 let identity_keys = account.identity_keys();
762
763 Ok(Self {
764 static_data: StaticAccountData {
765 user_id: (*pickle.user_id).into(),
766 device_id: (*pickle.device_id).into(),
767 identity_keys: Arc::new(identity_keys),
768 dehydrated: pickle.dehydrated,
769 creation_local_time: pickle.creation_local_time,
770 },
771 inner: Box::new(account),
772 shared: pickle.shared,
773 uploaded_signed_key_count: pickle.uploaded_signed_key_count,
774 fallback_creation_timestamp: pickle.fallback_key_creation_timestamp,
775 })
776 }
777
778 pub fn device_keys(&self) -> DeviceKeys {
781 let mut device_keys = self.unsigned_device_keys();
782
783 let json_device_keys =
786 serde_json::to_value(&device_keys).expect("device key is always safe to serialize");
787 let signature = self
788 .sign_json(json_device_keys)
789 .expect("Newly created device keys can always be signed");
790
791 device_keys.signatures.add_signature(
792 self.user_id().to_owned(),
793 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, &self.static_data.device_id),
794 signature,
795 );
796
797 device_keys
798 }
799
800 pub async fn bootstrap_cross_signing(
802 &self,
803 ) -> (PrivateCrossSigningIdentity, UploadSigningKeysRequest, SignatureUploadRequest) {
804 PrivateCrossSigningIdentity::with_account(self).await
805 }
806
807 pub fn sign_cross_signing_key(
809 &self,
810 cross_signing_key: &mut CrossSigningKey,
811 ) -> Result<(), SignatureError> {
812 #[allow(clippy::needless_borrows_for_generic_args)]
813 let signature = self.sign_json(serde_json::to_value(&cross_signing_key)?)?;
815
816 cross_signing_key.signatures.add_signature(
817 self.user_id().to_owned(),
818 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
819 signature,
820 );
821
822 Ok(())
823 }
824
825 pub fn sign_master_key(
827 &self,
828 master_key: &MasterPubkey,
829 ) -> Result<SignatureUploadRequest, SignatureError> {
830 let public_key =
831 master_key.get_first_key().ok_or(SignatureError::MissingSigningKey)?.to_base64().into();
832
833 let mut cross_signing_key: CrossSigningKey = master_key.as_ref().clone();
834 cross_signing_key.signatures.clear();
835 self.sign_cross_signing_key(&mut cross_signing_key)?;
836
837 let mut user_signed_keys = SignedKeys::new();
838 user_signed_keys.add_cross_signing_keys(public_key, cross_signing_key.to_raw());
839
840 let signed_keys = [(self.user_id().to_owned(), user_signed_keys)].into();
841 Ok(SignatureUploadRequest::new(signed_keys))
842 }
843
844 pub fn sign_json(&self, json: Value) -> Result<Ed25519Signature, SignatureError> {
852 self.inner.sign_json(json)
853 }
854
855 pub fn signed_one_time_keys(&self) -> OneTimeKeys {
859 let one_time_keys = self.one_time_keys();
860
861 if one_time_keys.is_empty() {
862 BTreeMap::new()
863 } else {
864 self.signed_keys(one_time_keys, false)
865 }
866 }
867
868 pub fn signed_fallback_keys(&self) -> FallbackKeys {
872 let fallback_key = self.fallback_key();
873
874 if fallback_key.is_empty() {
875 BTreeMap::new()
876 } else {
877 self.signed_keys(fallback_key, true)
878 }
879 }
880
881 fn signed_keys(
882 &self,
883 keys: HashMap<KeyId, Curve25519PublicKey>,
884 fallback: bool,
885 ) -> OneTimeKeys {
886 let mut keys_map = BTreeMap::new();
887
888 for (key_id, key) in keys {
889 let signed_key = self.sign_key(key, fallback);
890
891 keys_map.insert(
892 OneTimeKeyId::from_parts(
893 OneTimeKeyAlgorithm::SignedCurve25519,
894 key_id.to_base64().as_str().into(),
895 ),
896 signed_key.into_raw(),
897 );
898 }
899
900 keys_map
901 }
902
903 fn sign_key(&self, key: Curve25519PublicKey, fallback: bool) -> SignedKey {
904 let mut key = if fallback {
905 SignedKey::new_fallback(key.to_owned())
906 } else {
907 SignedKey::new(key.to_owned())
908 };
909
910 let signature = self
911 .sign_json(serde_json::to_value(&key).expect("Can't serialize a signed key"))
912 .expect("Newly created one-time keys can always be signed");
913
914 key.signatures_mut().add_signature(
915 self.user_id().to_owned(),
916 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
917 signature,
918 );
919
920 key
921 }
922
923 pub fn create_outbound_session_helper(
943 &self,
944 config: SessionConfig,
945 identity_key: Curve25519PublicKey,
946 one_time_key: Curve25519PublicKey,
947 fallback_used: bool,
948 our_device_keys: DeviceKeys,
949 ) -> Session {
950 let session = self.inner.create_outbound_session(config, identity_key, one_time_key);
951
952 let now = SecondsSinceUnixEpoch::now();
953 let session_id = session.session_id();
954
955 Session {
956 inner: Arc::new(Mutex::new(session)),
957 session_id: session_id.into(),
958 sender_key: identity_key,
959 our_device_keys,
960 created_using_fallback_key: fallback_used,
961 creation_time: now,
962 last_use_time: now,
963 }
964 }
965
966 #[instrument(
967 skip_all,
968 fields(
969 user_id = ?device.user_id(),
970 device_id = ?device.device_id(),
971 algorithms = ?device.algorithms()
972 )
973 )]
974 fn find_pre_key_bundle(
975 device: &DeviceData,
976 key_map: &OneTimeKeys,
977 ) -> Result<PrekeyBundle, SessionCreationError> {
978 let mut keys = key_map.iter();
979
980 let first_key = keys.next().ok_or_else(|| {
981 SessionCreationError::OneTimeKeyMissing(
982 device.user_id().to_owned(),
983 device.device_id().into(),
984 )
985 })?;
986
987 let first_key_id = first_key.0.to_owned();
988 let first_key = OneTimeKey::deserialize(first_key_id.algorithm(), first_key.1)?;
989
990 let result = match first_key {
991 OneTimeKey::SignedKey(key) => Ok(PrekeyBundle::Olm3DH { key }),
992 };
993
994 trace!(?result, "Finished searching for a valid pre-key bundle");
995
996 result
997 }
998
999 #[allow(clippy::result_large_err)]
1014 pub fn create_outbound_session(
1015 &self,
1016 device: &DeviceData,
1017 key_map: &OneTimeKeys,
1018 our_device_keys: DeviceKeys,
1019 ) -> Result<Session, SessionCreationError> {
1020 let pre_key_bundle = Self::find_pre_key_bundle(device, key_map)?;
1021
1022 match pre_key_bundle {
1023 PrekeyBundle::Olm3DH { key } => {
1024 device.verify_one_time_key(&key).map_err(|error| {
1025 SessionCreationError::InvalidSignature {
1026 signing_key: device.ed25519_key().map(Box::new),
1027 one_time_key: key.clone().into(),
1028 error: error.into(),
1029 }
1030 })?;
1031
1032 let identity_key = device.curve25519_key().ok_or_else(|| {
1033 SessionCreationError::DeviceMissingCurveKey(
1034 device.user_id().to_owned(),
1035 device.device_id().into(),
1036 )
1037 })?;
1038
1039 let is_fallback = key.fallback();
1040 let one_time_key = key.key();
1041 let config = device.olm_session_config();
1042
1043 Ok(self.create_outbound_session_helper(
1044 config,
1045 identity_key,
1046 one_time_key,
1047 is_fallback,
1048 our_device_keys,
1049 ))
1050 }
1051 }
1052 }
1053
1054 pub fn create_inbound_session(
1069 &mut self,
1070 their_identity_key: Curve25519PublicKey,
1071 our_device_keys: DeviceKeys,
1072 message: &PreKeyMessage,
1073 ) -> Result<InboundCreationResult, SessionCreationError> {
1074 Span::current().record("session_id", debug(message.session_id()));
1075 trace!("Creating a new Olm session from a pre-key message");
1076
1077 let result = self.inner.create_inbound_session(their_identity_key, message)?;
1078 let now = SecondsSinceUnixEpoch::now();
1079 let session_id = result.session.session_id();
1080
1081 debug!(session=?result.session, "Decrypted an Olm message from a new Olm session");
1082
1083 let session = Session {
1084 inner: Arc::new(Mutex::new(result.session)),
1085 session_id: session_id.into(),
1086 sender_key: their_identity_key,
1087 our_device_keys,
1088 created_using_fallback_key: false,
1089 creation_time: now,
1090 last_use_time: now,
1091 };
1092
1093 let plaintext = String::from_utf8_lossy(&result.plaintext).to_string();
1094
1095 Ok(InboundCreationResult { session, plaintext })
1096 }
1097
1098 #[cfg(any(test, feature = "testing"))]
1099 #[allow(dead_code)]
1100 pub async fn create_session_for_test_helper(
1102 &mut self,
1103 other: &mut Account,
1104 ) -> (Session, Session) {
1105 use ruma::events::dummy::ToDeviceDummyEventContent;
1106
1107 other.generate_one_time_keys(1);
1108 let one_time_map = other.signed_one_time_keys();
1109 let device = DeviceData::from_account(other);
1110
1111 let mut our_session =
1112 self.create_outbound_session(&device, &one_time_map, self.device_keys()).unwrap();
1113
1114 other.mark_keys_as_published();
1115
1116 let message = our_session
1117 .encrypt(&device, "m.dummy", ToDeviceDummyEventContent::new(), None)
1118 .await
1119 .unwrap()
1120 .deserialize()
1121 .unwrap();
1122
1123 #[cfg(feature = "experimental-algorithms")]
1124 let content = if let ToDeviceEncryptedEventContent::OlmV2Curve25519AesSha2(c) = message {
1125 c
1126 } else {
1127 panic!("Invalid encrypted event algorithm {}", message.algorithm());
1128 };
1129
1130 #[cfg(not(feature = "experimental-algorithms"))]
1131 let content = if let ToDeviceEncryptedEventContent::OlmV1Curve25519AesSha2(c) = message {
1132 c
1133 } else {
1134 panic!("Invalid encrypted event algorithm {}", message.algorithm());
1135 };
1136
1137 let prekey = if let OlmMessage::PreKey(m) = content.ciphertext {
1138 m
1139 } else {
1140 panic!("Wrong Olm message type");
1141 };
1142
1143 let our_device = DeviceData::from_account(self);
1144 let other_session = other
1145 .create_inbound_session(
1146 our_device.curve25519_key().unwrap(),
1147 other.device_keys(),
1148 &prekey,
1149 )
1150 .unwrap();
1151
1152 (our_session, other_session.session)
1153 }
1154
1155 async fn decrypt_olm_helper(
1156 &mut self,
1157 store: &Store,
1158 sender: &UserId,
1159 sender_key: Curve25519PublicKey,
1160 ciphertext: &OlmMessage,
1161 ) -> OlmResult<OlmDecryptionInfo> {
1162 let message_hash = OlmMessageHash::new(sender_key, ciphertext);
1163
1164 match self.decrypt_and_parse_olm_message(store, sender, sender_key, ciphertext).await {
1165 Ok((session, result)) => {
1166 Ok(OlmDecryptionInfo { session, message_hash, result, inbound_group_session: None })
1167 }
1168 Err(OlmError::SessionWedged(user_id, sender_key)) => {
1169 if store.is_message_known(&message_hash).await? {
1170 info!(?sender_key, "An Olm message got replayed, decryption failed");
1171 Err(OlmError::ReplayedMessage(user_id, sender_key))
1172 } else {
1173 Err(OlmError::SessionWedged(user_id, sender_key))
1174 }
1175 }
1176 Err(e) => Err(e),
1177 }
1178 }
1179
1180 #[cfg(feature = "experimental-algorithms")]
1181 async fn decrypt_olm_v2(
1182 &mut self,
1183 store: &Store,
1184 sender: &UserId,
1185 content: &OlmV2Curve25519AesSha2Content,
1186 ) -> OlmResult<OlmDecryptionInfo> {
1187 self.decrypt_olm_helper(store, sender, content.sender_key, &content.ciphertext).await
1188 }
1189
1190 #[instrument(skip_all, fields(sender, sender_key = ?content.sender_key))]
1191 async fn decrypt_olm_v1(
1192 &mut self,
1193 store: &Store,
1194 sender: &UserId,
1195 content: &OlmV1Curve25519AesSha2Content,
1196 ) -> OlmResult<OlmDecryptionInfo> {
1197 if content.recipient_key != self.static_data.identity_keys.curve25519 {
1198 warn!("Olm event doesn't contain a ciphertext for our key");
1199
1200 Err(EventError::MissingCiphertext.into())
1201 } else {
1202 Box::pin(self.decrypt_olm_helper(
1203 store,
1204 sender,
1205 content.sender_key,
1206 &content.ciphertext,
1207 ))
1208 .await
1209 }
1210 }
1211
1212 #[instrument(skip_all, fields(algorithm = ?event.content.algorithm()))]
1213 pub(crate) async fn decrypt_to_device_event(
1214 &mut self,
1215 store: &Store,
1216 event: &EncryptedToDeviceEvent,
1217 ) -> OlmResult<OlmDecryptionInfo> {
1218 trace!("Decrypting a to-device event");
1219
1220 match &event.content {
1221 ToDeviceEncryptedEventContent::OlmV1Curve25519AesSha2(c) => {
1222 self.decrypt_olm_v1(store, &event.sender, c).await
1223 }
1224 #[cfg(feature = "experimental-algorithms")]
1225 ToDeviceEncryptedEventContent::OlmV2Curve25519AesSha2(c) => {
1226 self.decrypt_olm_v2(store, &event.sender, c).await
1227 }
1228 ToDeviceEncryptedEventContent::Unknown(_) => {
1229 warn!(
1230 "Error decrypting an to-device event, unsupported \
1231 encryption algorithm"
1232 );
1233
1234 Err(EventError::UnsupportedAlgorithm.into())
1235 }
1236 }
1237 }
1238
1239 pub fn receive_keys_upload_response(
1241 &mut self,
1242 response: &upload_keys::v3::Response,
1243 ) -> OlmResult<()> {
1244 if !self.shared() {
1245 debug!("Marking account as shared");
1246 }
1247 self.mark_as_shared();
1248
1249 debug!("Marking one-time keys as published");
1250 self.mark_keys_as_published();
1253 self.update_key_counts(&response.one_time_key_counts, None);
1254
1255 Ok(())
1256 }
1257
1258 async fn decrypt_olm_message(
1260 &mut self,
1261 store: &Store,
1262 sender: &UserId,
1263 sender_key: Curve25519PublicKey,
1264 message: &OlmMessage,
1265 ) -> Result<(SessionType, String), OlmError> {
1266 let existing_sessions = store.get_sessions(&sender_key.to_base64()).await?;
1267
1268 match message {
1269 OlmMessage::Normal(_) => {
1270 let mut errors_by_olm_session = Vec::new();
1271
1272 if let Some(sessions) = existing_sessions {
1273 for session in sessions.lock().await.iter_mut() {
1276 match session.decrypt(message).await {
1277 Ok(p) => {
1278 return Ok((SessionType::Existing(session.clone()), p));
1280 }
1281
1282 Err(e) => {
1283 errors_by_olm_session.push((session.session_id().to_owned(), e));
1288 }
1289 }
1290 }
1291 }
1292
1293 warn!(
1294 ?errors_by_olm_session,
1295 "Failed to decrypt a non-pre-key message with all available sessions"
1296 );
1297 Err(OlmError::SessionWedged(sender.to_owned(), sender_key))
1298 }
1299
1300 OlmMessage::PreKey(prekey_message) => {
1301 if let Some(sessions) = existing_sessions {
1303 for session in sessions.lock().await.iter_mut() {
1304 if prekey_message.session_id() != session.session_id() {
1305 continue;
1307 }
1308
1309 if let Ok(p) = session.decrypt(message).await {
1310 return Ok((SessionType::Existing(session.clone()), p));
1312 }
1313
1314 warn!(
1328 session_id = session.session_id(),
1329 "Failed to decrypt a pre-key message with the corresponding session"
1330 );
1331
1332 return Err(OlmError::SessionWedged(
1333 session.our_device_keys.user_id.to_owned(),
1334 session.sender_key(),
1335 ));
1336 }
1337 }
1338
1339 let device_keys = store.get_own_device().await?.as_device_keys().clone();
1340 let result =
1341 match self.create_inbound_session(sender_key, device_keys, prekey_message) {
1342 Ok(r) => r,
1343 Err(e) => {
1344 warn!(
1345 "Failed to create a new Olm session from a pre-key message: {e:?}"
1346 );
1347 return Err(OlmError::SessionWedged(sender.to_owned(), sender_key));
1348 }
1349 };
1350
1351 let mut changes =
1356 Changes { sessions: vec![result.session.clone()], ..Default::default() };
1357
1358 if let Some(device) = store.get_device_from_curve_key(sender, sender_key).await? {
1365 let mut device_data = device.inner;
1366 device_data.olm_wedging_index.increment();
1367
1368 changes.devices =
1369 DeviceChanges { changed: vec![device_data], ..Default::default() };
1370 }
1371
1372 store.save_changes(changes).await?;
1373
1374 Ok((SessionType::New(result.session), result.plaintext))
1375 }
1376 }
1377 }
1378
1379 #[instrument(skip(self, store), fields(session, session_id))]
1382 async fn decrypt_and_parse_olm_message(
1383 &mut self,
1384 store: &Store,
1385 sender: &UserId,
1386 sender_key: Curve25519PublicKey,
1387 message: &OlmMessage,
1388 ) -> OlmResult<(SessionType, DecryptionResult)> {
1389 let (session, plaintext) =
1390 self.decrypt_olm_message(store, sender, sender_key, message).await?;
1391
1392 trace!("Successfully decrypted an Olm message");
1393
1394 match self.parse_decrypted_to_device_event(store, sender, sender_key, plaintext).await {
1395 Ok(result) => Ok((session, result)),
1396 Err(e) => {
1397 match session {
1401 SessionType::New(s) | SessionType::Existing(s) => {
1402 store.save_sessions(&[s]).await?;
1403 }
1404 }
1405
1406 warn!(
1407 error = ?e,
1408 "A to-device message was successfully decrypted but \
1409 parsing and checking the event fields failed"
1410 );
1411
1412 Err(e)
1413 }
1414 }
1415 }
1416
1417 async fn parse_decrypted_to_device_event(
1438 &self,
1439 store: &Store,
1440 sender: &UserId,
1441 sender_key: Curve25519PublicKey,
1442 plaintext: String,
1443 ) -> OlmResult<DecryptionResult> {
1444 let event: Box<AnyDecryptedOlmEvent> = serde_json::from_str(&plaintext)?;
1445 let identity_keys = &self.static_data.identity_keys;
1446
1447 if event.recipient() != self.static_data.user_id {
1448 Err(EventError::MismatchedSender(
1449 event.recipient().to_owned(),
1450 self.static_data.user_id.clone(),
1451 )
1452 .into())
1453 }
1454 else if event.sender() != sender {
1457 Err(EventError::MismatchedSender(event.sender().to_owned(), sender.to_owned()).into())
1458 } else if identity_keys.ed25519 != event.recipient_keys().ed25519 {
1459 Err(EventError::MismatchedKeys(
1460 identity_keys.ed25519.into(),
1461 event.recipient_keys().ed25519.into(),
1462 )
1463 .into())
1464 } else {
1465 if !matches!(*event, AnyDecryptedOlmEvent::RoomKey(_)) {
1470 let Some(device) =
1471 store.get_device_from_curve_key(event.sender(), sender_key).await?
1472 else {
1473 return Err(EventError::MissingSigningKey.into());
1474 };
1475
1476 let Some(key) = device.ed25519_key() else {
1477 return Err(EventError::MissingSigningKey.into());
1478 };
1479
1480 if key != event.keys().ed25519 {
1481 return Err(EventError::MismatchedKeys(
1482 key.into(),
1483 event.keys().ed25519.into(),
1484 )
1485 .into());
1486 }
1487 }
1488
1489 Ok(DecryptionResult {
1490 event,
1491 raw_event: Raw::from_json(RawJsonValue::from_string(plaintext)?),
1492 sender_key,
1493 })
1494 }
1495 }
1496
1497 #[doc(hidden)]
1502 pub fn deep_clone(&self) -> Self {
1503 Self::from_pickle(self.pickle()).unwrap()
1505 }
1506}
1507
1508impl PartialEq for Account {
1509 fn eq(&self, other: &Self) -> bool {
1510 self.identity_keys() == other.identity_keys() && self.shared() == other.shared()
1511 }
1512}
1513
1514fn expand_legacy_pickle_key(key: &[u8; 32], device_id: &DeviceId) -> Box<[u8; 32]> {
1533 let kdf: Hkdf<Sha256> = Hkdf::new(Some(device_id.as_bytes()), key);
1534 let mut key = Box::new([0u8; 32]);
1535
1536 kdf.expand(b"dehydrated-device-pickle-key", key.as_mut_slice())
1537 .expect("We should be able to expand the 32 byte pickle key");
1538
1539 key
1540}
1541
1542#[cfg(test)]
1543mod tests {
1544 use std::{
1545 collections::{BTreeMap, BTreeSet},
1546 ops::Deref,
1547 time::Duration,
1548 };
1549
1550 use anyhow::Result;
1551 use matrix_sdk_test::async_test;
1552 use ruma::{
1553 device_id, user_id, DeviceId, MilliSecondsSinceUnixEpoch, OneTimeKeyAlgorithm,
1554 OneTimeKeyId, UserId,
1555 };
1556 use serde_json::json;
1557
1558 use super::Account;
1559 use crate::{
1560 olm::SignedJsonObject,
1561 types::{DeviceKeys, SignedKey},
1562 DeviceData,
1563 };
1564
1565 fn user_id() -> &'static UserId {
1566 user_id!("@alice:localhost")
1567 }
1568
1569 fn device_id() -> &'static DeviceId {
1570 device_id!("DEVICEID")
1571 }
1572
1573 #[test]
1574 fn test_one_time_key_creation() -> Result<()> {
1575 let mut account = Account::with_device_id(user_id(), device_id());
1576
1577 let (_, one_time_keys, _) = account.keys_for_upload();
1578 assert!(!one_time_keys.is_empty());
1579
1580 let (_, second_one_time_keys, _) = account.keys_for_upload();
1581 assert!(!second_one_time_keys.is_empty());
1582
1583 let one_time_key_ids: BTreeSet<&OneTimeKeyId> =
1584 one_time_keys.keys().map(Deref::deref).collect();
1585 let second_one_time_key_ids: BTreeSet<&OneTimeKeyId> =
1586 second_one_time_keys.keys().map(Deref::deref).collect();
1587
1588 assert_eq!(one_time_key_ids, second_one_time_key_ids);
1589
1590 account.mark_keys_as_published();
1591 account.update_uploaded_key_count(50);
1592 account.generate_one_time_keys_if_needed();
1593
1594 let (_, third_one_time_keys, _) = account.keys_for_upload();
1595 assert!(third_one_time_keys.is_empty());
1596
1597 account.update_uploaded_key_count(0);
1598 account.generate_one_time_keys_if_needed();
1599
1600 let (_, fourth_one_time_keys, _) = account.keys_for_upload();
1601 assert!(!fourth_one_time_keys.is_empty());
1602
1603 let fourth_one_time_key_ids: BTreeSet<&OneTimeKeyId> =
1604 fourth_one_time_keys.keys().map(Deref::deref).collect();
1605
1606 assert_ne!(one_time_key_ids, fourth_one_time_key_ids);
1607 Ok(())
1608 }
1609
1610 #[test]
1611 fn test_fallback_key_creation() -> Result<()> {
1612 let mut account = Account::with_device_id(user_id(), device_id());
1613
1614 let (_, _, fallback_keys) = account.keys_for_upload();
1615
1616 assert!(
1620 fallback_keys.is_empty(),
1621 "We should not upload fallback keys until we know if the server supports them."
1622 );
1623
1624 let one_time_keys = BTreeMap::from([(OneTimeKeyAlgorithm::SignedCurve25519, 50u8.into())]);
1625
1626 account.update_key_counts(&one_time_keys, None);
1629 let (_, _, fallback_keys) = account.keys_for_upload();
1630 assert!(
1631 fallback_keys.is_empty(),
1632 "We should not upload a fallback key if we're certain that the server doesn't support \
1633 them."
1634 );
1635
1636 let unused_fallback_keys = &[];
1640 account.update_key_counts(&one_time_keys, Some(unused_fallback_keys.as_ref()));
1641 let (_, _, fallback_keys) = account.keys_for_upload();
1642 assert!(
1643 !fallback_keys.is_empty(),
1644 "We should upload the initial fallback key if the server supports them."
1645 );
1646 account.mark_keys_as_published();
1647
1648 let unused_fallback_keys = &[];
1651 account.update_key_counts(&one_time_keys, Some(unused_fallback_keys.as_ref()));
1652 let (_, _, fallback_keys) = account.keys_for_upload();
1653 assert!(
1654 fallback_keys.is_empty(),
1655 "We should not upload new fallback keys unless our current fallback key expires."
1656 );
1657
1658 let fallback_key_timestamp =
1659 account.fallback_creation_timestamp.unwrap().to_system_time().unwrap()
1660 - Duration::from_secs(3600 * 24 * 30);
1661
1662 account.fallback_creation_timestamp =
1663 Some(MilliSecondsSinceUnixEpoch::from_system_time(fallback_key_timestamp).unwrap());
1664
1665 account.update_key_counts(&one_time_keys, None);
1666 let (_, _, fallback_keys) = account.keys_for_upload();
1667 assert!(
1668 !fallback_keys.is_empty(),
1669 "Now that our fallback key has expired, we should try to upload a new one, even if the \
1670 server supposedly doesn't support fallback keys anymore"
1671 );
1672
1673 Ok(())
1674 }
1675
1676 #[test]
1677 fn test_fallback_key_signing() -> Result<()> {
1678 let key = vodozemac::Curve25519PublicKey::from_base64(
1679 "7PUPP6Ijt5R8qLwK2c8uK5hqCNF9tOzWYgGaAay5JBs",
1680 )?;
1681 let account = Account::with_device_id(user_id(), device_id());
1682
1683 let key = account.sign_key(key, true);
1684
1685 let canonical_key = key.to_canonical_json()?;
1686
1687 assert_eq!(
1688 canonical_key,
1689 "{\"fallback\":true,\"key\":\"7PUPP6Ijt5R8qLwK2c8uK5hqCNF9tOzWYgGaAay5JBs\"}"
1690 );
1691
1692 account
1693 .has_signed_raw(key.signatures(), &canonical_key)
1694 .expect("Couldn't verify signature");
1695
1696 let device = DeviceData::from_account(&account);
1697 device.verify_one_time_key(&key).expect("The device can verify its own signature");
1698
1699 Ok(())
1700 }
1701
1702 #[test]
1703 fn test_account_and_device_creation_timestamp() -> Result<()> {
1704 let now = MilliSecondsSinceUnixEpoch::now();
1705 let account = Account::with_device_id(user_id(), device_id());
1706 let then = MilliSecondsSinceUnixEpoch::now();
1707
1708 assert!(account.creation_local_time() >= now);
1709 assert!(account.creation_local_time() <= then);
1710
1711 let device = DeviceData::from_account(&account);
1712 assert_eq!(account.creation_local_time(), device.first_time_seen_ts());
1713
1714 Ok(())
1715 }
1716
1717 #[async_test]
1718 async fn test_fallback_key_signature_verification() -> Result<()> {
1719 let fallback_key = json!({
1720 "fallback": true,
1721 "key": "XPFqtLvBepBmW6jSAbBuJbhEpprBhQOX1IjUu+cnMF4",
1722 "signatures": {
1723 "@dkasak_c:matrix.org": {
1724 "ed25519:EXPDYDPWZH": "RJCBMJPL5hvjxgq8rmLmqkNOuPsaan7JeL1wsE+gW6R39G894lb2sBmzapHeKCn/KFjmkonPLkICApRDS+zyDw"
1725 }
1726 }
1727 });
1728
1729 let device_keys = json!({
1730 "algorithms": [
1731 "m.olm.v1.curve25519-aes-sha2",
1732 "m.megolm.v1.aes-sha2"
1733 ],
1734 "device_id": "EXPDYDPWZH",
1735 "keys": {
1736 "curve25519:EXPDYDPWZH": "k7f3igo0Vrdm88JSSA5d3OCuUfHYELChB2b57aOROB8",
1737 "ed25519:EXPDYDPWZH": "GdjYI8fxs175gSpYRJkyN6FRfvcyTsNOhJ2OR/Ggp+E"
1738 },
1739 "signatures": {
1740 "@dkasak_c:matrix.org": {
1741 "ed25519:EXPDYDPWZH": "kzrtfQMbJXWXQ1uzhybtwFnGk0JJBS4Mg8VPMusMu6U8MPJccwoHVZKo5+owuHTzIodI+GZYqLmMSzvfvsChAA"
1742 }
1743 },
1744 "user_id": "@dkasak_c:matrix.org",
1745 "unsigned": {}
1746 });
1747
1748 let device_keys: DeviceKeys = serde_json::from_value(device_keys).unwrap();
1749 let device = DeviceData::try_from(&device_keys).unwrap();
1750 let fallback_key: SignedKey = serde_json::from_value(fallback_key).unwrap();
1751
1752 device
1753 .verify_one_time_key(&fallback_key)
1754 .expect("The fallback key should pass the signature verification");
1755
1756 Ok(())
1757 }
1758}