From 9052843acbc762388f4ae59e6dad0d580914cf59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 29 Jun 2021 09:16:22 +0200 Subject: [PATCH] crypto: Add another SAS state so we know when both parties accepted --- .../src/verification/sas/inner_sas.rs | 33 ++++++++++++++-- matrix_sdk_crypto/src/verification/sas/mod.rs | 39 +++++++++++++------ .../src/verification/sas/sas_state.rs | 34 ++++++++++++++-- 3 files changed, 88 insertions(+), 18 deletions(-) diff --git a/matrix_sdk_crypto/src/verification/sas/inner_sas.rs b/matrix_sdk_crypto/src/verification/sas/inner_sas.rs index d8f35332..fd6fe7a1 100644 --- a/matrix_sdk_crypto/src/verification/sas/inner_sas.rs +++ b/matrix_sdk_crypto/src/verification/sas/inner_sas.rs @@ -24,6 +24,7 @@ use ruma::{ use super::{ sas_state::{ Accepted, Confirmed, Created, KeyReceived, MacReceived, SasState, Started, WaitingForDone, + WeAccepted, }, FlowId, }; @@ -41,6 +42,7 @@ pub enum InnerSas { Created(SasState), Started(SasState), Accepted(SasState), + WeAccepted(SasState), KeyReceived(SasState), Confirmed(SasState), MacReceived(SasState), @@ -65,6 +67,7 @@ impl InnerSas { match self { InnerSas::Created(s) => s.started_from_request, InnerSas::Started(s) => s.started_from_request, + InnerSas::WeAccepted(s) => s.started_from_request, InnerSas::Accepted(s) => s.started_from_request, InnerSas::KeyReceived(s) => s.started_from_request, InnerSas::Confirmed(s) => s.started_from_request, @@ -75,6 +78,19 @@ impl InnerSas { } } + pub fn has_been_accepted(&self) -> bool { + match self { + InnerSas::Created(_) | InnerSas::Started(_) | InnerSas::Cancelled(_) => false, + InnerSas::Accepted(_) + | InnerSas::WeAccepted(_) + | InnerSas::KeyReceived(_) + | InnerSas::Confirmed(_) + | InnerSas::MacReceived(_) + | InnerSas::WaitingForDone(_) + | InnerSas::Done(_) => true, + } + } + pub fn supports_emoji(&self) -> bool { match self { InnerSas::Created(_) => false, @@ -83,6 +99,11 @@ impl InnerSas { .accepted_protocols .short_auth_string .contains(&ShortAuthenticationString::Emoji), + InnerSas::WeAccepted(s) => s + .state + .accepted_protocols + .short_auth_string + .contains(&ShortAuthenticationString::Emoji), InnerSas::Accepted(s) => s .state .accepted_protocols @@ -144,9 +165,11 @@ impl InnerSas { } } - pub fn accept(&self) -> Option { + pub fn accept(self) -> Option<(InnerSas, OwnedAcceptContent)> { if let InnerSas::Started(s) = self { - Some(s.as_content()) + let sas = s.into_accepted(); + let content = sas.as_content(); + Some((InnerSas::WeAccepted(sas), content)) } else { None } @@ -165,6 +188,7 @@ impl InnerSas { InnerSas::MacReceived(s) => s.set_creation_time(time), InnerSas::Done(s) => s.set_creation_time(time), InnerSas::WaitingForDone(s) => s.set_creation_time(time), + InnerSas::WeAccepted(s) => s.set_creation_time(time), } } @@ -177,6 +201,7 @@ impl InnerSas { InnerSas::Created(s) => s.cancel(cancelled_by_us, code), InnerSas::Started(s) => s.cancel(cancelled_by_us, code), InnerSas::Accepted(s) => s.cancel(cancelled_by_us, code), + InnerSas::WeAccepted(s) => s.cancel(cancelled_by_us, code), InnerSas::KeyReceived(s) => s.cancel(cancelled_by_us, code), InnerSas::MacReceived(s) => s.cancel(cancelled_by_us, code), _ => return (self, None), @@ -245,7 +270,7 @@ impl InnerSas { (InnerSas::Cancelled(s), Some(content)) } }, - InnerSas::Started(s) => match s.into_key_received(sender, c) { + InnerSas::WeAccepted(s) => match s.into_key_received(sender, c) { Ok(s) => { let content = s.as_content(); (InnerSas::KeyReceived(s), Some(content)) @@ -347,6 +372,7 @@ impl InnerSas { InnerSas::MacReceived(s) => s.timed_out(), InnerSas::WaitingForDone(s) => s.timed_out(), InnerSas::Done(s) => s.timed_out(), + InnerSas::WeAccepted(s) => s.timed_out(), } } @@ -361,6 +387,7 @@ impl InnerSas { InnerSas::MacReceived(s) => s.verification_flow_id.clone(), InnerSas::WaitingForDone(s) => s.verification_flow_id.clone(), InnerSas::Done(s) => s.verification_flow_id.clone(), + InnerSas::WeAccepted(s) => s.verification_flow_id.clone(), } } diff --git a/matrix_sdk_crypto/src/verification/sas/mod.rs b/matrix_sdk_crypto/src/verification/sas/mod.rs index 0079a4b0..eb4b78af 100644 --- a/matrix_sdk_crypto/src/verification/sas/mod.rs +++ b/matrix_sdk_crypto/src/verification/sas/mod.rs @@ -119,6 +119,11 @@ impl Sas { self.inner.lock().unwrap().have_we_confirmed() } + /// Has the verification been accepted by both parties. + pub fn has_been_accepted(&self) -> bool { + self.inner.lock().unwrap().has_been_accepted() + } + /// Get the cancel code of this SAS verification if it has been cancelled pub fn cancel_code(&self) -> Option { self.inner.lock().unwrap().cancel_code() @@ -310,18 +315,28 @@ impl Sas { &self, settings: AcceptSettings, ) -> Option { - self.inner.lock().unwrap().accept().map(|c| match settings.apply(c) { - OwnedAcceptContent::ToDevice(c) => { - let content = AnyToDeviceEventContent::KeyVerificationAccept(c); - self.content_to_request(content).into() - } - OwnedAcceptContent::Room(room_id, content) => RoomMessageRequest { - room_id, - txn_id: Uuid::new_v4(), - content: AnyMessageEventContent::KeyVerificationAccept(content), - } - .into(), - }) + let mut guard = self.inner.lock().unwrap(); + let sas: InnerSas = (*guard).clone(); + + if let Some((sas, content)) = sas.accept() { + *guard = sas; + let content = settings.apply(content); + + Some(match content { + OwnedAcceptContent::ToDevice(c) => { + let content = AnyToDeviceEventContent::KeyVerificationAccept(c); + self.content_to_request(content).into() + } + OwnedAcceptContent::Room(room_id, content) => RoomMessageRequest { + room_id, + txn_id: Uuid::new_v4(), + content: AnyMessageEventContent::KeyVerificationAccept(content), + } + .into(), + }) + } else { + None + } } /// Confirm the Sas verification. diff --git a/matrix_sdk_crypto/src/verification/sas/sas_state.rs b/matrix_sdk_crypto/src/verification/sas/sas_state.rs index eb9d78c8..af5dad17 100644 --- a/matrix_sdk_crypto/src/verification/sas/sas_state.rs +++ b/matrix_sdk_crypto/src/verification/sas/sas_state.rs @@ -241,6 +241,15 @@ pub struct Accepted { commitment: String, } +/// The SAS state we're going to be in after we accepted our +/// verification start event. +#[derive(Clone, Debug)] +pub struct WeAccepted { + we_started: bool, + pub accepted_protocols: Arc, + commitment: String, +} + /// The SAS state we're going to be in after we received the public key of the /// other participant. /// @@ -548,6 +557,24 @@ impl SasState { } } + pub fn into_accepted(self) -> SasState { + SasState { + inner: self.inner, + ids: self.ids, + verification_flow_id: self.verification_flow_id, + creation_time: self.creation_time, + last_event_time: self.last_event_time, + started_from_request: self.started_from_request, + state: Arc::new(WeAccepted { + we_started: false, + accepted_protocols: self.state.accepted_protocols.clone(), + commitment: self.state.commitment.clone(), + }), + } + } +} + +impl SasState { /// Get the content for the accept event. /// /// The content needs to be sent to the other device. @@ -1093,7 +1120,7 @@ mod test { }; use serde_json::json; - use super::{Accepted, Created, SasState, Started}; + use super::{Accepted, Created, SasState, Started, WeAccepted}; use crate::{ verification::event_enums::{AcceptContent, KeyContent, MacContent, StartContent}, ReadOnlyAccount, ReadOnlyDevice, @@ -1115,7 +1142,7 @@ mod test { "BOBDEVCIE".into() } - async fn get_sas_pair() -> (SasState, SasState) { + async fn get_sas_pair() -> (SasState, SasState) { let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id()); let alice_device = ReadOnlyDevice::from_account(&alice).await; @@ -1135,8 +1162,9 @@ mod test { &start_content.as_start_content(), false, ); + let bob_sas = bob_sas.unwrap().into_accepted(); - (alice_sas, bob_sas.unwrap()) + (alice_sas, bob_sas) } #[tokio::test]