crypto: WIP genrealize the sas so it can handle in-room and to-device events.

master
Damir Jelić 2020-12-11 15:42:49 +01:00
parent b0ac9d3320
commit 7570cf5ac2
6 changed files with 219 additions and 78 deletions

View File

@ -112,17 +112,23 @@ impl VerificationMachine {
&self, &self,
recipient: &UserId, recipient: &UserId,
recipient_device: &DeviceId, recipient_device: &DeviceId,
content: AnyToDeviceEventContent, content: OutgoingContent,
) { ) {
let request = content_to_request(recipient, recipient_device, content); match content {
let request_id = request.txn_id; OutgoingContent::ToDevice(c) => {
let request = content_to_request(recipient, recipient_device, c);
let request_id = request.txn_id;
let request = OutgoingRequest { let request = OutgoingRequest {
request_id, request_id,
request: Arc::new(request.into()), 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) { fn receive_event_helper(&self, sas: &Sas, event: &AnyToDeviceEvent) {
@ -165,29 +171,41 @@ impl VerificationMachine {
room_id: &RoomId, room_id: &RoomId,
event: &AnySyncRoomEvent, event: &AnySyncRoomEvent,
) -> Result<(), CryptoStoreError> { ) -> Result<(), CryptoStoreError> {
match event { if let AnySyncRoomEvent::Message(m) = event {
AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomMessage(m)) => { match m {
if let MessageEventContent::VerificationRequest(r) = &m.content { AnySyncMessageEvent::RoomMessage(m) => {
if self.account.user_id() == &r.to { if let MessageEventContent::VerificationRequest(r) = &m.content {
info!( if self.account.user_id() == &r.to {
"Received a new verification request from {} {}", info!(
m.sender, r.from_device "Received a new verification request from {} {}",
); m.sender, r.from_device
);
let request = VerificationRequest::from_request_event( let request = VerificationRequest::from_request_event(
self.account.clone(), self.account.clone(),
self.store.clone(), self.private_identity.lock().await.clone(),
room_id, self.store.clone(),
&m.sender, room_id,
&m.event_id, &m.sender,
r, &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(()) Ok(())
@ -215,7 +233,8 @@ impl VerificationMachine {
private_identity, private_identity,
d, d,
self.store.clone(), self.store.clone(),
e, &e.sender,
e.content.clone(),
self.store.get_user_identity(&e.sender).await?, self.store.get_user_identity(&e.sender).await?,
) { ) {
Ok(s) => { Ok(s) => {

View File

@ -23,6 +23,7 @@ use matrix_sdk_common::{
ready::ReadyEventContent, start::StartEventContent, Relation, VerificationMethod, ready::ReadyEventContent, start::StartEventContent, Relation, VerificationMethod,
}, },
room::message::KeyVerificationRequestEventContent, room::message::KeyVerificationRequestEventContent,
MessageEvent,
}, },
identifiers::{DeviceId, DeviceIdBox, EventId, RoomId, UserId}, identifiers::{DeviceId, DeviceIdBox, EventId, RoomId, UserId},
}; };
@ -42,6 +43,7 @@ const SUPPORTED_METHODS: &[VerificationMethod] = &[VerificationMethod::MSasV1];
pub struct VerificationRequest { pub struct VerificationRequest {
inner: Arc<Mutex<InnerRequest>>, inner: Arc<Mutex<InnerRequest>>,
account: ReadOnlyAccount, account: ReadOnlyAccount,
private_cross_signing_identity: PrivateCrossSigningIdentity,
store: Arc<Box<dyn CryptoStore>>, store: Arc<Box<dyn CryptoStore>>,
room_id: Arc<RoomId>, room_id: Arc<RoomId>,
} }
@ -49,6 +51,7 @@ pub struct VerificationRequest {
impl VerificationRequest { impl VerificationRequest {
pub(crate) fn from_request_event( pub(crate) fn from_request_event(
account: ReadOnlyAccount, account: ReadOnlyAccount,
private_cross_signing_identity: PrivateCrossSigningIdentity,
store: Arc<Box<dyn CryptoStore>>, store: Arc<Box<dyn CryptoStore>>,
room_id: &RoomId, room_id: &RoomId,
sender: &UserId, sender: &UserId,
@ -66,6 +69,7 @@ impl VerificationRequest {
), ),
))), ))),
account, account,
private_cross_signing_identity,
store, store,
room_id: room_id.clone().into(), room_id: room_id.clone().into(),
} }
@ -80,6 +84,25 @@ impl VerificationRequest {
pub fn accept(&self) -> Option<ReadyEventContent> { pub fn accept(&self) -> Option<ReadyEventContent> {
self.inner.lock().unwrap().accept() self.inner.lock().unwrap().accept()
} }
pub(crate) fn into_started_sas(
&self,
event: &MessageEvent<StartEventContent>,
device: ReadOnlyDevice,
user_identity: Option<UserIdentities>,
) -> Result<Sas, OutgoingContent> {
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)] #[derive(Debug)]
@ -102,6 +125,29 @@ impl InnerRequest {
None None
} }
} }
fn into_started_sas(
&mut self,
event: &MessageEvent<StartEventContent>,
store: Arc<Box<dyn CryptoStore>>,
account: ReadOnlyAccount,
private_identity: PrivateCrossSigningIdentity,
other_device: ReadOnlyDevice,
other_identity: Option<UserIdentities>,
) -> Result<Option<Sas>, 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)] #[derive(Clone, Debug)]
@ -252,14 +298,23 @@ struct Ready {
impl RequestState<Ready> { impl RequestState<Ready> {
fn into_started_sas( fn into_started_sas(
self, &self,
event: &MessageEvent<StartEventContent>,
store: Arc<Box<dyn CryptoStore>>,
account: ReadOnlyAccount, account: ReadOnlyAccount,
private_identity: PrivateCrossSigningIdentity, private_identity: PrivateCrossSigningIdentity,
other_device: ReadOnlyDevice, other_device: ReadOnlyDevice,
other_identity: UserIdentity, other_identity: Option<UserIdentities>,
) -> Sas { ) -> Result<Sas, OutgoingContent> {
todo!() Sas::from_start_event(
// Sas::from_start_event(account, private_identity, other_device, other_identity, event) account,
private_identity,
other_device,
store,
&event.sender,
event.content.clone(),
other_identity,
)
} }
fn start_sas( fn start_sas(
@ -289,3 +344,6 @@ struct Passive {
/// unique id identifying this verification flow. /// unique id identifying this verification flow.
pub flow_id: EventId, pub flow_id: EventId,
} }
#[derive(Clone, Debug)]
struct Started {}

View File

@ -18,12 +18,17 @@ use std::convert::TryInto;
use matrix_sdk_common::{ use matrix_sdk_common::{
events::{ events::{
key::verification::start::{StartEventContent, StartToDeviceEventContent}, key::verification::{
start::{StartEventContent, StartMethod, StartToDeviceEventContent},
KeyAgreementProtocol,
},
AnyMessageEventContent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent, AnyMessageEventContent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
}, },
CanonicalJsonValue, CanonicalJsonValue,
}; };
use super::FlowId;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum StartContent { pub enum StartContent {
ToDevice(StartToDeviceEventContent), ToDevice(StartToDeviceEventContent),
@ -31,6 +36,20 @@ pub enum StartContent {
} }
impl 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 { pub fn to_canonical_json(self) -> CanonicalJsonValue {
let content = match self { let content = match self {
StartContent::Room(c) => serde_json::to_value(c), StartContent::Room(c) => serde_json::to_value(c),
@ -65,12 +84,20 @@ pub enum OutgoingContent {
impl From<StartContent> for OutgoingContent { impl From<StartContent> for OutgoingContent {
fn from(content: StartContent) -> Self { fn from(content: StartContent) -> Self {
match content { match content {
StartContent::Room(c) => { StartContent::Room(c) => AnyMessageEventContent::KeyVerificationStart(c).into(),
OutgoingContent::Room(AnyMessageEventContent::KeyVerificationStart(c)) StartContent::ToDevice(c) => AnyToDeviceEventContent::KeyVerificationStart(c).into(),
}
StartContent::ToDevice(c) => {
OutgoingContent::ToDevice(AnyToDeviceEventContent::KeyVerificationStart(c))
}
} }
} }
} }
impl From<AnyToDeviceEventContent> for OutgoingContent {
fn from(content: AnyToDeviceEventContent) -> Self {
OutgoingContent::ToDevice(content)
}
}
impl From<AnyMessageEventContent> for OutgoingContent {
fn from(content: AnyMessageEventContent) -> Self {
OutgoingContent::Room(content)
}
}

View File

@ -20,12 +20,14 @@ use std::sync::Arc;
use matrix_sdk_common::{ use matrix_sdk_common::{
events::{ events::{
key::verification::{ key::verification::{
accept::AcceptToDeviceEventContent, cancel::CancelCode, mac::MacToDeviceEventContent, accept::AcceptToDeviceEventContent,
start::StartToDeviceEventContent, cancel::CancelCode,
mac::MacToDeviceEventContent,
start::{StartEventContent, StartToDeviceEventContent},
}, },
AnyToDeviceEvent, AnyToDeviceEventContent, ToDeviceEvent, AnyToDeviceEvent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
}, },
identifiers::EventId, identifiers::{EventId, UserId},
}; };
use crate::{ use crate::{
@ -39,6 +41,7 @@ use super::{
Accepted, Canceled, Confirmed, Created, Done, FlowId, KeyReceived, MacReceived, SasState, Accepted, Canceled, Confirmed, Created, Done, FlowId, KeyReceived, MacReceived, SasState,
Started, Started,
}, },
StartContent,
}; };
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -78,10 +81,17 @@ impl InnerSas {
pub fn from_start_event( pub fn from_start_event(
account: ReadOnlyAccount, account: ReadOnlyAccount,
other_device: ReadOnlyDevice, other_device: ReadOnlyDevice,
event: &ToDeviceEvent<StartToDeviceEventContent>, sender: &UserId,
content: impl Into<StartContent>,
other_identity: Option<UserIdentities>, other_identity: Option<UserIdentities>,
) -> Result<InnerSas, AnyToDeviceEventContent> { ) -> Result<InnerSas, OutgoingContent> {
match SasState::<Started>::from_start_event(account, other_device, event, other_identity) { match SasState::<Started>::from_start_event(
account,
other_device,
other_identity,
&sender,
content,
) {
Ok(s) => Ok(InnerSas::Started(s)), Ok(s) => Ok(InnerSas::Started(s)),
Err(s) => Err(s.as_content()), Err(s) => Err(s.as_content()),
} }
@ -110,7 +120,7 @@ impl InnerSas {
} }
} }
pub fn cancel(self, code: CancelCode) -> (InnerSas, Option<AnyToDeviceEventContent>) { pub fn cancel(self, code: CancelCode) -> (InnerSas, Option<OutgoingContent>) {
let sas = match self { let sas = match self {
InnerSas::Created(s) => s.cancel(code), InnerSas::Created(s) => s.cancel(code),
InnerSas::Started(s) => s.cancel(code), InnerSas::Started(s) => s.cancel(code),
@ -141,10 +151,7 @@ impl InnerSas {
} }
} }
pub fn receive_event( pub fn receive_event(self, event: &AnyToDeviceEvent) -> (InnerSas, Option<OutgoingContent>) {
self,
event: &AnyToDeviceEvent,
) -> (InnerSas, Option<AnyToDeviceEventContent>) {
match event { match event {
AnyToDeviceEvent::KeyVerificationAccept(e) => { AnyToDeviceEvent::KeyVerificationAccept(e) => {
if let InnerSas::Created(s) = self { if let InnerSas::Created(s) = self {
@ -153,7 +160,7 @@ impl InnerSas {
let content = s.as_content(); let content = s.as_content();
( (
InnerSas::Accepted(s), InnerSas::Accepted(s),
Some(AnyToDeviceEventContent::KeyVerificationKey(content)), Some(AnyToDeviceEventContent::KeyVerificationKey(content).into()),
) )
} }
Err(s) => { Err(s) => {
@ -178,7 +185,7 @@ impl InnerSas {
let content = s.as_content(); let content = s.as_content();
( (
InnerSas::KeyRecieved(s), InnerSas::KeyRecieved(s),
Some(AnyToDeviceEventContent::KeyVerificationKey(content)), Some(AnyToDeviceEventContent::KeyVerificationKey(content).into()),
) )
} }
Err(s) => { Err(s) => {

View File

@ -30,7 +30,7 @@ use matrix_sdk_common::{
cancel::CancelCode, cancel::CancelCode,
start::{StartEventContent, StartToDeviceEventContent}, start::{StartEventContent, StartToDeviceEventContent},
}, },
AnyToDeviceEvent, AnyToDeviceEventContent, ToDeviceEvent, AnyToDeviceEvent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
}, },
identifiers::{DeviceId, EventId, RoomId, UserId}, identifiers::{DeviceId, EventId, RoomId, UserId},
}; };
@ -220,15 +220,18 @@ impl Sas {
private_identity: PrivateCrossSigningIdentity, private_identity: PrivateCrossSigningIdentity,
other_device: ReadOnlyDevice, other_device: ReadOnlyDevice,
store: Arc<Box<dyn CryptoStore>>, store: Arc<Box<dyn CryptoStore>>,
event: &ToDeviceEvent<StartToDeviceEventContent>, sender: &UserId,
content: impl Into<StartContent>,
other_identity: Option<UserIdentities>, other_identity: Option<UserIdentities>,
) -> Result<Sas, AnyToDeviceEventContent> { ) -> Result<Sas, OutgoingContent> {
let inner = InnerSas::from_start_event( let inner = InnerSas::from_start_event(
account.clone(), account.clone(),
other_device.clone(), other_device.clone(),
event, &sender,
content,
other_identity.clone(), other_identity.clone(),
)?; )?;
let flow_id = inner.verification_flow_id(); let flow_id = inner.verification_flow_id();
Ok(Sas { Ok(Sas {
@ -520,7 +523,13 @@ impl Sas {
let (sas, content) = sas.cancel(CancelCode::User); let (sas, content) = sas.cancel(CancelCode::User);
*guard = sas; *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<ToDeviceRequest> { pub(crate) fn cancel_if_timed_out(&self) -> Option<ToDeviceRequest> {
@ -531,7 +540,13 @@ impl Sas {
let sas: InnerSas = (*guard).clone(); let sas: InnerSas = (*guard).clone();
let (sas, content) = sas.cancel(CancelCode::Timeout); let (sas, content) = sas.cancel(CancelCode::Timeout);
*guard = sas; *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 { } else {
None None
} }
@ -574,10 +589,7 @@ impl Sas {
self.inner.lock().unwrap().decimals() self.inner.lock().unwrap().decimals()
} }
pub(crate) fn receive_event( pub(crate) fn receive_event(&self, event: &AnyToDeviceEvent) -> Option<OutgoingContent> {
&self,
event: &AnyToDeviceEvent,
) -> Option<AnyToDeviceEventContent> {
let mut guard = self.inner.lock().unwrap(); let mut guard = self.inner.lock().unwrap();
let sas: InnerSas = (*guard).clone(); let sas: InnerSas = (*guard).clone();
let (sas, content) = sas.receive_event(event); let (sas, content) = sas.receive_event(event);

View File

@ -37,7 +37,7 @@ use matrix_sdk_common::{
HashAlgorithm, KeyAgreementProtocol, MessageAuthenticationCode, Relation, HashAlgorithm, KeyAgreementProtocol, MessageAuthenticationCode, Relation,
ShortAuthenticationString, VerificationMethod, ShortAuthenticationString, VerificationMethod,
}, },
AnyMessageEventContent, AnyToDeviceEventContent, ToDeviceEvent, AnyMessageEventContent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
}, },
identifiers::{DeviceId, EventId, UserId}, identifiers::{DeviceId, EventId, UserId},
uuid::Uuid, uuid::Uuid,
@ -447,7 +447,7 @@ impl SasState<Created> {
} }
impl SasState<Started> { impl SasState<Started> {
/// 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. /// event.
/// ///
/// This will put us in the `started` state. /// This will put us in the `started` state.
@ -463,18 +463,35 @@ impl SasState<Started> {
pub fn from_start_event( pub fn from_start_event(
account: ReadOnlyAccount, account: ReadOnlyAccount,
other_device: ReadOnlyDevice, other_device: ReadOnlyDevice,
event: &ToDeviceEvent<StartToDeviceEventContent>,
other_identity: Option<UserIdentities>, other_identity: Option<UserIdentities>,
sender: &UserId,
content: impl Into<StartContent>,
) -> Result<SasState<Started>, SasState<Canceled>> { ) -> Result<SasState<Started>, SasState<Canceled>> {
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<UserIdentities>,
sender: &UserId,
content: &StartContent,
) -> Result<SasState<Started>, SasState<Canceled>> {
if let StartMethod::MSasV1(method_content) = content.method() {
let sas = OlmSas::new(); let sas = OlmSas::new();
let pubkey = sas.public_key(); let pubkey = sas.public_key();
let commitment = calculate_commitment(&pubkey, event.content.clone()); let commitment = calculate_commitment(&pubkey, content.clone());
error!( error!(
"Calculated commitment for pubkey {} and content {:?} {}", "Calculated commitment for pubkey {} and content {:?} {}",
pubkey, event.content, commitment pubkey, content, commitment
); );
let sas = SasState { let sas = SasState {
@ -489,25 +506,25 @@ impl SasState<Started> {
creation_time: Arc::new(Instant::now()), creation_time: Arc::new(Instant::now()),
last_event_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 { state: Arc::new(Started {
protocol_definitions: content.clone(), protocol_definitions: method_content.clone(),
commitment, commitment,
}), }),
}; };
if !content if !method_content
.key_agreement_protocols .key_agreement_protocols
.contains(&KeyAgreementProtocol::Curve25519HkdfSha256) .contains(&KeyAgreementProtocol::Curve25519HkdfSha256)
|| !content || !method_content
.message_authentication_codes .message_authentication_codes
.contains(&MessageAuthenticationCode::HkdfHmacSha256) .contains(&MessageAuthenticationCode::HkdfHmacSha256)
|| !content.hashes.contains(&HashAlgorithm::Sha256) || !method_content.hashes.contains(&HashAlgorithm::Sha256)
|| (!content || (!method_content
.short_authentication_string .short_authentication_string
.contains(&ShortAuthenticationString::Decimal) .contains(&ShortAuthenticationString::Decimal)
&& !content && !method_content
.short_authentication_string .short_authentication_string
.contains(&ShortAuthenticationString::Emoji)) .contains(&ShortAuthenticationString::Emoji))
{ {
@ -528,7 +545,7 @@ impl SasState<Started> {
other_identity, 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)), state: Arc::new(Canceled::new(CancelCode::UnknownMethod)),
}) })
} }
@ -914,7 +931,7 @@ impl Canceled {
} }
impl SasState<Canceled> { impl SasState<Canceled> {
pub fn as_content(&self) -> AnyToDeviceEventContent { pub fn as_content(&self) -> OutgoingContent {
match self.verification_flow_id.as_ref() { match self.verification_flow_id.as_ref() {
FlowId::ToDevice(s) => { FlowId::ToDevice(s) => {
AnyToDeviceEventContent::KeyVerificationCancel(CancelToDeviceEventContent { AnyToDeviceEventContent::KeyVerificationCancel(CancelToDeviceEventContent {
@ -922,6 +939,7 @@ impl SasState<Canceled> {
reason: self.state.reason.to_string(), reason: self.state.reason.to_string(),
code: self.state.cancel_code.clone(), code: self.state.cancel_code.clone(),
}) })
.into()
} }
_ => todo!(), _ => todo!(),
} }