crypto: Prepare the sas structs to handle in-room verifications.
parent
b9ddbb11af
commit
1bb5b42b1d
|
@ -1825,7 +1825,7 @@ pub(crate) mod test {
|
||||||
let mut event = request_to_event(alice.user_id(), &request);
|
let mut event = request_to_event(alice.user_id(), &request);
|
||||||
bob.handle_verification_event(&mut event).await;
|
bob.handle_verification_event(&mut event).await;
|
||||||
|
|
||||||
let bob_sas = bob.get_verification(alice_sas.flow_id()).unwrap();
|
let bob_sas = bob.get_verification(alice_sas.flow_id().as_str()).unwrap();
|
||||||
|
|
||||||
assert!(alice_sas.emoji().is_none());
|
assert!(alice_sas.emoji().is_none());
|
||||||
assert!(bob_sas.emoji().is_none());
|
assert!(bob_sas.emoji().is_none());
|
||||||
|
|
|
@ -88,7 +88,7 @@ impl VerificationMachine {
|
||||||
);
|
);
|
||||||
|
|
||||||
self.verifications
|
self.verifications
|
||||||
.insert(sas.flow_id().to_owned(), sas.clone());
|
.insert(sas.flow_id().to_string(), sas.clone());
|
||||||
|
|
||||||
Ok((sas, request))
|
Ok((sas, request))
|
||||||
}
|
}
|
||||||
|
@ -367,7 +367,7 @@ mod test {
|
||||||
async fn full_flow() {
|
async fn full_flow() {
|
||||||
let (alice_machine, bob) = setup_verification_machine().await;
|
let (alice_machine, bob) = setup_verification_machine().await;
|
||||||
|
|
||||||
let alice = alice_machine.get_sas(bob.flow_id()).unwrap();
|
let alice = alice_machine.get_sas(bob.flow_id().as_str()).unwrap();
|
||||||
|
|
||||||
let mut event = alice
|
let mut event = alice
|
||||||
.accept()
|
.accept()
|
||||||
|
@ -428,7 +428,7 @@ mod test {
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn timing_out() {
|
async fn timing_out() {
|
||||||
let (alice_machine, bob) = setup_verification_machine().await;
|
let (alice_machine, bob) = setup_verification_machine().await;
|
||||||
let alice = alice_machine.get_sas(bob.flow_id()).unwrap();
|
let alice = alice_machine.get_sas(bob.flow_id().as_str()).unwrap();
|
||||||
|
|
||||||
assert!(!alice.timed_out());
|
assert!(!alice.timed_out());
|
||||||
assert!(alice_machine.outgoing_to_device_messages.is_empty());
|
assert!(alice_machine.outgoing_to_device_messages.is_empty());
|
||||||
|
|
|
@ -38,6 +38,8 @@ use crate::{
|
||||||
ReadOnlyAccount, ToDeviceRequest,
|
ReadOnlyAccount, ToDeviceRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::sas_state::FlowId;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SasIds {
|
pub struct SasIds {
|
||||||
pub account: ReadOnlyAccount,
|
pub account: ReadOnlyAccount,
|
||||||
|
@ -298,12 +300,12 @@ fn extra_mac_info_send(ids: &SasIds, flow_id: &str) -> String {
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// This will panic if the public key of the other side wasn't set.
|
/// This will panic if the public key of the other side wasn't set.
|
||||||
pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &str) -> MacToDeviceEventContent {
|
pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &FlowId) -> MacToDeviceEventContent {
|
||||||
let mut mac: BTreeMap<String, String> = BTreeMap::new();
|
let mut mac: BTreeMap<String, String> = BTreeMap::new();
|
||||||
|
|
||||||
let key_id = DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, ids.account.device_id());
|
let key_id = DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, ids.account.device_id());
|
||||||
let key = ids.account.identity_keys().ed25519();
|
let key = ids.account.identity_keys().ed25519();
|
||||||
let info = extra_mac_info_send(ids, flow_id);
|
let info = extra_mac_info_send(ids, flow_id.as_str());
|
||||||
|
|
||||||
mac.insert(
|
mac.insert(
|
||||||
key_id.to_string(),
|
key_id.to_string(),
|
||||||
|
@ -319,10 +321,13 @@ pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &str) -> MacToDevice
|
||||||
.calculate_mac(&keys.join(","), &format!("{}KEY_IDS", &info))
|
.calculate_mac(&keys.join(","), &format!("{}KEY_IDS", &info))
|
||||||
.expect("Can't calculate SAS MAC");
|
.expect("Can't calculate SAS MAC");
|
||||||
|
|
||||||
MacToDeviceEventContent {
|
match flow_id {
|
||||||
transaction_id: flow_id.to_owned(),
|
FlowId::ToDevice(s) => MacToDeviceEventContent {
|
||||||
|
transaction_id: s.to_string(),
|
||||||
keys,
|
keys,
|
||||||
mac,
|
mac,
|
||||||
|
},
|
||||||
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,8 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::sas_state::{
|
use super::sas_state::{
|
||||||
Accepted, Canceled, Confirmed, Created, Done, KeyReceived, MacReceived, SasState, Started,
|
Accepted, Canceled, Confirmed, Created, Done, FlowId, KeyReceived, MacReceived, SasState,
|
||||||
|
Started,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -220,7 +221,7 @@ impl InnerSas {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verification_flow_id(&self) -> Arc<str> {
|
pub fn verification_flow_id(&self) -> Arc<FlowId> {
|
||||||
match self {
|
match self {
|
||||||
InnerSas::Created(s) => s.verification_flow_id.clone(),
|
InnerSas::Created(s) => s.verification_flow_id.clone(),
|
||||||
InnerSas::Started(s) => s.verification_flow_id.clone(),
|
InnerSas::Started(s) => s.verification_flow_id.clone(),
|
||||||
|
|
|
@ -31,7 +31,7 @@ use matrix_sdk_common::{
|
||||||
},
|
},
|
||||||
AnyToDeviceEvent, AnyToDeviceEventContent, ToDeviceEvent,
|
AnyToDeviceEvent, AnyToDeviceEventContent, ToDeviceEvent,
|
||||||
},
|
},
|
||||||
identifiers::{DeviceId, UserId},
|
identifiers::{DeviceId, EventId, RoomId, UserId},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -44,6 +44,7 @@ use crate::{
|
||||||
|
|
||||||
pub use helpers::content_to_request;
|
pub use helpers::content_to_request;
|
||||||
use inner_sas::InnerSas;
|
use inner_sas::InnerSas;
|
||||||
|
pub use sas_state::FlowId;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// A result of a verification flow.
|
/// A result of a verification flow.
|
||||||
|
@ -65,7 +66,7 @@ pub struct Sas {
|
||||||
private_identity: PrivateCrossSigningIdentity,
|
private_identity: PrivateCrossSigningIdentity,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
flow_id: Arc<str>,
|
flow_id: Arc<FlowId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sas {
|
impl Sas {
|
||||||
|
@ -95,7 +96,7 @@ impl Sas {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the unique ID that identifies this SAS verification flow.
|
/// Get the unique ID that identifies this SAS verification flow.
|
||||||
pub fn flow_id(&self) -> &str {
|
pub fn flow_id(&self) -> &FlowId {
|
||||||
&self.flow_id
|
&self.flow_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ use matrix_sdk_common::{
|
||||||
},
|
},
|
||||||
AnyToDeviceEventContent, ToDeviceEvent,
|
AnyToDeviceEventContent, ToDeviceEvent,
|
||||||
},
|
},
|
||||||
identifiers::{DeviceId, UserId},
|
identifiers::{DeviceId, RoomId, UserId},
|
||||||
uuid::Uuid,
|
uuid::Uuid,
|
||||||
};
|
};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
@ -65,6 +65,28 @@ const MAX_AGE: Duration = Duration::from_secs(60 * 5);
|
||||||
// The max time a SAS object will wait for a new event to arrive.
|
// The max time a SAS object will wait for a new event to arrive.
|
||||||
const MAX_EVENT_TIMEOUT: Duration = Duration::from_secs(60);
|
const MAX_EVENT_TIMEOUT: Duration = Duration::from_secs(60);
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum FlowId {
|
||||||
|
ToDevice(String),
|
||||||
|
InRoom(RoomId),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlowId {
|
||||||
|
pub fn to_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
FlowId::InRoom(r) => r.to_string(),
|
||||||
|
FlowId::ToDevice(t) => t.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
FlowId::InRoom(r) => r.as_str(),
|
||||||
|
FlowId::ToDevice(t) => t.as_str(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Struct containing the protocols that were agreed to be used for the SAS
|
/// Struct containing the protocols that were agreed to be used for the SAS
|
||||||
/// flow.
|
/// flow.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -143,7 +165,7 @@ pub struct SasState<S: Clone> {
|
||||||
///
|
///
|
||||||
/// This will be the transaction id for to-device events and the relates_to
|
/// This will be the transaction id for to-device events and the relates_to
|
||||||
/// field for in-room events.
|
/// field for in-room events.
|
||||||
pub verification_flow_id: Arc<str>,
|
pub verification_flow_id: Arc<FlowId>,
|
||||||
|
|
||||||
/// The SAS state we're in.
|
/// The SAS state we're in.
|
||||||
state: Arc<S>,
|
state: Arc<S>,
|
||||||
|
@ -268,7 +290,7 @@ impl<S: Clone> SasState<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_event(&self, sender: &UserId, flow_id: &str) -> Result<(), CancelCode> {
|
fn check_event(&self, sender: &UserId, flow_id: &str) -> Result<(), CancelCode> {
|
||||||
if *flow_id != *self.verification_flow_id {
|
if *flow_id != *self.verification_flow_id.as_str() {
|
||||||
Err(CancelCode::UnknownTransaction)
|
Err(CancelCode::UnknownTransaction)
|
||||||
} else if sender != self.ids.other_device.user_id() {
|
} else if sender != self.ids.other_device.user_id() {
|
||||||
Err(CancelCode::UserMismatch)
|
Err(CancelCode::UserMismatch)
|
||||||
|
@ -302,7 +324,7 @@ impl SasState<Created> {
|
||||||
other_device,
|
other_device,
|
||||||
other_identity,
|
other_identity,
|
||||||
},
|
},
|
||||||
verification_flow_id: verification_flow_id.into(),
|
verification_flow_id: FlowId::ToDevice(verification_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()),
|
||||||
|
@ -413,7 +435,7 @@ 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: event.content.transaction_id.as_str().into(),
|
verification_flow_id: FlowId::ToDevice(event.content.transaction_id.clone()).into(),
|
||||||
|
|
||||||
state: Arc::new(Started {
|
state: Arc::new(Started {
|
||||||
protocol_definitions: content.clone(),
|
protocol_definitions: content.clone(),
|
||||||
|
@ -452,7 +474,7 @@ impl SasState<Started> {
|
||||||
other_identity,
|
other_identity,
|
||||||
},
|
},
|
||||||
|
|
||||||
verification_flow_id: event.content.transaction_id.as_str().into(),
|
verification_flow_id: FlowId::ToDevice(event.content.transaction_id.clone()).into(),
|
||||||
state: Arc::new(Canceled::new(CancelCode::UnknownMethod)),
|
state: Arc::new(Canceled::new(CancelCode::UnknownMethod)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -575,9 +597,14 @@ impl SasState<Accepted> {
|
||||||
///
|
///
|
||||||
/// The content needs to be automatically sent to the other side.
|
/// The content needs to be automatically sent to the other side.
|
||||||
pub fn as_content(&self) -> KeyToDeviceEventContent {
|
pub fn as_content(&self) -> KeyToDeviceEventContent {
|
||||||
KeyToDeviceEventContent {
|
match &*self.verification_flow_id {
|
||||||
transaction_id: self.verification_flow_id.to_string(),
|
FlowId::ToDevice(s) => KeyToDeviceEventContent {
|
||||||
|
transaction_id: s.to_string(),
|
||||||
key: self.inner.lock().unwrap().public_key(),
|
key: self.inner.lock().unwrap().public_key(),
|
||||||
|
},
|
||||||
|
FlowId::InRoom(r) => {
|
||||||
|
todo!("In-room verifications aren't implemented")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -588,9 +615,12 @@ impl SasState<KeyReceived> {
|
||||||
/// The content needs to be automatically sent to the other side if and only
|
/// The content needs to be automatically sent to the other side if and only
|
||||||
/// if we_started is false.
|
/// if we_started is false.
|
||||||
pub fn as_content(&self) -> KeyToDeviceEventContent {
|
pub fn as_content(&self) -> KeyToDeviceEventContent {
|
||||||
KeyToDeviceEventContent {
|
match self.verification_flow_id.as_ref() {
|
||||||
transaction_id: self.verification_flow_id.to_string(),
|
FlowId::ToDevice(s) => KeyToDeviceEventContent {
|
||||||
|
transaction_id: s.to_string(),
|
||||||
key: self.inner.lock().unwrap().public_key(),
|
key: self.inner.lock().unwrap().public_key(),
|
||||||
|
},
|
||||||
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -603,7 +633,7 @@ impl SasState<KeyReceived> {
|
||||||
&self.inner.lock().unwrap(),
|
&self.inner.lock().unwrap(),
|
||||||
&self.ids,
|
&self.ids,
|
||||||
&self.state.their_pubkey,
|
&self.state.their_pubkey,
|
||||||
&self.verification_flow_id,
|
self.verification_flow_id.as_str(),
|
||||||
self.state.we_started,
|
self.state.we_started,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -617,7 +647,7 @@ impl SasState<KeyReceived> {
|
||||||
&self.inner.lock().unwrap(),
|
&self.inner.lock().unwrap(),
|
||||||
&self.ids,
|
&self.ids,
|
||||||
&self.state.their_pubkey,
|
&self.state.their_pubkey,
|
||||||
&self.verification_flow_id,
|
self.verification_flow_id.as_str(),
|
||||||
self.state.we_started,
|
self.state.we_started,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -639,7 +669,7 @@ impl SasState<KeyReceived> {
|
||||||
let (devices, master_keys) = receive_mac_event(
|
let (devices, master_keys) = receive_mac_event(
|
||||||
&self.inner.lock().unwrap(),
|
&self.inner.lock().unwrap(),
|
||||||
&self.ids,
|
&self.ids,
|
||||||
&self.verification_flow_id,
|
self.verification_flow_id.as_str(),
|
||||||
event,
|
event,
|
||||||
)
|
)
|
||||||
.map_err(|c| self.clone().cancel(c))?;
|
.map_err(|c| self.clone().cancel(c))?;
|
||||||
|
@ -695,7 +725,7 @@ impl SasState<Confirmed> {
|
||||||
let (devices, master_keys) = receive_mac_event(
|
let (devices, master_keys) = receive_mac_event(
|
||||||
&self.inner.lock().unwrap(),
|
&self.inner.lock().unwrap(),
|
||||||
&self.ids,
|
&self.ids,
|
||||||
&self.verification_flow_id,
|
&self.verification_flow_id.as_str(),
|
||||||
event,
|
event,
|
||||||
)
|
)
|
||||||
.map_err(|c| self.clone().cancel(c))?;
|
.map_err(|c| self.clone().cancel(c))?;
|
||||||
|
@ -754,7 +784,7 @@ impl SasState<MacReceived> {
|
||||||
&self.inner.lock().unwrap(),
|
&self.inner.lock().unwrap(),
|
||||||
&self.ids,
|
&self.ids,
|
||||||
&self.state.their_pubkey,
|
&self.state.their_pubkey,
|
||||||
&self.verification_flow_id,
|
&self.verification_flow_id.as_str(),
|
||||||
self.state.we_started,
|
self.state.we_started,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -768,7 +798,7 @@ impl SasState<MacReceived> {
|
||||||
&self.inner.lock().unwrap(),
|
&self.inner.lock().unwrap(),
|
||||||
&self.ids,
|
&self.ids,
|
||||||
&self.state.their_pubkey,
|
&self.state.their_pubkey,
|
||||||
&self.verification_flow_id,
|
&self.verification_flow_id.as_str(),
|
||||||
self.state.we_started,
|
self.state.we_started,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -828,12 +858,17 @@ impl Canceled {
|
||||||
|
|
||||||
impl SasState<Canceled> {
|
impl SasState<Canceled> {
|
||||||
pub fn as_content(&self) -> AnyToDeviceEventContent {
|
pub fn as_content(&self) -> AnyToDeviceEventContent {
|
||||||
|
match self.verification_flow_id.as_ref() {
|
||||||
|
FlowId::ToDevice(s) => {
|
||||||
AnyToDeviceEventContent::KeyVerificationCancel(CancelToDeviceEventContent {
|
AnyToDeviceEventContent::KeyVerificationCancel(CancelToDeviceEventContent {
|
||||||
transaction_id: self.verification_flow_id.to_string(),
|
transaction_id: self.verification_flow_id.to_string(),
|
||||||
reason: self.state.reason.to_string(),
|
reason: self.state.reason.to_string(),
|
||||||
code: self.state.cancel_code.clone(),
|
code: self.state.cancel_code.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Reference in New Issue