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