crypto: Move the outbound session creation logic into the account.

master
Damir Jelić 2020-07-15 15:39:56 +02:00
parent 6cced25ae1
commit de1988265d
4 changed files with 108 additions and 63 deletions

View File

@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
use cjson::Error as CjsonError; use cjson::Error as CjsonError;
use matrix_sdk_common::identifiers::{DeviceId, UserId};
use olm_rs::errors::{OlmGroupSessionError, OlmSessionError}; use olm_rs::errors::{OlmGroupSessionError, OlmSessionError};
use serde_json::Error as SerdeError; use serde_json::Error as SerdeError;
use thiserror::Error; use thiserror::Error;
@ -121,6 +122,29 @@ pub enum SignatureError {
VerificationError, VerificationError,
} }
#[derive(Error, Debug)]
pub(crate) enum SessionCreationError {
#[error(
"Failed to create a new Olm session for {0} {1}, the requested \
one-time key isn't a signed curve key"
)]
OneTimeKeyNotSigned(UserId, DeviceId),
#[error(
"Tried to create a new Olm session for {0} {1}, but the signed \
one-time key is missing"
)]
OneTimeKeyMissing(UserId, DeviceId),
#[error("Failed to verify the one-time key signatures for {0} {1}: {2:?}")]
InvalidSignature(UserId, DeviceId, SignatureError),
#[error(
"Tried to create an Olm session for {0} {1}, but the device is missing \
a curve25519 key"
)]
DeviceMissingCurveKey(UserId, DeviceId),
#[error("Error creating new Olm session for {0} {1}: {2:?}")]
OlmError(UserId, DeviceId, OlmSessionError),
}
impl From<CjsonError> for SignatureError { impl From<CjsonError> for SignatureError {
fn from(error: CjsonError) -> Self { fn from(error: CjsonError) -> Self {
Self::CanonicalJsonError(error) Self::CanonicalJsonError(error)

View File

@ -306,76 +306,35 @@ impl OlmMachine {
for (user_id, user_devices) in &response.one_time_keys { for (user_id, user_devices) in &response.one_time_keys {
for (device_id, key_map) in user_devices { for (device_id, key_map) in user_devices {
let device = if let Some(d) = self let device: Device = match self.store.get_device(&user_id, device_id).await {
.store Ok(d) => {
.get_device(&user_id, device_id) if let Some(d) = d {
.await d
.expect("Can't get devices") } else {
{
d
} else {
warn!(
"Tried to create an Olm session for {} {}, but the device is unknown",
user_id, device_id
);
continue;
};
// TODO move this logic into the account, pass the device to the
// account when creating an outbound session.
let one_time_key = if let Some(k) = key_map.values().next() {
match k {
OneTimeKey::SignedKey(k) => k,
OneTimeKey::Key(_) => {
warn!( warn!(
"Tried to create an Olm session for {} {}, but "Tried to create an Olm session for {} {}, but \
the requested key isn't a signed curve key", the device is unknown",
user_id, device_id user_id, device_id
); );
continue; continue;
} }
} }
} else { Err(e) => {
warn!( warn!(
"Tried to create an Olm session for {} {}, but the "Tried to create an Olm session for {} {}, but \
signed one-time key is missing", can't fetch the device from the store {:?}",
user_id, device_id user_id, device_id, e
); );
continue; continue;
}; }
if let Err(e) = device.verify_one_time_key(&one_time_key) {
warn!(
"Failed to verify the one-time key signatures for {} {}: {:?}",
user_id, device_id, e
);
continue;
}
let curve_key = if let Some(k) = device.get_key(KeyAlgorithm::Curve25519) {
k
} else {
warn!(
"Tried to create an Olm session for {} {}, but the
device is missing the curve key",
user_id, device_id
);
continue;
}; };
info!("Creating outbound Session for {} {}", user_id, device_id); info!("Creating outbound Session for {} {}", user_id, device_id);
let session = match self let session = match self.account.create_outbound_session(device, &key_map).await {
.account
.create_outbound_session(curve_key, &one_time_key)
.await
{
Ok(s) => s, Ok(s) => s,
Err(e) => { Err(e) => {
warn!( warn!("{:?}", e);
"Error creating new Olm session for {} {}: {}",
user_id, device_id, e
);
continue; continue;
} }
}; };

View File

@ -33,7 +33,8 @@ use olm_rs::outbound_group_session::OlmOutboundGroupSession;
use olm_rs::session::OlmSession; use olm_rs::session::OlmSession;
use olm_rs::PicklingMode; use olm_rs::PicklingMode;
use crate::error::{EventError, MegolmResult}; use crate::device::Device;
use crate::error::{EventError, MegolmResult, SessionCreationError};
pub use olm_rs::{ pub use olm_rs::{
session::{OlmMessage, PreKeyMessage}, session::{OlmMessage, PreKeyMessage},
utility::OlmUtility, utility::OlmUtility,
@ -386,7 +387,7 @@ impl Account {
/// ///
/// * `their_one_time_key` - A signed one-time key that the other account /// * `their_one_time_key` - A signed one-time key that the other account
/// created and shared with us. /// created and shared with us.
pub(crate) async fn create_outbound_session( pub(crate) async fn create_outbound_session_helper(
&self, &self,
their_identity_key: &str, their_identity_key: &str,
their_one_time_key: &SignedKey, their_one_time_key: &SignedKey,
@ -409,6 +410,67 @@ impl Account {
}) })
} }
/// Create a new session with another account given a one-time key and a
/// device.
///
/// Returns the newly created session or a `OlmSessionError` if creating a
/// session failed.
///
/// # Arguments
/// * `device` - The other account's device.
///
/// * `key_map` - A map from the algorithm and device id to the one-time
/// key that the other account created and shared with us.
pub(crate) async fn create_outbound_session(
&self,
device: Device,
key_map: &BTreeMap<AlgorithmAndDeviceId, OneTimeKey>,
) -> Result<Session, SessionCreationError> {
let one_time_key =
key_map
.values()
.next()
.ok_or(SessionCreationError::OneTimeKeyMissing(
device.user_id().to_owned(),
device.device_id().to_owned(),
))?;
let one_time_key = match one_time_key {
OneTimeKey::SignedKey(k) => k,
OneTimeKey::Key(_) => {
return Err(SessionCreationError::OneTimeKeyNotSigned(
device.user_id().to_owned(),
device.device_id().to_owned(),
));
}
};
device.verify_one_time_key(&one_time_key).map_err(|e| {
SessionCreationError::InvalidSignature(
device.user_id().to_owned(),
device.device_id().to_owned(),
e,
)
})?;
let curve_key = device.get_key(KeyAlgorithm::Curve25519).ok_or(
SessionCreationError::DeviceMissingCurveKey(
device.user_id().to_owned(),
device.device_id().to_owned(),
),
)?;
self.create_outbound_session_helper(curve_key, &one_time_key)
.await
.map_err(|e| {
SessionCreationError::OlmError(
device.user_id().to_owned(),
device.device_id().to_owned(),
e,
)
})
}
/// Create a new session with another account given a pre-key Olm message. /// Create a new session with another account given a pre-key Olm message.
/// ///
/// Returns the newly created session or a `OlmSessionError` if creating a /// Returns the newly created session or a `OlmSessionError` if creating a
@ -1014,7 +1076,7 @@ pub(crate) mod test {
}; };
let sender_key = bob.identity_keys().curve25519().to_owned(); let sender_key = bob.identity_keys().curve25519().to_owned();
let session = alice let session = alice
.create_outbound_session(&sender_key, &one_time_key) .create_outbound_session_helper(&sender_key, &one_time_key)
.await .await
.unwrap(); .unwrap();
@ -1092,7 +1154,7 @@ pub(crate) mod test {
}; };
let mut bob_session = bob let mut bob_session = bob
.create_outbound_session(alice_keys.curve25519(), &one_time_key) .create_outbound_session_helper(alice_keys.curve25519(), &one_time_key)
.await .await
.unwrap(); .unwrap();

View File

@ -876,7 +876,7 @@ mod test {
}; };
let sender_key = bob.identity_keys().curve25519().to_owned(); let sender_key = bob.identity_keys().curve25519().to_owned();
let session = alice let session = alice
.create_outbound_session(&sender_key, &one_time_key) .create_outbound_session_helper(&sender_key, &one_time_key)
.await .await
.unwrap(); .unwrap();