1use std::{
29 borrow::Borrow,
30 collections::{
31 btree_map::{IntoIter, Iter},
32 BTreeMap,
33 },
34};
35
36use as_variant::as_variant;
37use matrix_sdk_common::deserialized_responses::PrivOwnedStr;
38use ruma::{
39 serde::StringEnum, DeviceKeyAlgorithm, DeviceKeyId, OwnedDeviceKeyId, OwnedUserId, RoomId,
40 UserId,
41};
42use serde::{Deserialize, Deserializer, Serialize, Serializer};
43use vodozemac::{Curve25519PublicKey, Ed25519PublicKey, Ed25519Signature, KeyError};
44use zeroize::{Zeroize, ZeroizeOnDrop};
45
46mod backup;
47mod cross_signing;
48mod device_keys;
49pub mod events;
50mod one_time_keys;
51pub mod qr_login;
52pub mod requests;
53pub mod room_history;
54
55pub use self::{backup::*, cross_signing::*, device_keys::*, one_time_keys::*};
56use crate::store::types::BackupDecryptionKey;
57
58macro_rules! from_base64 {
59 ($foo:ident, $name:ident) => {
60 pub(crate) fn $name<'de, D>(deserializer: D) -> Result<$foo, D::Error>
61 where
62 D: Deserializer<'de>,
63 {
64 let mut string = String::deserialize(deserializer)?;
65
66 let result = $foo::from_base64(&string);
67 string.zeroize();
68
69 result.map_err(serde::de::Error::custom)
70 }
71 };
72}
73
74macro_rules! to_base64 {
75 ($foo:ident, $name:ident) => {
76 pub(crate) fn $name<S>(v: &$foo, serializer: S) -> Result<S::Ok, S::Error>
77 where
78 S: Serializer,
79 {
80 let mut string = v.to_base64();
81 let ret = string.serialize(serializer);
82
83 string.zeroize();
84
85 ret
86 }
87 };
88}
89
90#[derive(Debug, Deserialize, Clone, Serialize, ZeroizeOnDrop)]
93pub struct SecretsBundle {
94 pub cross_signing: CrossSigningSecrets,
96 pub backup: Option<BackupSecrets>,
98}
99
100#[derive(Deserialize, Clone, Serialize, ZeroizeOnDrop)]
102pub struct CrossSigningSecrets {
103 pub master_key: String,
106 pub user_signing_key: String,
109 pub self_signing_key: String,
112}
113
114impl std::fmt::Debug for CrossSigningSecrets {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 f.debug_struct("CrossSigningSecrets")
117 .field("master_key", &"...")
118 .field("user_signing_key", &"...")
119 .field("self_signing_key", &"...")
120 .finish()
121 }
122}
123
124#[derive(Debug, Deserialize, Clone, Serialize, ZeroizeOnDrop)]
127pub struct MegolmBackupV1Curve25519AesSha2Secrets {
128 #[serde(serialize_with = "backup_key_to_base64", deserialize_with = "backup_key_from_base64")]
132 pub key: BackupDecryptionKey,
133 pub backup_version: String,
135}
136
137from_base64!(BackupDecryptionKey, backup_key_from_base64);
138to_base64!(BackupDecryptionKey, backup_key_to_base64);
139
140#[derive(Debug, Clone, ZeroizeOnDrop, Serialize, Deserialize)]
142#[serde(tag = "algorithm")]
143pub enum BackupSecrets {
144 #[serde(rename = "m.megolm_backup.v1.curve25519-aes-sha2")]
147 MegolmBackupV1Curve25519AesSha2(MegolmBackupV1Curve25519AesSha2Secrets),
148}
149
150impl BackupSecrets {
151 pub fn algorithm(&self) -> &str {
153 match &self {
154 BackupSecrets::MegolmBackupV1Curve25519AesSha2(_) => {
155 "m.megolm_backup.v1.curve25519-aes-sha2"
156 }
157 }
158 }
159}
160
161#[derive(Clone, Debug, PartialEq, Eq)]
172pub enum Signature {
173 Ed25519(Ed25519Signature),
175 Other(String),
178}
179
180#[derive(Debug, Clone, PartialEq, Eq)]
184pub struct InvalidSignature {
185 pub source: String,
188}
189
190impl Signature {
191 pub fn ed25519(&self) -> Option<Ed25519Signature> {
193 as_variant!(self, Self::Ed25519).copied()
194 }
195
196 pub fn to_base64(&self) -> String {
198 match self {
199 Signature::Ed25519(s) => s.to_base64(),
200 Signature::Other(s) => s.to_owned(),
201 }
202 }
203}
204
205impl From<Ed25519Signature> for Signature {
206 fn from(signature: Ed25519Signature) -> Self {
207 Self::Ed25519(signature)
208 }
209}
210
211#[derive(Debug, Clone, PartialEq, Eq)]
213pub struct Signatures(
214 BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceKeyId, Result<Signature, InvalidSignature>>>,
215);
216
217impl Signatures {
218 pub fn new() -> Self {
220 Signatures(Default::default())
221 }
222
223 pub fn add_signature(
226 &mut self,
227 signer: OwnedUserId,
228 key_id: OwnedDeviceKeyId,
229 signature: Ed25519Signature,
230 ) -> Option<Result<Signature, InvalidSignature>> {
231 self.0.entry(signer).or_default().insert(key_id, Ok(signature.into()))
232 }
233
234 pub fn get_signature(&self, signer: &UserId, key_id: &DeviceKeyId) -> Option<Ed25519Signature> {
237 self.get(signer)?.get(key_id)?.as_ref().ok()?.ed25519()
238 }
239
240 pub fn get(
242 &self,
243 signer: &UserId,
244 ) -> Option<&BTreeMap<OwnedDeviceKeyId, Result<Signature, InvalidSignature>>> {
245 self.0.get(signer)
246 }
247
248 pub fn clear(&mut self) {
250 self.0.clear()
251 }
252
253 pub fn is_empty(&self) -> bool {
255 self.0.is_empty()
256 }
257
258 pub fn signature_count(&self) -> usize {
260 self.0.values().map(|u| u.len()).sum()
261 }
262}
263
264impl Default for Signatures {
265 fn default() -> Self {
266 Self::new()
267 }
268}
269
270impl IntoIterator for Signatures {
271 type Item = (OwnedUserId, BTreeMap<OwnedDeviceKeyId, Result<Signature, InvalidSignature>>);
272
273 type IntoIter =
274 IntoIter<OwnedUserId, BTreeMap<OwnedDeviceKeyId, Result<Signature, InvalidSignature>>>;
275
276 fn into_iter(self) -> Self::IntoIter {
277 self.0.into_iter()
278 }
279}
280
281impl<'de> Deserialize<'de> for Signatures {
282 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
283 where
284 D: Deserializer<'de>,
285 {
286 let map: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceKeyId, String>> =
287 Deserialize::deserialize(deserializer)?;
288
289 let map = map
290 .into_iter()
291 .map(|(user, signatures)| {
292 let signatures = signatures
293 .into_iter()
294 .map(|(key_id, s)| {
295 let algorithm = key_id.algorithm();
296 let signature = match algorithm {
297 DeviceKeyAlgorithm::Ed25519 => Ed25519Signature::from_base64(&s)
298 .map(|s| s.into())
299 .map_err(|_| InvalidSignature { source: s }),
300 _ => Ok(Signature::Other(s)),
301 };
302
303 Ok((key_id, signature))
304 })
305 .collect::<Result<BTreeMap<_, _>, _>>()?;
306
307 Ok((user, signatures))
308 })
309 .collect::<Result<_, _>>()?;
310
311 Ok(Signatures(map))
312 }
313}
314
315impl Serialize for Signatures {
316 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
317 where
318 S: Serializer,
319 {
320 let signatures: BTreeMap<&OwnedUserId, BTreeMap<&OwnedDeviceKeyId, String>> = self
321 .0
322 .iter()
323 .map(|(u, m)| {
324 (
325 u,
326 m.iter()
327 .map(|(d, s)| {
328 (
329 d,
330 match s {
331 Ok(s) => s.to_base64(),
332 Err(i) => i.source.to_owned(),
333 },
334 )
335 })
336 .collect(),
337 )
338 })
339 .collect();
340
341 Serialize::serialize(&signatures, serializer)
342 }
343}
344
345#[derive(Debug, Clone, PartialEq, Eq)]
347pub struct SigningKeys<T: Ord>(BTreeMap<T, SigningKey>);
348
349impl<T: Ord> SigningKeys<T> {
350 pub fn new() -> Self {
352 Self(BTreeMap::new())
353 }
354
355 pub fn insert(&mut self, key_id: T, key: SigningKey) -> Option<SigningKey> {
357 self.0.insert(key_id, key)
358 }
359
360 pub fn get<Q>(&self, key_id: &Q) -> Option<&SigningKey>
362 where
363 T: Borrow<Q>,
364 Q: Ord + ?Sized,
365 {
366 self.0.get(key_id)
367 }
368
369 pub fn iter(&self) -> Iter<'_, T, SigningKey> {
371 self.0.iter()
372 }
373
374 pub fn is_empty(&self) -> bool {
376 self.0.is_empty()
377 }
378}
379
380impl<T: Ord> Default for SigningKeys<T> {
381 fn default() -> Self {
382 Self::new()
383 }
384}
385
386impl<T: Ord> IntoIterator for SigningKeys<T> {
387 type Item = (T, SigningKey);
388
389 type IntoIter = IntoIter<T, SigningKey>;
390
391 fn into_iter(self) -> Self::IntoIter {
392 self.0.into_iter()
393 }
394}
395
396impl<K: Ord> FromIterator<(K, SigningKey)> for SigningKeys<K> {
397 fn from_iter<T: IntoIterator<Item = (K, SigningKey)>>(iter: T) -> Self {
398 let map = BTreeMap::from_iter(iter);
399
400 Self(map)
401 }
402}
403
404impl<K: Ord, const N: usize> From<[(K, SigningKey); N]> for SigningKeys<K> {
405 fn from(v: [(K, SigningKey); N]) -> Self {
406 let map = BTreeMap::from(v);
407
408 Self(map)
409 }
410}
411
412trait Algorithm {
416 fn algorithm(&self) -> DeviceKeyAlgorithm;
417}
418
419impl Algorithm for OwnedDeviceKeyId {
420 fn algorithm(&self) -> DeviceKeyAlgorithm {
421 DeviceKeyId::algorithm(self)
422 }
423}
424
425impl Algorithm for DeviceKeyAlgorithm {
426 fn algorithm(&self) -> DeviceKeyAlgorithm {
427 self.to_owned()
428 }
429}
430
431#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, StringEnum)]
433#[non_exhaustive]
434pub enum EventEncryptionAlgorithm {
435 #[ruma_enum(rename = "m.olm.v1.curve25519-aes-sha2")]
437 OlmV1Curve25519AesSha2,
438
439 #[cfg(feature = "experimental-algorithms")]
441 #[ruma_enum(rename = "m.olm.v2.curve25519-aes-sha2")]
442 OlmV2Curve25519AesSha2,
443
444 #[ruma_enum(rename = "m.megolm.v1.aes-sha2")]
446 MegolmV1AesSha2,
447
448 #[cfg(feature = "experimental-algorithms")]
450 #[ruma_enum(rename = "m.megolm.v2.aes-sha2")]
451 MegolmV2AesSha2,
452
453 #[doc(hidden)]
454 _Custom(PrivOwnedStr),
455}
456
457impl<T: Ord + Serialize> Serialize for SigningKeys<T> {
458 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
459 where
460 S: Serializer,
461 {
462 let keys: BTreeMap<&T, String> =
463 self.0.iter().map(|(key_id, key)| (key_id, key.to_base64())).collect();
464
465 keys.serialize(serializer)
466 }
467}
468
469impl<'de, T: Algorithm + Ord + Deserialize<'de>> Deserialize<'de> for SigningKeys<T> {
470 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
471 where
472 D: Deserializer<'de>,
473 {
474 let map: BTreeMap<T, String> = Deserialize::deserialize(deserializer)?;
475
476 let map: Result<_, _> = map
477 .into_iter()
478 .map(|(key_id, key)| {
479 let key = SigningKey::from_parts(&key_id.algorithm(), key)
480 .map_err(serde::de::Error::custom)?;
481
482 Ok((key_id, key))
483 })
484 .collect();
485
486 Ok(SigningKeys(map?))
487 }
488}
489
490from_base64!(Curve25519PublicKey, deserialize_curve_key);
495to_base64!(Curve25519PublicKey, serialize_curve_key);
496
497from_base64!(Ed25519PublicKey, deserialize_ed25519_key);
498to_base64!(Ed25519PublicKey, serialize_ed25519_key);
499
500pub(crate) fn deserialize_curve_key_vec<'de, D>(de: D) -> Result<Vec<Curve25519PublicKey>, D::Error>
501where
502 D: Deserializer<'de>,
503{
504 let keys: Vec<String> = Deserialize::deserialize(de)?;
505 let keys: Result<Vec<Curve25519PublicKey>, KeyError> =
506 keys.iter().map(|k| Curve25519PublicKey::from_base64(k)).collect();
507
508 keys.map_err(serde::de::Error::custom)
509}
510
511pub(crate) fn serialize_curve_key_vec<S>(
512 keys: &[Curve25519PublicKey],
513 s: S,
514) -> Result<S::Ok, S::Error>
515where
516 S: Serializer,
517{
518 let keys: Vec<String> = keys.iter().map(|k| k.to_base64()).collect();
519 keys.serialize(s)
520}
521
522mod serde_curve_key_option {
523 use super::{Curve25519PublicKey, Deserialize, Deserializer, Serialize, Serializer};
524
525 pub(crate) fn deserialize<'de, D>(de: D) -> Result<Option<Curve25519PublicKey>, D::Error>
526 where
527 D: Deserializer<'de>,
528 {
529 let key: Option<String> = Deserialize::deserialize(de)?;
530 key.map(|k| Curve25519PublicKey::from_base64(&k))
531 .transpose()
532 .map_err(serde::de::Error::custom)
533 }
534
535 pub(crate) fn serialize<S>(key: &Option<Curve25519PublicKey>, s: S) -> Result<S::Ok, S::Error>
536 where
537 S: Serializer,
538 {
539 let key = key.as_ref().map(|k| k.to_base64());
540 key.serialize(s)
541 }
542}
543
544pub trait RoomKeyExport {
547 fn room_id(&self) -> &RoomId;
549 fn session_id(&self) -> &str;
551 fn sender_key(&self) -> Curve25519PublicKey;
554}
555
556#[cfg(test)]
557mod test {
558 use insta::{assert_debug_snapshot, assert_json_snapshot, with_settings};
559 use ruma::{device_id, user_id};
560 use serde_json::json;
561 use similar_asserts::assert_eq;
562
563 use super::*;
564
565 #[test]
566 fn serialize_secrets_bundle() {
567 let json = json!({
568 "cross_signing": {
569 "master_key": "rTtSv67XGS6k/rg6/yTG/m573cyFTPFRqluFhQY+hSw",
570 "self_signing_key": "4jbPt7jh5D2iyM4U+3IDa+WthgJB87IQN1ATdkau+xk",
571 "user_signing_key": "YkFKtkjcsTxF6UAzIIG/l6Nog/G2RigCRfWj3cjNWeM",
572 },
573 "backup": {
574 "algorithm": "m.megolm_backup.v1.curve25519-aes-sha2",
575 "backup_version": "2",
576 "key": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
577 },
578 });
579
580 let deserialized: SecretsBundle = serde_json::from_value(json.clone())
581 .expect("We should be able to deserialize the secrets bundle");
582
583 let serialized = serde_json::to_value(&deserialized)
584 .expect("We should be able to serialize a secrets bundle");
585
586 assert_eq!(json, serialized, "A serialization cycle should yield the same result");
587 }
588
589 #[test]
590 fn snapshot_backup_decryption_key() {
591 let decryption_key = BackupDecryptionKey { inner: Box::new([1u8; 32]) };
592 assert_json_snapshot!(decryption_key);
593
594 assert_debug_snapshot!(decryption_key);
596 }
597
598 #[test]
599 fn snapshot_signatures() {
600 let signatures = Signatures(BTreeMap::from([
601 (
602 user_id!("@alice:localhost").to_owned(),
603 BTreeMap::from([
604 (
605 DeviceKeyId::from_parts(
606 DeviceKeyAlgorithm::Ed25519,
607 device_id!("ABCDEFGH"),
608 ),
609 Ok(Signature::from(Ed25519Signature::from_slice(&[0u8; 64]).unwrap())),
610 ),
611 (
612 DeviceKeyId::from_parts(
613 DeviceKeyAlgorithm::Curve25519,
614 device_id!("IJKLMNOP"),
615 ),
616 Ok(Signature::from(Ed25519Signature::from_slice(&[1u8; 64]).unwrap())),
617 ),
618 ]),
619 ),
620 (
621 user_id!("@bob:localhost").to_owned(),
622 BTreeMap::from([(
623 DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, device_id!("ABCDEFGH")),
624 Err(InvalidSignature { source: "SOME+B64+SOME+B64+SOME+B64+==".to_owned() }),
625 )]),
626 ),
627 ]));
628
629 with_settings!({sort_maps =>true}, {
630 assert_json_snapshot!(signatures)
631 });
632 }
633
634 #[test]
635 fn snapshot_secret_bundle() {
636 let secret_bundle = SecretsBundle {
637 cross_signing: CrossSigningSecrets {
638 master_key: "MSKMSKMSKMSKMSKMSKMSKMSKMSKMSKMSKMSK".to_owned(),
639 user_signing_key: "USKUSKUSKUSKUSKUSKUSKUSKUSKUSKUSKUSK".to_owned(),
640 self_signing_key: "SSKSSKSSKSSKSSKSSKSSKSSKSSKSSKSSK".to_owned(),
641 },
642 backup: Some(BackupSecrets::MegolmBackupV1Curve25519AesSha2(
643 MegolmBackupV1Curve25519AesSha2Secrets {
644 key: BackupDecryptionKey::from_bytes(&[0u8; 32]),
645 backup_version: "v1.1".to_owned(),
646 },
647 )),
648 };
649
650 assert_json_snapshot!(secret_bundle);
651
652 let secret_bundle = SecretsBundle {
653 cross_signing: CrossSigningSecrets {
654 master_key: "MSKMSKMSKMSKMSKMSKMSKMSKMSKMSKMSKMSK".to_owned(),
655 user_signing_key: "USKUSKUSKUSKUSKUSKUSKUSKUSKUSKUSKUSK".to_owned(),
656 self_signing_key: "SSKSSKSSKSSKSSKSSKSSKSSKSSKSSKSSK".to_owned(),
657 },
658 backup: None,
659 };
660
661 assert_json_snapshot!(secret_bundle);
662 }
663}