crypto: Initial scaffolding for handling user identities in key queries.
parent
150862ec0c
commit
f96437a242
|
@ -60,6 +60,10 @@ use super::{
|
||||||
OlmMessage, OutboundGroupSession,
|
OlmMessage, OutboundGroupSession,
|
||||||
},
|
},
|
||||||
store::{memorystore::MemoryStore, Result as StoreResult},
|
store::{memorystore::MemoryStore, Result as StoreResult},
|
||||||
|
user_identity::{
|
||||||
|
MasterPubkey, OwnUserIdentity, SelfSigningPubkey, UserIdentities, UserIdentity,
|
||||||
|
UserSigningPubkey,
|
||||||
|
},
|
||||||
verification::{Sas, VerificationMachine},
|
verification::{Sas, VerificationMachine},
|
||||||
CryptoStore,
|
CryptoStore,
|
||||||
};
|
};
|
||||||
|
@ -429,6 +433,9 @@ impl OlmMachine {
|
||||||
let mut changed_devices = Vec::new();
|
let mut changed_devices = Vec::new();
|
||||||
|
|
||||||
for (user_id, device_map) in device_keys_map {
|
for (user_id, device_map) in device_keys_map {
|
||||||
|
// TODO move this out into the handle keys query response method
|
||||||
|
// since we might fail handle the new device at any point here or
|
||||||
|
// when updating the user identities.
|
||||||
self.store.update_tracked_user(user_id, false).await?;
|
self.store.update_tracked_user(user_id, false).await?;
|
||||||
|
|
||||||
for (device_id, device_keys) in device_map.iter() {
|
for (device_id, device_keys) in device_map.iter() {
|
||||||
|
@ -492,6 +499,63 @@ impl OlmMachine {
|
||||||
Ok(changed_devices)
|
Ok(changed_devices)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn handle_cross_singing_keys(
|
||||||
|
&self,
|
||||||
|
response: &get_keys::Response,
|
||||||
|
) -> StoreResult<Vec<UserIdentities>> {
|
||||||
|
let mut changed = Vec::new();
|
||||||
|
|
||||||
|
for (user_id, master_key) in &response.master_keys {
|
||||||
|
let master_key = MasterPubkey::from(master_key);
|
||||||
|
|
||||||
|
let self_signing = if let Some(s) = response.self_signing_keys.get(user_id) {
|
||||||
|
SelfSigningPubkey::from(s)
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let identity = if let Some(mut i) = self.store.get_user_identity(user_id).await? {
|
||||||
|
match &mut i {
|
||||||
|
UserIdentities::Own(ref mut identity) => {
|
||||||
|
let user_signing = if let Some(s) = response.user_signing_keys.get(user_id)
|
||||||
|
{
|
||||||
|
UserSigningPubkey::from(s)
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
identity
|
||||||
|
.update(master_key, self_signing, user_signing)
|
||||||
|
.map(|_| i)
|
||||||
|
}
|
||||||
|
UserIdentities::Other(ref mut identity) => {
|
||||||
|
identity.update(master_key, self_signing).map(|_| i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if user_id == self.user_id() {
|
||||||
|
if let Some(s) = response.user_signing_keys.get(user_id) {
|
||||||
|
let user_signing = UserSigningPubkey::from(s);
|
||||||
|
OwnUserIdentity::new(master_key, self_signing, user_signing)
|
||||||
|
.map(UserIdentities::Own)
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
UserIdentity::new(master_key, self_signing).map(UserIdentities::Other)
|
||||||
|
};
|
||||||
|
|
||||||
|
match identity {
|
||||||
|
Ok(i) => changed.push(i),
|
||||||
|
Err(_e) => {
|
||||||
|
// TODO log some error here
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(changed)
|
||||||
|
}
|
||||||
|
|
||||||
/// Receive a successful keys query response.
|
/// Receive a successful keys query response.
|
||||||
///
|
///
|
||||||
/// Returns a list of devices newly discovered devices and devices that
|
/// Returns a list of devices newly discovered devices and devices that
|
||||||
|
@ -504,13 +568,14 @@ impl OlmMachine {
|
||||||
pub async fn receive_keys_query_response(
|
pub async fn receive_keys_query_response(
|
||||||
&self,
|
&self,
|
||||||
response: &get_keys::Response,
|
response: &get_keys::Response,
|
||||||
) -> OlmResult<Vec<ReadOnlyDevice>> {
|
) -> OlmResult<(Vec<ReadOnlyDevice>, Vec<UserIdentities>)> {
|
||||||
let changed_devices = self
|
let changed_devices = self
|
||||||
.handle_devices_from_key_query(&response.device_keys)
|
.handle_devices_from_key_query(&response.device_keys)
|
||||||
.await?;
|
.await?;
|
||||||
self.store.save_devices(&changed_devices).await?;
|
self.store.save_devices(&changed_devices).await?;
|
||||||
|
let changed_identities = self.handle_cross_singing_keys(response).await?;
|
||||||
|
|
||||||
Ok(changed_devices)
|
Ok((changed_devices, changed_identities))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a request to upload E2EE keys to the server.
|
/// Get a request to upload E2EE keys to the server.
|
||||||
|
|
|
@ -25,6 +25,7 @@ use super::{Account, CryptoStore, InboundGroupSession, Result, Session};
|
||||||
use crate::{
|
use crate::{
|
||||||
device::ReadOnlyDevice,
|
device::ReadOnlyDevice,
|
||||||
memory_stores::{DeviceStore, GroupSessionStore, ReadOnlyUserDevices, SessionStore},
|
memory_stores::{DeviceStore, GroupSessionStore, ReadOnlyUserDevices, SessionStore},
|
||||||
|
user_identity::UserIdentities,
|
||||||
};
|
};
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MemoryStore {
|
pub struct MemoryStore {
|
||||||
|
@ -131,6 +132,10 @@ impl CryptoStore for MemoryStore {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_user_identity(&self, _user_id: &UserId) -> Result<Option<UserIdentities>> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -30,6 +30,7 @@ use super::{
|
||||||
device::ReadOnlyDevice,
|
device::ReadOnlyDevice,
|
||||||
memory_stores::ReadOnlyUserDevices,
|
memory_stores::ReadOnlyUserDevices,
|
||||||
olm::{Account, InboundGroupSession, Session},
|
olm::{Account, InboundGroupSession, Session},
|
||||||
|
user_identity::UserIdentities,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod memorystore;
|
pub mod memorystore;
|
||||||
|
@ -197,4 +198,11 @@ pub trait CryptoStore: Debug {
|
||||||
///
|
///
|
||||||
/// * `user_id` - The user for which we should get all the devices.
|
/// * `user_id` - The user for which we should get all the devices.
|
||||||
async fn get_user_devices(&self, user_id: &UserId) -> Result<ReadOnlyUserDevices>;
|
async fn get_user_devices(&self, user_id: &UserId) -> Result<ReadOnlyUserDevices>;
|
||||||
|
|
||||||
|
/// Get the user identity that is attached to the given user id.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `user_id` - The user for which we should get the identity.
|
||||||
|
async fn get_user_identity(&self, user_id: &UserId) -> Result<Option<UserIdentities>>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ use super::{CryptoStore, CryptoStoreError, Result};
|
||||||
use crate::{
|
use crate::{
|
||||||
device::{ReadOnlyDevice, TrustState},
|
device::{ReadOnlyDevice, TrustState},
|
||||||
memory_stores::{DeviceStore, GroupSessionStore, ReadOnlyUserDevices, SessionStore},
|
memory_stores::{DeviceStore, GroupSessionStore, ReadOnlyUserDevices, SessionStore},
|
||||||
|
user_identity::UserIdentities,
|
||||||
Account, IdentityKeys, InboundGroupSession, Session,
|
Account, IdentityKeys, InboundGroupSession, Session,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -883,6 +884,10 @@ impl CryptoStore for SqliteStore {
|
||||||
async fn get_user_devices(&self, user_id: &UserId) -> Result<ReadOnlyUserDevices> {
|
async fn get_user_devices(&self, user_id: &UserId) -> Result<ReadOnlyUserDevices> {
|
||||||
Ok(self.devices.user_devices(user_id))
|
Ok(self.devices.user_devices(user_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_user_identity(&self, _user_id: &UserId) -> Result<Option<UserIdentities>> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(tarpaulin_include))]
|
#[cfg(not(tarpaulin_include))]
|
||||||
|
|
|
@ -77,12 +77,6 @@ impl<'a> CrossSigningSubKeys<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UserIdentity {
|
|
||||||
user_id: Arc<UserId>,
|
|
||||||
master_key: MasterPubkey,
|
|
||||||
self_signing_key: SelfSigningPubkey,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MasterPubkey {
|
impl MasterPubkey {
|
||||||
fn verify_subkey<'a>(
|
fn verify_subkey<'a>(
|
||||||
&self,
|
&self,
|
||||||
|
@ -151,6 +145,19 @@ impl SelfSigningPubkey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum UserIdentities {
|
||||||
|
Own(OwnUserIdentity),
|
||||||
|
Other(UserIdentity),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct UserIdentity {
|
||||||
|
user_id: Arc<UserId>,
|
||||||
|
master_key: MasterPubkey,
|
||||||
|
self_signing_key: SelfSigningPubkey,
|
||||||
|
}
|
||||||
|
|
||||||
impl UserIdentity {
|
impl UserIdentity {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
master_key: MasterPubkey,
|
master_key: MasterPubkey,
|
||||||
|
@ -165,11 +172,25 @@ impl UserIdentity {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update(
|
||||||
|
&mut self,
|
||||||
|
master_key: MasterPubkey,
|
||||||
|
self_signing_key: SelfSigningPubkey,
|
||||||
|
) -> Result<(), SignatureError> {
|
||||||
|
master_key.verify_subkey(&self_signing_key)?;
|
||||||
|
|
||||||
|
self.master_key = master_key;
|
||||||
|
self.self_signing_key = self_signing_key;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_device_signed(&self, device: &ReadOnlyDevice) -> Result<(), SignatureError> {
|
pub fn is_device_signed(&self, device: &ReadOnlyDevice) -> Result<(), SignatureError> {
|
||||||
self.self_signing_key.verify_device(device)
|
self.self_signing_key.verify_device(device)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct OwnUserIdentity {
|
pub struct OwnUserIdentity {
|
||||||
user_id: Arc<UserId>,
|
user_id: Arc<UserId>,
|
||||||
master_key: MasterPubkey,
|
master_key: MasterPubkey,
|
||||||
|
@ -196,6 +217,25 @@ impl OwnUserIdentity {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update(
|
||||||
|
&mut self,
|
||||||
|
master_key: MasterPubkey,
|
||||||
|
self_signing_key: SelfSigningPubkey,
|
||||||
|
user_signing_key: UserSigningPubkey,
|
||||||
|
) -> Result<(), SignatureError> {
|
||||||
|
master_key.verify_subkey(&self_signing_key)?;
|
||||||
|
master_key.verify_subkey(&user_signing_key)?;
|
||||||
|
|
||||||
|
self.self_signing_key = self_signing_key;
|
||||||
|
self.user_signing_key = user_signing_key;
|
||||||
|
|
||||||
|
self.master_key = master_key;
|
||||||
|
|
||||||
|
// FIXME reset the verification state if the master key changed.
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_identity_signed(&self, identity: &UserIdentity) -> Result<(), SignatureError> {
|
pub fn is_identity_signed(&self, identity: &UserIdentity) -> Result<(), SignatureError> {
|
||||||
self.user_signing_key
|
self.user_signing_key
|
||||||
.verify_master_key(&identity.master_key)
|
.verify_master_key(&identity.master_key)
|
||||||
|
|
Loading…
Reference in New Issue