crypto: Pass the identity further through the SAS layer and try to verify it.
parent
6d0b73cb3d
commit
38cf771f1f
|
@ -13,6 +13,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::BTreeMap,
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
sync::{atomic::AtomicBool, Arc},
|
sync::{atomic::AtomicBool, Arc},
|
||||||
};
|
};
|
||||||
|
@ -151,6 +152,15 @@ pub enum UserIdentities {
|
||||||
Other(UserIdentity),
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct UserIdentity {
|
pub struct UserIdentity {
|
||||||
user_id: Arc<UserId>,
|
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(
|
pub fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
master_key: MasterPubkey,
|
master_key: MasterPubkey,
|
||||||
|
@ -236,6 +250,10 @@ impl OwnUserIdentity {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn master_key(&self) -> &BTreeMap<String, String> {
|
||||||
|
&self.master_key.0.keys
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_identity_signed(&self, identity: &UserIdentity) -> Result<(), SignatureError> {
|
pub fn is_identity_signed(&self, identity: &UserIdentity) -> Result<(), SignatureError> {
|
||||||
self.user_signing_key
|
self.user_signing_key
|
||||||
.verify_master_key(&identity.master_key)
|
.verify_master_key(&identity.master_key)
|
||||||
|
|
|
@ -30,12 +30,13 @@ use matrix_sdk_common::{
|
||||||
uuid::Uuid,
|
uuid::Uuid,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{Account, ReadOnlyDevice};
|
use crate::{user_identity::UserIdentities, Account, ReadOnlyDevice};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SasIds {
|
pub struct SasIds {
|
||||||
pub account: Account,
|
pub account: Account,
|
||||||
pub other_device: ReadOnlyDevice,
|
pub other_device: ReadOnlyDevice,
|
||||||
|
pub other_identity: Option<UserIdentities>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a tuple of an emoji and a description of the emoji using a number.
|
/// 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>,
|
event: &ToDeviceEvent<MacEventContent>,
|
||||||
) -> Result<(Vec<ReadOnlyDevice>, Vec<String>), CancelCode> {
|
) -> Result<(Vec<ReadOnlyDevice>, Vec<String>), CancelCode> {
|
||||||
let mut verified_devices = Vec::new();
|
let mut verified_devices = Vec::new();
|
||||||
|
let mut verified_identities = Vec::new();
|
||||||
|
|
||||||
let info = extra_mac_info_receive(&ids, flow_id);
|
let info = extra_mac_info_receive(&ids, flow_id);
|
||||||
|
|
||||||
|
@ -201,6 +203,25 @@ pub fn receive_mac_event(
|
||||||
} else {
|
} else {
|
||||||
return Err(CancelCode::KeyMismatch);
|
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 {
|
} else {
|
||||||
warn!(
|
warn!(
|
||||||
"Key ID {} in MAC event from {} {} doesn't belong to any device \
|
"Key ID {} in MAC event from {} {} doesn't belong to any device \
|
||||||
|
|
|
@ -107,7 +107,11 @@ impl Sas {
|
||||||
store: Arc<Box<dyn CryptoStore>>,
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
) -> (Sas, StartEventContent) {
|
) -> (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 flow_id = inner.verification_flow_id();
|
||||||
|
|
||||||
let sas = Sas {
|
let sas = Sas {
|
||||||
|
@ -139,7 +143,12 @@ impl Sas {
|
||||||
event: &ToDeviceEvent<StartEventContent>,
|
event: &ToDeviceEvent<StartEventContent>,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
) -> Result<Sas, AnyToDeviceEventContent> {
|
) -> 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();
|
let flow_id = inner.verification_flow_id();
|
||||||
Ok(Sas {
|
Ok(Sas {
|
||||||
inner: Arc::new(Mutex::new(inner)),
|
inner: Arc::new(Mutex::new(inner)),
|
||||||
|
@ -346,8 +355,12 @@ enum InnerSas {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InnerSas {
|
impl InnerSas {
|
||||||
fn start(account: Account, other_device: ReadOnlyDevice) -> (InnerSas, StartEventContent) {
|
fn start(
|
||||||
let sas = SasState::<Created>::new(account, other_device);
|
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();
|
let content = sas.as_content();
|
||||||
(InnerSas::Created(sas), content)
|
(InnerSas::Created(sas), content)
|
||||||
}
|
}
|
||||||
|
@ -356,8 +369,9 @@ impl InnerSas {
|
||||||
account: Account,
|
account: Account,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
event: &ToDeviceEvent<StartEventContent>,
|
event: &ToDeviceEvent<StartEventContent>,
|
||||||
|
other_identity: Option<UserIdentities>,
|
||||||
) -> Result<InnerSas, AnyToDeviceEventContent> {
|
) -> 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)),
|
Ok(s) => Ok(InnerSas::Started(s)),
|
||||||
Err(s) => Err(s.as_content()),
|
Err(s) => Err(s.as_content()),
|
||||||
}
|
}
|
||||||
|
@ -599,12 +613,13 @@ mod test {
|
||||||
let bob = Account::new(&bob_id(), &bob_device_id());
|
let bob = Account::new(&bob_id(), &bob_device_id());
|
||||||
let bob_device = ReadOnlyDevice::from_account(&bob).await;
|
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 start_content = alice_sas.as_content();
|
||||||
let event = wrap_to_device_event(alice_sas.user_id(), start_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())
|
(alice_sas, bob_sas.unwrap())
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ use matrix_sdk_common::{
|
||||||
|
|
||||||
use super::helpers::{get_decimal, get_emoji, get_mac_content, receive_mac_event, SasIds};
|
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] =
|
const KEY_AGREEMENT_PROTOCOLS: &[KeyAgreementProtocol] =
|
||||||
&[KeyAgreementProtocol::Curve25519HkdfSha256];
|
&[KeyAgreementProtocol::Curve25519HkdfSha256];
|
||||||
|
@ -286,7 +286,11 @@ impl SasState<Created> {
|
||||||
/// * `account` - Our own account.
|
/// * `account` - Our own account.
|
||||||
///
|
///
|
||||||
/// * `other_device` - The other device which we are going to verify.
|
/// * `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();
|
let verification_flow_id = Uuid::new_v4().to_string();
|
||||||
|
|
||||||
SasState {
|
SasState {
|
||||||
|
@ -294,6 +298,7 @@ impl SasState<Created> {
|
||||||
ids: SasIds {
|
ids: SasIds {
|
||||||
account,
|
account,
|
||||||
other_device,
|
other_device,
|
||||||
|
other_identity,
|
||||||
},
|
},
|
||||||
verification_flow_id: Arc::new(verification_flow_id),
|
verification_flow_id: Arc::new(verification_flow_id),
|
||||||
|
|
||||||
|
@ -382,6 +387,7 @@ impl SasState<Started> {
|
||||||
account: Account,
|
account: Account,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
event: &ToDeviceEvent<StartEventContent>,
|
event: &ToDeviceEvent<StartEventContent>,
|
||||||
|
other_identity: Option<UserIdentities>,
|
||||||
) -> Result<SasState<Started>, SasState<Canceled>> {
|
) -> Result<SasState<Started>, SasState<Canceled>> {
|
||||||
if let StartMethod::MSasV1(content) = &event.content.method {
|
if let StartMethod::MSasV1(content) = &event.content.method {
|
||||||
let sas = OlmSas::new();
|
let sas = OlmSas::new();
|
||||||
|
@ -397,6 +403,7 @@ impl SasState<Started> {
|
||||||
ids: SasIds {
|
ids: SasIds {
|
||||||
account,
|
account,
|
||||||
other_device,
|
other_device,
|
||||||
|
other_identity,
|
||||||
},
|
},
|
||||||
|
|
||||||
creation_time: Arc::new(Instant::now()),
|
creation_time: Arc::new(Instant::now()),
|
||||||
|
@ -438,6 +445,7 @@ impl SasState<Started> {
|
||||||
ids: SasIds {
|
ids: SasIds {
|
||||||
account,
|
account,
|
||||||
other_device,
|
other_device,
|
||||||
|
other_identity,
|
||||||
},
|
},
|
||||||
|
|
||||||
verification_flow_id: Arc::new(event.content.transaction_id.clone()),
|
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 = Account::new(&bob_id(), &bob_device_id());
|
||||||
let bob_device = ReadOnlyDevice::from_account(&bob).await;
|
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 start_content = alice_sas.as_content();
|
||||||
let event = wrap_to_device_event(alice_sas.user_id(), start_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())
|
(alice_sas, bob_sas.unwrap())
|
||||||
}
|
}
|
||||||
|
@ -1027,7 +1036,7 @@ mod test {
|
||||||
let bob = Account::new(&bob_id(), &bob_device_id());
|
let bob = Account::new(&bob_id(), &bob_device_id());
|
||||||
let bob_device = ReadOnlyDevice::from_account(&bob).await;
|
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();
|
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);
|
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");
|
.expect_err("Didn't cancel on invalid MAC method");
|
||||||
|
|
||||||
let mut start_content = alice_sas.as_content();
|
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);
|
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");
|
.expect_err("Didn't cancel on unknown sas method");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue