crypto: Add another SAS state so we know when both parties accepted

master
Damir Jelić 2021-06-29 09:16:22 +02:00
parent 113587247e
commit 9052843acb
3 changed files with 88 additions and 18 deletions

View File

@ -24,6 +24,7 @@ use ruma::{
use super::{ use super::{
sas_state::{ sas_state::{
Accepted, Confirmed, Created, KeyReceived, MacReceived, SasState, Started, WaitingForDone, Accepted, Confirmed, Created, KeyReceived, MacReceived, SasState, Started, WaitingForDone,
WeAccepted,
}, },
FlowId, FlowId,
}; };
@ -41,6 +42,7 @@ pub enum InnerSas {
Created(SasState<Created>), Created(SasState<Created>),
Started(SasState<Started>), Started(SasState<Started>),
Accepted(SasState<Accepted>), Accepted(SasState<Accepted>),
WeAccepted(SasState<WeAccepted>),
KeyReceived(SasState<KeyReceived>), KeyReceived(SasState<KeyReceived>),
Confirmed(SasState<Confirmed>), Confirmed(SasState<Confirmed>),
MacReceived(SasState<MacReceived>), MacReceived(SasState<MacReceived>),
@ -65,6 +67,7 @@ impl InnerSas {
match self { match self {
InnerSas::Created(s) => s.started_from_request, InnerSas::Created(s) => s.started_from_request,
InnerSas::Started(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::Accepted(s) => s.started_from_request,
InnerSas::KeyReceived(s) => s.started_from_request, InnerSas::KeyReceived(s) => s.started_from_request,
InnerSas::Confirmed(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 { pub fn supports_emoji(&self) -> bool {
match self { match self {
InnerSas::Created(_) => false, InnerSas::Created(_) => false,
@ -83,6 +99,11 @@ impl InnerSas {
.accepted_protocols .accepted_protocols
.short_auth_string .short_auth_string
.contains(&ShortAuthenticationString::Emoji), .contains(&ShortAuthenticationString::Emoji),
InnerSas::WeAccepted(s) => s
.state
.accepted_protocols
.short_auth_string
.contains(&ShortAuthenticationString::Emoji),
InnerSas::Accepted(s) => s InnerSas::Accepted(s) => s
.state .state
.accepted_protocols .accepted_protocols
@ -144,9 +165,11 @@ impl InnerSas {
} }
} }
pub fn accept(&self) -> Option<OwnedAcceptContent> { pub fn accept(self) -> Option<(InnerSas, OwnedAcceptContent)> {
if let InnerSas::Started(s) = self { 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 { } else {
None None
} }
@ -165,6 +188,7 @@ impl InnerSas {
InnerSas::MacReceived(s) => s.set_creation_time(time), InnerSas::MacReceived(s) => s.set_creation_time(time),
InnerSas::Done(s) => s.set_creation_time(time), InnerSas::Done(s) => s.set_creation_time(time),
InnerSas::WaitingForDone(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::Created(s) => s.cancel(cancelled_by_us, code),
InnerSas::Started(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::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::KeyReceived(s) => s.cancel(cancelled_by_us, code),
InnerSas::MacReceived(s) => s.cancel(cancelled_by_us, code), InnerSas::MacReceived(s) => s.cancel(cancelled_by_us, code),
_ => return (self, None), _ => return (self, None),
@ -245,7 +270,7 @@ impl InnerSas {
(InnerSas::Cancelled(s), Some(content)) (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) => { Ok(s) => {
let content = s.as_content(); let content = s.as_content();
(InnerSas::KeyReceived(s), Some(content)) (InnerSas::KeyReceived(s), Some(content))
@ -347,6 +372,7 @@ impl InnerSas {
InnerSas::MacReceived(s) => s.timed_out(), InnerSas::MacReceived(s) => s.timed_out(),
InnerSas::WaitingForDone(s) => s.timed_out(), InnerSas::WaitingForDone(s) => s.timed_out(),
InnerSas::Done(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::MacReceived(s) => s.verification_flow_id.clone(),
InnerSas::WaitingForDone(s) => s.verification_flow_id.clone(), InnerSas::WaitingForDone(s) => s.verification_flow_id.clone(),
InnerSas::Done(s) => s.verification_flow_id.clone(), InnerSas::Done(s) => s.verification_flow_id.clone(),
InnerSas::WeAccepted(s) => s.verification_flow_id.clone(),
} }
} }

View File

@ -119,6 +119,11 @@ impl Sas {
self.inner.lock().unwrap().have_we_confirmed() 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 /// Get the cancel code of this SAS verification if it has been cancelled
pub fn cancel_code(&self) -> Option<CancelCode> { pub fn cancel_code(&self) -> Option<CancelCode> {
self.inner.lock().unwrap().cancel_code() self.inner.lock().unwrap().cancel_code()
@ -310,18 +315,28 @@ impl Sas {
&self, &self,
settings: AcceptSettings, settings: AcceptSettings,
) -> Option<OutgoingVerificationRequest> { ) -> Option<OutgoingVerificationRequest> {
self.inner.lock().unwrap().accept().map(|c| match settings.apply(c) { let mut guard = self.inner.lock().unwrap();
OwnedAcceptContent::ToDevice(c) => { let sas: InnerSas = (*guard).clone();
let content = AnyToDeviceEventContent::KeyVerificationAccept(c);
self.content_to_request(content).into() if let Some((sas, content)) = sas.accept() {
} *guard = sas;
OwnedAcceptContent::Room(room_id, content) => RoomMessageRequest { let content = settings.apply(content);
room_id,
txn_id: Uuid::new_v4(), Some(match content {
content: AnyMessageEventContent::KeyVerificationAccept(content), OwnedAcceptContent::ToDevice(c) => {
} let content = AnyToDeviceEventContent::KeyVerificationAccept(c);
.into(), 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. /// Confirm the Sas verification.

View File

@ -241,6 +241,15 @@ pub struct Accepted {
commitment: String, 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<AcceptedProtocols>,
commitment: String,
}
/// The SAS state we're going to be in after we received the public key of the /// The SAS state we're going to be in after we received the public key of the
/// other participant. /// other participant.
/// ///
@ -548,6 +557,24 @@ impl SasState<Started> {
} }
} }
pub fn into_accepted(self) -> SasState<WeAccepted> {
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<WeAccepted> {
/// Get the content for the accept event. /// Get the content for the accept event.
/// ///
/// The content needs to be sent to the other device. /// The content needs to be sent to the other device.
@ -1093,7 +1120,7 @@ mod test {
}; };
use serde_json::json; use serde_json::json;
use super::{Accepted, Created, SasState, Started}; use super::{Accepted, Created, SasState, Started, WeAccepted};
use crate::{ use crate::{
verification::event_enums::{AcceptContent, KeyContent, MacContent, StartContent}, verification::event_enums::{AcceptContent, KeyContent, MacContent, StartContent},
ReadOnlyAccount, ReadOnlyDevice, ReadOnlyAccount, ReadOnlyDevice,
@ -1115,7 +1142,7 @@ mod test {
"BOBDEVCIE".into() "BOBDEVCIE".into()
} }
async fn get_sas_pair() -> (SasState<Created>, SasState<Started>) { async fn get_sas_pair() -> (SasState<Created>, SasState<WeAccepted>) {
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id()); let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
let alice_device = ReadOnlyDevice::from_account(&alice).await; let alice_device = ReadOnlyDevice::from_account(&alice).await;
@ -1135,8 +1162,9 @@ mod test {
&start_content.as_start_content(), &start_content.as_start_content(),
false, false,
); );
let bob_sas = bob_sas.unwrap().into_accepted();
(alice_sas, bob_sas.unwrap()) (alice_sas, bob_sas)
} }
#[tokio::test] #[tokio::test]