crypto: Pass the identity further through the SAS layer and try to verify it.

This commit is contained in:
Damir Jelić 2020-08-18 14:24:27 +02:00
parent 6d0b73cb3d
commit 38cf771f1f
4 changed files with 78 additions and 15 deletions

View file

@ -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<String, String> {
match self {
UserIdentities::Own(i) => i.master_key(),
UserIdentities::Other(i) => i.master_key(),
}
}
}
#[derive(Debug, Clone)]
pub struct UserIdentity {
user_id: Arc<UserId>,
@ -172,6 +182,10 @@ impl UserIdentity {
})
}
pub fn master_key(&self) -> &BTreeMap<String, String> {
&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<String, String> {
&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)

View file

@ -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<UserIdentities>,
}
/// 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<MacEventContent>,
) -> Result<(Vec<ReadOnlyDevice>, Vec<String>), 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 \

View file

@ -107,7 +107,11 @@ impl Sas {
store: Arc<Box<dyn CryptoStore>>,
other_identity: Option<UserIdentities>,
) -> (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<StartEventContent>,
other_identity: Option<UserIdentities>,
) -> Result<Sas, AnyToDeviceEventContent> {
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::<Created>::new(account, other_device);
fn start(
account: Account,
other_device: ReadOnlyDevice,
other_identity: Option<UserIdentities>,
) -> (InnerSas, StartEventContent) {
let sas = SasState::<Created>::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<StartEventContent>,
other_identity: Option<UserIdentities>,
) -> Result<InnerSas, AnyToDeviceEventContent> {
match SasState::<Started>::from_start_event(account, other_device, event) {
match SasState::<Started>::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::<Created>::new(alice.clone(), bob_device);
let alice_sas = SasState::<Created>::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::<Started>::from_start_event(bob.clone(), alice_device, &event);
let bob_sas =
SasState::<Started>::from_start_event(bob.clone(), alice_device, &event, None);
(alice_sas, bob_sas.unwrap())
}

View file

@ -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<Created> {
/// * `account` - Our own account.
///
/// * `other_device` - The other device which we are going to verify.
pub fn new(account: Account, other_device: ReadOnlyDevice) -> SasState<Created> {
pub fn new(
account: Account,
other_device: ReadOnlyDevice,
other_identity: Option<UserIdentities>,
) -> SasState<Created> {
let verification_flow_id = Uuid::new_v4().to_string();
SasState {
@ -294,6 +298,7 @@ impl SasState<Created> {
ids: SasIds {
account,
other_device,
other_identity,
},
verification_flow_id: Arc::new(verification_flow_id),
@ -382,6 +387,7 @@ impl SasState<Started> {
account: Account,
other_device: ReadOnlyDevice,
event: &ToDeviceEvent<StartEventContent>,
other_identity: Option<UserIdentities>,
) -> Result<SasState<Started>, SasState<Canceled>> {
if let StartMethod::MSasV1(content) = &event.content.method {
let sas = OlmSas::new();
@ -397,6 +403,7 @@ impl SasState<Started> {
ids: SasIds {
account,
other_device,
other_identity,
},
creation_time: Arc::new(Instant::now()),
@ -438,6 +445,7 @@ impl SasState<Started> {
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::<Created>::new(alice.clone(), bob_device);
let alice_sas = SasState::<Created>::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::<Started>::from_start_event(bob.clone(), alice_device, &event);
let bob_sas =
SasState::<Started>::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::<Created>::new(alice.clone(), bob_device);
let alice_sas = SasState::<Created>::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::<Started>::from_start_event(bob.clone(), alice_device.clone(), &event)
SasState::<Started>::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::<Started>::from_start_event(bob.clone(), alice_device, &event)
SasState::<Started>::from_start_event(bob.clone(), alice_device, &event, None)
.expect_err("Didn't cancel on unknown sas method");
}
}