crypto: Use the verification cache in verification requests

master
Damir Jelić 2021-05-24 14:54:11 +02:00
parent d928f39f68
commit 300189bb37
3 changed files with 170 additions and 75 deletions

View File

@ -44,7 +44,7 @@ pub struct VerificationCache {
} }
impl VerificationCache { impl VerificationCache {
fn new() -> Self { pub fn new() -> Self {
Self { Self {
sas_verification: DashMap::new().into(), sas_verification: DashMap::new().into(),
room_sas_verifications: DashMap::new().into(), room_sas_verifications: DashMap::new().into(),
@ -257,6 +257,7 @@ impl VerificationMachine {
); );
let request = VerificationRequest::from_room_request( let request = VerificationRequest::from_room_request(
self.verifications.clone(),
self.account.clone(), self.account.clone(),
self.private_identity.lock().await.clone(), self.private_identity.lock().await.clone(),
self.store.clone(), self.store.clone(),
@ -291,7 +292,7 @@ impl VerificationMachine {
self.store.get_device(&e.sender, &e.content.from_device).await? self.store.get_device(&e.sender, &e.content.from_device).await?
{ {
match request.into_started_sas( match request.into_started_sas(
e, &e.content,
d, d,
self.store.get_user_identity(&e.sender).await?, self.store.get_user_identity(&e.sender).await?,
) { ) {
@ -388,6 +389,7 @@ impl VerificationMachine {
match event { match event {
AnyToDeviceEvent::KeyVerificationRequest(e) => { AnyToDeviceEvent::KeyVerificationRequest(e) => {
let request = VerificationRequest::from_request( let request = VerificationRequest::from_request(
self.verifications.clone(),
self.account.clone(), self.account.clone(),
self.private_identity.lock().await.clone(), self.private_identity.lock().await.clone(),
self.store.clone(), self.store.clone(),

View File

@ -16,7 +16,7 @@ mod machine;
mod requests; mod requests;
mod sas; mod sas;
pub use machine::VerificationMachine; pub use machine::{VerificationCache, VerificationMachine};
use matrix_sdk_common::identifiers::{EventId, RoomId}; use matrix_sdk_common::identifiers::{EventId, RoomId};
pub use requests::VerificationRequest; pub use requests::VerificationRequest;
pub use sas::{AcceptSettings, Sas, VerificationResult}; pub use sas::{AcceptSettings, Sas, VerificationResult};

View File

@ -25,19 +25,20 @@ use matrix_sdk_common::{
key::verification::{ key::verification::{
ready::{ReadyEventContent, ReadyToDeviceEventContent}, ready::{ReadyEventContent, ReadyToDeviceEventContent},
request::RequestToDeviceEventContent, request::RequestToDeviceEventContent,
start::StartEventContent, start::{StartEventContent, StartMethod, StartToDeviceEventContent},
Relation, VerificationMethod, Relation, VerificationMethod,
}, },
room::message::KeyVerificationRequestEventContent, room::message::KeyVerificationRequestEventContent,
AnyMessageEventContent, AnyToDeviceEventContent, MessageEvent, SyncMessageEvent, AnyMessageEventContent, AnyToDeviceEventContent,
}, },
identifiers::{DeviceId, DeviceIdBox, EventId, RoomId, UserId}, identifiers::{DeviceId, DeviceIdBox, EventId, RoomId, UserId},
uuid::Uuid, uuid::Uuid,
MilliSecondsSinceUnixEpoch,
}; };
use super::{ use super::{
sas::{content_to_request, OutgoingContent, StartContent}, sas::{content_to_request, OutgoingContent, StartContent as OwnedStartContent},
FlowId, FlowId, VerificationCache,
}; };
use crate::{ use crate::{
olm::{PrivateCrossSigningIdentity, ReadOnlyAccount}, olm::{PrivateCrossSigningIdentity, ReadOnlyAccount},
@ -137,9 +138,74 @@ impl<'a> TryFrom<&'a OutgoingContent> for ReadyContent<'a> {
} }
} }
pub enum StartContent<'a> {
ToDevice(&'a StartToDeviceEventContent),
Room(&'a StartEventContent),
}
impl<'a> StartContent<'a> {
pub fn from_device(&self) -> &DeviceId {
match self {
StartContent::ToDevice(c) => &c.from_device,
StartContent::Room(c) => &c.from_device,
}
}
pub fn flow_id(&self) -> &str {
match self {
StartContent::ToDevice(c) => &c.transaction_id,
StartContent::Room(c) => &c.relation.event_id.as_str(),
}
}
pub fn methods(&self) -> &StartMethod {
match self {
StartContent::ToDevice(c) => &c.method,
StartContent::Room(c) => &c.method,
}
}
}
impl<'a> From<&'a StartEventContent> for StartContent<'a> {
fn from(c: &'a StartEventContent) -> Self {
Self::Room(c)
}
}
impl<'a> From<&'a StartToDeviceEventContent> for StartContent<'a> {
fn from(c: &'a StartToDeviceEventContent) -> Self {
Self::ToDevice(c)
}
}
impl<'a> TryFrom<&'a OutgoingContent> for StartContent<'a> {
type Error = ();
fn try_from(value: &'a OutgoingContent) -> Result<Self, Self::Error> {
match value {
OutgoingContent::Room(_, c) => {
if let AnyMessageEventContent::KeyVerificationStart(c) = c {
Ok(StartContent::Room(c))
} else {
Err(())
}
}
OutgoingContent::ToDevice(c) => {
if let AnyToDeviceEventContent::KeyVerificationStart(c) = c {
Ok(StartContent::ToDevice(c))
} else {
Err(())
}
}
}
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
/// TODO /// TODO
pub struct VerificationRequest { pub struct VerificationRequest {
verification_cache: VerificationCache,
account: ReadOnlyAccount,
flow_id: Arc<FlowId>, flow_id: Arc<FlowId>,
other_user_id: Arc<UserId>, other_user_id: Arc<UserId>,
inner: Arc<Mutex<InnerRequest>>, inner: Arc<Mutex<InnerRequest>>,
@ -147,7 +213,8 @@ pub struct VerificationRequest {
impl VerificationRequest { impl VerificationRequest {
/// TODO /// TODO
pub fn new( pub(crate) fn new(
cache: VerificationCache,
account: ReadOnlyAccount, account: ReadOnlyAccount,
private_cross_signing_identity: PrivateCrossSigningIdentity, private_cross_signing_identity: PrivateCrossSigningIdentity,
store: Arc<Box<dyn CryptoStore>>, store: Arc<Box<dyn CryptoStore>>,
@ -158,7 +225,7 @@ impl VerificationRequest {
let flow_id = (room_id.to_owned(), event_id.to_owned()).into(); let flow_id = (room_id.to_owned(), event_id.to_owned()).into();
let inner = Mutex::new(InnerRequest::Created(RequestState::new( let inner = Mutex::new(InnerRequest::Created(RequestState::new(
account, account.clone(),
private_cross_signing_identity, private_cross_signing_identity,
store, store,
other_user, other_user,
@ -166,7 +233,23 @@ impl VerificationRequest {
))) )))
.into(); .into();
Self { flow_id: flow_id.into(), inner, other_user_id: other_user.to_owned().into() } Self {
account,
verification_cache: cache,
flow_id: flow_id.into(),
inner,
other_user_id: other_user.to_owned().into(),
}
}
/// TODO
pub fn request_to_device(&self) -> RequestToDeviceEventContent {
RequestToDeviceEventContent::new(
self.account.device_id().into(),
self.flow_id().as_str().to_string(),
SUPPORTED_METHODS.to_vec(),
MilliSecondsSinceUnixEpoch::now(),
)
} }
/// TODO /// TODO
@ -200,6 +283,7 @@ impl VerificationRequest {
} }
pub(crate) fn from_room_request( pub(crate) fn from_room_request(
cache: VerificationCache,
account: ReadOnlyAccount, account: ReadOnlyAccount,
private_cross_signing_identity: PrivateCrossSigningIdentity, private_cross_signing_identity: PrivateCrossSigningIdentity,
store: Arc<Box<dyn CryptoStore>>, store: Arc<Box<dyn CryptoStore>>,
@ -210,6 +294,7 @@ impl VerificationRequest {
) -> Self { ) -> Self {
let flow_id = FlowId::from((room_id.to_owned(), event_id.to_owned())); let flow_id = FlowId::from((room_id.to_owned(), event_id.to_owned()));
Self::from_helper( Self::from_helper(
cache,
account, account,
private_cross_signing_identity, private_cross_signing_identity,
store, store,
@ -220,6 +305,7 @@ impl VerificationRequest {
} }
pub(crate) fn from_request( pub(crate) fn from_request(
cache: VerificationCache,
account: ReadOnlyAccount, account: ReadOnlyAccount,
private_cross_signing_identity: PrivateCrossSigningIdentity, private_cross_signing_identity: PrivateCrossSigningIdentity,
store: Arc<Box<dyn CryptoStore>>, store: Arc<Box<dyn CryptoStore>>,
@ -228,6 +314,7 @@ impl VerificationRequest {
) -> Self { ) -> Self {
let flow_id = FlowId::from(content.transaction_id.to_owned()); let flow_id = FlowId::from(content.transaction_id.to_owned());
Self::from_helper( Self::from_helper(
cache,
account, account,
private_cross_signing_identity, private_cross_signing_identity,
store, store,
@ -238,6 +325,7 @@ impl VerificationRequest {
} }
fn from_helper( fn from_helper(
cache: VerificationCache,
account: ReadOnlyAccount, account: ReadOnlyAccount,
private_cross_signing_identity: PrivateCrossSigningIdentity, private_cross_signing_identity: PrivateCrossSigningIdentity,
store: Arc<Box<dyn CryptoStore>>, store: Arc<Box<dyn CryptoStore>>,
@ -246,14 +334,16 @@ impl VerificationRequest {
content: RequestContent, content: RequestContent,
) -> Self { ) -> Self {
Self { Self {
verification_cache: cache,
inner: Arc::new(Mutex::new(InnerRequest::Requested(RequestState::from_request_event( inner: Arc::new(Mutex::new(InnerRequest::Requested(RequestState::from_request_event(
account, account.clone(),
private_cross_signing_identity, private_cross_signing_identity,
store, store,
sender, sender,
&flow_id, &flow_id,
content, content,
)))), )))),
account,
other_user_id: sender.to_owned().into(), other_user_id: sender.to_owned().into(),
flow_id: flow_id.into(), flow_id: flow_id.into(),
} }
@ -294,24 +384,21 @@ impl VerificationRequest {
matches!(&*self.inner.lock().unwrap(), InnerRequest::Ready(_)) matches!(&*self.inner.lock().unwrap(), InnerRequest::Ready(_))
} }
pub(crate) fn into_started_sas( pub(crate) fn into_started_sas<'a>(
self, self,
event: &SyncMessageEvent<StartEventContent>, content: impl Into<StartContent<'a>>,
device: ReadOnlyDevice, device: ReadOnlyDevice,
user_identity: Option<UserIdentities>, user_identity: Option<UserIdentities>,
) -> Result<Sas, OutgoingContent> { ) -> Result<Sas, OutgoingContent> {
match &*self.inner.lock().unwrap() { match &*self.inner.lock().unwrap() {
InnerRequest::Ready(s) => match &s.state.flow_id { InnerRequest::Ready(s) => s.clone().into_started_sas(
FlowId::ToDevice(_) => todo!(), content,
FlowId::InRoom(r, _) => s.clone().into_started_sas(
&event.clone().into_full_event(r.to_owned()),
s.store.clone(), s.store.clone(),
s.account.clone(), s.account.clone(),
s.private_cross_signing_identity.clone(), s.private_cross_signing_identity.clone(),
device, device,
user_identity, user_identity,
), ),
},
// TODO cancel here since we got a missmatched message or do // TODO cancel here since we got a missmatched message or do
// nothing? // nothing?
_ => todo!(), _ => todo!(),
@ -322,18 +409,15 @@ impl VerificationRequest {
&self, &self,
device: ReadOnlyDevice, device: ReadOnlyDevice,
user_identity: Option<UserIdentities>, user_identity: Option<UserIdentities>,
) -> Option<(Sas, StartContent)> { ) -> Option<(Sas, OutgoingContent)> {
match &*self.inner.lock().unwrap() { match &*self.inner.lock().unwrap() {
InnerRequest::Ready(s) => match &s.state.flow_id { InnerRequest::Ready(s) => Some(s.clone().start_sas(
FlowId::ToDevice(_) => todo!(),
FlowId::InRoom(_, _) => Some(s.clone().start_sas(
s.store.clone(), s.store.clone(),
s.account.clone(), s.account.clone(),
s.private_cross_signing_identity.clone(), s.private_cross_signing_identity.clone(),
device, device,
user_identity, user_identity,
)), )),
},
_ => None, _ => None,
} }
} }
@ -387,9 +471,9 @@ impl InnerRequest {
} }
} }
fn into_started_sas( fn into_started_sas<'a>(
self, self,
event: &MessageEvent<StartEventContent>, content: impl Into<StartContent<'a>>,
store: Arc<Box<dyn CryptoStore>>, store: Arc<Box<dyn CryptoStore>>,
account: ReadOnlyAccount, account: ReadOnlyAccount,
private_identity: PrivateCrossSigningIdentity, private_identity: PrivateCrossSigningIdentity,
@ -398,7 +482,7 @@ impl InnerRequest {
) -> Result<Option<Sas>, OutgoingContent> { ) -> Result<Option<Sas>, OutgoingContent> {
if let InnerRequest::Ready(s) = self { if let InnerRequest::Ready(s) = self {
Ok(Some(s.into_started_sas( Ok(Some(s.into_started_sas(
event, content,
store, store,
account, account,
private_identity, private_identity,
@ -559,21 +643,33 @@ struct Ready {
} }
impl RequestState<Ready> { impl RequestState<Ready> {
fn into_started_sas( fn into_started_sas<'a>(
self, self,
event: &MessageEvent<StartEventContent>, content: impl Into<StartContent<'a>>,
store: Arc<Box<dyn CryptoStore>>, store: Arc<Box<dyn CryptoStore>>,
account: ReadOnlyAccount, account: ReadOnlyAccount,
private_identity: PrivateCrossSigningIdentity, private_identity: PrivateCrossSigningIdentity,
other_device: ReadOnlyDevice, other_device: ReadOnlyDevice,
other_identity: Option<UserIdentities>, other_identity: Option<UserIdentities>,
) -> Result<Sas, OutgoingContent> { ) -> Result<Sas, OutgoingContent> {
let content: OwnedStartContent = match content.into() {
StartContent::Room(c) => {
if let FlowId::InRoom(r, _) = &*self.flow_id {
(r.to_owned(), c.to_owned()).into()
} else {
// TODO cancel here
panic!("Missmatch between content and flow id");
}
}
StartContent::ToDevice(c) => c.clone().into(),
};
Sas::from_start_event( Sas::from_start_event(
account, account,
private_identity, private_identity,
other_device, other_device,
store, store,
(event.room_id.clone(), event.content.clone()), content,
other_identity, other_identity,
) )
} }
@ -585,12 +681,21 @@ impl RequestState<Ready> {
private_identity: PrivateCrossSigningIdentity, private_identity: PrivateCrossSigningIdentity,
other_device: ReadOnlyDevice, other_device: ReadOnlyDevice,
other_identity: Option<UserIdentities>, other_identity: Option<UserIdentities>,
) -> (Sas, StartContent) { ) -> (Sas, OutgoingContent) {
match self.state.flow_id { match self.state.flow_id {
FlowId::ToDevice(t) => { FlowId::ToDevice(t) => {
Sas::start(account, private_identity, other_device, store, other_identity, Some(t)) let (sas, content) = Sas::start(
account,
private_identity,
other_device,
store,
other_identity,
Some(t),
);
(sas, content.into())
} }
FlowId::InRoom(r, e) => Sas::start_in_room( FlowId::InRoom(r, e) => {
let (sas, content) = Sas::start_in_room(
e, e,
r, r,
account, account,
@ -598,7 +703,9 @@ impl RequestState<Ready> {
other_device, other_device,
store, store,
other_identity, other_identity,
), );
(sas, content.into())
}
} }
} }
} }
@ -617,21 +724,14 @@ struct Passive {
mod test { mod test {
use std::convert::TryFrom; use std::convert::TryFrom;
use matrix_sdk_common::{ use matrix_sdk_common::identifiers::{event_id, room_id, DeviceIdBox, UserId};
events::{SyncMessageEvent, Unsigned},
identifiers::{event_id, room_id, DeviceIdBox, UserId},
MilliSecondsSinceUnixEpoch,
};
use matrix_sdk_test::async_test; use matrix_sdk_test::async_test;
use super::VerificationRequest; use super::{StartContent, VerificationRequest};
use crate::{ use crate::{
olm::{PrivateCrossSigningIdentity, ReadOnlyAccount}, olm::{PrivateCrossSigningIdentity, ReadOnlyAccount},
store::{CryptoStore, MemoryStore}, store::{CryptoStore, MemoryStore},
verification::{ verification::{requests::ReadyContent, sas::OutgoingContent, VerificationCache},
requests::ReadyContent,
sas::{OutgoingContent, StartContent},
},
ReadOnlyDevice, ReadOnlyDevice,
}; };
@ -667,6 +767,7 @@ mod test {
let content = VerificationRequest::request(bob.user_id(), bob.device_id(), &alice_id()); let content = VerificationRequest::request(bob.user_id(), bob.device_id(), &alice_id());
let bob_request = VerificationRequest::new( let bob_request = VerificationRequest::new(
VerificationCache::new(),
bob, bob,
bob_identity, bob_identity,
bob_store.into(), bob_store.into(),
@ -676,6 +777,7 @@ mod test {
); );
let alice_request = VerificationRequest::from_room_request( let alice_request = VerificationRequest::from_room_request(
VerificationCache::new(),
alice, alice,
alice_identity, alice_identity,
alice_store.into(), alice_store.into(),
@ -713,6 +815,7 @@ mod test {
let content = VerificationRequest::request(bob.user_id(), bob.device_id(), &alice_id()); let content = VerificationRequest::request(bob.user_id(), bob.device_id(), &alice_id());
let bob_request = VerificationRequest::new( let bob_request = VerificationRequest::new(
VerificationCache::new(),
bob, bob,
bob_identity, bob_identity,
bob_store.into(), bob_store.into(),
@ -722,6 +825,7 @@ mod test {
); );
let alice_request = VerificationRequest::from_room_request( let alice_request = VerificationRequest::from_room_request(
VerificationCache::new(),
alice, alice,
alice_identity, alice_identity,
alice_store.into(), alice_store.into(),
@ -741,19 +845,8 @@ mod test {
let (bob_sas, start_content) = bob_request.start(alice_device, None).unwrap(); let (bob_sas, start_content) = bob_request.start(alice_device, None).unwrap();
let event = if let StartContent::Room(_, c) = start_content { let content = StartContent::try_from(&start_content).unwrap();
SyncMessageEvent { let alice_sas = alice_request.into_started_sas(content, bob_device, None).unwrap();
content: c,
event_id: event_id.clone(),
sender: bob_id(),
origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
unsigned: Unsigned::default(),
}
} else {
panic!("Invalid start event content type");
};
let alice_sas = alice_request.into_started_sas(&event, bob_device, None).unwrap();
assert!(!bob_sas.is_canceled()); assert!(!bob_sas.is_canceled());
assert!(!alice_sas.is_canceled()); assert!(!alice_sas.is_canceled());