diff --git a/matrix_sdk_crypto/src/user_identity.rs b/matrix_sdk_crypto/src/user_identity.rs index cabd1c04..6141ea67 100644 --- a/matrix_sdk_crypto/src/user_identity.rs +++ b/matrix_sdk_crypto/src/user_identity.rs @@ -13,6 +13,7 @@ // limitations under the License. use std::{ + collections::BTreeMap, convert::TryFrom, sync::{atomic::AtomicBool, Arc}, }; @@ -151,6 +152,15 @@ pub enum UserIdentities { Other(UserIdentity), } +impl UserIdentities { + pub fn master_key(&self) -> &BTreeMap { + match self { + UserIdentities::Own(i) => i.master_key(), + UserIdentities::Other(i) => i.master_key(), + } + } +} + #[derive(Debug, Clone)] pub struct UserIdentity { user_id: Arc, @@ -172,6 +182,10 @@ impl UserIdentity { }) } + pub fn master_key(&self) -> &BTreeMap { + &self.master_key.0.keys + } + pub fn update( &mut self, master_key: MasterPubkey, @@ -236,6 +250,10 @@ impl OwnUserIdentity { Ok(()) } + pub fn master_key(&self) -> &BTreeMap { + &self.master_key.0.keys + } + pub fn is_identity_signed(&self, identity: &UserIdentity) -> Result<(), SignatureError> { self.user_signing_key .verify_master_key(&identity.master_key) diff --git a/matrix_sdk_crypto/src/verification/sas/helpers.rs b/matrix_sdk_crypto/src/verification/sas/helpers.rs index ac364ba7..d644884f 100644 --- a/matrix_sdk_crypto/src/verification/sas/helpers.rs +++ b/matrix_sdk_crypto/src/verification/sas/helpers.rs @@ -30,12 +30,13 @@ use matrix_sdk_common::{ uuid::Uuid, }; -use crate::{Account, ReadOnlyDevice}; +use crate::{user_identity::UserIdentities, Account, ReadOnlyDevice}; #[derive(Clone, Debug)] pub struct SasIds { pub account: Account, pub other_device: ReadOnlyDevice, + pub other_identity: Option, } /// Get a tuple of an emoji and a description of the emoji using a number. @@ -160,6 +161,7 @@ pub fn receive_mac_event( event: &ToDeviceEvent, ) -> Result<(Vec, Vec), CancelCode> { let mut verified_devices = Vec::new(); + let mut verified_identities = Vec::new(); let info = extra_mac_info_receive(&ids, flow_id); @@ -201,6 +203,25 @@ pub fn receive_mac_event( } else { return Err(CancelCode::KeyMismatch); } + } else if let Some(identity) = &ids.other_identity { + if let Some(key) = identity.master_key().get(key_id.as_str()) { + // TODO we should check that the master key signs the device, + // this way we know the master key also trusts the device + if key_mac + == &sas + .calculate_mac(key, &format!("{}{}", info, key_id)) + .expect("Can't calculate SAS MAC") + { + trace!( + "Successfully verified the master key {} from {}", + key_id, + event.sender + ); + verified_identities.push(identity) + } else { + return Err(CancelCode::KeyMismatch); + } + } } else { warn!( "Key ID {} in MAC event from {} {} doesn't belong to any device \ diff --git a/matrix_sdk_crypto/src/verification/sas/mod.rs b/matrix_sdk_crypto/src/verification/sas/mod.rs index eebcac46..c3837203 100644 --- a/matrix_sdk_crypto/src/verification/sas/mod.rs +++ b/matrix_sdk_crypto/src/verification/sas/mod.rs @@ -107,7 +107,11 @@ impl Sas { store: Arc>, other_identity: Option, ) -> (Sas, StartEventContent) { - let (inner, content) = InnerSas::start(account.clone(), other_device.clone()); + let (inner, content) = InnerSas::start( + account.clone(), + other_device.clone(), + other_identity.clone(), + ); let flow_id = inner.verification_flow_id(); let sas = Sas { @@ -139,7 +143,12 @@ impl Sas { event: &ToDeviceEvent, other_identity: Option, ) -> Result { - let inner = InnerSas::from_start_event(account.clone(), other_device.clone(), event)?; + let inner = InnerSas::from_start_event( + account.clone(), + other_device.clone(), + event, + other_identity.clone(), + )?; let flow_id = inner.verification_flow_id(); Ok(Sas { inner: Arc::new(Mutex::new(inner)), @@ -346,8 +355,12 @@ enum InnerSas { } impl InnerSas { - fn start(account: Account, other_device: ReadOnlyDevice) -> (InnerSas, StartEventContent) { - let sas = SasState::::new(account, other_device); + fn start( + account: Account, + other_device: ReadOnlyDevice, + other_identity: Option, + ) -> (InnerSas, StartEventContent) { + let sas = SasState::::new(account, other_device, other_identity); let content = sas.as_content(); (InnerSas::Created(sas), content) } @@ -356,8 +369,9 @@ impl InnerSas { account: Account, other_device: ReadOnlyDevice, event: &ToDeviceEvent, + other_identity: Option, ) -> Result { - match SasState::::from_start_event(account, other_device, event) { + match SasState::::from_start_event(account, other_device, event, other_identity) { Ok(s) => Ok(InnerSas::Started(s)), Err(s) => Err(s.as_content()), } @@ -599,12 +613,13 @@ mod test { let bob = Account::new(&bob_id(), &bob_device_id()); let bob_device = ReadOnlyDevice::from_account(&bob).await; - let alice_sas = SasState::::new(alice.clone(), bob_device); + let alice_sas = SasState::::new(alice.clone(), bob_device, None); let start_content = alice_sas.as_content(); let event = wrap_to_device_event(alice_sas.user_id(), start_content); - let bob_sas = SasState::::from_start_event(bob.clone(), alice_device, &event); + let bob_sas = + SasState::::from_start_event(bob.clone(), alice_device, &event, None); (alice_sas, bob_sas.unwrap()) } diff --git a/matrix_sdk_crypto/src/verification/sas/sas_state.rs b/matrix_sdk_crypto/src/verification/sas/sas_state.rs index 0ff6d61d..5c072800 100644 --- a/matrix_sdk_crypto/src/verification/sas/sas_state.rs +++ b/matrix_sdk_crypto/src/verification/sas/sas_state.rs @@ -43,7 +43,7 @@ use matrix_sdk_common::{ use super::helpers::{get_decimal, get_emoji, get_mac_content, receive_mac_event, SasIds}; -use crate::{Account, ReadOnlyDevice}; +use crate::{user_identity::UserIdentities, Account, ReadOnlyDevice}; const KEY_AGREEMENT_PROTOCOLS: &[KeyAgreementProtocol] = &[KeyAgreementProtocol::Curve25519HkdfSha256]; @@ -286,7 +286,11 @@ impl SasState { /// * `account` - Our own account. /// /// * `other_device` - The other device which we are going to verify. - pub fn new(account: Account, other_device: ReadOnlyDevice) -> SasState { + pub fn new( + account: Account, + other_device: ReadOnlyDevice, + other_identity: Option, + ) -> SasState { let verification_flow_id = Uuid::new_v4().to_string(); SasState { @@ -294,6 +298,7 @@ impl SasState { ids: SasIds { account, other_device, + other_identity, }, verification_flow_id: Arc::new(verification_flow_id), @@ -382,6 +387,7 @@ impl SasState { account: Account, other_device: ReadOnlyDevice, event: &ToDeviceEvent, + other_identity: Option, ) -> Result, SasState> { if let StartMethod::MSasV1(content) = &event.content.method { let sas = OlmSas::new(); @@ -397,6 +403,7 @@ impl SasState { ids: SasIds { account, other_device, + other_identity, }, creation_time: Arc::new(Instant::now()), @@ -438,6 +445,7 @@ impl SasState { ids: SasIds { account, other_device, + other_identity, }, verification_flow_id: Arc::new(event.content.transaction_id.clone()), @@ -871,12 +879,13 @@ mod test { let bob = Account::new(&bob_id(), &bob_device_id()); let bob_device = ReadOnlyDevice::from_account(&bob).await; - let alice_sas = SasState::::new(alice.clone(), bob_device); + let alice_sas = SasState::::new(alice.clone(), bob_device, None); let start_content = alice_sas.as_content(); let event = wrap_to_device_event(alice_sas.user_id(), start_content); - let bob_sas = SasState::::from_start_event(bob.clone(), alice_device, &event); + let bob_sas = + SasState::::from_start_event(bob.clone(), alice_device, &event, None); (alice_sas, bob_sas.unwrap()) } @@ -1027,7 +1036,7 @@ mod test { let bob = Account::new(&bob_id(), &bob_device_id()); let bob_device = ReadOnlyDevice::from_account(&bob).await; - let alice_sas = SasState::::new(alice.clone(), bob_device); + let alice_sas = SasState::::new(alice.clone(), bob_device, None); let mut start_content = alice_sas.as_content(); @@ -1039,7 +1048,7 @@ mod test { } let event = wrap_to_device_event(alice_sas.user_id(), start_content); - SasState::::from_start_event(bob.clone(), alice_device.clone(), &event) + SasState::::from_start_event(bob.clone(), alice_device.clone(), &event, None) .expect_err("Didn't cancel on invalid MAC method"); let mut start_content = alice_sas.as_content(); @@ -1050,7 +1059,7 @@ mod test { }); let event = wrap_to_device_event(alice_sas.user_id(), start_content); - SasState::::from_start_event(bob.clone(), alice_device, &event) + SasState::::from_start_event(bob.clone(), alice_device, &event, None) .expect_err("Didn't cancel on unknown sas method"); } }