crypto: WIP change the types of the sas sturcts to allow in-room verifications.
parent
1bb5b42b1d
commit
b0ac9d3320
|
@ -42,6 +42,7 @@ use tracing::warn;
|
||||||
use crate::{
|
use crate::{
|
||||||
olm::{InboundGroupSession, PrivateCrossSigningIdentity, Session},
|
olm::{InboundGroupSession, PrivateCrossSigningIdentity, Session},
|
||||||
store::{Changes, DeviceChanges},
|
store::{Changes, DeviceChanges},
|
||||||
|
OutgoingRequest, OutgoingRequests,
|
||||||
};
|
};
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use crate::{OlmMachine, ReadOnlyAccount};
|
use crate::{OlmMachine, ReadOnlyAccount};
|
||||||
|
@ -91,9 +92,16 @@ impl Device {
|
||||||
///
|
///
|
||||||
/// Returns a `Sas` object and to-device request that needs to be sent out.
|
/// Returns a `Sas` object and to-device request that needs to be sent out.
|
||||||
pub async fn start_verification(&self) -> StoreResult<(Sas, ToDeviceRequest)> {
|
pub async fn start_verification(&self) -> StoreResult<(Sas, ToDeviceRequest)> {
|
||||||
self.verification_machine
|
let (sas, request) = self
|
||||||
|
.verification_machine
|
||||||
.start_sas(self.inner.clone())
|
.start_sas(self.inner.clone())
|
||||||
.await
|
.await?;
|
||||||
|
|
||||||
|
if let OutgoingRequests::ToDeviceRequest(r) = request {
|
||||||
|
Ok((sas, r))
|
||||||
|
} else {
|
||||||
|
panic!("Invalid verification request type");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the Olm sessions that belong to this device.
|
/// Get the Olm sessions that belong to this device.
|
||||||
|
|
|
@ -30,14 +30,14 @@ use matrix_sdk_common::{
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
requests::VerificationRequest,
|
requests::VerificationRequest,
|
||||||
sas::{content_to_request, Sas, VerificationResult},
|
sas::{content_to_request, OutgoingContent, Sas, VerificationResult},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
olm::PrivateCrossSigningIdentity,
|
olm::PrivateCrossSigningIdentity,
|
||||||
requests::{OutgoingRequest, ToDeviceRequest},
|
requests::{OutgoingRequest, ToDeviceRequest},
|
||||||
store::{CryptoStore, CryptoStoreError},
|
store::{CryptoStore, CryptoStoreError},
|
||||||
ReadOnlyAccount, ReadOnlyDevice,
|
OutgoingRequests, ReadOnlyAccount, ReadOnlyDevice,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -46,6 +46,7 @@ pub struct VerificationMachine {
|
||||||
private_identity: Arc<Mutex<PrivateCrossSigningIdentity>>,
|
private_identity: Arc<Mutex<PrivateCrossSigningIdentity>>,
|
||||||
pub(crate) store: Arc<Box<dyn CryptoStore>>,
|
pub(crate) store: Arc<Box<dyn CryptoStore>>,
|
||||||
verifications: Arc<DashMap<String, Sas>>,
|
verifications: Arc<DashMap<String, Sas>>,
|
||||||
|
room_verifications: Arc<DashMap<String, Sas>>,
|
||||||
requests: Arc<DashMap<EventId, VerificationRequest>>,
|
requests: Arc<DashMap<EventId, VerificationRequest>>,
|
||||||
outgoing_to_device_messages: Arc<DashMap<Uuid, OutgoingRequest>>,
|
outgoing_to_device_messages: Arc<DashMap<Uuid, OutgoingRequest>>,
|
||||||
}
|
}
|
||||||
|
@ -63,13 +64,14 @@ impl VerificationMachine {
|
||||||
verifications: DashMap::new().into(),
|
verifications: DashMap::new().into(),
|
||||||
requests: DashMap::new().into(),
|
requests: DashMap::new().into(),
|
||||||
outgoing_to_device_messages: DashMap::new().into(),
|
outgoing_to_device_messages: DashMap::new().into(),
|
||||||
|
room_verifications: DashMap::new().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start_sas(
|
pub async fn start_sas(
|
||||||
&self,
|
&self,
|
||||||
device: ReadOnlyDevice,
|
device: ReadOnlyDevice,
|
||||||
) -> Result<(Sas, ToDeviceRequest), CryptoStoreError> {
|
) -> Result<(Sas, OutgoingRequests), CryptoStoreError> {
|
||||||
let identity = self.store.get_user_identity(device.user_id()).await?;
|
let identity = self.store.get_user_identity(device.user_id()).await?;
|
||||||
let private_identity = self.private_identity.lock().await.clone();
|
let private_identity = self.private_identity.lock().await.clone();
|
||||||
|
|
||||||
|
@ -81,14 +83,17 @@ impl VerificationMachine {
|
||||||
identity,
|
identity,
|
||||||
);
|
);
|
||||||
|
|
||||||
let request = content_to_request(
|
let request: OutgoingRequests = match content {
|
||||||
device.user_id(),
|
OutgoingContent::Room(c) => todo!(),
|
||||||
device.device_id(),
|
OutgoingContent::ToDevice(c) => {
|
||||||
AnyToDeviceEventContent::KeyVerificationStart(content),
|
let request = content_to_request(device.user_id(), device.device_id(), c);
|
||||||
);
|
|
||||||
|
|
||||||
self.verifications
|
self.verifications
|
||||||
.insert(sas.flow_id().to_string(), sas.clone());
|
.insert(sas.flow_id().to_string(), sas.clone());
|
||||||
|
|
||||||
|
request.into()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok((sas, request))
|
Ok((sas, request))
|
||||||
}
|
}
|
||||||
|
@ -170,9 +175,9 @@ impl VerificationMachine {
|
||||||
);
|
);
|
||||||
|
|
||||||
let request = VerificationRequest::from_request_event(
|
let request = VerificationRequest::from_request_event(
|
||||||
|
self.account.clone(),
|
||||||
|
self.store.clone(),
|
||||||
room_id,
|
room_id,
|
||||||
self.account.user_id(),
|
|
||||||
self.account.device_id(),
|
|
||||||
&m.sender,
|
&m.sender,
|
||||||
&m.event_id,
|
&m.event_id,
|
||||||
r,
|
r,
|
||||||
|
|
|
@ -19,26 +19,38 @@ use std::sync::{Arc, Mutex};
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
api::r0::message::send_message_event::Response as RoomMessageResponse,
|
api::r0::message::send_message_event::Response as RoomMessageResponse,
|
||||||
events::{
|
events::{
|
||||||
key::verification::{ready::ReadyEventContent, Relation, VerificationMethod},
|
key::verification::{
|
||||||
|
ready::ReadyEventContent, start::StartEventContent, Relation, VerificationMethod,
|
||||||
|
},
|
||||||
room::message::KeyVerificationRequestEventContent,
|
room::message::KeyVerificationRequestEventContent,
|
||||||
},
|
},
|
||||||
identifiers::{DeviceId, DeviceIdBox, EventId, RoomId, UserId},
|
identifiers::{DeviceId, DeviceIdBox, EventId, RoomId, UserId},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
olm::{PrivateCrossSigningIdentity, ReadOnlyAccount},
|
||||||
|
store::CryptoStore,
|
||||||
|
ReadOnlyDevice, Sas, UserIdentities, UserIdentity,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::sas::{OutgoingContent, StartContent};
|
||||||
|
|
||||||
const SUPPORTED_METHODS: &[VerificationMethod] = &[VerificationMethod::MSasV1];
|
const SUPPORTED_METHODS: &[VerificationMethod] = &[VerificationMethod::MSasV1];
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
/// TODO
|
/// TODO
|
||||||
pub struct VerificationRequest {
|
pub struct VerificationRequest {
|
||||||
inner: Arc<Mutex<InnerRequest>>,
|
inner: Arc<Mutex<InnerRequest>>,
|
||||||
|
account: ReadOnlyAccount,
|
||||||
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
room_id: Arc<RoomId>,
|
room_id: Arc<RoomId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VerificationRequest {
|
impl VerificationRequest {
|
||||||
pub(crate) fn from_request_event(
|
pub(crate) fn from_request_event(
|
||||||
|
account: ReadOnlyAccount,
|
||||||
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
room_id: &RoomId,
|
room_id: &RoomId,
|
||||||
own_user_id: &UserId,
|
|
||||||
own_device_id: &DeviceId,
|
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
event_id: &EventId,
|
event_id: &EventId,
|
||||||
content: &KeyVerificationRequestEventContent,
|
content: &KeyVerificationRequestEventContent,
|
||||||
|
@ -46,13 +58,15 @@ impl VerificationRequest {
|
||||||
Self {
|
Self {
|
||||||
inner: Arc::new(Mutex::new(InnerRequest::Requested(
|
inner: Arc::new(Mutex::new(InnerRequest::Requested(
|
||||||
RequestState::from_request_event(
|
RequestState::from_request_event(
|
||||||
own_user_id,
|
account.user_id(),
|
||||||
own_device_id,
|
account.device_id(),
|
||||||
sender,
|
sender,
|
||||||
event_id,
|
event_id,
|
||||||
content,
|
content,
|
||||||
),
|
),
|
||||||
))),
|
))),
|
||||||
|
account,
|
||||||
|
store,
|
||||||
room_id: room_id.clone().into(),
|
room_id: room_id.clone().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +88,6 @@ enum InnerRequest {
|
||||||
Sent(RequestState<Sent>),
|
Sent(RequestState<Sent>),
|
||||||
Requested(RequestState<Requested>),
|
Requested(RequestState<Requested>),
|
||||||
Ready(RequestState<Ready>),
|
Ready(RequestState<Ready>),
|
||||||
Accepted(RequestState<Accepted>),
|
|
||||||
Passive(RequestState<Passive>),
|
Passive(RequestState<Passive>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +95,7 @@ impl InnerRequest {
|
||||||
fn accept(&mut self) -> Option<ReadyEventContent> {
|
fn accept(&mut self) -> Option<ReadyEventContent> {
|
||||||
if let InnerRequest::Requested(s) = self {
|
if let InnerRequest::Requested(s) = self {
|
||||||
let (state, content) = s.clone().accept();
|
let (state, content) = s.clone().accept();
|
||||||
*self = InnerRequest::Accepted(state);
|
*self = InnerRequest::Ready(state);
|
||||||
|
|
||||||
Some(content)
|
Some(content)
|
||||||
} else {
|
} else {
|
||||||
|
@ -200,13 +213,12 @@ impl RequestState<Requested> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accept(self) -> (RequestState<Accepted>, ReadyEventContent) {
|
fn accept(self) -> (RequestState<Ready>, ReadyEventContent) {
|
||||||
// TODO let the user pick a method here.
|
|
||||||
let state = RequestState {
|
let state = RequestState {
|
||||||
own_user_id: self.own_user_id,
|
own_user_id: self.own_user_id,
|
||||||
own_device_id: self.own_device_id.clone(),
|
own_device_id: self.own_device_id.clone(),
|
||||||
other_user_id: self.other_user_id,
|
other_user_id: self.other_user_id,
|
||||||
state: Accepted {
|
state: Ready {
|
||||||
methods: self.state.methods.clone(),
|
methods: self.state.methods.clone(),
|
||||||
other_device_id: self.state.other_device_id.clone(),
|
other_device_id: self.state.other_device_id.clone(),
|
||||||
flow_id: self.state.flow_id.clone(),
|
flow_id: self.state.flow_id.clone(),
|
||||||
|
@ -238,17 +250,34 @@ struct Ready {
|
||||||
pub flow_id: EventId,
|
pub flow_id: EventId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
impl RequestState<Ready> {
|
||||||
struct Accepted {
|
fn into_started_sas(
|
||||||
/// The verification methods that were accepted
|
self,
|
||||||
pub methods: Vec<VerificationMethod>,
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
/// The device id of the device that responded to the verification request.
|
fn start_sas(
|
||||||
pub other_device_id: DeviceIdBox,
|
self,
|
||||||
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
/// The event id of the `m.key.verification.request` event which acts as an
|
account: ReadOnlyAccount,
|
||||||
/// unique id identifying this verification flow.
|
private_identity: PrivateCrossSigningIdentity,
|
||||||
pub flow_id: EventId,
|
other_device: ReadOnlyDevice,
|
||||||
|
other_identity: Option<UserIdentities>,
|
||||||
|
) -> (Sas, OutgoingContent) {
|
||||||
|
Sas::start(
|
||||||
|
account,
|
||||||
|
private_identity,
|
||||||
|
other_device,
|
||||||
|
store,
|
||||||
|
other_identity,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
// Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
use matrix_sdk_common::{
|
||||||
|
events::{
|
||||||
|
key::verification::start::{StartEventContent, StartToDeviceEventContent},
|
||||||
|
AnyMessageEventContent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
|
||||||
|
},
|
||||||
|
CanonicalJsonValue,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum StartContent {
|
||||||
|
ToDevice(StartToDeviceEventContent),
|
||||||
|
Room(StartEventContent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StartContent {
|
||||||
|
pub fn to_canonical_json(self) -> CanonicalJsonValue {
|
||||||
|
let content = match self {
|
||||||
|
StartContent::Room(c) => serde_json::to_value(c),
|
||||||
|
StartContent::ToDevice(c) => serde_json::to_value(c),
|
||||||
|
};
|
||||||
|
|
||||||
|
content
|
||||||
|
.expect("Can't serialize content")
|
||||||
|
.try_into()
|
||||||
|
.expect("Can't canonicalize content")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<StartEventContent> for StartContent {
|
||||||
|
fn from(content: StartEventContent) -> Self {
|
||||||
|
StartContent::Room(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<StartToDeviceEventContent> for StartContent {
|
||||||
|
fn from(content: StartToDeviceEventContent) -> Self {
|
||||||
|
StartContent::ToDevice(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum OutgoingContent {
|
||||||
|
Room(AnyMessageEventContent),
|
||||||
|
ToDevice(AnyToDeviceEventContent),
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,7 +38,7 @@ use crate::{
|
||||||
ReadOnlyAccount, ToDeviceRequest,
|
ReadOnlyAccount, ToDeviceRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::sas_state::FlowId;
|
use super::{event_enums::StartContent, sas_state::FlowId};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SasIds {
|
pub struct SasIds {
|
||||||
|
@ -57,15 +57,12 @@ pub struct SasIds {
|
||||||
///
|
///
|
||||||
/// * `content` - The `m.key.verification.start` event content that started the
|
/// * `content` - The `m.key.verification.start` event content that started the
|
||||||
/// interactive verification process.
|
/// interactive verification process.
|
||||||
pub fn calculate_commitment(public_key: &str, content: &StartToDeviceEventContent) -> String {
|
pub fn calculate_commitment(public_key: &str, content: impl Into<StartContent>) -> String {
|
||||||
let json_content: CanonicalJsonValue = serde_json::to_value(content)
|
let content = content.into().to_canonical_json();
|
||||||
.expect("Can't serialize content")
|
|
||||||
.try_into()
|
|
||||||
.expect("Can't canonicalize content");
|
|
||||||
|
|
||||||
encode(
|
encode(
|
||||||
Sha256::new()
|
Sha256::new()
|
||||||
.chain(&format!("{}{}", public_key, json_content))
|
.chain(&format!("{}{}", public_key, content))
|
||||||
.finalize(),
|
.finalize(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,15 @@ use std::time::Instant;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use matrix_sdk_common::events::{
|
use matrix_sdk_common::{
|
||||||
key::verification::{
|
events::{
|
||||||
accept::AcceptToDeviceEventContent, cancel::CancelCode, mac::MacToDeviceEventContent,
|
key::verification::{
|
||||||
start::StartToDeviceEventContent,
|
accept::AcceptToDeviceEventContent, cancel::CancelCode, mac::MacToDeviceEventContent,
|
||||||
|
start::StartToDeviceEventContent,
|
||||||
|
},
|
||||||
|
AnyToDeviceEvent, AnyToDeviceEventContent, ToDeviceEvent,
|
||||||
},
|
},
|
||||||
AnyToDeviceEvent, AnyToDeviceEventContent, ToDeviceEvent,
|
identifiers::EventId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -30,9 +33,12 @@ use crate::{
|
||||||
ReadOnlyAccount,
|
ReadOnlyAccount,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::sas_state::{
|
use super::{
|
||||||
Accepted, Canceled, Confirmed, Created, Done, FlowId, KeyReceived, MacReceived, SasState,
|
event_enums::OutgoingContent,
|
||||||
Started,
|
sas_state::{
|
||||||
|
Accepted, Canceled, Confirmed, Created, Done, FlowId, KeyReceived, MacReceived, SasState,
|
||||||
|
Started,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -52,12 +58,23 @@ impl InnerSas {
|
||||||
account: ReadOnlyAccount,
|
account: ReadOnlyAccount,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
) -> (InnerSas, StartToDeviceEventContent) {
|
) -> (InnerSas, OutgoingContent) {
|
||||||
let sas = SasState::<Created>::new(account, other_device, other_identity);
|
let sas = SasState::<Created>::new(account, other_device, other_identity);
|
||||||
let content = sas.as_content();
|
let content = sas.as_content();
|
||||||
(InnerSas::Created(sas), content)
|
(InnerSas::Created(sas), content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn start_in_room(
|
||||||
|
event_id: EventId,
|
||||||
|
account: ReadOnlyAccount,
|
||||||
|
other_device: ReadOnlyDevice,
|
||||||
|
other_identity: Option<UserIdentities>,
|
||||||
|
) -> (InnerSas, OutgoingContent) {
|
||||||
|
let sas = SasState::<Created>::new_in_room(event_id, account, other_device, other_identity);
|
||||||
|
let content = sas.as_content();
|
||||||
|
(InnerSas::Created(sas), content)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_start_event(
|
pub fn from_start_event(
|
||||||
account: ReadOnlyAccount,
|
account: ReadOnlyAccount,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
mod event_enums;
|
||||||
mod helpers;
|
mod helpers;
|
||||||
mod inner_sas;
|
mod inner_sas;
|
||||||
mod sas_state;
|
mod sas_state;
|
||||||
|
@ -46,6 +47,8 @@ pub use helpers::content_to_request;
|
||||||
use inner_sas::InnerSas;
|
use inner_sas::InnerSas;
|
||||||
pub use sas_state::FlowId;
|
pub use sas_state::FlowId;
|
||||||
|
|
||||||
|
pub use event_enums::{OutgoingContent, StartContent};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// A result of a verification flow.
|
/// A result of a verification flow.
|
||||||
pub enum VerificationResult {
|
pub enum VerificationResult {
|
||||||
|
@ -106,6 +109,30 @@ impl Sas {
|
||||||
self.inner.lock().unwrap().set_creation_time(time)
|
self.inner.lock().unwrap().set_creation_time(time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn start_helper(
|
||||||
|
inner_sas: InnerSas,
|
||||||
|
content: OutgoingContent,
|
||||||
|
account: ReadOnlyAccount,
|
||||||
|
private_identity: PrivateCrossSigningIdentity,
|
||||||
|
other_device: ReadOnlyDevice,
|
||||||
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
|
other_identity: Option<UserIdentities>,
|
||||||
|
) -> (Sas, OutgoingContent) {
|
||||||
|
let flow_id = inner_sas.verification_flow_id();
|
||||||
|
|
||||||
|
let sas = Sas {
|
||||||
|
inner: Arc::new(Mutex::new(inner_sas)),
|
||||||
|
account,
|
||||||
|
private_identity,
|
||||||
|
store,
|
||||||
|
other_device,
|
||||||
|
flow_id,
|
||||||
|
other_identity,
|
||||||
|
};
|
||||||
|
|
||||||
|
(sas, content)
|
||||||
|
}
|
||||||
|
|
||||||
/// Start a new SAS auth flow with the given device.
|
/// Start a new SAS auth flow with the given device.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
@ -122,25 +149,60 @@ impl Sas {
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
store: Arc<Box<dyn CryptoStore>>,
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
) -> (Sas, StartToDeviceEventContent) {
|
) -> (Sas, OutgoingContent) {
|
||||||
let (inner, content) = InnerSas::start(
|
let (inner, content) = InnerSas::start(
|
||||||
account.clone(),
|
account.clone(),
|
||||||
other_device.clone(),
|
other_device.clone(),
|
||||||
other_identity.clone(),
|
other_identity.clone(),
|
||||||
);
|
);
|
||||||
let flow_id = inner.verification_flow_id();
|
|
||||||
|
|
||||||
let sas = Sas {
|
Self::start_helper(
|
||||||
inner: Arc::new(Mutex::new(inner)),
|
inner,
|
||||||
|
content,
|
||||||
account,
|
account,
|
||||||
private_identity,
|
private_identity,
|
||||||
store,
|
|
||||||
other_device,
|
other_device,
|
||||||
flow_id,
|
store,
|
||||||
other_identity,
|
other_identity,
|
||||||
};
|
)
|
||||||
|
}
|
||||||
|
|
||||||
(sas, content)
|
/// Start a new SAS auth flow with the given device inside the given room.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `account` - Our own account.
|
||||||
|
///
|
||||||
|
/// * `other_device` - The other device which we are going to verify.
|
||||||
|
///
|
||||||
|
/// Returns the new `Sas` object and a `StartEventContent` that needs to be
|
||||||
|
/// sent out through the server to the other device.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn start_in_room(
|
||||||
|
flow_id: EventId,
|
||||||
|
room_id: RoomId,
|
||||||
|
account: ReadOnlyAccount,
|
||||||
|
private_identity: PrivateCrossSigningIdentity,
|
||||||
|
other_device: ReadOnlyDevice,
|
||||||
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
|
other_identity: Option<UserIdentities>,
|
||||||
|
) -> (Sas, OutgoingContent) {
|
||||||
|
let (inner, content) = InnerSas::start_in_room(
|
||||||
|
flow_id,
|
||||||
|
account.clone(),
|
||||||
|
other_device.clone(),
|
||||||
|
other_identity.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::start_helper(
|
||||||
|
inner,
|
||||||
|
content,
|
||||||
|
account,
|
||||||
|
private_identity,
|
||||||
|
other_device,
|
||||||
|
store,
|
||||||
|
other_identity,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new Sas object from a m.key.verification.start request.
|
/// Create a new Sas object from a m.key.verification.start request.
|
||||||
|
|
|
@ -30,19 +30,25 @@ use matrix_sdk_common::{
|
||||||
cancel::{CancelCode, CancelToDeviceEventContent},
|
cancel::{CancelCode, CancelToDeviceEventContent},
|
||||||
key::KeyToDeviceEventContent,
|
key::KeyToDeviceEventContent,
|
||||||
mac::MacToDeviceEventContent,
|
mac::MacToDeviceEventContent,
|
||||||
start::{MSasV1Content, MSasV1ContentInit, StartMethod, StartToDeviceEventContent},
|
start::{
|
||||||
HashAlgorithm, KeyAgreementProtocol, MessageAuthenticationCode,
|
MSasV1Content, MSasV1ContentInit, StartEventContent, StartMethod,
|
||||||
|
StartToDeviceEventContent,
|
||||||
|
},
|
||||||
|
HashAlgorithm, KeyAgreementProtocol, MessageAuthenticationCode, Relation,
|
||||||
ShortAuthenticationString, VerificationMethod,
|
ShortAuthenticationString, VerificationMethod,
|
||||||
},
|
},
|
||||||
AnyToDeviceEventContent, ToDeviceEvent,
|
AnyMessageEventContent, AnyToDeviceEventContent, ToDeviceEvent,
|
||||||
},
|
},
|
||||||
identifiers::{DeviceId, RoomId, UserId},
|
identifiers::{DeviceId, EventId, UserId},
|
||||||
uuid::Uuid,
|
uuid::Uuid,
|
||||||
};
|
};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
use super::helpers::{
|
use super::{
|
||||||
calculate_commitment, get_decimal, get_emoji, get_mac_content, receive_mac_event, SasIds,
|
event_enums::{OutgoingContent, StartContent},
|
||||||
|
helpers::{
|
||||||
|
calculate_commitment, get_decimal, get_emoji, get_mac_content, receive_mac_event, SasIds,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -68,7 +74,7 @@ const MAX_EVENT_TIMEOUT: Duration = Duration::from_secs(60);
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum FlowId {
|
pub enum FlowId {
|
||||||
ToDevice(String),
|
ToDevice(String),
|
||||||
InRoom(RoomId),
|
InRoom(EventId),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowId {
|
impl FlowId {
|
||||||
|
@ -200,7 +206,7 @@ pub struct Started {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Accepted {
|
pub struct Accepted {
|
||||||
accepted_protocols: Arc<AcceptedProtocols>,
|
accepted_protocols: Arc<AcceptedProtocols>,
|
||||||
start_content: Arc<StartToDeviceEventContent>,
|
start_content: Arc<StartContent>,
|
||||||
commitment: String,
|
commitment: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,13 +316,45 @@ impl SasState<Created> {
|
||||||
/// * `account` - Our own account.
|
/// * `account` - Our own account.
|
||||||
///
|
///
|
||||||
/// * `other_device` - The other device which we are going to verify.
|
/// * `other_device` - The other device which we are going to verify.
|
||||||
|
///
|
||||||
|
/// * `other_identity` - The identity of the other user if one exists.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
account: ReadOnlyAccount,
|
account: ReadOnlyAccount,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
) -> SasState<Created> {
|
) -> SasState<Created> {
|
||||||
let verification_flow_id = Uuid::new_v4().to_string();
|
let flow_id = FlowId::ToDevice(Uuid::new_v4().to_string());
|
||||||
|
Self::new_helper(flow_id, account, other_device, other_identity)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new SAS in-room verification flow.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `event_id` - The event id of the `m.key.verification.request` event
|
||||||
|
/// that started the verification flow.
|
||||||
|
///
|
||||||
|
/// * `account` - Our own account.
|
||||||
|
///
|
||||||
|
/// * `other_device` - The other device which we are going to verify.
|
||||||
|
///
|
||||||
|
/// * `other_identity` - The identity of the other user if one exists.
|
||||||
|
pub fn new_in_room(
|
||||||
|
event_id: EventId,
|
||||||
|
account: ReadOnlyAccount,
|
||||||
|
other_device: ReadOnlyDevice,
|
||||||
|
other_identity: Option<UserIdentities>,
|
||||||
|
) -> SasState<Created> {
|
||||||
|
let flow_id = FlowId::InRoom(event_id);
|
||||||
|
Self::new_helper(flow_id, account, other_device, other_identity)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_helper(
|
||||||
|
flow_id: FlowId,
|
||||||
|
account: ReadOnlyAccount,
|
||||||
|
other_device: ReadOnlyDevice,
|
||||||
|
other_identity: Option<UserIdentities>,
|
||||||
|
) -> SasState<Created> {
|
||||||
SasState {
|
SasState {
|
||||||
inner: Arc::new(Mutex::new(OlmSas::new())),
|
inner: Arc::new(Mutex::new(OlmSas::new())),
|
||||||
ids: SasIds {
|
ids: SasIds {
|
||||||
|
@ -324,7 +362,7 @@ impl SasState<Created> {
|
||||||
other_device,
|
other_device,
|
||||||
other_identity,
|
other_identity,
|
||||||
},
|
},
|
||||||
verification_flow_id: FlowId::ToDevice(verification_flow_id).into(),
|
verification_flow_id: flow_id.into(),
|
||||||
|
|
||||||
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()),
|
||||||
|
@ -340,18 +378,34 @@ impl SasState<Created> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_start_content(&self) -> StartContent {
|
||||||
|
match self.verification_flow_id.as_ref() {
|
||||||
|
FlowId::ToDevice(s) => StartContent::ToDevice(StartToDeviceEventContent {
|
||||||
|
transaction_id: self.verification_flow_id.to_string(),
|
||||||
|
from_device: self.device_id().into(),
|
||||||
|
method: StartMethod::MSasV1(
|
||||||
|
MSasV1Content::new(self.state.protocol_definitions.clone())
|
||||||
|
.expect("Invalid initial protocol definitions."),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
FlowId::InRoom(e) => StartContent::Room(StartEventContent {
|
||||||
|
from_device: self.device_id().into(),
|
||||||
|
method: StartMethod::MSasV1(
|
||||||
|
MSasV1Content::new(self.state.protocol_definitions.clone())
|
||||||
|
.expect("Invalid initial protocol definitions."),
|
||||||
|
),
|
||||||
|
relation: Relation {
|
||||||
|
event_id: e.clone(),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the content for the start event.
|
/// Get the content for the start event.
|
||||||
///
|
///
|
||||||
/// The content needs to be sent to the other device.
|
/// The content needs to be sent to the other device.
|
||||||
pub fn as_content(&self) -> StartToDeviceEventContent {
|
pub fn as_content(&self) -> OutgoingContent {
|
||||||
StartToDeviceEventContent {
|
self.as_start_content().into()
|
||||||
transaction_id: self.verification_flow_id.to_string(),
|
|
||||||
from_device: self.device_id().into(),
|
|
||||||
method: StartMethod::MSasV1(
|
|
||||||
MSasV1Content::new(self.state.protocol_definitions.clone())
|
|
||||||
.expect("Invalid initial protocol definitions."),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Receive a m.key.verification.accept event, changing the state into
|
/// Receive a m.key.verification.accept event, changing the state into
|
||||||
|
@ -372,7 +426,7 @@ impl SasState<Created> {
|
||||||
let accepted_protocols =
|
let accepted_protocols =
|
||||||
AcceptedProtocols::try_from(content.clone()).map_err(|c| self.clone().cancel(c))?;
|
AcceptedProtocols::try_from(content.clone()).map_err(|c| self.clone().cancel(c))?;
|
||||||
|
|
||||||
let start_content = self.as_content().into();
|
let start_content = self.as_start_content().into();
|
||||||
|
|
||||||
Ok(SasState {
|
Ok(SasState {
|
||||||
inner: self.inner,
|
inner: self.inner,
|
||||||
|
@ -416,7 +470,7 @@ impl SasState<Started> {
|
||||||
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);
|
let commitment = calculate_commitment(&pubkey, event.content.clone());
|
||||||
|
|
||||||
error!(
|
error!(
|
||||||
"Calculated commitment for pubkey {} and content {:?} {}",
|
"Calculated commitment for pubkey {} and content {:?} {}",
|
||||||
|
@ -565,7 +619,10 @@ impl SasState<Accepted> {
|
||||||
self.check_event(&event.sender, &event.content.transaction_id)
|
self.check_event(&event.sender, &event.content.transaction_id)
|
||||||
.map_err(|c| self.clone().cancel(c))?;
|
.map_err(|c| self.clone().cancel(c))?;
|
||||||
|
|
||||||
let commitment = calculate_commitment(&event.content.key, &self.state.start_content);
|
let commitment = calculate_commitment(
|
||||||
|
&event.content.key,
|
||||||
|
self.state.start_content.as_ref().clone(),
|
||||||
|
);
|
||||||
|
|
||||||
if self.state.commitment != commitment {
|
if self.state.commitment != commitment {
|
||||||
Err(self.cancel(CancelCode::InvalidMessage))
|
Err(self.cancel(CancelCode::InvalidMessage))
|
||||||
|
|
Loading…
Reference in New Issue