crypto: Wrap inbound group sessions.

master
Damir Jelić 2020-03-25 11:32:40 +01:00
parent d4f0799e6c
commit ae4d90057a
4 changed files with 92 additions and 36 deletions

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
use cjson::Error as CjsonError; use cjson::Error as CjsonError;
use olm_rs::errors::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;
@ -36,7 +36,9 @@ pub enum OlmError {
#[error("the Encrypted message doesn't contain a ciphertext for our device")] #[error("the Encrypted message doesn't contain a ciphertext for our device")]
MissingCiphertext, MissingCiphertext,
#[error("can't finish Olm Session operation {0}")] #[error("can't finish Olm Session operation {0}")]
OlmSessionError(#[from] OlmSessionError), OlmSession(#[from] OlmSessionError),
#[error("can't finish Olm Session operation {0}")]
OlmGroupSession(#[from] OlmGroupSessionError),
#[error("error deserializing a string to json")] #[error("error deserializing a string to json")]
JsonError(#[from] SerdeError), JsonError(#[from] SerdeError),
#[error("the provided JSON value isn't an object")] #[error("the provided JSON value isn't an object")]

View File

@ -21,7 +21,7 @@ use std::sync::Arc;
use super::error::{OlmError, Result, SignatureError, VerificationResult}; use super::error::{OlmError, Result, SignatureError, VerificationResult};
use super::memory_stores::GroupSessionStore; use super::memory_stores::GroupSessionStore;
use super::olm::Account; use super::olm::{Account, InboundGroupSession};
#[cfg(feature = "sqlite-cryptostore")] #[cfg(feature = "sqlite-cryptostore")]
use super::store::sqlite::SqliteStore; use super::store::sqlite::SqliteStore;
use super::store::MemoryStore; use super::store::MemoryStore;
@ -31,9 +31,7 @@ use crate::api;
use api::r0::keys; use api::r0::keys;
use cjson; use cjson;
use olm_rs::{ use olm_rs::{session::OlmMessage, utility::OlmUtility};
inbound_group_session::OlmInboundGroupSession, session::OlmMessage, utility::OlmUtility,
};
use serde_json::{json, Value}; use serde_json::{json, Value};
use tokio::sync::Mutex; use tokio::sync::Mutex;
use tracing::{debug, info, instrument, trace, warn}; use tracing::{debug, info, instrument, trace, warn};
@ -499,7 +497,7 @@ impl OlmMachine {
.decrypt_olm_message(&event.sender.to_string(), &content.sender_key, message) .decrypt_olm_message(&event.sender.to_string(), &content.sender_key, message)
.await?; .await?;
debug!("Decrypted a to-device event {:?}", decrypted_event); debug!("Decrypted a to-device event {:?}", decrypted_event);
self.handle_decrypted_to_device_event(&content.sender_key, &decrypted_event); self.handle_decrypted_to_device_event(&content.sender_key, &decrypted_event)?;
Ok(decrypted_event) Ok(decrypted_event)
} else { } else {
@ -508,22 +506,35 @@ impl OlmMachine {
} }
} }
fn add_room_key(&mut self, sender_key: &str, event: &ToDeviceRoomKey) { fn add_room_key(&mut self, sender_key: &str, event: &ToDeviceRoomKey) -> Result<()> {
match event.content.algorithm { match event.content.algorithm {
Algorithm::MegolmV1AesSha2 => { Algorithm::MegolmV1AesSha2 => {
// TODO check for all the valid fields. // TODO check for all the valid fields.
let session = OlmInboundGroupSession::new(&event.content.session_key).unwrap(); let session = InboundGroupSession::new(
self.inbound_group_sessions sender_key,
.add(&event.sender.to_string(), sender_key, session); &event.content.room_id.to_string(),
&event.content.session_key,
)?;
self.inbound_group_sessions.add(session);
// TODO save the session in the store.
Ok(())
} }
_ => warn!( _ => {
warn!(
"Received room key with unsupported key algorithm {}", "Received room key with unsupported key algorithm {}",
event.content.algorithm event.content.algorithm
), );
Ok(())
}
} }
} }
fn add_forwarded_room_key(&self, event: &ToDeviceForwardedRoomKey) { fn add_forwarded_room_key(
&self,
sender_key: &str,
event: &ToDeviceForwardedRoomKey,
) -> Result<()> {
Ok(())
// TODO // TODO
} }
@ -531,18 +542,21 @@ impl OlmMachine {
&mut self, &mut self,
sender_key: &str, sender_key: &str,
event: &EventResult<ToDeviceEvent>, event: &EventResult<ToDeviceEvent>,
) { ) -> Result<()> {
let event = if let EventResult::Ok(e) = event { let event = if let EventResult::Ok(e) = event {
e e
} else { } else {
warn!("Decrypted to-device event failed to be parsed correctly"); warn!("Decrypted to-device event failed to be parsed correctly");
return; return Ok(());
}; };
match event { match event {
ToDeviceEvent::RoomKey(e) => self.add_room_key(sender_key, e), ToDeviceEvent::RoomKey(e) => self.add_room_key(sender_key, e),
ToDeviceEvent::ForwardedRoomKey(e) => self.add_forwarded_room_key(e), ToDeviceEvent::ForwardedRoomKey(e) => self.add_forwarded_room_key(sender_key, e),
_ => warn!("Received a unexpected encrypted to-device event"), _ => {
warn!("Received a unexpected encrypted to-device event");
Ok(())
}
} }
} }
@ -555,6 +569,13 @@ impl OlmMachine {
} }
#[instrument(skip(response))] #[instrument(skip(response))]
/// Handle a sync response and update the internal state of the Olm machine.
///
/// This will decrypt to-device events but will not touch room messages.
///
/// # Arguments
///
/// * `response` - The sync latest sync response.
pub async fn receive_sync_response(&mut self, response: &mut SyncResponse) { pub async fn receive_sync_response(&mut self, response: &mut SyncResponse) {
let one_time_key_count = response let one_time_key_count = response
.device_one_time_keys_count .device_one_time_keys_count

View File

@ -12,12 +12,12 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use olm_rs::inbound_group_session::OlmInboundGroupSession; use super::olm::InboundGroupSession;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Debug)] #[derive(Debug)]
pub struct GroupSessionStore { pub struct GroupSessionStore {
entries: HashMap<String, HashMap<String, HashMap<String, OlmInboundGroupSession>>>, entries: HashMap<String, HashMap<String, HashMap<String, InboundGroupSession>>>,
} }
impl GroupSessionStore { impl GroupSessionStore {
@ -27,23 +27,19 @@ impl GroupSessionStore {
} }
} }
pub fn add( pub fn add(&mut self, session: InboundGroupSession) -> bool {
&mut self, if !self.entries.contains_key(&session.room_id) {
room_id: &str, self.entries
sender_key: &str, .insert(session.room_id.to_owned(), HashMap::new());
session: OlmInboundGroupSession,
) -> bool {
if !self.entries.contains_key(room_id) {
self.entries.insert(room_id.to_owned(), HashMap::new());
} }
let mut room_map = self.entries.get_mut(room_id).unwrap(); let mut room_map = self.entries.get_mut(&session.room_id).unwrap();
if !room_map.contains_key(sender_key) { if !room_map.contains_key(&session.sender_key) {
room_map.insert(sender_key.to_owned(), HashMap::new()); room_map.insert(session.sender_key.to_owned(), HashMap::new());
} }
let mut sender_map = room_map.get_mut(sender_key).unwrap(); let mut sender_map = room_map.get_mut(&session.sender_key).unwrap();
let ret = sender_map.insert(session.session_id(), session); let ret = sender_map.insert(session.session_id(), session);
ret.is_some() ret.is_some()
@ -54,7 +50,7 @@ impl GroupSessionStore {
room_id: &str, room_id: &str,
sender_key: &str, sender_key: &str,
session_id: &str, session_id: &str,
) -> Option<&OlmInboundGroupSession> { ) -> Option<&InboundGroupSession> {
self.entries self.entries
.get(room_id) .get(room_id)
.and_then(|m| m.get(sender_key).and_then(|m| m.get(session_id))) .and_then(|m| m.get(sender_key).and_then(|m| m.get(session_id)))

View File

@ -16,7 +16,8 @@ use std::fmt;
use std::time::Instant; use std::time::Instant;
use olm_rs::account::{IdentityKeys, OlmAccount, OneTimeKeys}; use olm_rs::account::{IdentityKeys, OlmAccount, OneTimeKeys};
use olm_rs::errors::{OlmAccountError, OlmSessionError}; use olm_rs::errors::{OlmAccountError, OlmGroupSessionError, OlmSessionError};
use olm_rs::inbound_group_session::OlmInboundGroupSession;
use olm_rs::session::{OlmMessage, OlmSession, PreKeyMessage}; use olm_rs::session::{OlmMessage, OlmSession, PreKeyMessage};
use olm_rs::PicklingMode; use olm_rs::PicklingMode;
@ -42,6 +43,7 @@ impl fmt::Debug for Account {
/// get Sync for it /// get Sync for it
unsafe impl Send for Account {} unsafe impl Send for Account {}
unsafe impl Send for Session {} unsafe impl Send for Session {}
unsafe impl Send for InboundGroupSession {}
impl Account { impl Account {
/// Create a new account. /// Create a new account.
@ -149,6 +151,41 @@ impl Session {
} }
} }
#[derive(Debug)]
pub struct InboundGroupSession {
inner: OlmInboundGroupSession,
pub(crate) sender_key: String,
pub(crate) room_id: String,
forwarding_chains: Option<Vec<String>>,
}
impl InboundGroupSession {
pub fn new(
sender_key: &str,
room_id: &str,
session_key: &str,
) -> Result<Self, OlmGroupSessionError> {
Ok(InboundGroupSession {
inner: OlmInboundGroupSession::new(session_key)?,
sender_key: sender_key.to_owned(),
room_id: room_id.to_owned(),
forwarding_chains: None,
})
}
pub fn session_id(&self) -> String {
self.inner.session_id()
}
pub fn first_known_index(&self) -> u32 {
self.inner.first_known_index()
}
pub fn decrypt(&self, mut message: String) -> Result<(String, u32), OlmGroupSessionError> {
self.inner.decrypt(message)
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::crypto::olm::Account; use crate::crypto::olm::Account;