Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crypto | Add support for verified identities change detection. #3795

Merged
merged 12 commits into from
Aug 8, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
crypto: Verified identity changes TDD
  • Loading branch information
BillCarsonFr committed Aug 7, 2024
commit 3d3f93a33dbb169282be0db76fc83d7ff95c1425
265 changes: 265 additions & 0 deletions crates/matrix-sdk-crypto/src/identities/manager.rs
Original file line number Diff line number Diff line change
@@ -2023,4 +2023,269 @@ pub(crate) mod tests {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit: "crypto: Verified identity changes TDD" - I would say that the tests for something could be in the same commit as the code itself, so no need for a separate commit here.

If you want a separate commit I suggest "crypto: Tests for verified_latch" or similar.

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
BillCarsonFr marked this conversation as resolved.
Show resolved Hide resolved
// ######
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
BillCarsonFr marked this conversation as resolved.
Show resolved Hide resolved
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());
}
}
Loading