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