crypto: Initial support for device tracking.

This commit is contained in:
Damir Jelić 2020-04-02 11:14:23 +02:00
parent 5e22eb9faf
commit 56084a7809
7 changed files with 148 additions and 5 deletions

71
src/crypto/device.rs Normal file
View file

@ -0,0 +1,71 @@
// 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.
use std::collections::HashMap;
use ruma_client_api::r0::keys::{DeviceKeys, KeyAlgorithm};
use ruma_events::Algorithm;
#[derive(Debug)]
pub struct Device {
user_id: String,
device_id: String,
algorithms: Vec<Algorithm>,
keys: HashMap<KeyAlgorithm, String>,
display_name: Option<String>,
deleted: bool,
trust_state: TrustState,
}
#[derive(Debug)]
pub enum TrustState {
Verified,
BlackListed,
Ignored,
Unset,
}
impl Device {
pub fn id(&self) -> &str {
&self.device_id
}
pub fn user_id(&self) -> &str {
&self.user_id
}
}
impl From<&DeviceKeys> for Device {
fn from(device_keys: &DeviceKeys) -> Self {
let mut keys = HashMap::new();
for (key_id, key) in device_keys.keys.iter() {
let key_id = key_id.0;
keys.insert(key_id, key.clone());
}
Device {
user_id: device_keys.user_id.to_string(),
device_id: device_keys.device_id.clone(),
algorithms: device_keys.algorithms.clone(),
keys,
display_name: device_keys
.unsigned
.as_ref()
.map(|d| d.device_display_name.clone()),
deleted: false,
trust_state: TrustState::Unset,
}
}
}

View file

@ -25,7 +25,7 @@ use super::olm::{Account, InboundGroupSession, Session};
use super::store::memorystore::MemoryStore;
#[cfg(feature = "sqlite-cryptostore")]
use super::store::sqlite::SqliteStore;
use super::CryptoStore;
use super::{device::Device, CryptoStore};
use crate::api;
use api::r0::keys;
@ -188,13 +188,71 @@ impl OlmMachine {
///
/// * `response` - The keys query response of the request that the client
/// performed.
// TODO this should return a
#[instrument]
// TODO this should return a list of changed devices.
pub async fn receive_keys_query_response(
&mut self,
response: &keys::get_keys::Response,
) -> Result<()> {
todo!()
for (user_id, device_map) in &response.device_keys {
let user_id_string = user_id.to_string();
self.users_for_key_query.remove(&user_id_string);
for (device_id, device_keys) in device_map.iter() {
// We don't need our own device in the device store.
if user_id == &self.user_id && device_id == &self.device_id {
continue;
}
if user_id != &device_keys.user_id || device_id != &device_keys.device_id {
warn!(
"Mismatch in device keys payload of device {} from user {}",
device_keys.device_id, device_keys.user_id
);
continue;
}
let curve_key_id =
AlgorithmAndDeviceId(KeyAlgorithm::Curve25519, device_id.to_owned());
let ed_key_id = AlgorithmAndDeviceId(KeyAlgorithm::Ed25519, device_id.to_owned());
let sender_key = if let Some(k) = device_keys.keys.get(&curve_key_id) {
k
} else {
continue;
};
let signing_key = if let Some(k) = device_keys.keys.get(&ed_key_id) {
k
} else {
continue;
};
if self
.verify_json(user_id, device_id, signing_key, &mut json!(&device_keys))
.is_err()
{
warn!(
"Failed to verify the device key signatures for {} {}",
user_id, device_id
);
continue;
}
let device = self
.store
.get_user_device(&user_id_string, device_id)
.await
.expect("Can't load device");
if let Some(d) = device {
todo!()
} else {
let device = Device::from(device_keys);
info!("Found new device {:?}", device);
}
}
}
Ok(())
}
/// Generate new one-time keys.

View file

@ -14,6 +14,7 @@
mod error;
// TODO remove this.
mod device;
mod machine;
mod memory_stores;
#[allow(dead_code)]

View file

@ -19,6 +19,7 @@ use async_trait::async_trait;
use tokio::sync::Mutex;
use super::{Account, CryptoStore, CryptoStoreError, InboundGroupSession, Result, Session};
use crate::crypto::device::Device;
use crate::crypto::memory_stores::{GroupSessionStore, SessionStore};
#[derive(Debug)]
@ -86,4 +87,8 @@ impl CryptoStore for MemoryStore {
async fn add_user_for_tracking(&mut self, user: &str) -> Result<bool> {
Ok(self.tracked_users.insert(user.to_string()))
}
async fn get_user_device(&self, user_id: &str, device_id: &str) -> Result<Option<Device>> {
Ok(None)
}
}

View file

@ -24,6 +24,7 @@ use serde_json::Error as SerdeError;
use thiserror::Error;
use tokio::sync::Mutex;
use super::device::Device;
use super::olm::{Account, InboundGroupSession, Session};
use olm_rs::errors::{OlmAccountError, OlmGroupSessionError, OlmSessionError};
use olm_rs::PicklingMode;
@ -81,4 +82,5 @@ pub trait CryptoStore: Debug + Send + Sync {
) -> Result<Option<Arc<Mutex<InboundGroupSession>>>>;
fn tracked_users(&self) -> &HashSet<String>;
async fn add_user_for_tracking(&mut self, user: &str) -> Result<bool>;
async fn get_user_device(&self, user_id: &str, device_id: &str) -> Result<Option<Device>>;
}

View file

@ -27,6 +27,7 @@ use tokio::sync::Mutex;
use zeroize::Zeroizing;
use super::{Account, CryptoStore, CryptoStoreError, InboundGroupSession, Result, Session};
use crate::crypto::device::Device;
use crate::crypto::memory_stores::{GroupSessionStore, SessionStore};
pub struct SqliteStore {
@ -406,6 +407,10 @@ impl CryptoStore for SqliteStore {
}
async fn add_user_for_tracking(&mut self, user: &str) -> Result<bool> {
Ok(self.tracked_users.insert(user.to_string()))
}
async fn get_user_device(&self, user_id: &str, device_id: &str) -> Result<Option<Device>> {
todo!()
}
}

View file

@ -242,7 +242,8 @@ impl Room {
}
}
fn handle_encryption_event(&mut self, event: &EncryptionEvent) -> bool {
fn handle_encryption_event(&mut self, _: &EncryptionEvent) -> bool {
// TODO store the encryption settings.
self.encrypted = true;
true
}