crypto: More work on the incoming key request handling.

master
Damir Jelić 2020-09-28 13:32:30 +02:00
parent a357536ade
commit e29508938b
2 changed files with 120 additions and 31 deletions

View File

@ -29,8 +29,8 @@
use dashmap::DashMap; use dashmap::DashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::{value::to_raw_value, Value}; use serde_json::{value::to_raw_value, Value};
use std::{collections::BTreeMap, convert::TryInto, sync::Arc}; use std::{collections::BTreeMap, convert::TryInto, ops::Deref, sync::Arc};
use tracing::{info, trace}; use tracing::{info, instrument, trace};
use matrix_sdk_common::{ use matrix_sdk_common::{
api::r0::to_device::DeviceIdOrAllDevices, api::r0::to_device::DeviceIdOrAllDevices,
@ -48,7 +48,7 @@ use matrix_sdk_common::{
use crate::{ use crate::{
error::OlmResult, error::OlmResult,
identities::{OwnUserIdentity, ReadOnlyDevice, UserIdentities}, identities::{OwnUserIdentity, ReadOnlyDevice, UserIdentities},
olm::InboundGroupSession, olm::{InboundGroupSession, OutboundGroupSession},
requests::{OutgoingRequest, ToDeviceRequest}, requests::{OutgoingRequest, ToDeviceRequest},
store::{CryptoStoreError, Store}, store::{CryptoStoreError, Store},
}; };
@ -77,6 +77,14 @@ impl Device {
} }
} }
impl Deref for Device {
type Target = ReadOnlyDevice;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct KeyRequestMachine { pub(crate) struct KeyRequestMachine {
user_id: Arc<UserId>, user_id: Arc<UserId>,
@ -173,6 +181,9 @@ impl KeyRequestMachine {
.insert((sender, device_id, request_id), event.clone()); .insert((sender, device_id, request_id), event.clone());
} }
/// Handle all the incoming key requests that are queued up and empty our
/// key request queue.
#[instrument]
pub async fn collect_incoming_key_requests(&self) -> Result<(), CryptoStoreError> { pub async fn collect_incoming_key_requests(&self) -> Result<(), CryptoStoreError> {
for item in self.incoming_key_requests.iter() { for item in self.incoming_key_requests.iter() {
let event = item.value(); let event = item.value();
@ -226,12 +237,14 @@ impl KeyRequestMachine {
}); });
if let Some(device) = device { if let Some(device) = device {
if self.user_id() == &event.sender { if self.should_share_session(&device, None) {
self.handle_key_request_from_own_user(event, session, device) self.share_session(session, device).await;
.await?;
} else { } else {
self.handle_key_request_from_others(event, session, device) info!(
.await?; "Received a key request from {} {} that we won't serve.",
device.user_id(),
device.device_id()
);
} }
} else { } else {
info!("Received a key request from an unknown device."); info!("Received a key request from an unknown device.");
@ -241,32 +254,103 @@ impl KeyRequestMachine {
Ok(()) Ok(())
} }
async fn handle_key_request_from_own_user( async fn share_session(&self, session: InboundGroupSession, device: Device) {
&self,
event: &ToDeviceEvent<RoomKeyRequestEventContent>,
session: InboundGroupSession,
device: Device,
) -> Result<(), CryptoStoreError> {
// TODO should we create yet another Device type that holds a store
// but not a verification machine?
if device.trust_state() {
let export = session.export().await; let export = session.export().await;
let content: ForwardedRoomKeyEventContent = export.try_into().unwrap(); let content: ForwardedRoomKeyEventContent = export.try_into().unwrap();
let content = serde_json::to_value(content).unwrap();
let content = device
.encrypt(EventType::ForwardedRoomKey, content)
.await
.unwrap();
todo!("Queue up a key to be shared"); let id = Uuid::new_v4();
} else {
info!("Received a key request from an untrusted device."); let mut messages = BTreeMap::new();
messages
.entry(device.user_id().to_owned())
.or_insert_with(BTreeMap::new)
.insert(
DeviceIdOrAllDevices::DeviceId(device.device_id().into()),
to_raw_value(&content).unwrap(),
);
let request = OutgoingRequest {
request_id: id,
request: Arc::new(
ToDeviceRequest {
event_type: EventType::RoomKeyRequest,
txn_id: id,
messages,
} }
todo!() .into(),
),
};
self.outgoing_to_device_requests.insert(id, request);
} }
async fn handle_key_request_from_others( /// Check if it's ok to share a session with the given device.
///
/// The logic for this currently is as follows:
///
/// * Share any session with our own devices as long as they are trusted.
///
/// * Share with devices of other users only sessions that were meant to be
/// shared with them in the first place, in other words if an outbound
/// session still exists and the session was shared with that user/device
/// pair.
///
/// # Arguments
///
/// * `device` - The device that is requesting a session from us.
///
/// * `outbound_session` - If one still exists, the matching outbound
/// session that was used to create the inbound session that is being
/// requested.
fn should_share_session(
&self, &self,
event: &ToDeviceEvent<RoomKeyRequestEventContent>, device: &Device,
session: InboundGroupSession, outbound_session: Option<&OutboundGroupSession>,
device: Device, ) -> bool {
) -> Result<(), CryptoStoreError> { if device.user_id() == self.user_id() {
todo!() if device.trust_state() {
true
} else {
info!(
"Received a key share request from {} {}, but the \
device isn't trusted.",
device.user_id(),
device.device_id()
);
false
}
} else {
if let Some(outbound) = outbound_session {
if outbound
.shared_with()
.contains(&(device.user_id().to_owned(), device.device_id().to_owned()))
{
true
} else {
info!(
"Received a key share request from {} {}, but the \
outbound session was never shared with them.",
device.user_id(),
device.device_id()
);
false
}
} else {
info!(
"Received a key share request from {} {}, but no \
outbound session was found.",
device.user_id(),
device.device_id()
);
false
}
}
} }
/// Create a new outgoing key request for the key with the given session id. /// Create a new outgoing key request for the key with the given session id.

View File

@ -101,7 +101,7 @@ pub struct OutboundGroupSession {
message_count: Arc<AtomicU64>, message_count: Arc<AtomicU64>,
shared: Arc<AtomicBool>, shared: Arc<AtomicBool>,
settings: Arc<EncryptionSettings>, settings: Arc<EncryptionSettings>,
shared_with_set: Arc<DashSet<UserId>>, shared_with_set: Arc<DashSet<(UserId, DeviceIdBox)>>,
to_share_with_set: Arc<DashSet<UserId>>, to_share_with_set: Arc<DashSet<UserId>>,
} }
@ -271,6 +271,11 @@ impl OutboundGroupSession {
"chain_index": self.message_index().await, "chain_index": self.message_index().await,
}) })
} }
/// The set of users this session is shared with.
pub(crate) fn shared_with(&self) -> &DashSet<(UserId, DeviceIdBox)> {
&self.shared_with_set
}
} }
#[cfg(not(tarpaulin_include))] #[cfg(not(tarpaulin_include))]