From 7570cf5ac28425b664e8fd578fe7e9028bec5e94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 11 Dec 2020 15:42:49 +0100 Subject: [PATCH] crypto: WIP genrealize the sas so it can handle in-room and to-device events. --- matrix_sdk_crypto/src/verification/machine.rs | 73 ++++++++++++------- .../src/verification/requests.rs | 68 +++++++++++++++-- .../src/verification/sas/event_enums.rs | 41 +++++++++-- .../src/verification/sas/inner_sas.rs | 35 +++++---- matrix_sdk_crypto/src/verification/sas/mod.rs | 32 +++++--- .../src/verification/sas/sas_state.rs | 48 ++++++++---- 6 files changed, 219 insertions(+), 78 deletions(-) diff --git a/matrix_sdk_crypto/src/verification/machine.rs b/matrix_sdk_crypto/src/verification/machine.rs index 0e185418..ccdcf61e 100644 --- a/matrix_sdk_crypto/src/verification/machine.rs +++ b/matrix_sdk_crypto/src/verification/machine.rs @@ -112,17 +112,23 @@ impl VerificationMachine { &self, recipient: &UserId, recipient_device: &DeviceId, - content: AnyToDeviceEventContent, + content: OutgoingContent, ) { - let request = content_to_request(recipient, recipient_device, content); - let request_id = request.txn_id; + match content { + OutgoingContent::ToDevice(c) => { + let request = content_to_request(recipient, recipient_device, c); + let request_id = request.txn_id; - let request = OutgoingRequest { - request_id, - request: Arc::new(request.into()), - }; + let request = OutgoingRequest { + request_id, + request: Arc::new(request.into()), + }; - self.outgoing_to_device_messages.insert(request_id, request); + self.outgoing_to_device_messages.insert(request_id, request); + } + + OutgoingContent::Room(c) => todo!(), + } } fn receive_event_helper(&self, sas: &Sas, event: &AnyToDeviceEvent) { @@ -165,29 +171,41 @@ impl VerificationMachine { room_id: &RoomId, event: &AnySyncRoomEvent, ) -> Result<(), CryptoStoreError> { - match event { - AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomMessage(m)) => { - if let MessageEventContent::VerificationRequest(r) = &m.content { - if self.account.user_id() == &r.to { - info!( - "Received a new verification request from {} {}", - m.sender, r.from_device - ); + if let AnySyncRoomEvent::Message(m) = event { + match m { + AnySyncMessageEvent::RoomMessage(m) => { + if let MessageEventContent::VerificationRequest(r) = &m.content { + if self.account.user_id() == &r.to { + info!( + "Received a new verification request from {} {}", + m.sender, r.from_device + ); - let request = VerificationRequest::from_request_event( - self.account.clone(), - self.store.clone(), - room_id, - &m.sender, - &m.event_id, - r, - ); + let request = VerificationRequest::from_request_event( + self.account.clone(), + self.private_identity.lock().await.clone(), + self.store.clone(), + room_id, + &m.sender, + &m.event_id, + r, + ); - self.requests.insert(m.event_id.clone(), request); + self.requests.insert(m.event_id.clone(), request); + } } } + AnySyncMessageEvent::KeyVerificationStart(e) => { + info!( + "Received a new verification start event from {} {}", + e.sender, e.content.from_device + ); + + if let Some((_, request)) = self.requests.remove(&e.content.relation.event_id) { + } + } + _ => (), } - _ => (), } Ok(()) @@ -215,7 +233,8 @@ impl VerificationMachine { private_identity, d, self.store.clone(), - e, + &e.sender, + e.content.clone(), self.store.get_user_identity(&e.sender).await?, ) { Ok(s) => { diff --git a/matrix_sdk_crypto/src/verification/requests.rs b/matrix_sdk_crypto/src/verification/requests.rs index 2d27af43..5b3102e8 100644 --- a/matrix_sdk_crypto/src/verification/requests.rs +++ b/matrix_sdk_crypto/src/verification/requests.rs @@ -23,6 +23,7 @@ use matrix_sdk_common::{ ready::ReadyEventContent, start::StartEventContent, Relation, VerificationMethod, }, room::message::KeyVerificationRequestEventContent, + MessageEvent, }, identifiers::{DeviceId, DeviceIdBox, EventId, RoomId, UserId}, }; @@ -42,6 +43,7 @@ const SUPPORTED_METHODS: &[VerificationMethod] = &[VerificationMethod::MSasV1]; pub struct VerificationRequest { inner: Arc>, account: ReadOnlyAccount, + private_cross_signing_identity: PrivateCrossSigningIdentity, store: Arc>, room_id: Arc, } @@ -49,6 +51,7 @@ pub struct VerificationRequest { impl VerificationRequest { pub(crate) fn from_request_event( account: ReadOnlyAccount, + private_cross_signing_identity: PrivateCrossSigningIdentity, store: Arc>, room_id: &RoomId, sender: &UserId, @@ -66,6 +69,7 @@ impl VerificationRequest { ), ))), account, + private_cross_signing_identity, store, room_id: room_id.clone().into(), } @@ -80,6 +84,25 @@ impl VerificationRequest { pub fn accept(&self) -> Option { self.inner.lock().unwrap().accept() } + + pub(crate) fn into_started_sas( + &self, + event: &MessageEvent, + device: ReadOnlyDevice, + user_identity: Option, + ) -> Result { + match &*self.inner.lock().unwrap() { + InnerRequest::Ready(s) => s.into_started_sas( + event, + self.store.clone(), + self.account.clone(), + self.private_cross_signing_identity.clone(), + device, + user_identity, + ), + _ => todo!(), + } + } } #[derive(Debug)] @@ -102,6 +125,29 @@ impl InnerRequest { None } } + + fn into_started_sas( + &mut self, + event: &MessageEvent, + store: Arc>, + account: ReadOnlyAccount, + private_identity: PrivateCrossSigningIdentity, + other_device: ReadOnlyDevice, + other_identity: Option, + ) -> Result, OutgoingContent> { + if let InnerRequest::Ready(s) = self { + Ok(Some(s.into_started_sas( + event, + store, + account, + private_identity, + other_device, + other_identity, + )?)) + } else { + Ok(None) + } + } } #[derive(Clone, Debug)] @@ -252,14 +298,23 @@ struct Ready { impl RequestState { fn into_started_sas( - self, + &self, + event: &MessageEvent, + store: Arc>, account: ReadOnlyAccount, private_identity: PrivateCrossSigningIdentity, other_device: ReadOnlyDevice, - other_identity: UserIdentity, - ) -> Sas { - todo!() - // Sas::from_start_event(account, private_identity, other_device, other_identity, event) + other_identity: Option, + ) -> Result { + Sas::from_start_event( + account, + private_identity, + other_device, + store, + &event.sender, + event.content.clone(), + other_identity, + ) } fn start_sas( @@ -289,3 +344,6 @@ struct Passive { /// unique id identifying this verification flow. pub flow_id: EventId, } + +#[derive(Clone, Debug)] +struct Started {} diff --git a/matrix_sdk_crypto/src/verification/sas/event_enums.rs b/matrix_sdk_crypto/src/verification/sas/event_enums.rs index e34ccd6d..830b2939 100644 --- a/matrix_sdk_crypto/src/verification/sas/event_enums.rs +++ b/matrix_sdk_crypto/src/verification/sas/event_enums.rs @@ -18,12 +18,17 @@ use std::convert::TryInto; use matrix_sdk_common::{ events::{ - key::verification::start::{StartEventContent, StartToDeviceEventContent}, + key::verification::{ + start::{StartEventContent, StartMethod, StartToDeviceEventContent}, + KeyAgreementProtocol, + }, AnyMessageEventContent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent, }, CanonicalJsonValue, }; +use super::FlowId; + #[derive(Clone, Debug)] pub enum StartContent { ToDevice(StartToDeviceEventContent), @@ -31,6 +36,20 @@ pub enum StartContent { } impl StartContent { + pub fn method(&self) -> &StartMethod { + match self { + StartContent::ToDevice(c) => &c.method, + StartContent::Room(c) => &c.method, + } + } + + pub fn flow_id(&self) -> FlowId { + match self { + StartContent::ToDevice(c) => FlowId::ToDevice(c.transaction_id.clone()), + StartContent::Room(c) => FlowId::InRoom(c.relation.event_id.clone()), + } + } + pub fn to_canonical_json(self) -> CanonicalJsonValue { let content = match self { StartContent::Room(c) => serde_json::to_value(c), @@ -65,12 +84,20 @@ pub enum OutgoingContent { impl From for OutgoingContent { fn from(content: StartContent) -> Self { match content { - StartContent::Room(c) => { - OutgoingContent::Room(AnyMessageEventContent::KeyVerificationStart(c)) - } - StartContent::ToDevice(c) => { - OutgoingContent::ToDevice(AnyToDeviceEventContent::KeyVerificationStart(c)) - } + StartContent::Room(c) => AnyMessageEventContent::KeyVerificationStart(c).into(), + StartContent::ToDevice(c) => AnyToDeviceEventContent::KeyVerificationStart(c).into(), } } } + +impl From for OutgoingContent { + fn from(content: AnyToDeviceEventContent) -> Self { + OutgoingContent::ToDevice(content) + } +} + +impl From for OutgoingContent { + fn from(content: AnyMessageEventContent) -> Self { + OutgoingContent::Room(content) + } +} diff --git a/matrix_sdk_crypto/src/verification/sas/inner_sas.rs b/matrix_sdk_crypto/src/verification/sas/inner_sas.rs index 4eb1bc0d..cf2a2476 100644 --- a/matrix_sdk_crypto/src/verification/sas/inner_sas.rs +++ b/matrix_sdk_crypto/src/verification/sas/inner_sas.rs @@ -20,12 +20,14 @@ use std::sync::Arc; use matrix_sdk_common::{ events::{ key::verification::{ - accept::AcceptToDeviceEventContent, cancel::CancelCode, mac::MacToDeviceEventContent, - start::StartToDeviceEventContent, + accept::AcceptToDeviceEventContent, + cancel::CancelCode, + mac::MacToDeviceEventContent, + start::{StartEventContent, StartToDeviceEventContent}, }, - AnyToDeviceEvent, AnyToDeviceEventContent, ToDeviceEvent, + AnyToDeviceEvent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent, }, - identifiers::EventId, + identifiers::{EventId, UserId}, }; use crate::{ @@ -39,6 +41,7 @@ use super::{ Accepted, Canceled, Confirmed, Created, Done, FlowId, KeyReceived, MacReceived, SasState, Started, }, + StartContent, }; #[derive(Clone, Debug)] @@ -78,10 +81,17 @@ impl InnerSas { pub fn from_start_event( account: ReadOnlyAccount, other_device: ReadOnlyDevice, - event: &ToDeviceEvent, + sender: &UserId, + content: impl Into, other_identity: Option, - ) -> Result { - match SasState::::from_start_event(account, other_device, event, other_identity) { + ) -> Result { + match SasState::::from_start_event( + account, + other_device, + other_identity, + &sender, + content, + ) { Ok(s) => Ok(InnerSas::Started(s)), Err(s) => Err(s.as_content()), } @@ -110,7 +120,7 @@ impl InnerSas { } } - pub fn cancel(self, code: CancelCode) -> (InnerSas, Option) { + pub fn cancel(self, code: CancelCode) -> (InnerSas, Option) { let sas = match self { InnerSas::Created(s) => s.cancel(code), InnerSas::Started(s) => s.cancel(code), @@ -141,10 +151,7 @@ impl InnerSas { } } - pub fn receive_event( - self, - event: &AnyToDeviceEvent, - ) -> (InnerSas, Option) { + pub fn receive_event(self, event: &AnyToDeviceEvent) -> (InnerSas, Option) { match event { AnyToDeviceEvent::KeyVerificationAccept(e) => { if let InnerSas::Created(s) = self { @@ -153,7 +160,7 @@ impl InnerSas { let content = s.as_content(); ( InnerSas::Accepted(s), - Some(AnyToDeviceEventContent::KeyVerificationKey(content)), + Some(AnyToDeviceEventContent::KeyVerificationKey(content).into()), ) } Err(s) => { @@ -178,7 +185,7 @@ impl InnerSas { let content = s.as_content(); ( InnerSas::KeyRecieved(s), - Some(AnyToDeviceEventContent::KeyVerificationKey(content)), + Some(AnyToDeviceEventContent::KeyVerificationKey(content).into()), ) } Err(s) => { diff --git a/matrix_sdk_crypto/src/verification/sas/mod.rs b/matrix_sdk_crypto/src/verification/sas/mod.rs index 3f531b17..590f0de7 100644 --- a/matrix_sdk_crypto/src/verification/sas/mod.rs +++ b/matrix_sdk_crypto/src/verification/sas/mod.rs @@ -30,7 +30,7 @@ use matrix_sdk_common::{ cancel::CancelCode, start::{StartEventContent, StartToDeviceEventContent}, }, - AnyToDeviceEvent, AnyToDeviceEventContent, ToDeviceEvent, + AnyToDeviceEvent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent, }, identifiers::{DeviceId, EventId, RoomId, UserId}, }; @@ -220,15 +220,18 @@ impl Sas { private_identity: PrivateCrossSigningIdentity, other_device: ReadOnlyDevice, store: Arc>, - event: &ToDeviceEvent, + sender: &UserId, + content: impl Into, other_identity: Option, - ) -> Result { + ) -> Result { let inner = InnerSas::from_start_event( account.clone(), other_device.clone(), - event, + &sender, + content, other_identity.clone(), )?; + let flow_id = inner.verification_flow_id(); Ok(Sas { @@ -520,7 +523,13 @@ impl Sas { let (sas, content) = sas.cancel(CancelCode::User); *guard = sas; - content.map(|c| self.content_to_request(c)) + content.map(|c| { + if let OutgoingContent::ToDevice(c) = c { + self.content_to_request(c) + } else { + todo!() + } + }) } pub(crate) fn cancel_if_timed_out(&self) -> Option { @@ -531,7 +540,13 @@ impl Sas { let sas: InnerSas = (*guard).clone(); let (sas, content) = sas.cancel(CancelCode::Timeout); *guard = sas; - content.map(|c| self.content_to_request(c)) + content.map(|c| { + if let OutgoingContent::ToDevice(c) = c { + self.content_to_request(c) + } else { + todo!() + } + }) } else { None } @@ -574,10 +589,7 @@ impl Sas { self.inner.lock().unwrap().decimals() } - pub(crate) fn receive_event( - &self, - event: &AnyToDeviceEvent, - ) -> Option { + pub(crate) fn receive_event(&self, event: &AnyToDeviceEvent) -> Option { let mut guard = self.inner.lock().unwrap(); let sas: InnerSas = (*guard).clone(); let (sas, content) = sas.receive_event(event); diff --git a/matrix_sdk_crypto/src/verification/sas/sas_state.rs b/matrix_sdk_crypto/src/verification/sas/sas_state.rs index 44e23f3b..3f1d7373 100644 --- a/matrix_sdk_crypto/src/verification/sas/sas_state.rs +++ b/matrix_sdk_crypto/src/verification/sas/sas_state.rs @@ -37,7 +37,7 @@ use matrix_sdk_common::{ HashAlgorithm, KeyAgreementProtocol, MessageAuthenticationCode, Relation, ShortAuthenticationString, VerificationMethod, }, - AnyMessageEventContent, AnyToDeviceEventContent, ToDeviceEvent, + AnyMessageEventContent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent, }, identifiers::{DeviceId, EventId, UserId}, uuid::Uuid, @@ -447,7 +447,7 @@ impl SasState { } impl SasState { - /// Create a new SAS verification flow from a m.key.verification.start + /// Create a new SAS verification flow from an in-room m.key.verification.start /// event. /// /// This will put us in the `started` state. @@ -463,18 +463,35 @@ impl SasState { pub fn from_start_event( account: ReadOnlyAccount, other_device: ReadOnlyDevice, - event: &ToDeviceEvent, other_identity: Option, + sender: &UserId, + content: impl Into, ) -> Result, SasState> { - if let StartMethod::MSasV1(content) = &event.content.method { + Self::from_start_helper( + account, + other_device, + other_identity, + sender, + &content.into(), + ) + } + + fn from_start_helper( + account: ReadOnlyAccount, + other_device: ReadOnlyDevice, + other_identity: Option, + sender: &UserId, + content: &StartContent, + ) -> Result, SasState> { + if let StartMethod::MSasV1(method_content) = content.method() { let sas = OlmSas::new(); let pubkey = sas.public_key(); - let commitment = calculate_commitment(&pubkey, event.content.clone()); + let commitment = calculate_commitment(&pubkey, content.clone()); error!( "Calculated commitment for pubkey {} and content {:?} {}", - pubkey, event.content, commitment + pubkey, content, commitment ); let sas = SasState { @@ -489,25 +506,25 @@ impl SasState { creation_time: Arc::new(Instant::now()), last_event_time: Arc::new(Instant::now()), - verification_flow_id: FlowId::ToDevice(event.content.transaction_id.clone()).into(), + verification_flow_id: content.flow_id().into(), state: Arc::new(Started { - protocol_definitions: content.clone(), + protocol_definitions: method_content.clone(), commitment, }), }; - if !content + if !method_content .key_agreement_protocols .contains(&KeyAgreementProtocol::Curve25519HkdfSha256) - || !content + || !method_content .message_authentication_codes .contains(&MessageAuthenticationCode::HkdfHmacSha256) - || !content.hashes.contains(&HashAlgorithm::Sha256) - || (!content + || !method_content.hashes.contains(&HashAlgorithm::Sha256) + || (!method_content .short_authentication_string .contains(&ShortAuthenticationString::Decimal) - && !content + && !method_content .short_authentication_string .contains(&ShortAuthenticationString::Emoji)) { @@ -528,7 +545,7 @@ impl SasState { other_identity, }, - verification_flow_id: FlowId::ToDevice(event.content.transaction_id.clone()).into(), + verification_flow_id: content.flow_id().into(), state: Arc::new(Canceled::new(CancelCode::UnknownMethod)), }) } @@ -914,7 +931,7 @@ impl Canceled { } impl SasState { - pub fn as_content(&self) -> AnyToDeviceEventContent { + pub fn as_content(&self) -> OutgoingContent { match self.verification_flow_id.as_ref() { FlowId::ToDevice(s) => { AnyToDeviceEventContent::KeyVerificationCancel(CancelToDeviceEventContent { @@ -922,6 +939,7 @@ impl SasState { reason: self.state.reason.to_string(), code: self.state.cancel_code.clone(), }) + .into() } _ => todo!(), }