crypto: Respect the encryption settings of a room when creating sessions.
This commit is contained in:
parent
f3e03c66a5
commit
344631b4ee
9 changed files with 171 additions and 30 deletions
|
@ -1305,7 +1305,12 @@ impl BaseClient {
|
|||
let joined_members = room.joined_members.keys();
|
||||
let invited_members = room.joined_members.keys();
|
||||
let members: Vec<&UserId> = joined_members.chain(invited_members).collect();
|
||||
Ok(o.share_group_session(room_id, members.into_iter()).await?)
|
||||
Ok(o.share_group_session(
|
||||
room_id,
|
||||
members.into_iter(),
|
||||
room.encrypted.clone().unwrap_or_default(),
|
||||
)
|
||||
.await?)
|
||||
}
|
||||
None => panic!("Olm machine wasn't started"),
|
||||
}
|
||||
|
|
|
@ -13,13 +13,20 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#[cfg(feature = "messages")]
|
||||
use std::ops::DerefMut;
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap, HashSet},
|
||||
convert::TryFrom,
|
||||
};
|
||||
|
||||
#[cfg(feature = "messages")]
|
||||
use std::ops::DerefMut;
|
||||
|
||||
#[cfg(feature = "encryption")]
|
||||
use std::time::Duration;
|
||||
|
||||
#[cfg(feature = "encryption")]
|
||||
use matrix_sdk_crypto::EncryptionSettings;
|
||||
|
||||
#[cfg(feature = "messages")]
|
||||
use matrix_sdk_common::events::{
|
||||
room::redaction::SyncRedactionEvent, AnyPossiblyRedactedSyncMessageEvent, AnySyncMessageEvent,
|
||||
|
@ -111,6 +118,16 @@ pub struct EncryptionInfo {
|
|||
rotation_period_messages: u64,
|
||||
}
|
||||
|
||||
impl Default for EncryptionInfo {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
algorithm: Algorithm::MegolmV1AesSha2,
|
||||
rotation_period_ms: 604_800_000,
|
||||
rotation_period_messages: 100,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EncryptionInfo {
|
||||
/// The encryption algorithm that should be used to encrypt messages in the
|
||||
/// room.
|
||||
|
@ -143,6 +160,17 @@ impl From<&SyncStateEvent<EncryptionEventContent>> for EncryptionInfo {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "encryption")]
|
||||
impl Into<EncryptionSettings> for EncryptionInfo {
|
||||
fn into(self) -> EncryptionSettings {
|
||||
EncryptionSettings {
|
||||
algorithm: self.algorithm,
|
||||
rotation_period: Duration::from_millis(self.rotation_period_messages),
|
||||
rotation_period_msgs: self.rotation_period_messages,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Tombstone {
|
||||
/// A server-defined message.
|
||||
|
|
|
@ -39,7 +39,9 @@ pub use device::{Device, TrustState};
|
|||
pub use error::{MegolmError, OlmError};
|
||||
pub use machine::{OlmMachine, OneTimeKeys};
|
||||
pub use memory_stores::{DeviceStore, GroupSessionStore, SessionStore, UserDevices};
|
||||
pub use olm::{Account, IdentityKeys, InboundGroupSession, OutboundGroupSession, Session};
|
||||
pub use olm::{
|
||||
Account, EncryptionSettings, IdentityKeys, InboundGroupSession, OutboundGroupSession, Session,
|
||||
};
|
||||
#[cfg(feature = "sqlite_cryptostore")]
|
||||
pub use store::sqlite::SqliteStore;
|
||||
pub use store::{CryptoStore, CryptoStoreError};
|
||||
|
|
|
@ -53,8 +53,8 @@ use super::{
|
|||
device::Device,
|
||||
error::{EventError, MegolmError, MegolmResult, OlmError, OlmResult},
|
||||
olm::{
|
||||
Account, GroupSessionKey, IdentityKeys, InboundGroupSession, OlmMessage,
|
||||
OutboundGroupSession,
|
||||
Account, EncryptionSettings, GroupSessionKey, IdentityKeys, InboundGroupSession,
|
||||
OlmMessage, OutboundGroupSession,
|
||||
},
|
||||
store::{memorystore::MemoryStore, Result as StoreResult},
|
||||
verification::{Sas, VerificationMachine},
|
||||
|
@ -824,8 +824,16 @@ impl OlmMachine {
|
|||
///
|
||||
/// This also creates a matching inbound group session and saves that one in
|
||||
/// the store.
|
||||
async fn create_outbound_group_session(&self, room_id: &RoomId) -> OlmResult<()> {
|
||||
let (outbound, inbound) = self.account.create_group_session_pair(room_id).await;
|
||||
async fn create_outbound_group_session(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
settings: EncryptionSettings,
|
||||
) -> OlmResult<()> {
|
||||
let (outbound, inbound) = self
|
||||
.account
|
||||
.create_group_session_pair(room_id, settings)
|
||||
.await
|
||||
.map_err(|_| EventError::UnsupportedAlgorithm)?;
|
||||
|
||||
let _ = self.store.save_inbound_group_session(inbound).await?;
|
||||
|
||||
|
@ -835,6 +843,15 @@ impl OlmMachine {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
async fn create_outnbound_group_session_with_defaults(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
) -> OlmResult<()> {
|
||||
self.create_outbound_group_session(room_id, EncryptionSettings::default())
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get an outbound group session for a room, if one exists.
|
||||
///
|
||||
/// # Arguments
|
||||
|
@ -961,7 +978,6 @@ impl OlmMachine {
|
|||
self.outbound_group_sessions.remove(room_id).is_some()
|
||||
}
|
||||
|
||||
// TODO accept an algorithm here
|
||||
/// Get to-device requests to share a group session with users in a room.
|
||||
///
|
||||
/// # Arguments
|
||||
|
@ -970,15 +986,18 @@ impl OlmMachine {
|
|||
/// used.
|
||||
///
|
||||
/// `users` - The list of users that should receive the group session.
|
||||
pub async fn share_group_session<'a, I>(
|
||||
pub async fn share_group_session<'a, I, S>(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
users: I,
|
||||
encryption_settings: S,
|
||||
) -> OlmResult<Vec<OwnedToDeviceRequest>>
|
||||
where
|
||||
I: IntoIterator<Item = &'a UserId>,
|
||||
S: Into<EncryptionSettings> + Sized,
|
||||
{
|
||||
self.create_outbound_group_session(room_id).await?;
|
||||
self.create_outbound_group_session(room_id, encryption_settings.into())
|
||||
.await?;
|
||||
let session = self.outbound_group_sessions.get(room_id).unwrap();
|
||||
|
||||
if session.shared() {
|
||||
|
@ -1373,7 +1392,7 @@ mod test {
|
|||
|
||||
use crate::{
|
||||
machine::{OlmMachine, OneTimeKeys},
|
||||
verify_json, Device,
|
||||
verify_json, Device, EncryptionSettings,
|
||||
};
|
||||
|
||||
use matrix_sdk_common::{
|
||||
|
@ -1618,7 +1637,7 @@ mod test {
|
|||
let room_id = room_id!("!test:example.org");
|
||||
|
||||
machine
|
||||
.create_outbound_group_session(&room_id)
|
||||
.create_outnbound_group_session_with_defaults(&room_id)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(machine.outbound_group_sessions.get(&room_id).is_some());
|
||||
|
@ -1825,7 +1844,11 @@ mod test {
|
|||
let room_id = room_id!("!test:example.org");
|
||||
|
||||
let to_device_requests = alice
|
||||
.share_group_session(&room_id, [bob.user_id.clone()].iter())
|
||||
.share_group_session(
|
||||
&room_id,
|
||||
[bob.user_id.clone()].iter(),
|
||||
EncryptionSettings::default(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
@ -1868,7 +1891,11 @@ mod test {
|
|||
let room_id = room_id!("!test:example.org");
|
||||
|
||||
let to_device_requests = alice
|
||||
.share_group_session(&room_id, [bob.user_id().clone()].iter())
|
||||
.share_group_session(
|
||||
&room_id,
|
||||
[bob.user_id().clone()].iter(),
|
||||
EncryptionSettings::default(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -258,7 +258,10 @@ mod test {
|
|||
let (account, _) = get_account_and_session().await;
|
||||
let room_id = room_id!("!test:localhost");
|
||||
|
||||
let (outbound, _) = account.create_group_session_pair(&room_id).await;
|
||||
let (outbound, _) = account
|
||||
.create_group_session_pair(&room_id, Default::default())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(0, outbound.message_index().await);
|
||||
assert!(!outbound.shared());
|
||||
|
|
|
@ -42,7 +42,7 @@ pub use olm_rs::{
|
|||
utility::OlmUtility,
|
||||
};
|
||||
|
||||
use super::{InboundGroupSession, OutboundGroupSession, Session};
|
||||
use super::{EncryptionSettings, InboundGroupSession, OutboundGroupSession, Session};
|
||||
use crate::{device::Device, error::SessionCreationError};
|
||||
|
||||
/// Account holding identity keys for which sessions can be created.
|
||||
|
@ -537,12 +537,24 @@ impl Account {
|
|||
/// # Arguments
|
||||
///
|
||||
/// * `room_id` - The ID of the room where the group session will be used.
|
||||
///
|
||||
/// * `settings` - Settings determining the algorithm and rotation period of
|
||||
/// the outbound group session.
|
||||
pub(crate) async fn create_group_session_pair(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
) -> (OutboundGroupSession, InboundGroupSession) {
|
||||
let outbound =
|
||||
OutboundGroupSession::new(self.device_id.clone(), self.identity_keys.clone(), room_id);
|
||||
settings: EncryptionSettings,
|
||||
) -> Result<(OutboundGroupSession, InboundGroupSession), ()> {
|
||||
if settings.algorithm != Algorithm::MegolmV1AesSha2 {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let outbound = OutboundGroupSession::new(
|
||||
self.device_id.clone(),
|
||||
self.identity_keys.clone(),
|
||||
room_id,
|
||||
settings,
|
||||
);
|
||||
let identity_keys = self.identity_keys();
|
||||
|
||||
let sender_key = identity_keys.curve25519();
|
||||
|
@ -556,7 +568,7 @@ impl Account {
|
|||
)
|
||||
.expect("Can't create inbound group session from a newly created outbound group session");
|
||||
|
||||
(outbound, inbound)
|
||||
Ok((outbound, inbound))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,14 +16,18 @@ use std::{
|
|||
convert::TryInto,
|
||||
fmt,
|
||||
sync::{
|
||||
atomic::{AtomicBool, AtomicUsize, Ordering},
|
||||
atomic::{AtomicBool, AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use matrix_sdk_common::{
|
||||
events::{
|
||||
room::{encrypted::EncryptedEventContent, message::MessageEventContent},
|
||||
room::{
|
||||
encrypted::EncryptedEventContent, encryption::EncryptionEventContent,
|
||||
message::MessageEventContent,
|
||||
},
|
||||
Algorithm, AnySyncRoomEvent, EventType, SyncMessageEvent,
|
||||
},
|
||||
identifiers::{DeviceId, RoomId},
|
||||
|
@ -47,6 +51,49 @@ pub use olm_rs::{
|
|||
|
||||
use crate::error::{EventError, MegolmResult};
|
||||
|
||||
const ROTATION_PERIOD: Duration = Duration::from_millis(604800000);
|
||||
const ROTATION_MESSAGES: u64 = 100;
|
||||
|
||||
/// Settings for an encrypted room.
|
||||
///
|
||||
/// This determines the algorithm and rotation periods of a group session.
|
||||
#[derive(Debug)]
|
||||
pub struct EncryptionSettings {
|
||||
/// The encryption algorithm that should be used in the room.
|
||||
pub algorithm: Algorithm,
|
||||
/// How long the session should be used before changing it.
|
||||
pub rotation_period: Duration,
|
||||
/// How many messages should be sent before changing the session.
|
||||
pub rotation_period_msgs: u64,
|
||||
}
|
||||
|
||||
impl Default for EncryptionSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
algorithm: Algorithm::MegolmV1AesSha2,
|
||||
rotation_period: ROTATION_PERIOD,
|
||||
rotation_period_msgs: ROTATION_MESSAGES,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&EncryptionEventContent> for EncryptionSettings {
|
||||
fn from(content: &EncryptionEventContent) -> Self {
|
||||
let rotation_period: Duration = content
|
||||
.rotation_period_ms
|
||||
.map_or(ROTATION_PERIOD, |r| Duration::from_millis(r.into()));
|
||||
let rotation_period_msgs: u64 = content
|
||||
.rotation_period_msgs
|
||||
.map_or(ROTATION_MESSAGES, Into::into);
|
||||
|
||||
Self {
|
||||
algorithm: content.algorithm.clone(),
|
||||
rotation_period,
|
||||
rotation_period_msgs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The private session key of a group session.
|
||||
/// Can be used to create a new inbound group session.
|
||||
#[derive(Clone, Debug, Serialize, Zeroize)]
|
||||
|
@ -250,8 +297,9 @@ pub struct OutboundGroupSession {
|
|||
session_id: Arc<String>,
|
||||
room_id: Arc<RoomId>,
|
||||
creation_time: Arc<Instant>,
|
||||
message_count: Arc<AtomicUsize>,
|
||||
message_count: Arc<AtomicU64>,
|
||||
shared: Arc<AtomicBool>,
|
||||
settings: Arc<EncryptionSettings>,
|
||||
}
|
||||
|
||||
impl OutboundGroupSession {
|
||||
|
@ -267,10 +315,14 @@ impl OutboundGroupSession {
|
|||
/// session.
|
||||
///
|
||||
/// * `room_id` - The id of the room that the session is used in.
|
||||
///
|
||||
/// * `settings` - Settings determining the algorithm and rotation period of
|
||||
/// the outbound group session.
|
||||
pub fn new(
|
||||
device_id: Arc<Box<DeviceId>>,
|
||||
identity_keys: Arc<IdentityKeys>,
|
||||
room_id: &RoomId,
|
||||
settings: EncryptionSettings,
|
||||
) -> Self {
|
||||
let session = OlmOutboundGroupSession::new();
|
||||
let session_id = session.session_id();
|
||||
|
@ -282,8 +334,9 @@ impl OutboundGroupSession {
|
|||
account_identity_keys: identity_keys,
|
||||
session_id: Arc::new(session_id),
|
||||
creation_time: Arc::new(Instant::now()),
|
||||
message_count: Arc::new(AtomicUsize::new(0)),
|
||||
message_count: Arc::new(AtomicU64::new(0)),
|
||||
shared: Arc::new(AtomicBool::new(false)),
|
||||
settings: Arc::new(settings),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -296,6 +349,7 @@ impl OutboundGroupSession {
|
|||
/// * `plaintext` - The plaintext that should be encrypted.
|
||||
pub(crate) async fn encrypt_helper(&self, plaintext: String) -> String {
|
||||
let session = self.inner.lock().await;
|
||||
self.message_count.fetch_add(1, Ordering::SeqCst);
|
||||
session.encrypt(plaintext)
|
||||
}
|
||||
|
||||
|
@ -349,8 +403,10 @@ impl OutboundGroupSession {
|
|||
/// A session will expire after some time or if enough messages have been
|
||||
/// encrypted using it.
|
||||
pub fn expired(&self) -> bool {
|
||||
// TODO implement this.
|
||||
false
|
||||
let count = self.message_count.load(Ordering::SeqCst);
|
||||
|
||||
count >= self.settings.rotation_period_msgs
|
||||
|| self.creation_time.elapsed() >= self.settings.rotation_period
|
||||
}
|
||||
|
||||
/// Mark the session as shared.
|
||||
|
|
|
@ -17,7 +17,9 @@ mod group_sessions;
|
|||
mod session;
|
||||
|
||||
pub use account::{Account, IdentityKeys};
|
||||
pub use group_sessions::{GroupSessionKey, InboundGroupSession, OutboundGroupSession};
|
||||
pub use group_sessions::{
|
||||
EncryptionSettings, GroupSessionKey, InboundGroupSession, OutboundGroupSession,
|
||||
};
|
||||
pub use session::{OlmMessage, Session};
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -179,7 +181,10 @@ pub(crate) mod test {
|
|||
let alice = Account::new(&alice_id(), &alice_device_id());
|
||||
let room_id = room_id!("!test:localhost");
|
||||
|
||||
let (outbound, _) = alice.create_group_session_pair(&room_id).await;
|
||||
let (outbound, _) = alice
|
||||
.create_group_session_pair(&room_id, Default::default())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(0, outbound.message_index().await);
|
||||
assert!(!outbound.shared());
|
||||
|
|
|
@ -165,7 +165,10 @@ mod test {
|
|||
let (account, _) = get_account_and_session().await;
|
||||
let room_id = room_id!("!test:localhost");
|
||||
|
||||
let (outbound, _) = account.create_group_session_pair(&room_id).await;
|
||||
let (outbound, _) = account
|
||||
.create_group_session_pair(&room_id, Default::default())
|
||||
.await
|
||||
.unwrap();
|
||||
let inbound = InboundGroupSession::new(
|
||||
"test_key",
|
||||
"test_key",
|
||||
|
|
Loading…
Reference in a new issue