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,
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) => {

View File

@ -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<Mutex<InnerRequest>>,
account: ReadOnlyAccount,
private_cross_signing_identity: PrivateCrossSigningIdentity,
store: Arc<Box<dyn CryptoStore>>,
room_id: Arc<RoomId>,
}
@ -49,6 +51,7 @@ pub struct VerificationRequest {
impl VerificationRequest {
pub(crate) fn from_request_event(
account: ReadOnlyAccount,
private_cross_signing_identity: PrivateCrossSigningIdentity,
store: Arc<Box<dyn CryptoStore>>,
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<ReadyEventContent> {
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)]
@ -102,6 +125,29 @@ impl InnerRequest {
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)]
@ -252,14 +298,23 @@ struct Ready {
impl RequestState<Ready> {
fn into_started_sas(
self,
&self,
event: &MessageEvent<StartEventContent>,
store: Arc<Box<dyn CryptoStore>>,
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<UserIdentities>,
) -> Result<Sas, OutgoingContent> {
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 {}

View File

@ -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<StartContent> 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<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::{
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<StartToDeviceEventContent>,
sender: &UserId,
content: impl Into<StartContent>,
other_identity: Option<UserIdentities>,
) -> Result<InnerSas, AnyToDeviceEventContent> {
match SasState::<Started>::from_start_event(account, other_device, event, other_identity) {
) -> Result<InnerSas, OutgoingContent> {
match SasState::<Started>::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<AnyToDeviceEventContent>) {
pub fn cancel(self, code: CancelCode) -> (InnerSas, Option<OutgoingContent>) {
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<AnyToDeviceEventContent>) {
pub fn receive_event(self, event: &AnyToDeviceEvent) -> (InnerSas, Option<OutgoingContent>) {
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) => {

View File

@ -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<Box<dyn CryptoStore>>,
event: &ToDeviceEvent<StartToDeviceEventContent>,
sender: &UserId,
content: impl Into<StartContent>,
other_identity: Option<UserIdentities>,
) -> Result<Sas, AnyToDeviceEventContent> {
) -> Result<Sas, OutgoingContent> {
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<ToDeviceRequest> {
@ -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<AnyToDeviceEventContent> {
pub(crate) fn receive_event(&self, event: &AnyToDeviceEvent) -> Option<OutgoingContent> {
let mut guard = self.inner.lock().unwrap();
let sas: InnerSas = (*guard).clone();
let (sas, content) = sas.receive_event(event);

View File

@ -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<Created> {
}
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.
///
/// This will put us in the `started` state.
@ -463,18 +463,35 @@ impl SasState<Started> {
pub fn from_start_event(
account: ReadOnlyAccount,
other_device: ReadOnlyDevice,
event: &ToDeviceEvent<StartToDeviceEventContent>,
other_identity: Option<UserIdentities>,
sender: &UserId,
content: impl Into<StartContent>,
) -> 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 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<Started> {
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<Started> {
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<Canceled> {
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<Canceled> {
reason: self.state.reason.to_string(),
code: self.state.cancel_code.clone(),
})
.into()
}
_ => todo!(),
}