crypto: Initial scaffolding for handling user identities in key queries.
parent
150862ec0c
commit
f96437a242
|
@ -60,6 +60,10 @@ use super::{
|
|||
OlmMessage, OutboundGroupSession,
|
||||
},
|
||||
store::{memorystore::MemoryStore, Result as StoreResult},
|
||||
user_identity::{
|
||||
MasterPubkey, OwnUserIdentity, SelfSigningPubkey, UserIdentities, UserIdentity,
|
||||
UserSigningPubkey,
|
||||
},
|
||||
verification::{Sas, VerificationMachine},
|
||||
CryptoStore,
|
||||
};
|
||||
|
@ -429,6 +433,9 @@ impl OlmMachine {
|
|||
let mut changed_devices = Vec::new();
|
||||
|
||||
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?;
|
||||
|
||||
for (device_id, device_keys) in device_map.iter() {
|
||||
|
@ -492,6 +499,63 @@ impl OlmMachine {
|
|||
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.
|
||||
///
|
||||
/// Returns a list of devices newly discovered devices and devices that
|
||||
|
@ -504,13 +568,14 @@ impl OlmMachine {
|
|||
pub async fn receive_keys_query_response(
|
||||
&self,
|
||||
response: &get_keys::Response,
|
||||
) -> OlmResult<Vec<ReadOnlyDevice>> {
|
||||
) -> OlmResult<(Vec<ReadOnlyDevice>, Vec<UserIdentities>)> {
|
||||
let changed_devices = self
|
||||
.handle_devices_from_key_query(&response.device_keys)
|
||||
.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.
|
||||
|
|
|
@ -25,6 +25,7 @@ use super::{Account, CryptoStore, InboundGroupSession, Result, Session};
|
|||
use crate::{
|
||||
device::ReadOnlyDevice,
|
||||
memory_stores::{DeviceStore, GroupSessionStore, ReadOnlyUserDevices, SessionStore},
|
||||
user_identity::UserIdentities,
|
||||
};
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MemoryStore {
|
||||
|
@ -131,6 +132,10 @@ impl CryptoStore for MemoryStore {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_user_identity(&self, _user_id: &UserId) -> Result<Option<UserIdentities>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -30,6 +30,7 @@ use super::{
|
|||
device::ReadOnlyDevice,
|
||||
memory_stores::ReadOnlyUserDevices,
|
||||
olm::{Account, InboundGroupSession, Session},
|
||||
user_identity::UserIdentities,
|
||||
};
|
||||
|
||||
pub mod memorystore;
|
||||
|
@ -197,4 +198,11 @@ pub trait CryptoStore: Debug {
|
|||
///
|
||||
/// * `user_id` - The user for which we should get all the devices.
|
||||
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::{
|
||||
device::{ReadOnlyDevice, TrustState},
|
||||
memory_stores::{DeviceStore, GroupSessionStore, ReadOnlyUserDevices, SessionStore},
|
||||
user_identity::UserIdentities,
|
||||
Account, IdentityKeys, InboundGroupSession, Session,
|
||||
};
|
||||
|
||||
|
@ -883,6 +884,10 @@ impl CryptoStore for SqliteStore {
|
|||
async fn get_user_devices(&self, user_id: &UserId) -> Result<ReadOnlyUserDevices> {
|
||||
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))]
|
||||
|
|
|
@ -77,12 +77,6 @@ impl<'a> CrossSigningSubKeys<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct UserIdentity {
|
||||
user_id: Arc<UserId>,
|
||||
master_key: MasterPubkey,
|
||||
self_signing_key: SelfSigningPubkey,
|
||||
}
|
||||
|
||||
impl MasterPubkey {
|
||||
fn verify_subkey<'a>(
|
||||
&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 {
|
||||
pub fn new(
|
||||
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> {
|
||||
self.self_signing_key.verify_device(device)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct OwnUserIdentity {
|
||||
user_id: Arc<UserId>,
|
||||
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> {
|
||||
self.user_signing_key
|
||||
.verify_master_key(&identity.master_key)
|
||||
|
|
Loading…
Reference in New Issue