1use std::{collections::BTreeMap, default::Default};
2
3use insta::{assert_json_snapshot, with_settings};
4use ruma::{
5 CanonicalJsonValue, CrossSigningKeyId, CrossSigningOrDeviceSignatures,
6 CrossSigningOrDeviceSigningKeyId, DeviceId, OwnedBase64PublicKey,
7 OwnedBase64PublicKeyOrDeviceId, OwnedDeviceId, OwnedUserId, SigningKeyAlgorithm, UserId,
8 api::client::keys::get_keys::v3::Response as KeyQueryResponse,
9 device_id,
10 encryption::{CrossSigningKey, DeviceKeys, KeyUsage},
11 owned_device_id,
12 serde::Raw,
13 user_id,
14};
15use serde_json::{Value, json};
16use vodozemac::{Curve25519PublicKey, Ed25519PublicKey, Ed25519SecretKey, Ed25519Signature};
17
18use super::keys_query::{KeysQueryUser, keys_query, master_keys};
19use crate::{
20 ruma_response_from_json, ruma_response_to_json,
21 test_json::keys_query::{device_keys_payload, self_signing_keys},
22};
23
24pub struct KeyQueryResponseTemplate {
81 user_id: OwnedUserId,
83
84 master_cross_signing_key: Option<Ed25519SecretKey>,
87
88 self_signing_key: Option<Ed25519SecretKey>,
91
92 user_signing_key: Option<Ed25519SecretKey>,
95
96 master_cross_signing_key_json: Option<CrossSigningKey>,
104
105 device_keys: BTreeMap<OwnedDeviceId, Raw<DeviceKeys>>,
108}
109
110impl KeyQueryResponseTemplate {
111 pub fn new(user_id: OwnedUserId) -> Self {
113 KeyQueryResponseTemplate {
114 user_id,
115 master_cross_signing_key: None,
116 self_signing_key: None,
117 user_signing_key: None,
118 master_cross_signing_key_json: None,
119 device_keys: Default::default(),
120 }
121 }
122
123 pub fn with_cross_signing_keys(
128 mut self,
129 master_cross_signing_key: Ed25519SecretKey,
130 self_signing_key: Ed25519SecretKey,
131 user_signing_key: Ed25519SecretKey,
132 ) -> Self {
133 let master_public_key = master_cross_signing_key.public_key();
134 self.master_cross_signing_key = Some(master_cross_signing_key);
135 self.self_signing_key = Some(self_signing_key);
136 self.user_signing_key = Some(user_signing_key);
137
138 self.master_cross_signing_key_json =
142 Some(self.signed_cross_signing_key(&master_public_key, KeyUsage::Master));
143
144 self
145 }
146
147 pub fn with_device(
158 mut self,
159 device_id: &DeviceId,
160 curve25519_public_key: &Curve25519PublicKey,
161 ed25519_secret_key: &Ed25519SecretKey,
162 options: KeyQueryResponseTemplateDeviceOptions,
163 ) -> Self {
164 let mut device_keys = json!({
165 "algorithms": [
166 "m.olm.v1.curve25519-aes-sha2",
167 "m.megolm.v1.aes-sha2"
168 ],
169 "device_id": device_id.to_owned(),
170 "keys": {
171 format!("curve25519:{device_id}"): curve25519_public_key.to_base64(),
172 format!("ed25519:{device_id}"): ed25519_secret_key.public_key().to_base64(),
173 },
174 "signatures": {},
175 "user_id": self.user_id.clone(),
176 });
177
178 if options.dehydrated {
179 device_keys["dehydrated"] = Value::Bool(true);
180 }
181
182 sign_json(&mut device_keys, ed25519_secret_key, &self.user_id, device_id.as_str());
183 if options.verified {
184 let ssk = self
185 .self_signing_key
186 .as_ref()
187 .expect("must call with_cross_signing_keys() before creating cross-signed device");
188 sign_json(&mut device_keys, ssk, &self.user_id, &ssk.public_key().to_base64());
189 }
190
191 let raw_device_keys = serde_json::from_value(device_keys).unwrap();
192 self.device_keys.insert(device_id.to_owned(), raw_device_keys);
193 self
194 }
195
196 pub fn with_user_verification_signature(
199 mut self,
200 signing_user_id: &UserId,
201 signing_user_user_signing_key: &Ed25519SecretKey,
202 ) -> Self {
203 let master_key = self.master_cross_signing_key_json.as_mut().expect(
204 "must call with_cross_signing_key() before calling 'with_user_verification_signature'",
205 );
206 sign_cross_signing_key(master_key, signing_user_user_signing_key, signing_user_id);
207 self
208 }
209
210 pub fn build_response(&self) -> KeyQueryResponse {
212 let mut response = KeyQueryResponse::default();
213
214 if !self.device_keys.is_empty() {
215 response.device_keys =
216 BTreeMap::from([(self.user_id.clone(), self.device_keys.clone())]);
217 }
218
219 if let Some(master_key) = &self.master_cross_signing_key_json {
220 response.master_keys.insert(
221 self.user_id.clone(),
222 Raw::new(master_key).expect("unable to serialize msk"),
223 );
224 }
225
226 if let Some(self_signing_key) = &self.self_signing_key {
227 let ssk = self
228 .signed_cross_signing_key(&self_signing_key.public_key(), KeyUsage::SelfSigning);
229 response
230 .self_signing_keys
231 .insert(self.user_id.clone(), Raw::new(&ssk).expect("unable to serialize ssk"));
232 }
233
234 if let Some(user_signing_key) = &self.user_signing_key {
235 let usk = self
236 .signed_cross_signing_key(&user_signing_key.public_key(), KeyUsage::UserSigning);
237 response
238 .user_signing_keys
239 .insert(self.user_id.clone(), Raw::new(&usk).expect("unable to serialize usk"));
240 }
241
242 response
243 }
244
245 fn signed_cross_signing_key(
257 &self,
258 public_key: &Ed25519PublicKey,
259 key_usage: KeyUsage,
260 ) -> CrossSigningKey {
261 let public_key_base64 = OwnedBase64PublicKey::with_bytes(public_key.as_bytes());
262 let mut key = CrossSigningKey::new(
263 self.user_id.clone(),
264 vec![key_usage],
265 BTreeMap::from([(
266 CrossSigningKeyId::from_parts(SigningKeyAlgorithm::Ed25519, &public_key_base64),
267 public_key_base64.to_string(),
268 )]),
269 CrossSigningOrDeviceSignatures::new(),
270 );
271
272 let master_key = self
274 .master_cross_signing_key
275 .as_ref()
276 .expect("must set master key before calling `signed_cross_signing_key`");
277 sign_cross_signing_key(&mut key, master_key, &self.user_id);
278
279 key
280 }
281}
282
283#[derive(Default)]
286pub struct KeyQueryResponseTemplateDeviceOptions {
287 verified: bool,
288 dehydrated: bool,
289}
290
291impl KeyQueryResponseTemplateDeviceOptions {
292 pub fn new() -> Self {
296 Self::default()
297 }
298
299 pub fn verified(mut self, verified: bool) -> Self {
302 self.verified = verified;
303 self
304 }
305
306 pub fn dehydrated(mut self, dehydrated: bool) -> Self {
311 self.dehydrated = dehydrated;
312 self
313 }
314}
315
316pub struct KeyDistributionTestData {}
339
340impl KeyDistributionTestData {
341 pub const MASTER_KEY_PRIVATE_EXPORT: &'static str =
342 "9kquJqAtEUoTXljh5W2QSsCm4FH9WvWzIkDkIMUsM2k";
343 pub const SELF_SIGNING_KEY_PRIVATE_EXPORT: &'static str =
344 "QifnGfudByh/GpBgJYEMzq7/DGbp6fZjp58faQj3n1M";
345 pub const USER_SIGNING_KEY_PRIVATE_EXPORT: &'static str =
346 "zQSosK46giUFs2ACsaf32bA7drcIXbmViyEt+TLfloI";
347
348 pub fn me_private_user_signing_key() -> Ed25519SecretKey {
350 Ed25519SecretKey::from_base64(Self::USER_SIGNING_KEY_PRIVATE_EXPORT).unwrap()
351 }
352
353 pub fn me_keys_query_response() -> KeyQueryResponse {
355 let builder = KeyQueryResponseTemplate::new(Self::me_id().to_owned())
356 .with_cross_signing_keys(
357 Ed25519SecretKey::from_base64(Self::MASTER_KEY_PRIVATE_EXPORT).unwrap(),
358 Ed25519SecretKey::from_base64(Self::SELF_SIGNING_KEY_PRIVATE_EXPORT).unwrap(),
359 Self::me_private_user_signing_key(),
360 );
361
362 let response = builder.build_response();
363 with_settings!({sort_maps => true}, {
364 assert_json_snapshot!(
365 "KeyDistributionTestData__me_keys_query_response",
366 ruma_response_to_json(response.clone()),
367 );
368 });
369 response
370 }
371
372 const DAN_PRIVATE_MASTER_CROSS_SIGNING_KEY: &'static str =
374 "QGZo39k199RM0NYvPvFNXBspc5llftHWKKHqEi25q0U";
375
376 const DAN_PRIVATE_SELF_SIGNING_KEY: &'static str =
378 "0ES1HO5VXpy/BsXxadwsk6QcwH/ci99KkV9ZlPakHlU";
379
380 const DAN_PRIVATE_USER_SIGNING_KEY: &'static str =
382 "vSdfrHJO8sZH/54r1uCg8BE0CdcDVGkPQNOu7Ej8BBs";
383
384 pub fn dan_keys_query_response() -> KeyQueryResponse {
389 let response = Self::dan_keys_query_response_common();
390 with_settings!({sort_maps => true}, {
391 assert_json_snapshot!(
392 "KeyDistributionTestData__dan_keys_query_response",
393 ruma_response_to_json(response.clone()),
394 );
395 });
396 response
397 }
398
399 pub fn dan_keys_query_response_device_loggedout() -> KeyQueryResponse {
401 let mut response = Self::dan_keys_query_response_common();
402 response
403 .device_keys
404 .get_mut(Self::dan_id())
405 .unwrap()
406 .remove(Self::dan_unsigned_device_id());
407
408 with_settings!({sort_maps => true}, {
409 assert_json_snapshot!(
410 "KeyDistributionTestData__dan_keys_query_response_device_loggedout",
411 ruma_response_to_json(response.clone()),
412 );
413 });
414 response
415 }
416
417 fn dan_keys_query_response_common() -> KeyQueryResponse {
423 let builder = KeyQueryResponseTemplate::new(Self::dan_id().to_owned())
424 .with_cross_signing_keys(
425 Ed25519SecretKey::from_base64(Self::DAN_PRIVATE_MASTER_CROSS_SIGNING_KEY).unwrap(),
426 Ed25519SecretKey::from_base64(Self::DAN_PRIVATE_SELF_SIGNING_KEY).unwrap(),
427 Ed25519SecretKey::from_base64(Self::DAN_PRIVATE_USER_SIGNING_KEY).unwrap(),
428 )
429 .with_user_verification_signature(Self::me_id(), &Self::me_private_user_signing_key());
430
431 let builder = builder.with_device(
433 Self::dan_signed_device_id(),
434 &Curve25519PublicKey::from_base64("PBo2nKbink/HxgzMrBftGPogsD0d47LlIMsViTpCRn4")
435 .unwrap(),
436 &Ed25519SecretKey::from_base64("yzj53Kccfqx2yx9lcTwaRfPZX+7jU19harsDWWu5YnM").unwrap(),
437 KeyQueryResponseTemplateDeviceOptions::new().verified(true),
438 );
439
440 let builder = builder.with_device(
442 Self::dan_unsigned_device_id(),
443 &Curve25519PublicKey::from_base64("Hc/BC/xyQIEnScyZkEk+ilDMfOARxHMFoEcggPqqRw4")
444 .unwrap(),
445 &Ed25519SecretKey::from_base64("/SlFtNKxTPN+i4pHzSPWZ1Oc6ymMB33sS32GXZkaLos").unwrap(),
446 KeyQueryResponseTemplateDeviceOptions::new(),
447 );
448
449 builder.build_response()
450 }
451
452 pub fn dave_keys_query_response() -> KeyQueryResponse {
454 let data = json!({
455 "device_keys": {
456 "@dave:localhost": {
457 "HVCXJTHMBM": {
458 "algorithms": [
459 "m.olm.v1.curve25519-aes-sha2",
460 "m.megolm.v1.aes-sha2"
461 ],
462 "device_id": "HVCXJTHMBM",
463 "keys": {
464 "curve25519:HVCXJTHMBM": "0GPOoQwhAGVu1lIvOZway3/XjdxVNHEi5z/4by8TzxU",
465 "ed25519:HVCXJTHMBM": "/4ZzD1Ou70/Ojj5aaPqBopCN8SzQpKM7itiWZ/07fXc"
466 },
467 "signatures": {
468 "@dave:localhost": {
469 "ed25519:HVCXJTHMBM": "b1DV7xN2My2oXbZVVtTeJR9hzXIg1Cx4h+W51+tVq5GAoSYtrWR31PyKPROk28CvQ9Pu++/jdomaW7/oYPxoCg",
470 }
471 },
472 "user_id": "@dave:localhost",
473 }
474 }
475 }
476 });
477
478 ruma_response_from_json(&data)
479 }
480
481 pub fn good_keys_query_response() -> KeyQueryResponse {
483 let data = json!({
484 "device_keys": {
485 "@good:localhost": {
486 "JAXGBVZYLA": {
487 "algorithms": [
488 "m.olm.v1.curve25519-aes-sha2",
489 "m.megolm.v1.aes-sha2"
490 ],
491 "device_id": "JAXGBVZYLA",
492 "keys": {
493 "curve25519:JAXGBVZYLA": "a4vWxnHUKvELfB7WYLCW07vEbwybZReyKReWHxQhgW0",
494 "ed25519:JAXGBVZYLA": "m22nVxqJK72iph+FhOMqX/MDd7AoF9BJ033MlMLnDCg"
495 },
496 "signatures": {
497 "@good:localhost": {
498 "ed25519:JAXGBVZYLA": "EXKQiXNKjWSE76WxF8TUvxjCyw/qsV27gcbsgpSN1zzHzGzVdY1Qr4EB8t/76SL5rZP/9hqcAvqPSJW/N7iKCg",
499 "ed25519:YwQVBWn2sA5lLqp/dQsNk7fiYOuQuQhujefOPjejc+U": "sXJUXKE7hqXnsNbqlzS/1MGlGmeJU54v6/UMWAs+6bCzOFUC1+uqU1KlzfmpsVG3MKxR4r/ZLZdxoKVfUuQMAA"
500 }
501 },
502 "user_id": "@good:localhost"
503 },
504 "ZGLCFWEPCY": {
505 "algorithms": [
506 "m.olm.v1.curve25519-aes-sha2",
507 "m.megolm.v1.aes-sha2"
508 ],
509 "device_id": "ZGLCFWEPCY",
510 "keys": {
511 "curve25519:ZGLCFWEPCY": "kfcIEf6ZRgTP184yuIJYabfsBFsGXiVQE/cyW9qYnQA",
512 "ed25519:ZGLCFWEPCY": "WLSA1tSe0eOZCeESH5WMb9cp3AgRZzm4ooSud+NwcEw"
513 },
514 "signatures": {
515 "@good:localhost": {
516 "ed25519:ZGLCFWEPCY": "AVXFgHk/QcAbOVBF5Xu4OW+03CZKBs2qAYh0fjIA49r+X+aX7QIKrbRyXU/ictPBLMpj1yXF+2J5vwR/KQYVCA",
517 "ed25519:YwQVBWn2sA5lLqp/dQsNk7fiYOuQuQhujefOPjejc+U": "VZk70FWiYN/YSwGykt2CygcOl1bq2D+dVSSKBL5GA5uHXxt6ypDlYvtWprM1l7re3llp5j105MevsjQ+2sWmCw"
518 }
519 },
520 "user_id": "@good:localhost"
521 }
522 }
523 },
524 "failures": {},
525 "master_keys": {
526 "@good:localhost": {
527 "keys": {
528 "ed25519:5vTK2S2wVXo4xGT4BhcwpINVjRLjorkkJgCjnrHgtl8": "5vTK2S2wVXo4xGT4BhcwpINVjRLjorkkJgCjnrHgtl8"
529 },
530 "signatures": {
531 "@good:localhost": {
532 "ed25519:5vTK2S2wVXo4xGT4BhcwpINVjRLjorkkJgCjnrHgtl8": "imAhrTIlPuf6hNqlbcSUnC2ndZPk5NwQLzbi9kZ8nmnPGjmv39f4U4Vh/KiweqQnI4ActGpcYyM7k9S2Ef8/CQ",
533 "ed25519:HPNYOQGUEE": "6w3egsvd+oVPCclef+hF1CfFMZrGTf/plFvPU5iP69WNw4w0UPAKSV1jOzh7Wv4LVGX5O3afjA9DG+O7aHZmBw"
534 }
535 },
536 "usage": [
537 "master"
538 ],
539 "user_id": "@good:localhost"
540 }
541 },
542 "self_signing_keys": {
543 "@good:localhost": {
544 "keys": {
545 "ed25519:YwQVBWn2sA5lLqp/dQsNk7fiYOuQuQhujefOPjejc+U": "YwQVBWn2sA5lLqp/dQsNk7fiYOuQuQhujefOPjejc+U"
546 },
547 "signatures": {
548 "@good:localhost": {
549 "ed25519:5vTK2S2wVXo4xGT4BhcwpINVjRLjorkkJgCjnrHgtl8": "2AyR8lovFv8J1DwPwdCsAM9Tw877QhaVHmVkPopsmSokS2fst8LDQtsg/PiftVc+74NGz5tnYIMDxn4BjAisAg"
550 }
551 },
552 "usage": [
553 "self_signing"
554 ],
555 "user_id": "@good:localhost"
556 }
557 },
558 "user_signing_keys": {
559 "@good:localhost": {
560 "keys": {
561 "ed25519:u1PwO3/a/HTnN9IF7BVa2dJQ7bc00J22eNS0vM4FjTA": "u1PwO3/a/HTnN9IF7BVa2dJQ7bc00J22eNS0vM4FjTA"
562 },
563 "signatures": {
564 "@good:localhost": {
565 "ed25519:5vTK2S2wVXo4xGT4BhcwpINVjRLjorkkJgCjnrHgtl8": "88v9/Z3TJeY2lsu3cFQaEuhHH5ixjJs22ALQRKY+O6VPGCT/BAzH6kUb7teinFfpvQjoXN3t5fVJxbP9mVlxDg"
566 }
567 },
568 "usage": [
569 "user_signing"
570 ],
571 "user_id": "@good:localhost"
572 }
573 }
574 });
575
576 ruma_response_from_json(&data)
577 }
578
579 pub fn me_id() -> &'static UserId {
580 user_id!("@me:localhost")
581 }
582
583 pub fn me_device_id() -> &'static DeviceId {
584 device_id!("ABCDEFGH")
585 }
586
587 pub fn dan_unsigned_device_id() -> &'static DeviceId {
588 device_id!("FRGNMZVOKA")
589 }
590
591 pub fn dan_signed_device_id() -> &'static DeviceId {
592 device_id!("JHPUERYQUW")
593 }
594
595 pub fn dave_device_id() -> &'static DeviceId {
596 device_id!("HVCXJTHMBM")
597 }
598
599 pub fn dan_id() -> &'static UserId {
600 user_id!("@dan:localhost")
601 }
602
603 pub fn dave_id() -> &'static UserId {
604 user_id!("@dave:localhost")
605 }
606
607 pub fn good_id() -> &'static UserId {
608 user_id!("@good:localhost")
609 }
610
611 pub fn good_device_1_id() -> &'static DeviceId {
612 device_id!("JAXGBVZYLA")
613 }
614
615 pub fn good_device_2_id() -> &'static DeviceId {
616 device_id!("ZGLCFWEPCY")
617 }
618}
619
620pub struct IdentityChangeDataSet {}
623
624impl IdentityChangeDataSet {
625 pub fn user_id() -> &'static UserId {
626 assert_eq!(KeysQueryUser::bob_a().user_id, KeysQueryUser::bob_b().user_id);
628 assert_eq!(KeysQueryUser::bob_a().user_id, KeysQueryUser::bob_c().user_id);
629
630 KeysQueryUser::bob_a().user_id
631 }
632
633 pub fn device_a() -> &'static DeviceId {
634 KeysQueryUser::bob_a().device_id
635 }
636
637 pub fn device_b() -> &'static DeviceId {
638 KeysQueryUser::bob_b().device_id
639 }
640
641 pub fn device_c() -> &'static DeviceId {
642 KeysQueryUser::bob_c().device_id
643 }
644
645 pub fn master_signing_keys_a() -> Value {
646 master_keys(&KeysQueryUser::bob_a())
647 }
648
649 pub fn self_signing_keys_a() -> Value {
650 self_signing_keys(&KeysQueryUser::bob_a())
651 }
652
653 pub fn key_query_with_identity_a() -> KeyQueryResponse {
656 keys_query(&KeysQueryUser::bob_a(), &[])
657 }
658
659 pub fn master_signing_keys_b() -> Value {
660 master_keys(&KeysQueryUser::bob_b())
661 }
662
663 pub fn self_signing_keys_b() -> Value {
664 self_signing_keys(&KeysQueryUser::bob_b())
665 }
666
667 pub fn device_keys_payload_2_signed_by_b() -> Value {
668 device_keys_payload(&KeysQueryUser::bob_b())
669 }
670
671 pub fn key_query_with_identity_b() -> KeyQueryResponse {
675 keys_query(&KeysQueryUser::bob_b(), &[KeysQueryUser::bob_a()])
676 }
677
678 pub fn key_query_with_identity_no_identity() -> KeyQueryResponse {
681 keys_query(&KeysQueryUser::bob_c(), &[KeysQueryUser::bob_a(), KeysQueryUser::bob_b()])
682 }
683}
684
685pub struct VerificationViolationTestData {}
701
702impl VerificationViolationTestData {
703 pub const MASTER_KEY_PRIVATE_EXPORT: &'static str =
711 "bSa0nVTocZArMzL7OLmeFUIVF4ycp64rrkVMgqOYg6Y";
712
713 pub const SELF_SIGNING_KEY_PRIVATE_EXPORT: &'static str =
721 "MQ7b3MDXvOEMDvIOWkuH1XCNUyqBLqbdd1bT00p8HPU";
722
723 pub const USER_SIGNING_KEY_PRIVATE_EXPORT: &'static str =
731 "v77s+TlT5/NbcQym2B7Rwf20HOAhyInF2p1ZUYDPtow";
732
733 pub fn own_id() -> &'static UserId {
737 user_id!("@alice:localhost")
738 }
739
740 pub fn bob_id() -> &'static UserId {
742 user_id!("@bob:localhost")
743 }
744
745 pub fn carol_id() -> &'static UserId {
747 user_id!("@carol:localhost")
748 }
749
750 pub fn own_keys_query_response_1() -> KeyQueryResponse {
753 let builder = KeyQueryResponseTemplate::new(Self::own_id().to_owned())
754 .with_cross_signing_keys(
755 Ed25519SecretKey::from_base64(Self::MASTER_KEY_PRIVATE_EXPORT).unwrap(),
756 Ed25519SecretKey::from_base64(Self::SELF_SIGNING_KEY_PRIVATE_EXPORT).unwrap(),
757 Ed25519SecretKey::from_base64(Self::USER_SIGNING_KEY_PRIVATE_EXPORT).unwrap(),
758 );
759
760 let response = builder.build_response();
761 with_settings!({sort_maps => true}, {
762 assert_json_snapshot!(
763 "VerificationViolationTestData__own_keys_query_response_1",
764 ruma_response_to_json(response.clone()),
765 );
766 });
767 response
768 }
769
770 pub fn own_keys_query_response_2() -> KeyQueryResponse {
775 let data = json!({
776 "master_keys": {
777 "@alice:localhost": {
778 "keys": { "ed25519:J+5An10v1vzZpAXTYFokD1/PEVccFnLC61EfRXit0UY": "J+5An10v1vzZpAXTYFokD1/PEVccFnLC61EfRXit0UY" },
779 "user_id": "@alice:localhost",
780 "usage": [ "master" ]
781 }
782 },
783 "self_signing_keys": {
784 "@alice:localhost": {
785 "keys": { "ed25519:aU2+2CyXQTCuDcmWW0EL2bhJ6PdjFW2LbAsbHqf02AY": "aU2+2CyXQTCuDcmWW0EL2bhJ6PdjFW2LbAsbHqf02AY" },
786 "user_id": "@alice:localhost",
787 "usage": [ "self_signing" ],
788 "signatures": {
789 "@alice:localhost": {
790 "ed25519:J+5An10v1vzZpAXTYFokD1/PEVccFnLC61EfRXit0UY": "XfhYEhZmOs8BJdb3viatILBZ/bElsHXEW28V4tIaY5CxrBR0YOym3yZHWmRmypXessHZAKOhZn3yBMXzdajyCw"
791 }
792 }
793 }
794 },
795 "user_signing_keys": {
796 "@alice:localhost": {
797 "keys": { "ed25519:g5TC/zjQXyZYuDLZv7a41z5fFVrXpYPypG//AFQj8hY": "g5TC/zjQXyZYuDLZv7a41z5fFVrXpYPypG//AFQj8hY" },
798 "user_id": "@alice:localhost",
799 "usage": [ "user_signing" ],
800 "signatures": {
801 "@alice:localhost": {
802 "ed25519:J+5An10v1vzZpAXTYFokD1/PEVccFnLC61EfRXit0UY": "6AkD1XM2H0/ebgP9oBdMKNeft7uxsrb0XN1CsjjHgeZCvCTMmv3BHlLiT/Hzy4fe8H+S1tr484dcXN/PIdnfDA"
803 }
804 }
805 }
806 }
807 });
808
809 ruma_response_from_json(&data)
810 }
811
812 pub fn own_unsigned_device_id() -> OwnedDeviceId {
814 Self::own_unsigned_device_keys().0
815 }
816
817 pub fn own_unsigned_device_keys() -> (OwnedDeviceId, Raw<DeviceKeys>) {
824 let json = json!({
825 "algorithms": [
826 "m.olm.v1.curve25519-aes-sha2",
827 "m.megolm.v1.aes-sha2"
828 ],
829 "device_id": "AHIVRZICJK",
830 "keys": {
831 "curve25519:AHIVRZICJK": "3U73fbymtt6sn/H+5UYHiQxN2HfDmxzOMYZ+3JyPT2E",
832 "ed25519:AHIVRZICJK": "I0NV5nJYmnH+f5py4Fz2tdCeSKUChaaXV7m4UOq9bis"
833 },
834 "signatures": {
835 "@alice:localhost": {
836 "ed25519:AHIVRZICJK": "HIs13b2GizN8gdZrYLWs9KZbcmKubXE+O4716Uow513e84JO8REy53OX4TDdoBfmVhPiZg5CIRrUDH7JxY4wAQ"
837 }
838 },
839 "user_id": "@alice:localhost",
840 "unsigned": {
841 "device_display_name": "Element - dbg Android"
842 }
843 });
844 (owned_device_id!("AHIVRZICJK"), serde_json::from_value(json).unwrap())
845 }
846
847 pub fn own_signed_device_id() -> OwnedDeviceId {
849 Self::own_signed_device_keys().0
850 }
851
852 pub fn own_signed_device_keys() -> (OwnedDeviceId, Raw<DeviceKeys>) {
859 let json = json!({
860 "algorithms": [
861 "m.olm.v1.curve25519-aes-sha2",
862 "m.megolm.v1.aes-sha2"
863 ],
864 "device_id": "LCNRWQAVWK",
865 "keys": {
866 "curve25519:LCNRWQAVWK": "fULFq9I6uYmsdDwRFU76wc43RqF7TVGvlWvKXhSrsS4",
867 "ed25519:LCNRWQAVWK": "F7E0EF0lzVJN31cnetLdeBuNvZ8jQqkUzt8/nGD9M/E"
868 },
869 "signatures": {
870 "@alice:localhost": {
871 "ed25519:LCNRWQAVWK": "8kLsN76ytGRuHKMgIARaOds29QrPRzQ6Px+FOLsYK/ATmx5IVd65MpSh2pGjLAaPsSGWR1WLbBTq/LZtcpjTDQ",
872 "ed25519:WXLer0esHUanp8DCeu2Be0xB5ms9aKFFBrCFl50COjw": "lo4Vuuu+WvPt1hnOCv30iS1y/cF7DljfFZYF3ib5JH/6iPZTW4jYdlmWo4a7hDf0fb2pu3EFnghYMr7vVx41Aw"
873 }
874 },
875 "user_id": "@alice:localhost",
876 "unsigned": {
877 "device_display_name": "develop.element.io: Chrome on macOS"
878 }
879 });
880 (owned_device_id!("LCNRWQAVWK"), serde_json::from_value(json).unwrap())
881 }
882
883 pub fn bob_keys_query_response_signed() -> KeyQueryResponse {
889 let data = json!({
890 "device_keys": {
891 "@bob:localhost": {
892 "RLZGZIHKMP": {
893 "algorithms": [
894 "m.olm.v1.curve25519-aes-sha2",
895 "m.megolm.v1.aes-sha2"
896 ],
897 "device_id": "RLZGZIHKMP",
898 "keys": {
899 "curve25519:RLZGZIHKMP": "Zd8uO9Rr1PtqNno3//ybeUZ3JuqFtm17TQTWW0f47AU",
900 "ed25519:RLZGZIHKMP": "kH+Zn2m7LPES/XLOyVvnf8t4Byfj3mAbngHptHZFzk0"
901 },
902 "signatures": {
903 "@bob:localhost": {
904 "ed25519:RLZGZIHKMP": "w4MOkDiD+4XatQrRzGrcaqwVmiZrAjxmaIA8aSuzQveD2SJ2eVZq3OSpqx6QRUbG/gkkZxGmY13PkS/iAOv0AA",
905 "ed25519:e8JFSrW8LW3UK6SSXh2ZESUzptFbapr28/+WqndD+Xk": "ki+cV0EVe5cYXnzqU078qy1qu2rnaxaBQU+KwyvPpEUotNTXjWKUOJfxast42d5tjI5vsI5aiQ6XkYfjBJ74Bw"
906 }
907 },
908 "user_id": "@bob:localhost",
909 "unsigned": {}
910 },
911 "XCYNVRMTER": {
912 "algorithms": [
913 "m.olm.v1.curve25519-aes-sha2",
914 "m.megolm.v1.aes-sha2"
915 ],
916 "device_id": "XCYNVRMTER",
917 "keys": {
918 "curve25519:XCYNVRMTER": "xGKYkFcHGlJ+I1yiefPyZu1EY8i2h1eed5uk3PAW6GA",
919 "ed25519:XCYNVRMTER": "EsU8MJzTYE+/VJs1K9HkGqb8UXCByPioynGrV28WocU"
920 },
921 "signatures": {
922 "@bob:localhost": {
923 "ed25519:XCYNVRMTER": "yZ7cpaoA+0rRx+bmklsP1iAd0eGPH6gsdywC11VE98/mrcbeFuxjQVn39Ds7h+vmciu5GRzwWgDgv+6go6FHAQ",
924 }
927 },
928 "user_id": "@bob:localhost",
929 "unsigned": {},
930 },
931 }
932 },
933 "failures": {},
934 "master_keys": {
935 "@bob:localhost": {
936 "keys": {
937 "ed25519:xZPyb4hxM8zaedDFz5m8HsDpX1fknd/V/69THLhNX9I": "xZPyb4hxM8zaedDFz5m8HsDpX1fknd/V/69THLhNX9I"
938 },
939 "signatures": {
940 "@bob:localhost": {
941 "ed25519:RLZGZIHKMP": "5bHLrx0HwYsNRtd65s1a1wVGlwgJU8yb8cq/Qbq04o9nVdQuY8+woQVWq9nxk59u6QFZIpFdVjXsuTPkDJLsBA",
942 "ed25519:xZPyb4hxM8zaedDFz5m8HsDpX1fknd/V/69THLhNX9I": "NA+cLNIPpmECcBIcmAH5l1K4IDXI6Xss1VmU8TZ04AYQSAh/2sv7NixEBO1/Raz0nErzkOl8gpRswHbHv1p7Dw"
943 },
944 "@alice:localhost": {
945 "ed25519:MXob/N/bYI7U2655O1/AI9NOX1245RnE03Nl4Hvf+u0": "n3X6afWYoSywqBpPlaDfQ2BNjl3ez5AzxEVwaB5/KEAzgwsq5B2qBW9N5uZaNWEq5M3JBrh0doj1FgUg4R3yBQ"
946 }
947 },
948 "usage": [
949 "master"
950 ],
951 "user_id": "@bob:localhost"
952 }
953 },
954 "self_signing_keys": {
955 "@bob:localhost": {
956 "keys": {
957 "ed25519:e8JFSrW8LW3UK6SSXh2ZESUzptFbapr28/+WqndD+Xk": "e8JFSrW8LW3UK6SSXh2ZESUzptFbapr28/+WqndD+Xk"
958 },
959 "signatures": {
960 "@bob:localhost": {
961 "ed25519:xZPyb4hxM8zaedDFz5m8HsDpX1fknd/V/69THLhNX9I": "kkGZHLY18jyqXs412VB31u6vxijbaBgVrIMR/LBAFULhTZk6HGH951N6NxMZnYHyH0sFaQhsl4DUqt7XthBHBQ"
962 }
963 },
964 "usage": [
965 "self_signing"
966 ],
967 "user_id": "@bob:localhost"
968 }
969 },
970 "user_signing_keys": {}
971 });
972
973 ruma_response_from_json(&data)
974 }
975
976 pub fn bob_device_1_id() -> &'static DeviceId {
981 device_id!("RLZGZIHKMP")
982 }
983
984 pub fn bob_device_2_id() -> &'static DeviceId {
989 device_id!("XCYNVRMTER")
990 }
991
992 pub fn bob_keys_query_response_rotated() -> KeyQueryResponse {
1001 let data = json!({
1002 "device_keys": {
1003 "@bob:localhost": {
1004 "RLZGZIHKMP": {
1005 "algorithms": [
1006 "m.olm.v1.curve25519-aes-sha2",
1007 "m.megolm.v1.aes-sha2"
1008 ],
1009 "device_id": "RLZGZIHKMP",
1010 "keys": {
1011 "curve25519:RLZGZIHKMP": "Zd8uO9Rr1PtqNno3//ybeUZ3JuqFtm17TQTWW0f47AU",
1012 "ed25519:RLZGZIHKMP": "kH+Zn2m7LPES/XLOyVvnf8t4Byfj3mAbngHptHZFzk0"
1013 },
1014 "signatures": {
1015 "@bob:localhost": {
1016 "ed25519:RLZGZIHKMP": "w4MOkDiD+4XatQrRzGrcaqwVmiZrAjxmaIA8aSuzQveD2SJ2eVZq3OSpqx6QRUbG/gkkZxGmY13PkS/iAOv0AA",
1017 "ed25519:e8JFSrW8LW3UK6SSXh2ZESUzptFbapr28/+WqndD+Xk": "ki+cV0EVe5cYXnzqU078qy1qu2rnaxaBQU+KwyvPpEUotNTXjWKUOJfxast42d5tjI5vsI5aiQ6XkYfjBJ74Bw"
1019 }
1020 },
1021 "user_id": "@bob:localhost",
1022 "unsigned": {
1023 "device_display_name": "develop.element.io: Chrome on macOS"
1024 }
1025 },
1026 "XCYNVRMTER": {
1027 "algorithms": [
1028 "m.olm.v1.curve25519-aes-sha2",
1029 "m.megolm.v1.aes-sha2"
1030 ],
1031 "device_id": "XCYNVRMTER",
1032 "keys": {
1033 "curve25519:XCYNVRMTER": "xGKYkFcHGlJ+I1yiefPyZu1EY8i2h1eed5uk3PAW6GA",
1034 "ed25519:XCYNVRMTER": "EsU8MJzTYE+/VJs1K9HkGqb8UXCByPioynGrV28WocU"
1035 },
1036 "signatures": {
1037 "@bob:localhost": {
1038 "ed25519:XCYNVRMTER": "yZ7cpaoA+0rRx+bmklsP1iAd0eGPH6gsdywC11VE98/mrcbeFuxjQVn39Ds7h+vmciu5GRzwWgDgv+6go6FHAQ",
1039 "ed25519:e8JFSrW8LW3UK6SSXh2ZESUzptFbapr28/+WqndD+Xk": "xYnGmU9FEdoavB5P743gx3xbEy29tlfRX5lT3JO0dWhHdsP+muqBXUYMBl1RRFeZtIE0GYc9ORb6Yf88EdeoCw",
1040 "ed25519:NWoyMF4Ox8PEj+8l1e70zuIUg0D+wL9wtcj1KhWL0Bc": "2ieX8z+oW9JhdyIIkTDsQ2o5VWxcO6dOgeyPbRwbAL6Q8J6xujzYSIi568UAlPt+wg+RkNLshneexCPNMgSiDQ"
1041 }
1042 },
1043 "user_id": "@bob:localhost",
1044 "unsigned": {
1045 "device_display_name": "app.element.io: Chrome on mac"
1046 }
1047 }
1048 }
1049 },
1050 "failures": {},
1051 "master_keys": {
1052 "@bob:localhost": {
1053 "keys": {
1054 "ed25519:xaFlsDqlDRRy7Idtt1dW9mdhH/gvvax34q+HxepjNWY": "xaFlsDqlDRRy7Idtt1dW9mdhH/gvvax34q+HxepjNWY"
1055 },
1056 "signatures": {
1057 "@bob:localhost": {
1058 "ed25519:XCYNVRMTER": "K1aPl+GtcNi8yDqn1zvKIJMg3PFLQkwoXJeFJMmct4SA2SiQIl1S2x1bDTC3kQ4/LA7ULiQgKlxkXdQVf2GZDw",
1059 "ed25519:xaFlsDqlDRRy7Idtt1dW9mdhH/gvvax34q+HxepjNWY": "S5vw8moiPudKhmF1qIv3/ehbZ7uohJbcQaLcOV+DDh9iC/YX0UqnaGn1ZYWJpIN7Kxe2ZWCBwzp35DOVZKfxBw"
1060 }
1061 },
1062 "usage": [
1063 "master"
1064 ],
1065 "user_id": "@bob:localhost"
1066 }
1067 },
1068 "self_signing_keys": {
1069 "@bob:localhost": {
1070 "keys": {
1071 "ed25519:NWoyMF4Ox8PEj+8l1e70zuIUg0D+wL9wtcj1KhWL0Bc": "NWoyMF4Ox8PEj+8l1e70zuIUg0D+wL9wtcj1KhWL0Bc"
1072 },
1073 "signatures": {
1074 "@bob:localhost": {
1075 "ed25519:xaFlsDqlDRRy7Idtt1dW9mdhH/gvvax34q+HxepjNWY": "rwQIkR7JbZOrwGrmkW9QzFlK+lMjRDHVcGVlYNS/zVeDyvWxD0WFHcmy4p/LSgJDyrVt+th7LH7Bj+Ed/EGvCw"
1076 }
1077 },
1078 "usage": [
1079 "self_signing"
1080 ],
1081 "user_id": "@bob:localhost"
1082 }
1083 },
1084 "user_signing_keys": {}
1085 });
1086
1087 ruma_response_from_json(&data)
1088 }
1089
1090 pub fn carol_signed_device_id() -> &'static DeviceId {
1096 device_id!("JBRBCHOFDZ")
1097 }
1098
1099 pub fn carol_unsigned_device_id() -> &'static DeviceId {
1105 device_id!("BAZAPVEHGA")
1106 }
1107
1108 fn device_1_keys_payload_carol() -> Value {
1113 json!({
1114 "algorithms": [
1115 "m.olm.v1.curve25519-aes-sha2",
1116 "m.megolm.v1.aes-sha2"
1117 ],
1118 "device_id": "BAZAPVEHGA",
1119 "keys": {
1120 "curve25519:BAZAPVEHGA": "/mCcWJb5mtNGPC7m4iQeW8gVJB4nG8z/z2QQXzzNijw",
1121 "ed25519:BAZAPVEHGA": "MLSoOlk27qcS/2O9Etp6XwgF8j+UT06yy/ypSeE9JRA"
1122 },
1123 "signatures": {
1124 "@carol:localhost": {
1125 "ed25519:BAZAPVEHGA": "y2+Z0ofRRoNMj864SoAcNEXRToYVeiARu39CO0Vj2GcSIxlpR7B8K1wDYV4luP4gOL1t1tPgJPXL1WO//AHHCw",
1126 }
1127 },
1128 "user_id": "@carol:localhost"
1129 })
1130 }
1131
1132 fn device_2_keys_payload_carol() -> Value {
1135 json!({
1136 "algorithms": [
1137 "m.olm.v1.curve25519-aes-sha2",
1138 "m.megolm.v1.aes-sha2"
1139 ],
1140 "device_id": "JBRBCHOFDZ",
1141 "keys": {
1142 "curve25519:JBRBCHOFDZ": "900HdrlfxlH8yMSmEQ3C32uVyXCuxKs5oPKS/wUgzVQ",
1143 "ed25519:JBRBCHOFDZ": "BOINY06uroLYscHUq0e0FmUo/W0LC4/fsIPkZQe71NY"
1144 },
1145 "signatures": {
1146 "@carol:localhost": {
1147 "ed25519:JBRBCHOFDZ": "MmSJS3yEdeuseiLTDCQwImZBPNFMdhhkAFjRZZrIONoGFR0AMSzgLtx/nSgXP8RwVxpycvb6OAqvSk2toK3PDg",
1148 "ed25519:ZOMWgk5LAogkwDEdZl9Rv7FRGu0nGbeLtMHx6anzhQs": "VtoxmPn/BQVDlpEHPEI2wPUlruUX9m2zV3FChNkRyEEWur4St27WA1He8BwjVRiiT0bdUnVH3xfmucoV9UnbDA"
1149 }
1150 },
1151 "user_id": "@carol:localhost",
1152 })
1153 }
1154
1155 fn ssk_payload_carol() -> Value {
1157 json!({
1158 "@carol:localhost": {
1159 "keys": {
1160 "ed25519:ZOMWgk5LAogkwDEdZl9Rv7FRGu0nGbeLtMHx6anzhQs": "ZOMWgk5LAogkwDEdZl9Rv7FRGu0nGbeLtMHx6anzhQs"
1161 },
1162 "signatures": {
1163 "@carol:localhost": {
1164 "ed25519:itnwUCRfBPW08IrmBks9MTp/Qm5AJ2WNca13ptIZF8U": "thjR1/kxHADXqLqxc4Q3OZhAaLq7SPL96LNCGVGN64OYAJ5yG1cpqAXBiBCUaBUTdRTb0ys601RR8djPdTK/BQ"
1165 }
1166 },
1167 "usage": [
1168 "self_signing"
1169 ],
1170 "user_id": "@carol:localhost"
1171 }
1172 })
1173 }
1174
1175 pub fn carol_keys_query_response_unsigned() -> KeyQueryResponse {
1183 let data = json!({
1184 "device_keys": {
1185 "@carol:localhost": {
1186 "BAZAPVEHGA": Self::device_1_keys_payload_carol(),
1187 "JBRBCHOFDZ": Self::device_2_keys_payload_carol()
1188 }
1189 },
1190 "failures": {},
1191 "master_keys": {
1192 "@carol:localhost": {
1193 "keys": {
1194 "ed25519:itnwUCRfBPW08IrmBks9MTp/Qm5AJ2WNca13ptIZF8U": "itnwUCRfBPW08IrmBks9MTp/Qm5AJ2WNca13ptIZF8U"
1195 },
1196 "signatures": {
1197 "@carol:localhost": {
1198 "ed25519:JBRBCHOFDZ": "eRA4jRSszQVuYpMtHTBuWGLEzcdUojyCW4/XKHRIQ2solv7iTC/MWES6I20YrHJa7H82CVoyNxS1Y3AwttBbCg",
1199 "ed25519:itnwUCRfBPW08IrmBks9MTp/Qm5AJ2WNca13ptIZF8U": "e3r5L+JLv6FB8+Tt4BlIbz4wk2qPeMoKL1uR079qZzYMvtKoWGK9p000cZIhA5R1Tl7buQ9ODUfizued8g3TAg"
1200 },
1201 },
1206 "usage": [
1207 "master"
1208 ],
1209 "user_id": "@carol:localhost"
1210 }
1211 },
1212 "self_signing_keys": Self::ssk_payload_carol(),
1213 "user_signing_keys": {}
1214 });
1215
1216 ruma_response_from_json(&data)
1217 }
1218
1219 pub fn carol_keys_query_response_signed() -> KeyQueryResponse {
1224 let data = json!({
1225 "device_keys": {
1226 "@carol:localhost": {
1227 "BAZAPVEHGA": Self::device_1_keys_payload_carol(),
1228 "JBRBCHOFDZ": Self::device_2_keys_payload_carol()
1229 }
1230 },
1231 "failures": {},
1232 "master_keys": {
1233 "@carol:localhost": {
1234 "keys": {
1235 "ed25519:itnwUCRfBPW08IrmBks9MTp/Qm5AJ2WNca13ptIZF8U": "itnwUCRfBPW08IrmBks9MTp/Qm5AJ2WNca13ptIZF8U"
1236 },
1237 "signatures": {
1238 "@carol:localhost": {
1239 "ed25519:JBRBCHOFDZ": "eRA4jRSszQVuYpMtHTBuWGLEzcdUojyCW4/XKHRIQ2solv7iTC/MWES6I20YrHJa7H82CVoyNxS1Y3AwttBbCg",
1240 "ed25519:itnwUCRfBPW08IrmBks9MTp/Qm5AJ2WNca13ptIZF8U": "e3r5L+JLv6FB8+Tt4BlIbz4wk2qPeMoKL1uR079qZzYMvtKoWGK9p000cZIhA5R1Tl7buQ9ODUfizued8g3TAg"
1241 },
1242 "@alice:localhost": {
1243 "ed25519:MXob/N/bYI7U2655O1/AI9NOX1245RnE03Nl4Hvf+u0": "yfRUvkaVg3KizC/HDXcuP4+gtYhxgzr8X916Wt4GRXjj4qhDjsCkf8mYZ7x4lcEXzRkYql5KelabgVzP12qmAA"
1244 }
1245 },
1246 "usage": [
1247 "master"
1248 ],
1249 "user_id": "@carol:localhost"
1250 }
1251 },
1252 "self_signing_keys": Self::ssk_payload_carol(),
1253 "user_signing_keys": {}
1254 });
1255
1256 ruma_response_from_json(&data)
1257 }
1258}
1259
1260pub struct MaloIdentityChangeDataSet {}
1263
1264impl MaloIdentityChangeDataSet {
1265 pub fn user_id() -> &'static UserId {
1266 user_id!("@malo:localhost")
1267 }
1268
1269 pub fn device_id() -> &'static DeviceId {
1270 device_id!("NZFSPBRLDO")
1271 }
1272
1273 pub fn initial_key_query() -> KeyQueryResponse {
1275 let data = json!({
1276 "device_keys": {
1277 "@malo:localhost": {
1278 "NZFSPBRLDO": {
1279 "algorithms": [
1280 "m.olm.v1.curve25519-aes-sha2",
1281 "m.megolm.v1.aes-sha2"
1282 ],
1283 "device_id": "NZFSPBRLDO",
1284 "keys": {
1285 "curve25519:NZFSPBRLDO": "L3jdbw42+9i+K7LPjAY+kmqG9nr2n/U0ow8hEbLCoCs",
1286 "ed25519:NZFSPBRLDO": "VDJt3xI4SzrgQkuE3sEIauluaXawx3wWoWOynPI8Zko"
1287 },
1288 "signatures": {
1289 "@malo:localhost": {
1290 "ed25519:NZFSPBRLDO": "lmtbdrJ5xBweo677Fg2qrSHsRi4R3x2WNlvSNJY6Zbg0R5lJS9syN2HZw/irL9PA644GYm4QM/t+DX0grnn+BQ",
1291 "ed25519:+wbxNfSuDrch1jKuydQmEf4qlA4u4NgwqNXNuLVwug8": "Ql1fq+SvVDx+8mjNMzSaR0hBCEkdPirbs2+BK0gwsIH1zkuMADnBoNWP7LJiKo/EO9gnpiCzyQQgI4e9pIVPDA"
1292 }
1293 },
1294 "user_id": "@malo:localhost",
1295 "unsigned": {}
1296 }
1297 }
1298 },
1299 "failures": {},
1300 "master_keys": {
1301 "@malo:localhost": {
1302 "keys": {
1303 "ed25519:WBxliSP29guYr4ux0MW6otRe3V/wOLXXElpOcOmpdlE": "WBxliSP29guYr4ux0MW6otRe3V/wOLXXElpOcOmpdlE"
1304 },
1305 "signatures": {
1306 "@malo:localhost": {
1307 "ed25519:NZFSPBRLDO": "crJcXqFpEHRM8KNUw419XrVFaHoM8/kV4ebgpuuIiD9wfX0AhHE2iGRGpKzsrVCqne9k181/uN0sgDMpK2y4Aw",
1308 "ed25519:WBxliSP29guYr4ux0MW6otRe3V/wOLXXElpOcOmpdlE": "/xwFF5AC3GhkpvJ449Srh8kNQS6CXAxQMmBpQvPEHx5BHPXJ08u2ZDd1EPYY4zk4QsePk+tEYu8gDnB0bggHCA"
1309 }
1310 },
1311 "usage": [
1312 "master"
1313 ],
1314 "user_id": "@malo:localhost"
1315 }
1316 },
1317 "self_signing_keys": {
1318 "@malo:localhost": {
1319 "keys": {
1320 "ed25519:+wbxNfSuDrch1jKuydQmEf4qlA4u4NgwqNXNuLVwug8": "+wbxNfSuDrch1jKuydQmEf4qlA4u4NgwqNXNuLVwug8"
1321 },
1322 "signatures": {
1323 "@malo:localhost": {
1324 "ed25519:WBxliSP29guYr4ux0MW6otRe3V/wOLXXElpOcOmpdlE": "sSGQ6ny6aXtIvgKPGOYJzcmnNDSkbaJFVRe9wekOry7EaiWf2l28MkGTUBt4cPoRiMkNjuRBupNEARqHF72sAQ"
1325 }
1326 },
1327 "usage": [
1328 "self_signing"
1329 ],
1330 "user_id": "@malo:localhost"
1331 }
1332 },
1333 "user_signing_keys": {},
1334 });
1335
1336 ruma_response_from_json(&data)
1337 }
1338
1339 pub fn updated_key_query() -> KeyQueryResponse {
1341 let data = json!({
1342 "device_keys": {
1343 "@malo:localhost": {
1344 "NZFSPBRLDO": {
1345 "algorithms": [
1346 "m.olm.v1.curve25519-aes-sha2",
1347 "m.megolm.v1.aes-sha2"
1348 ],
1349 "device_id": "NZFSPBRLDO",
1350 "keys": {
1351 "curve25519:NZFSPBRLDO": "L3jdbw42+9i+K7LPjAY+kmqG9nr2n/U0ow8hEbLCoCs",
1352 "ed25519:NZFSPBRLDO": "VDJt3xI4SzrgQkuE3sEIauluaXawx3wWoWOynPI8Zko"
1353 },
1354 "signatures": {
1355 "@malo:localhost": {
1356 "ed25519:NZFSPBRLDO": "lmtbdrJ5xBweo677Fg2qrSHsRi4R3x2WNlvSNJY6Zbg0R5lJS9syN2HZw/irL9PA644GYm4QM/t+DX0grnn+BQ",
1357 "ed25519:+wbxNfSuDrch1jKuydQmEf4qlA4u4NgwqNXNuLVwug8": "Ql1fq+SvVDx+8mjNMzSaR0hBCEkdPirbs2+BK0gwsIH1zkuMADnBoNWP7LJiKo/EO9gnpiCzyQQgI4e9pIVPDA",
1358 "ed25519:8my6+zgnzEP0ZqmQFyvscJh7isHlf8lxBmHg+fzdJkE": "OvqDE7C2mrHxjwNyMIEz+m/AO6I6lM5HoPYY2bvLjrJJDOF5sJOtw4JoYiCWyt90ZIWsbEqmfbazrblLD50tCg"
1359 }
1360 },
1361 "user_id": "@malo:localhost",
1362 "unsigned": {}
1363 }
1364 }
1365 },
1366 "failures": {},
1367 "master_keys": {
1368 "@malo:localhost": {
1369 "keys": {
1370 "ed25519:dv2Mk7bFlRtP/0oSZpB01Ouc5frCXKfG8Bn9YrFxbxU": "dv2Mk7bFlRtP/0oSZpB01Ouc5frCXKfG8Bn9YrFxbxU"
1371 },
1372 "signatures": {
1373 "@malo:localhost": {
1374 "ed25519:NZFSPBRLDO": "2Ye96l4srBSWskNQszuMpea1r97rFoUyfNqegvu/hGeP47w0OVvqYuNtZRNwqb7TMS7aPEn6l9lhWEk7v06wCg",
1375 "ed25519:dv2Mk7bFlRtP/0oSZpB01Ouc5frCXKfG8Bn9YrFxbxU": "btkxAJpJeVtc9wgBmeHUI9QDpojd6ddLxK11E3403KoTQtP6Mnr5GsVdQr1HJToG7PG4k4eEZGWxVZr1GPndAA"
1376 }
1377 },
1378 "usage": [
1379 "master"
1380 ],
1381 "user_id": "@malo:localhost"
1382 }
1383 },
1384 "self_signing_keys": {
1385 "@malo:localhost": {
1386 "keys": {
1387 "ed25519:8my6+zgnzEP0ZqmQFyvscJh7isHlf8lxBmHg+fzdJkE": "8my6+zgnzEP0ZqmQFyvscJh7isHlf8lxBmHg+fzdJkE"
1388 },
1389 "signatures": {
1390 "@malo:localhost": {
1391 "ed25519:dv2Mk7bFlRtP/0oSZpB01Ouc5frCXKfG8Bn9YrFxbxU": "KJt0y1p8v8RGLGk2wUyCMbX1irXJqup/mdRuG/cxJxs24BZhDMyIzyGrGXnWq2gx3I4fKIMtFPi/ecxf92ePAQ"
1392 }
1393 },
1394 "usage": [
1395 "self_signing"
1396 ],
1397 "user_id": "@malo:localhost"
1398 }
1399 },
1400 "user_signing_keys": {}
1401 });
1402
1403 ruma_response_from_json(&data)
1404 }
1405}
1406
1407fn calculate_json_signature(mut value: Value, signing_key: &Ed25519SecretKey) -> Ed25519Signature {
1415 let json_object = value.as_object_mut().expect("value must be object");
1417 json_object.remove("signatures");
1418 json_object.remove("unsigned");
1419
1420 let canonical_json: CanonicalJsonValue =
1421 value.try_into().expect("could not convert to canonicaljson");
1422
1423 signing_key.sign(canonical_json.to_string().as_ref())
1425}
1426
1427fn sign_json(
1443 value: &mut Value,
1444 signing_key: &Ed25519SecretKey,
1445 user_id: &UserId,
1446 key_identifier: &str,
1447) {
1448 let signature = calculate_json_signature(value.clone(), signing_key);
1449
1450 let value_obj = value.as_object_mut().expect("value must be object");
1451
1452 let signatures_obj = value_obj
1453 .entry("signatures")
1454 .or_insert_with(|| serde_json::Map::new().into())
1455 .as_object_mut()
1456 .expect("signatures key must be object");
1457
1458 let user_signatures_obj = signatures_obj
1459 .entry(user_id.to_string())
1460 .or_insert_with(|| serde_json::Map::new().into())
1461 .as_object_mut()
1462 .expect("signatures keys must be object");
1463
1464 user_signatures_obj.insert(format!("ed25519:{key_identifier}"), signature.to_base64().into());
1465}
1466
1467fn sign_cross_signing_key(
1479 value: &mut CrossSigningKey,
1480 signing_key: &Ed25519SecretKey,
1481 user_id: &UserId,
1482) {
1483 let key_json = serde_json::to_value(value.clone()).unwrap();
1484 let signature = calculate_json_signature(key_json, signing_key);
1485
1486 let signing_key_id: OwnedBase64PublicKeyOrDeviceId =
1488 OwnedBase64PublicKey::with_bytes(signing_key.public_key().as_bytes()).into();
1489
1490 value.signatures.insert_signature(
1491 user_id.to_owned(),
1492 CrossSigningOrDeviceSigningKeyId::from_parts(SigningKeyAlgorithm::Ed25519, &signing_key_id),
1493 signature.to_base64(),
1494 );
1495}