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

View File

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

View File

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