diff --git a/matrix_sdk_crypto/src/machine.rs b/matrix_sdk_crypto/src/machine.rs index 4fd34053..2543b518 100644 --- a/matrix_sdk_crypto/src/machine.rs +++ b/matrix_sdk_crypto/src/machine.rs @@ -60,6 +60,10 @@ use super::{ OlmMessage, OutboundGroupSession, }, store::{memorystore::MemoryStore, Result as StoreResult}, + user_identity::{ + MasterPubkey, OwnUserIdentity, SelfSigningPubkey, UserIdentities, UserIdentity, + UserSigningPubkey, + }, verification::{Sas, VerificationMachine}, CryptoStore, }; @@ -429,6 +433,9 @@ impl OlmMachine { let mut changed_devices = Vec::new(); for (user_id, device_map) in device_keys_map { + // TODO move this out into the handle keys query response method + // since we might fail handle the new device at any point here or + // when updating the user identities. self.store.update_tracked_user(user_id, false).await?; for (device_id, device_keys) in device_map.iter() { @@ -492,6 +499,63 @@ impl OlmMachine { Ok(changed_devices) } + async fn handle_cross_singing_keys( + &self, + response: &get_keys::Response, + ) -> StoreResult> { + let mut changed = Vec::new(); + + for (user_id, master_key) in &response.master_keys { + let master_key = MasterPubkey::from(master_key); + + let self_signing = if let Some(s) = response.self_signing_keys.get(user_id) { + SelfSigningPubkey::from(s) + } else { + continue; + }; + + let identity = if let Some(mut i) = self.store.get_user_identity(user_id).await? { + match &mut i { + UserIdentities::Own(ref mut identity) => { + let user_signing = if let Some(s) = response.user_signing_keys.get(user_id) + { + UserSigningPubkey::from(s) + } else { + continue; + }; + + identity + .update(master_key, self_signing, user_signing) + .map(|_| i) + } + UserIdentities::Other(ref mut identity) => { + identity.update(master_key, self_signing).map(|_| i) + } + } + } else if user_id == self.user_id() { + if let Some(s) = response.user_signing_keys.get(user_id) { + let user_signing = UserSigningPubkey::from(s); + OwnUserIdentity::new(master_key, self_signing, user_signing) + .map(UserIdentities::Own) + } else { + continue; + } + } else { + UserIdentity::new(master_key, self_signing).map(UserIdentities::Other) + }; + + match identity { + Ok(i) => changed.push(i), + Err(_e) => { + // TODO log some error here + continue; + } + } + } + + Ok(changed) + } + /// Receive a successful keys query response. /// /// Returns a list of devices newly discovered devices and devices that @@ -504,13 +568,14 @@ impl OlmMachine { pub async fn receive_keys_query_response( &self, response: &get_keys::Response, - ) -> OlmResult> { + ) -> OlmResult<(Vec, Vec)> { let changed_devices = self .handle_devices_from_key_query(&response.device_keys) .await?; self.store.save_devices(&changed_devices).await?; + let changed_identities = self.handle_cross_singing_keys(response).await?; - Ok(changed_devices) + Ok((changed_devices, changed_identities)) } /// Get a request to upload E2EE keys to the server. diff --git a/matrix_sdk_crypto/src/store/memorystore.rs b/matrix_sdk_crypto/src/store/memorystore.rs index 660b3e90..4cbe31db 100644 --- a/matrix_sdk_crypto/src/store/memorystore.rs +++ b/matrix_sdk_crypto/src/store/memorystore.rs @@ -25,6 +25,7 @@ use super::{Account, CryptoStore, InboundGroupSession, Result, Session}; use crate::{ device::ReadOnlyDevice, memory_stores::{DeviceStore, GroupSessionStore, ReadOnlyUserDevices, SessionStore}, + user_identity::UserIdentities, }; #[derive(Debug, Clone)] pub struct MemoryStore { @@ -131,6 +132,10 @@ impl CryptoStore for MemoryStore { Ok(()) } + + async fn get_user_identity(&self, _user_id: &UserId) -> Result> { + Ok(None) + } } #[cfg(test)] diff --git a/matrix_sdk_crypto/src/store/mod.rs b/matrix_sdk_crypto/src/store/mod.rs index 5e01d8a1..6273a9ba 100644 --- a/matrix_sdk_crypto/src/store/mod.rs +++ b/matrix_sdk_crypto/src/store/mod.rs @@ -30,6 +30,7 @@ use super::{ device::ReadOnlyDevice, memory_stores::ReadOnlyUserDevices, olm::{Account, InboundGroupSession, Session}, + user_identity::UserIdentities, }; pub mod memorystore; @@ -197,4 +198,11 @@ pub trait CryptoStore: Debug { /// /// * `user_id` - The user for which we should get all the devices. async fn get_user_devices(&self, user_id: &UserId) -> Result; + + /// Get the user identity that is attached to the given user id. + /// + /// # Arguments + /// + /// * `user_id` - The user for which we should get the identity. + async fn get_user_identity(&self, user_id: &UserId) -> Result>; } diff --git a/matrix_sdk_crypto/src/store/sqlite.rs b/matrix_sdk_crypto/src/store/sqlite.rs index 1946a376..a44417aa 100644 --- a/matrix_sdk_crypto/src/store/sqlite.rs +++ b/matrix_sdk_crypto/src/store/sqlite.rs @@ -38,6 +38,7 @@ use super::{CryptoStore, CryptoStoreError, Result}; use crate::{ device::{ReadOnlyDevice, TrustState}, memory_stores::{DeviceStore, GroupSessionStore, ReadOnlyUserDevices, SessionStore}, + user_identity::UserIdentities, Account, IdentityKeys, InboundGroupSession, Session, }; @@ -883,6 +884,10 @@ impl CryptoStore for SqliteStore { async fn get_user_devices(&self, user_id: &UserId) -> Result { Ok(self.devices.user_devices(user_id)) } + + async fn get_user_identity(&self, _user_id: &UserId) -> Result> { + Ok(None) + } } #[cfg(not(tarpaulin_include))] diff --git a/matrix_sdk_crypto/src/user_identity.rs b/matrix_sdk_crypto/src/user_identity.rs index 77f349d0..cabd1c04 100644 --- a/matrix_sdk_crypto/src/user_identity.rs +++ b/matrix_sdk_crypto/src/user_identity.rs @@ -77,12 +77,6 @@ impl<'a> CrossSigningSubKeys<'a> { } } -pub struct UserIdentity { - user_id: Arc, - master_key: MasterPubkey, - self_signing_key: SelfSigningPubkey, -} - impl MasterPubkey { fn verify_subkey<'a>( &self, @@ -151,6 +145,19 @@ impl SelfSigningPubkey { } } +#[derive(Debug, Clone)] +pub enum UserIdentities { + Own(OwnUserIdentity), + Other(UserIdentity), +} + +#[derive(Debug, Clone)] +pub struct UserIdentity { + user_id: Arc, + master_key: MasterPubkey, + self_signing_key: SelfSigningPubkey, +} + impl UserIdentity { pub fn new( master_key: MasterPubkey, @@ -165,11 +172,25 @@ impl UserIdentity { }) } + pub fn update( + &mut self, + master_key: MasterPubkey, + self_signing_key: SelfSigningPubkey, + ) -> Result<(), SignatureError> { + master_key.verify_subkey(&self_signing_key)?; + + self.master_key = master_key; + self.self_signing_key = self_signing_key; + + Ok(()) + } + pub fn is_device_signed(&self, device: &ReadOnlyDevice) -> Result<(), SignatureError> { self.self_signing_key.verify_device(device) } } +#[derive(Debug, Clone)] pub struct OwnUserIdentity { user_id: Arc, master_key: MasterPubkey, @@ -196,6 +217,25 @@ impl OwnUserIdentity { }) } + pub fn update( + &mut self, + master_key: MasterPubkey, + self_signing_key: SelfSigningPubkey, + user_signing_key: UserSigningPubkey, + ) -> Result<(), SignatureError> { + master_key.verify_subkey(&self_signing_key)?; + master_key.verify_subkey(&user_signing_key)?; + + self.self_signing_key = self_signing_key; + self.user_signing_key = user_signing_key; + + self.master_key = master_key; + + // FIXME reset the verification state if the master key changed. + + Ok(()) + } + pub fn is_identity_signed(&self, identity: &UserIdentity) -> Result<(), SignatureError> { self.user_signing_key .verify_master_key(&identity.master_key)