Skip to content

Commit

Permalink
crypto: Expose a way to pin a user's identity
Browse files Browse the repository at this point in the history
  • Loading branch information
andybalaam committed Oct 7, 2024
1 parent a12a46b commit 181ee64
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 3 deletions.
1 change: 1 addition & 0 deletions bindings/matrix-sdk-ffi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ Breaking changes:

Additions:

- Add `Encryption::get_user_identity`
- Add `ClientBuilder::room_key_recipient_strategy`
44 changes: 44 additions & 0 deletions bindings/matrix-sdk-ffi/src/encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,50 @@ impl Encryption {
pub async fn wait_for_e2ee_initialization_tasks(&self) {
self.inner.wait_for_e2ee_initialization_tasks().await;
}

/// Get the E2EE identity of a user.
///
/// Returns an error if this user does not exist, if there is an error
/// contacting the crypto store, or if our client is not logged in.
pub async fn get_user_identity(
&self,
user_id: String,
) -> Result<Arc<UserIdentity>, ClientError> {
Ok(Arc::new(UserIdentity {
inner: self
.inner
.get_user_identity(user_id.as_str().try_into()?)
.await?
.ok_or(ClientError::new("User not found"))?,
}))
}
}

/// The E2EE identity of a user.
#[derive(uniffi::Object)]
pub struct UserIdentity {
inner: matrix_sdk::encryption::identities::UserIdentity,
}

#[uniffi::export]
impl UserIdentity {
/// Remember this identity, ensuring it does not result in a pin violation.
///
/// When we first see a user, we assume their cryptographic identity has not
/// been tampered with by the homeserver or another entity with
/// man-in-the-middle capabilities. We remember this identity and call this
/// action "pinning".
///
/// If the identity presented for the user changes later on, the newly
/// presented identity is considered to be in "pin violation". This
/// method explicitly accepts the new identity, allowing it to replace
/// the previously pinned one and bringing it out of pin violation.
///
/// UIs should display a warning to the user when encountering an identity
/// which is not verified and is in pin violation.
pub(crate) async fn pin(&self) -> Result<(), ClientError> {
Ok(self.inner.pin().await?)
}
}

#[derive(uniffi::Object)]
Expand Down
42 changes: 41 additions & 1 deletion crates/matrix-sdk-crypto/src/identities/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,32 @@ impl UserIdentity {
}
}

/// Remember this identity, ensuring it does not result in a pin violation.
///
/// When we first see a user, we assume their cryptographic identity has not
/// been tampered with by the homeserver or another entity with
/// man-in-the-middle capabilities. We remember this identity and call this
/// action "pinning".
///
/// If the identity presented for the user changes later on, the newly
/// presented identity is considered to be in "pin violation". This
/// method explicitly accepts the new identity, allowing it to replace
/// the previously pinned one and bringing it out of pin violation.
///
/// UIs should display a warning to the user when encountering an identity
/// which is not verified and is in pin violation. See
/// [`OtherUserIdentity::identity_needs_user_approval`].
pub async fn pin(&self) -> Result<(), CryptoStoreError> {
match self {
UserIdentity::Own(_) => {
// Nothing to be done for our own identity: we already
// consider it trusted in this sense.
Ok(())
}
UserIdentity::Other(u) => u.pin_current_master_key().await,
}
}

/// Was this identity previously verified, and is no longer?
pub fn has_verification_violation(&self) -> bool {
match self {
Expand Down Expand Up @@ -737,7 +763,21 @@ impl OtherUserIdentityData {
&self.self_signing_key
}

/// Pin the current identity
/// Remember this identity, ensuring it does not result in a pin violation.
///
/// When we first see a user, we assume their cryptographic identity has not
/// been tampered with by the homeserver or another entity with
/// man-in-the-middle capabilities. We remember this identity and call this
/// action "pinning".
///
/// If the identity presented for the user changes later on, the newly
/// presented identity is considered to be in "pin violation". This
/// method explicitly accepts the new identity, allowing it to replace
/// the previously pinned one and bringing it out of pin violation.
///
/// UIs should display a warning to the user when encountering an identity
/// which is not verified and is in pin violation. See
/// [`OtherUserIdentity::identity_needs_user_approval`].
pub(crate) fn pin(&self) {
let mut m = self.pinned_master_key.write().unwrap();
*m = self.master_key.as_ref().clone()
Expand Down
1 change: 1 addition & 0 deletions crates/matrix-sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Breaking changes:

Additions:

- new `UserIdentity::pin` method.
- new `ClientBuilder::with_decryption_trust_requirement` method.
- new `ClientBuilder::with_room_key_recipient_strategy` method
- new `Room.set_account_data` and `Room.set_account_data_raw` RoomAccountData setters, analogous to the GlobalAccountData
Expand Down
18 changes: 18 additions & 0 deletions crates/matrix-sdk/src/encryption/identities/users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,24 @@ impl UserIdentity {
self.inner.withdraw_verification().await
}

/// Remember this identity, ensuring it does not result in a pin violation.
///
/// When we first see a user, we assume their cryptographic identity has not
/// been tampered with by the homeserver or another entity with
/// man-in-the-middle capabilities. We remember this identity and call this
/// action "pinning".
///
/// If the identity presented for the user changes later on, the newly
/// presented identity is considered to be in "pin violation". This
/// method explicitly accepts the new identity, allowing it to replace
/// the previously pinned one and bringing it out of pin violation.
///
/// UIs should display a warning to the user when encountering an identity
/// which is not verified and is in pin violation.
pub async fn pin(&self) -> Result<(), CryptoStoreError> {
self.inner.pin().await
}

/// Get the public part of the Master key of this user identity.
///
/// The public part of the Master key is usually used to uniquely identify
Expand Down
5 changes: 3 additions & 2 deletions crates/matrix-sdk/src/room/identity_status_changes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,9 +430,10 @@ mod tests {
);

// Pin it
self.crypto_other_identity()
self.user_identity()
.await
.pin_current_master_key()
.expect("User should exist")
.pin()
.await
.expect("Should not fail to pin");
} else {
Expand Down

0 comments on commit 181ee64

Please sign in to comment.