diff --git a/crates/matrix-sdk-crypto/src/identities/manager.rs b/crates/matrix-sdk-crypto/src/identities/manager.rs index 5f9585381..64146332a 100644 --- a/crates/matrix-sdk-crypto/src/identities/manager.rs +++ b/crates/matrix-sdk-crypto/src/identities/manager.rs @@ -2023,4 +2023,269 @@ pub(crate) mod tests { assert!(!other_identity.has_pin_violation()); } + + // Set up a machine do initial own key query and import cross-signing secret to + // make the current session verified. + async fn common_verification_latch_machine_setup() -> OlmMachine { + use test_json::keys_query_sets::VerificationLatchTestData as DataSet; + + let machine = OlmMachine::new(DataSet::own_id(), device_id!("LOCAL")).await; + + let keys_query = DataSet::own_keys_query_response_1(); + let txn_id = TransactionId::new(); + machine.mark_request_as_sent(&txn_id, &keys_query).await.unwrap(); + + machine + .import_cross_signing_keys(CrossSigningKeyExport { + master_key: DataSet::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(), + self_signing_key: DataSet::SELF_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(), + user_signing_key: DataSet::USER_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(), + }) + .await + .unwrap(); + machine + } + #[async_test] + async fn test_manager_verified_latch_setup_on_new_identities() { + use test_json::keys_query_sets::VerificationLatchTestData as DataSet; + + let machine = common_verification_latch_machine_setup().await; + + // ###### + // First test: Assert that the latch is properly set on new identities + // ###### + let keys_query = DataSet::bob_keys_query_response_signed(); + let txn_id = TransactionId::new(); + machine.mark_request_as_sent(&txn_id, &keys_query).await.unwrap(); + + let own_identity = + machine.get_identity(DataSet::own_id(), None).await.unwrap().unwrap().own().unwrap(); + // For sanity check that own identity is trusted + assert!(own_identity.is_verified()); + + let bob_identity = + machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap().other().unwrap(); + // The verified latch should be true + assert!(bob_identity.is_verified_latch_set()); + // And bob is verified + assert!(bob_identity.is_verified()); + + // ###### + // Second test: Assert that the local latch stays on if the identity is rotated + // ###### + let keys_query = DataSet::bob_keys_query_response_rotated(); + let txn_id = TransactionId::new(); + machine.mark_request_as_sent(&txn_id, &keys_query).await.unwrap(); + + let bob_identity = + machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap().other().unwrap(); + // Bob is not verified anymore + assert!(!bob_identity.is_verified()); + // The verified latch should still be true + assert!(bob_identity.is_verified_latch_set()); + // Bob device_2 is self-signed even if there is this verification latch + // violation + let bob_device = machine + .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None) + .await + .unwrap() + .unwrap(); + assert!(bob_identity.is_device_signed(&bob_device).is_ok()); + // there is also a pin violation + assert!(bob_identity.has_pin_violation()); + // Fixing the pin violation won't fix the verification latch violation + bob_identity.pin_current_master_key().await.unwrap(); + assert!(!bob_identity.has_pin_violation()); + let has_latch_violation = + bob_identity.is_verified_latch_set() && !bob_identity.is_verified(); + assert!(has_latch_violation); + } + + #[async_test] + async fn test_manager_verified_latch_setup_on_updated_identities() { + use test_json::keys_query_sets::VerificationLatchTestData as DataSet; + + let machine = common_verification_latch_machine_setup().await; + + // ###### + // Get the Carol identity for the first time + // ###### + let keys_query = DataSet::carol_keys_query_response_unsigned(); + let txn_id = TransactionId::new(); + machine.mark_request_as_sent(&txn_id, &keys_query).await.unwrap(); + + let carol_identity = machine + .get_identity(DataSet::carol_id(), None) + .await + .unwrap() + .unwrap() + .other() + .unwrap(); + // The identity is not verified + assert!(!carol_identity.is_verified()); + // The verified latch is off + assert!(!carol_identity.is_verified_latch_set()); + + // Carol is verified, likely from another session. Ensure the latch is updated + // when the key query response is processes + let keys_query = DataSet::carol_keys_query_response_signed(); + let txn_id = TransactionId::new(); + machine.mark_request_as_sent(&txn_id, &keys_query).await.unwrap(); + + let carol_identity = machine + .get_identity(DataSet::carol_id(), None) + .await + .unwrap() + .unwrap() + .other() + .unwrap(); + assert!(carol_identity.is_verified()); + // This should have updated the latch + assert!(carol_identity.is_verified_latch_set()); + // It is the same identity, it's just signed now so no pin violation + assert!(!carol_identity.has_pin_violation()); + } + + // Set up a machine do initial own key query. + // The cross signing secrets are not yet uploaded. + // Then query keys for carol and bob (both signed by own identity) + async fn common_verification_latch_own_trust_change_machine_setup() -> OlmMachine { + use test_json::keys_query_sets::VerificationLatchTestData as DataSet; + + // Start on a non-verified session + let machine = OlmMachine::new(DataSet::own_id(), device_id!("LOCAL")).await; + + let keys_query = DataSet::own_keys_query_response_1(); + let txn_id = TransactionId::new(); + machine.mark_request_as_sent(&txn_id, &keys_query).await.unwrap(); + + // For sanity check that own identity is not trusted + let own_identity = + machine.get_identity(DataSet::own_id(), None).await.unwrap().unwrap().own().unwrap(); + assert!(!own_identity.is_verified()); + + let keys_query = DataSet::own_keys_query_response_1(); + let txn_id = TransactionId::new(); + machine.mark_request_as_sent(&txn_id, &keys_query).await.unwrap(); + + // Get Bob and Carol already signed + let keys_query = DataSet::bob_keys_query_response_signed(); + let txn_id = TransactionId::new(); + machine.mark_request_as_sent(&txn_id, &keys_query).await.unwrap(); + + let keys_query = DataSet::carol_keys_query_response_signed(); + let txn_id = TransactionId::new(); + machine.mark_request_as_sent(&txn_id, &keys_query).await.unwrap(); + + machine.update_tracked_users(vec![DataSet::bob_id(), DataSet::carol_id()]).await.unwrap(); + + machine + } + + #[async_test] + async fn test_manager_verified_latch_setup_on_own_identity_trust_change() { + use test_json::keys_query_sets::VerificationLatchTestData as DataSet; + let machine = common_verification_latch_own_trust_change_machine_setup().await; + + let own_identity = + machine.get_identity(DataSet::own_id(), None).await.unwrap().unwrap().own().unwrap(); + + let bob_identity = + machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap().other().unwrap(); + // Carol is verified by our identity but our own identity is not yet trusted + assert!(own_identity.is_identity_signed(&bob_identity).is_ok()); + assert!(!bob_identity.is_verified_latch_set()); + + let carol_identity = machine + .get_identity(DataSet::carol_id(), None) + .await + .unwrap() + .unwrap() + .other() + .unwrap(); + // Carol is verified by our identity but our own identity is not yet trusted + assert!(own_identity.is_identity_signed(&carol_identity).is_ok()); + assert!(!carol_identity.is_verified_latch_set()); + + // Marking our own identity as trusted should update the existing identities + let _ = own_identity.verify().await; + + let own_identity = + machine.get_identity(DataSet::own_id(), None).await.unwrap().unwrap().own().unwrap(); + assert!(own_identity.is_verified()); + + let carol_identity = machine + .get_identity(DataSet::carol_id(), None) + .await + .unwrap() + .unwrap() + .other() + .unwrap(); + assert!(carol_identity.is_verified()); + // The latch should be set now + assert!(carol_identity.is_verified_latch_set()); + + let bob_identity = + machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap().other().unwrap(); + assert!(bob_identity.is_verified()); + // The latch should be set now + assert!(bob_identity.is_verified_latch_set()); + } + + #[async_test] + async fn test_manager_verified_latch_setup_on_import_secrets() { + use test_json::keys_query_sets::VerificationLatchTestData as DataSet; + let machine = common_verification_latch_own_trust_change_machine_setup().await; + + let own_identity = + machine.get_identity(DataSet::own_id(), None).await.unwrap().unwrap().own().unwrap(); + + let bob_identity = + machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap().other().unwrap(); + // Carol is verified by our identity but our own identity is not yet trusted + assert!(own_identity.is_identity_signed(&bob_identity).is_ok()); + assert!(!bob_identity.is_verified_latch_set()); + + let carol_identity = machine + .get_identity(DataSet::carol_id(), None) + .await + .unwrap() + .unwrap() + .other() + .unwrap(); + // Carol is verified by our identity but our own identity is not yet trusted + assert!(own_identity.is_identity_signed(&carol_identity).is_ok()); + assert!(!carol_identity.is_verified_latch_set()); + + // Marking our own identity as trusted should update the existing identities + machine + .import_cross_signing_keys(CrossSigningKeyExport { + master_key: DataSet::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(), + self_signing_key: DataSet::SELF_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(), + user_signing_key: DataSet::USER_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(), + }) + .await + .unwrap(); + + let own_identity = + machine.get_identity(DataSet::own_id(), None).await.unwrap().unwrap().own().unwrap(); + assert!(own_identity.is_verified()); + + let carol_identity = machine + .get_identity(DataSet::carol_id(), None) + .await + .unwrap() + .unwrap() + .other() + .unwrap(); + assert!(carol_identity.is_verified()); + // The latch should be set now + assert!(carol_identity.is_verified_latch_set()); + + let bob_identity = + machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap().other().unwrap(); + assert!(bob_identity.is_verified()); + // The latch should be set now + assert!(bob_identity.is_verified_latch_set()); + } } diff --git a/testing/matrix-sdk-test/src/test_json/keys_query_sets.rs b/testing/matrix-sdk-test/src/test_json/keys_query_sets.rs index bf5c1a332..d481c09ea 100644 --- a/testing/matrix-sdk-test/src/test_json/keys_query_sets.rs +++ b/testing/matrix-sdk-test/src/test_json/keys_query_sets.rs @@ -667,3 +667,424 @@ impl IdentityChangeDataSet { .expect("Can't parse the `/keys/upload` response") } } + +pub struct VerificationLatchTestData {} + +#[allow(dead_code)] +impl VerificationLatchTestData { + pub const MASTER_KEY_PRIVATE_EXPORT: &'static str = + "bSa0nVTocZArMzL7OLmeFUIVF4ycp64rrkVMgqOYg6Y"; + pub const SELF_SIGNING_KEY_PRIVATE_EXPORT: &'static str = + "MQ7b3MDXvOEMDvIOWkuH1XCNUyqBLqbdd1bT00p8HPU"; + pub const USER_SIGNING_KEY_PRIVATE_EXPORT: &'static str = + "v77s+TlT5/NbcQym2B7Rwf20HOAhyInF2p1ZUYDPtow"; + + pub fn own_id() -> &'static UserId { + user_id!("@alice:localhost") + } + pub fn bob_id() -> &'static UserId { + user_id!("@bob:localhost") + } + + pub fn carol_id() -> &'static UserId { + user_id!("@carol:localhost") + } + + /// Current user keys query response containing the cross-signing keys + pub fn own_keys_query_response_1() -> KeyQueryResponse { + let data = json!({ + "master_keys": { + "@alice:localhost": { + "keys": { + "ed25519:EPVg/QLG9+FmNvKjNXfycZEpQLtfHDaTN+rENAURZSk": "EPVg/QLG9+FmNvKjNXfycZEpQLtfHDaTN+rENAURZSk" + }, + "signatures": { + "@alice:localhost": { + "ed25519:EPVg/QLG9+FmNvKjNXfycZEpQLtfHDaTN+rENAURZSk": "FX+srrw9SRmi12fexYHH1jrlEIWgOfre1aPNzDZWcAlaP9WKRdhcQGh70/3F9hk/PGr51I+ux62YgU4xnRTqAA", + "ed25519:PWVCNMMGCT": "teLq0rCYKX9h8WXu6kH8UE6HPKAtkF/DwCncxJGvVBCyZRtLHD8W1yYEzJXjTNynn+4fibQZBhR3th1RGLn4Ag" + } + }, + "usage": [ + "master" + ], + "user_id": "@alice:localhost" + } + }, + "self_signing_keys": { + "@alice:localhost": { + "keys": { + "ed25519:WXLer0esHUanp8DCeu2Be0xB5ms9aKFFBrCFl50COjw": "WXLer0esHUanp8DCeu2Be0xB5ms9aKFFBrCFl50COjw" + }, + "signatures": { + "@alice:localhost": { + "ed25519:EPVg/QLG9+FmNvKjNXfycZEpQLtfHDaTN+rENAURZSk": "lCV9R1xjD34arzq/CAuej1XBv+Ip4dFfAGHfe7znbW7rnwKDaX5PaX3MHk+EIC7nXvUYEAn502WcUFme5c0cCQ" + } + }, + "usage": [ + "self_signing" + ], + "user_id": "@alice:localhost" + } + }, + "user_signing_keys": { + "@alice:localhost": { + "keys": { + "ed25519:MXob/N/bYI7U2655O1/AI9NOX1245RnE03Nl4Hvf+u0": "MXob/N/bYI7U2655O1/AI9NOX1245RnE03Nl4Hvf+u0" + }, + "signatures": { + "@alice:localhost": { + "ed25519:EPVg/QLG9+FmNvKjNXfycZEpQLtfHDaTN+rENAURZSk": "A73QfZ5Dzhh7abdal/sEaq1bfgxzPFU8Bvwa9Y5TIe/a5jTmLVubNmsMSsO5tOT+b6aVJg1G4FtId0Q/cb1aAA" + } + }, + "usage": [ + "user_signing" + ], + "user_id": "@alice:localhost" + } + } + }); + + let data = response_from_file(&data); + + KeyQueryResponse::try_from_http_response(data) + .expect("Can't parse the `/keys/upload` response") + } + + pub fn device_keys_payload_bob_unsigned_device() -> Value { + json!({ + "algorithms": [ + "m.olm.v1.curve25519-aes-sha2", + "m.megolm.v1.aes-sha2" + ], + "device_id": "XCYNVRMTER", + "keys": { + "curve25519:XCYNVRMTER": "xGKYkFcHGlJ+I1yiefPyZu1EY8i2h1eed5uk3PAW6GA", + "ed25519:XCYNVRMTER": "EsU8MJzTYE+/VJs1K9HkGqb8UXCByPioynGrV28WocU" + }, + "signatures": { + "@bob:localhost": { + "ed25519:XCYNVRMTER": "yZ7cpaoA+0rRx+bmklsP1iAd0eGPH6gsdywC11VE98/mrcbeFuxjQVn39Ds7h+vmciu5GRzwWgDgv+6go6FHAQ", + // Remove the cross-signature + // "ed25519:e8JFSrW8LW3UK6SSXh2ZESUzptFbapr28/+WqndD+Xk": "xYnGmU9FEdoavB5P743gx3xbEy29tlfRX5lT3JO0dWhHdsP+muqBXUYMBl1RRFeZtIE0GYc9ORb6Yf88EdeoCw" + } + }, + "user_id": "@bob:localhost", + "unsigned": {} + }) + } + + pub fn bob_keys_query_response_signed() -> KeyQueryResponse { + let data = json!({ + "device_keys": { + "@bob:localhost": { + "RLZGZIHKMP": { + "algorithms": [ + "m.olm.v1.curve25519-aes-sha2", + "m.megolm.v1.aes-sha2" + ], + "device_id": "RLZGZIHKMP", + "keys": { + "curve25519:RLZGZIHKMP": "Zd8uO9Rr1PtqNno3//ybeUZ3JuqFtm17TQTWW0f47AU", + "ed25519:RLZGZIHKMP": "kH+Zn2m7LPES/XLOyVvnf8t4Byfj3mAbngHptHZFzk0" + }, + "signatures": { + "@bob:localhost": { + "ed25519:RLZGZIHKMP": "w4MOkDiD+4XatQrRzGrcaqwVmiZrAjxmaIA8aSuzQveD2SJ2eVZq3OSpqx6QRUbG/gkkZxGmY13PkS/iAOv0AA", + "ed25519:e8JFSrW8LW3UK6SSXh2ZESUzptFbapr28/+WqndD+Xk": "ki+cV0EVe5cYXnzqU078qy1qu2rnaxaBQU+KwyvPpEUotNTXjWKUOJfxast42d5tjI5vsI5aiQ6XkYfjBJ74Bw" + } + }, + "user_id": "@bob:localhost", + "unsigned": {} + }, + "XCYNVRMTER": Self::device_keys_payload_bob_unsigned_device(), + } + }, + "failures": {}, + "master_keys": { + "@bob:localhost": { + "keys": { + "ed25519:xZPyb4hxM8zaedDFz5m8HsDpX1fknd/V/69THLhNX9I": "xZPyb4hxM8zaedDFz5m8HsDpX1fknd/V/69THLhNX9I" + }, + "signatures": { + "@bob:localhost": { + "ed25519:RLZGZIHKMP": "5bHLrx0HwYsNRtd65s1a1wVGlwgJU8yb8cq/Qbq04o9nVdQuY8+woQVWq9nxk59u6QFZIpFdVjXsuTPkDJLsBA", + "ed25519:xZPyb4hxM8zaedDFz5m8HsDpX1fknd/V/69THLhNX9I": "NA+cLNIPpmECcBIcmAH5l1K4IDXI6Xss1VmU8TZ04AYQSAh/2sv7NixEBO1/Raz0nErzkOl8gpRswHbHv1p7Dw" + }, + "@alice:localhost": { + "ed25519:MXob/N/bYI7U2655O1/AI9NOX1245RnE03Nl4Hvf+u0": "n3X6afWYoSywqBpPlaDfQ2BNjl3ez5AzxEVwaB5/KEAzgwsq5B2qBW9N5uZaNWEq5M3JBrh0doj1FgUg4R3yBQ" + } + }, + "usage": [ + "master" + ], + "user_id": "@bob:localhost" + } + }, + "self_signing_keys": { + "@bob:localhost": { + "keys": { + "ed25519:e8JFSrW8LW3UK6SSXh2ZESUzptFbapr28/+WqndD+Xk": "e8JFSrW8LW3UK6SSXh2ZESUzptFbapr28/+WqndD+Xk" + }, + "signatures": { + "@bob:localhost": { + "ed25519:xZPyb4hxM8zaedDFz5m8HsDpX1fknd/V/69THLhNX9I": "kkGZHLY18jyqXs412VB31u6vxijbaBgVrIMR/LBAFULhTZk6HGH951N6NxMZnYHyH0sFaQhsl4DUqt7XthBHBQ" + } + }, + "usage": [ + "self_signing" + ], + "user_id": "@bob:localhost" + } + }, + "user_signing_keys": {} + }); + + let data = response_from_file(&data); + + KeyQueryResponse::try_from_http_response(data) + .expect("Can't parse the `/keys/upload` response") + } + + pub fn bob_device_1_id() -> &'static DeviceId { + device_id!("RLZGZIHKMP") + } + pub fn bob_device_2_id() -> &'static DeviceId { + device_id!("XCYNVRMTER") + } + + // Bob has a new identity, the two devices are properly self-signed + pub fn bob_keys_query_response_rotated() -> KeyQueryResponse { + let data = json!({ + "device_keys": { + "@bob:localhost": { + "RLZGZIHKMP": { + "algorithms": [ + "m.olm.v1.curve25519-aes-sha2", + "m.megolm.v1.aes-sha2" + ], + "device_id": "RLZGZIHKMP", + "keys": { + "curve25519:RLZGZIHKMP": "Zd8uO9Rr1PtqNno3//ybeUZ3JuqFtm17TQTWW0f47AU", + "ed25519:RLZGZIHKMP": "kH+Zn2m7LPES/XLOyVvnf8t4Byfj3mAbngHptHZFzk0" + }, + "signatures": { + "@bob:localhost": { + "ed25519:RLZGZIHKMP": "w4MOkDiD+4XatQrRzGrcaqwVmiZrAjxmaIA8aSuzQveD2SJ2eVZq3OSpqx6QRUbG/gkkZxGmY13PkS/iAOv0AA", + // "ed25519:At1ai1VUZrCncCI7V7fEAJmBShfpqZ30xRzqcEjTjdc": "rg3b3DovN3VztdcKyOcOlIGQxmm+8VC9+ImuXdgug/kPSi7QcljwOtjnk4LMkHexB3xVzB0ANcyNjbJ2cJuYBg", + "ed25519:e8JFSrW8LW3UK6SSXh2ZESUzptFbapr28/+WqndD+Xk": "ki+cV0EVe5cYXnzqU078qy1qu2rnaxaBQU+KwyvPpEUotNTXjWKUOJfxast42d5tjI5vsI5aiQ6XkYfjBJ74Bw" + } + }, + "user_id": "@bob:localhost", + "unsigned": { + "device_display_name": "develop.element.io: Chrome on macOS" + } + }, + "XCYNVRMTER": { + "algorithms": [ + "m.olm.v1.curve25519-aes-sha2", + "m.megolm.v1.aes-sha2" + ], + "device_id": "XCYNVRMTER", + "keys": { + "curve25519:XCYNVRMTER": "xGKYkFcHGlJ+I1yiefPyZu1EY8i2h1eed5uk3PAW6GA", + "ed25519:XCYNVRMTER": "EsU8MJzTYE+/VJs1K9HkGqb8UXCByPioynGrV28WocU" + }, + "signatures": { + "@bob:localhost": { + "ed25519:XCYNVRMTER": "yZ7cpaoA+0rRx+bmklsP1iAd0eGPH6gsdywC11VE98/mrcbeFuxjQVn39Ds7h+vmciu5GRzwWgDgv+6go6FHAQ", + "ed25519:e8JFSrW8LW3UK6SSXh2ZESUzptFbapr28/+WqndD+Xk": "xYnGmU9FEdoavB5P743gx3xbEy29tlfRX5lT3JO0dWhHdsP+muqBXUYMBl1RRFeZtIE0GYc9ORb6Yf88EdeoCw", + "ed25519:NWoyMF4Ox8PEj+8l1e70zuIUg0D+wL9wtcj1KhWL0Bc": "2ieX8z+oW9JhdyIIkTDsQ2o5VWxcO6dOgeyPbRwbAL6Q8J6xujzYSIi568UAlPt+wg+RkNLshneexCPNMgSiDQ" + } + }, + "user_id": "@bob:localhost", + "unsigned": { + "device_display_name": "app.element.io: Chrome on mac" + } + } + } + }, + "failures": {}, + "master_keys": { + "@bob:localhost": { + "keys": { + "ed25519:xaFlsDqlDRRy7Idtt1dW9mdhH/gvvax34q+HxepjNWY": "xaFlsDqlDRRy7Idtt1dW9mdhH/gvvax34q+HxepjNWY" + }, + "signatures": { + "@bob:localhost": { + "ed25519:XCYNVRMTER": "K1aPl+GtcNi8yDqn1zvKIJMg3PFLQkwoXJeFJMmct4SA2SiQIl1S2x1bDTC3kQ4/LA7ULiQgKlxkXdQVf2GZDw", + "ed25519:xaFlsDqlDRRy7Idtt1dW9mdhH/gvvax34q+HxepjNWY": "S5vw8moiPudKhmF1qIv3/ehbZ7uohJbcQaLcOV+DDh9iC/YX0UqnaGn1ZYWJpIN7Kxe2ZWCBwzp35DOVZKfxBw" + } + }, + "usage": [ + "master" + ], + "user_id": "@bob:localhost" + } + }, + "self_signing_keys": { + "@bob:localhost": { + "keys": { + "ed25519:NWoyMF4Ox8PEj+8l1e70zuIUg0D+wL9wtcj1KhWL0Bc": "NWoyMF4Ox8PEj+8l1e70zuIUg0D+wL9wtcj1KhWL0Bc" + }, + "signatures": { + "@bob:localhost": { + "ed25519:xaFlsDqlDRRy7Idtt1dW9mdhH/gvvax34q+HxepjNWY": "rwQIkR7JbZOrwGrmkW9QzFlK+lMjRDHVcGVlYNS/zVeDyvWxD0WFHcmy4p/LSgJDyrVt+th7LH7Bj+Ed/EGvCw" + } + }, + "usage": [ + "self_signing" + ], + "user_id": "@bob:localhost" + } + }, + "user_signing_keys": {} + }); + + let data = response_from_file(&data); + + KeyQueryResponse::try_from_http_response(data) + .expect("Can't parse the `/keys/upload` response") + } + + pub fn device_1_keys_payload_carol() -> Value { + json!({ + // Not self signed + "algorithms": [ + "m.olm.v1.curve25519-aes-sha2", + "m.megolm.v1.aes-sha2" + ], + "device_id": "BAZAPVEHGA", + "keys": { + "curve25519:BAZAPVEHGA": "/mCcWJb5mtNGPC7m4iQeW8gVJB4nG8z/z2QQXzzNijw", + "ed25519:BAZAPVEHGA": "MLSoOlk27qcS/2O9Etp6XwgF8j+UT06yy/ypSeE9JRA" + }, + "signatures": { + "@carol:localhost": { + "ed25519:BAZAPVEHGA": "y2+Z0ofRRoNMj864SoAcNEXRToYVeiARu39CO0Vj2GcSIxlpR7B8K1wDYV4luP4gOL1t1tPgJPXL1WO//AHHCw", + } + }, + "user_id": "@carol:localhost" + }) + } + + pub fn device_2_keys_payload_carol() -> Value { + // Self-signed device + json!({ + "algorithms": [ + "m.olm.v1.curve25519-aes-sha2", + "m.megolm.v1.aes-sha2" + ], + "device_id": "JBRBCHOFDZ", + "keys": { + "curve25519:JBRBCHOFDZ": "900HdrlfxlH8yMSmEQ3C32uVyXCuxKs5oPKS/wUgzVQ", + "ed25519:JBRBCHOFDZ": "BOINY06uroLYscHUq0e0FmUo/W0LC4/fsIPkZQe71NY" + }, + "signatures": { + "@carol:localhost": { + "ed25519:JBRBCHOFDZ": "MmSJS3yEdeuseiLTDCQwImZBPNFMdhhkAFjRZZrIONoGFR0AMSzgLtx/nSgXP8RwVxpycvb6OAqvSk2toK3PDg", + "ed25519:ZOMWgk5LAogkwDEdZl9Rv7FRGu0nGbeLtMHx6anzhQs": "VtoxmPn/BQVDlpEHPEI2wPUlruUX9m2zV3FChNkRyEEWur4St27WA1He8BwjVRiiT0bdUnVH3xfmucoV9UnbDA" + } + }, + "user_id": "@carol:localhost", + }) + } + + pub fn ssk_payload_carol() -> Value { + json!({ + "@carol:localhost": { + "keys": { + "ed25519:ZOMWgk5LAogkwDEdZl9Rv7FRGu0nGbeLtMHx6anzhQs": "ZOMWgk5LAogkwDEdZl9Rv7FRGu0nGbeLtMHx6anzhQs" + }, + "signatures": { + "@carol:localhost": { + "ed25519:itnwUCRfBPW08IrmBks9MTp/Qm5AJ2WNca13ptIZF8U": "thjR1/kxHADXqLqxc4Q3OZhAaLq7SPL96LNCGVGN64OYAJ5yG1cpqAXBiBCUaBUTdRTb0ys601RR8djPdTK/BQ" + } + }, + "usage": [ + "self_signing" + ], + "user_id": "@carol:localhost" + } + }) + } + + // Carol key query response with one signed and one unsigned device. + // Bob has not verified Carol yet + pub fn carol_keys_query_response_unsigned() -> KeyQueryResponse { + let data = json!({ + "device_keys": { + "@carol:localhost": { + "BAZAPVEHGA": Self::device_1_keys_payload_carol(), + "JBRBCHOFDZ": Self::device_2_keys_payload_carol() + } + }, + "failures": {}, + "master_keys": { + "@carol:localhost": { + "keys": { + "ed25519:itnwUCRfBPW08IrmBks9MTp/Qm5AJ2WNca13ptIZF8U": "itnwUCRfBPW08IrmBks9MTp/Qm5AJ2WNca13ptIZF8U" + }, + "signatures": { + "@carol:localhost": { + "ed25519:JBRBCHOFDZ": "eRA4jRSszQVuYpMtHTBuWGLEzcdUojyCW4/XKHRIQ2solv7iTC/MWES6I20YrHJa7H82CVoyNxS1Y3AwttBbCg", + "ed25519:itnwUCRfBPW08IrmBks9MTp/Qm5AJ2WNca13ptIZF8U": "e3r5L+JLv6FB8+Tt4BlIbz4wk2qPeMoKL1uR079qZzYMvtKoWGK9p000cZIhA5R1Tl7buQ9ODUfizued8g3TAg" + }, + // "@alice:localhost": { + // "ed25519:MXob/N/bYI7U2655O1/AI9NOX1245RnE03Nl4Hvf+u0": "yfRUvkaVg3KizC/HDXcuP4+gtYhxgzr8X916Wt4GRXjj4qhDjsCkf8mYZ7x4lcEXzRkYql5KelabgVzP12qmAA" + // } + }, + "usage": [ + "master" + ], + "user_id": "@carol:localhost" + } + }, + "self_signing_keys": Self::ssk_payload_carol(), + "user_signing_keys": {} + }); + + let data = response_from_file(&data); + + KeyQueryResponse::try_from_http_response(data) + .expect("Can't parse the `/keys/upload` response") + } + + pub fn carol_keys_query_response_signed() -> KeyQueryResponse { + let data = json!({ + "device_keys": { + "@carol:localhost": { + "BAZAPVEHGA": Self::device_1_keys_payload_carol(), + "JBRBCHOFDZ": Self::device_2_keys_payload_carol() + } + }, + "failures": {}, + "master_keys": { + "@carol:localhost": { + "keys": { + "ed25519:itnwUCRfBPW08IrmBks9MTp/Qm5AJ2WNca13ptIZF8U": "itnwUCRfBPW08IrmBks9MTp/Qm5AJ2WNca13ptIZF8U" + }, + "signatures": { + "@carol:localhost": { + "ed25519:JBRBCHOFDZ": "eRA4jRSszQVuYpMtHTBuWGLEzcdUojyCW4/XKHRIQ2solv7iTC/MWES6I20YrHJa7H82CVoyNxS1Y3AwttBbCg", + "ed25519:itnwUCRfBPW08IrmBks9MTp/Qm5AJ2WNca13ptIZF8U": "e3r5L+JLv6FB8+Tt4BlIbz4wk2qPeMoKL1uR079qZzYMvtKoWGK9p000cZIhA5R1Tl7buQ9ODUfizued8g3TAg" + }, + "@alice:localhost": { + "ed25519:MXob/N/bYI7U2655O1/AI9NOX1245RnE03Nl4Hvf+u0": "yfRUvkaVg3KizC/HDXcuP4+gtYhxgzr8X916Wt4GRXjj4qhDjsCkf8mYZ7x4lcEXzRkYql5KelabgVzP12qmAA" + } + }, + "usage": [ + "master" + ], + "user_id": "@carol:localhost" + } + }, + "self_signing_keys": Self::ssk_payload_carol(), + "user_signing_keys": {} + }); + + let data = response_from_file(&data); + + KeyQueryResponse::try_from_http_response(data) + .expect("Can't parse the `/keys/upload` response") + } +}