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