crypto: Wrap inbound group sessions.
parent
d4f0799e6c
commit
ae4d90057a
|
@ -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")]
|
||||||
|
|
|
@ -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!(
|
||||||
|
"Received room key with unsupported key algorithm {}",
|
||||||
|
event.content.algorithm
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => warn!(
|
|
||||||
"Received room key with unsupported key algorithm {}",
|
|
||||||
event.content.algorithm
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -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)))
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue