Skip to content

Commit

Permalink
crypto: Fetch immediately-available sender data when we receive a roo…
Browse files Browse the repository at this point in the history
…m key
  • Loading branch information
andybalaam committed Jun 20, 2024
1 parent 03dc672 commit d53fe25
Show file tree
Hide file tree
Showing 11 changed files with 418 additions and 46 deletions.
3 changes: 2 additions & 1 deletion bindings/matrix-sdk-crypto-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub use logger::{set_logger, Logger};
pub use machine::{KeyRequestPair, OlmMachine, SignatureVerification};
use matrix_sdk_common::deserialized_responses::ShieldState as RustShieldState;
use matrix_sdk_crypto::{
olm::{IdentityKeys, InboundGroupSession, Session},
olm::{IdentityKeys, InboundGroupSession, SenderData, Session},
store::{Changes, CryptoStore, PendingChanges, RoomSettings as RustRoomSettings},
types::{EventEncryptionAlgorithm as RustEventEncryptionAlgorithm, SigningKey},
EncryptionSettings as RustEncryptionSettings,
Expand Down Expand Up @@ -471,6 +471,7 @@ fn collect_sessions(
Ok((algorithm, key))
})
.collect::<anyhow::Result<_>>()?,
sender_data: SenderData::new(), // TODO: what should happen here?
room_id: RoomId::parse(session.room_id)?,
imported: session.imported,
backed_up: session.backed_up,
Expand Down
11 changes: 9 additions & 2 deletions crates/matrix-sdk-crypto/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ use crate::{
identities::{user::UserIdentities, Device, IdentityManager, UserDevices},
olm::{
Account, CrossSigningStatus, EncryptionSettings, IdentityKeys, InboundGroupSession,
OlmDecryptionInfo, PrivateCrossSigningIdentity, SessionType, StaticAccountData,
OlmDecryptionInfo, PrivateCrossSigningIdentity, SenderDataFinder, SessionType,
StaticAccountData,
},
requests::{IncomingResponse, OutgoingRequest, UploadSigningKeysRequest},
session_manager::{GroupSessionManager, SessionManager},
Expand Down Expand Up @@ -806,11 +807,14 @@ impl OlmMachine {
event: &DecryptedRoomKeyEvent,
content: &MegolmV1AesSha2Content,
) -> OlmResult<Option<InboundGroupSession>> {
let sender_data = SenderDataFinder::find(self, sender_key, event, content).await?;

let session = InboundGroupSession::new(
sender_key,
event.keys.ed25519,
&content.room_id,
&content.session_key,
sender_data,
event.content.algorithm(),
None,
);
Expand Down Expand Up @@ -2263,7 +2267,8 @@ pub(crate) mod tests {
error::{EventError, SetRoomSettingsError},
machine::{EncryptionSyncChanges, OlmMachine},
olm::{
BackedUpRoomKey, ExportedRoomKey, InboundGroupSession, OutboundGroupSession, VerifyJson,
BackedUpRoomKey, ExportedRoomKey, InboundGroupSession, OutboundGroupSession,
SenderData, VerifyJson,
},
store::{BackupDecryptionKey, Changes, CryptoStore, MemoryStore, RoomSettings},
types::{
Expand Down Expand Up @@ -3556,6 +3561,7 @@ pub(crate) mod tests {
Ed25519PublicKey::from_base64("loz5i40dP+azDtWvsD0L/xpnCjNkmrcvtXVXzCHX8Vw").unwrap(),
fake_room_id,
&olm,
SenderData::new(),
EventEncryptionAlgorithm::MegolmV1AesSha2,
None,
)
Expand All @@ -3573,6 +3579,7 @@ pub(crate) mod tests {
Ed25519PublicKey::from_base64("48f3WQAMGwYLBg5M5qUhqnEVA8yeibjZpPsShoWMFT8").unwrap(),
fake_room_id,
&olm,
SenderData::new(),
EventEncryptionAlgorithm::MegolmV1AesSha2,
None,
)
Expand Down
2 changes: 2 additions & 0 deletions crates/matrix-sdk-crypto/src/olm/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ use crate::{
dehydrated_devices::DehydrationError,
error::{EventError, OlmResult, SessionCreationError},
identities::ReadOnlyDevice,
olm::SenderData,
requests::UploadSigningKeysRequest,
store::{Changes, Store},
types::{
Expand Down Expand Up @@ -220,6 +221,7 @@ impl StaticAccountData {
signing_key,
room_id,
&outbound.session_key().await,
SenderData::new(), // TODO: provide sender data about ourself
algorithm,
Some(visibility),
)?;
Expand Down
47 changes: 20 additions & 27 deletions crates/matrix-sdk-crypto/src/olm/group_sessions/inbound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ use vodozemac::{
};

use super::{
inbound_group_session_sender_data::InboundGroupSessionSenderData, BackedUpRoomKey,
ExportedRoomKey, OutboundGroupSession, SessionCreationError, SessionKey,
BackedUpRoomKey, ExportedRoomKey, OutboundGroupSession, SenderData, SessionCreationError,
SessionKey,
};
use crate::{
error::{EventError, MegolmResult},
Expand Down Expand Up @@ -129,7 +129,7 @@ pub struct InboundGroupSession {
/// the session, or, if we can use that device information to find the
/// sender's cross-signing identity, holds the user ID and cross-signing
/// key.
pub(crate) sender_data: InboundGroupSessionSenderData,
pub(crate) sender_data: SenderData,

/// The Room this GroupSession belongs to
pub room_id: OwnedRoomId,
Expand Down Expand Up @@ -173,11 +173,15 @@ impl InboundGroupSession {
///
/// * `session_key` - The private session key that is used to decrypt
/// messages.
///
/// * `sender_data` - Information about the sender of the to-device
/// message that established this session.
pub fn new(
sender_key: Curve25519PublicKey,
signing_key: Ed25519PublicKey,
room_id: &RoomId,
session_key: &SessionKey,
sender_data: SenderData,
encryption_algorithm: EventEncryptionAlgorithm,
history_visibility: Option<HistoryVisibility>,
) -> Result<Self, SessionCreationError> {
Expand All @@ -199,7 +203,7 @@ impl InboundGroupSession {
curve25519_key: sender_key,
signing_keys: keys.into(),
},
sender_data: InboundGroupSessionSenderData::default(),
sender_data,
room_id: room_id.into(),
imported: false,
algorithm: encryption_algorithm.into(),
Expand Down Expand Up @@ -507,7 +511,7 @@ pub struct PickledInboundGroupSession {
pub signing_key: SigningKeys<DeviceKeyAlgorithm>,
/// Information on the device/sender who sent us this session
#[serde(default)]
pub sender_data: InboundGroupSessionSenderData,
pub sender_data: SenderData,
/// The id of the room that the session is used in.
pub room_id: OwnedRoomId,
/// Flag remembering if the session was directly sent to us by the sender
Expand Down Expand Up @@ -543,7 +547,7 @@ impl TryFrom<&ExportedRoomKey> for InboundGroupSession {
signing_keys: key.sender_claimed_keys.to_owned().into(),
},
// TODO: in future, exported keys should contain sender data that we can use here
sender_data: InboundGroupSessionSenderData::default(),
sender_data: SenderData::default(),
history_visibility: None.into(),
first_known_index,
room_id: key.room_id.to_owned(),
Expand Down Expand Up @@ -572,7 +576,7 @@ impl From<&ForwardedMegolmV1AesSha2Content> for InboundGroupSession {
.into(),
},
// TODO: in future, forwarded keys should contain sender data that we can use here
sender_data: InboundGroupSessionSenderData::default(),
sender_data: SenderData::default(),
history_visibility: None.into(),
first_known_index,
room_id: value.room_id.to_owned(),
Expand All @@ -597,7 +601,7 @@ impl From<&ForwardedMegolmV2AesSha2Content> for InboundGroupSession {
signing_keys: value.claimed_signing_keys.to_owned().into(),
},
// TODO: in future, forwarded keys should contain sender data that we can use here
sender_data: InboundGroupSessionSenderData::default(),
sender_data: SenderData::default(),
history_visibility: None.into(),
first_known_index,
room_id: value.room_id.to_owned(),
Expand Down Expand Up @@ -628,18 +632,15 @@ mod tests {
use matrix_sdk_test::async_test;
use ruma::{
device_id, events::room::history_visibility::HistoryVisibility, room_id, user_id, DeviceId,
MilliSecondsSinceUnixEpoch, UInt, UserId,
UInt, UserId,
};
use vodozemac::{
megolm::{SessionKey, SessionOrdering},
Curve25519PublicKey, Ed25519PublicKey,
};

use crate::{
olm::{
group_sessions::inbound_group_session_sender_data::InboundGroupSessionSenderData,
InboundGroupSession,
},
olm::{InboundGroupSession, SenderData, SenderDataRetryDetails},
types::EventEncryptionAlgorithm,
Account,
};
Expand Down Expand Up @@ -702,8 +703,7 @@ mod tests {

// We populated the InboundGroupSession's sender_data with a default value,
// with legacy_session set to true.
let InboundGroupSessionSenderData::UnknownDevice { retry_details, legacy_session } =
unpickled.sender_data
let SenderData::UnknownDevice { retry_details, legacy_session } = unpickled.sender_data
else {
panic!("Expected sender_data to be UnknownDevice!");
};
Expand All @@ -720,20 +720,14 @@ mod tests {
Ed25519PublicKey::from_base64("wTRTdz4rn4EY+68cKPzpMdQ6RAlg7T8cbTmEjaXuUww").unwrap(),
room_id!("!test:localhost"),
&create_session_key(),
SenderData::unknown(SenderDataRetryDetails::new(5, 1234)),
EventEncryptionAlgorithm::MegolmV1AesSha2,
Some(HistoryVisibility::Shared),
)
.unwrap();

// When we pickle it and set its retry time to a known value
let mut pickled = igs.pickle().await;

let InboundGroupSessionSenderData::UnknownDevice { retry_details, .. } =
&mut pickled.sender_data
else {
panic!("Expected sender_data to be UnknownDevice");
};
(*retry_details).next_retry_time_ms = MilliSecondsSinceUnixEpoch(UInt::new(1234).unwrap());
// When we pickle it
let pickled = igs.pickle().await;

// And serialise it
let serialised = serde_json::to_string(&pickled).unwrap();
Expand Down Expand Up @@ -770,7 +764,7 @@ mod tests {
"sender_data":{
"UnknownDevice":{
"retry_details":{
"retry_count":0,
"retry_count":5,
"next_retry_time_ms":1234
},
"legacy_session":true
Expand Down Expand Up @@ -843,8 +837,7 @@ mod tests {
assert_eq!(unpickled.session_id(), "XbmrPa1kMwmdtNYng1B2gsfoo8UtF+NklzsTZiaVKyY");

// We populated the InboundGroupSession's sender_data with a default value
let InboundGroupSessionSenderData::UnknownDevice { retry_details, legacy_session } =
unpickled.sender_data
let SenderData::UnknownDevice { retry_details, legacy_session } = unpickled.sender_data
else {
panic!("Expected sender_data to be UnknownDevice!");
};
Expand Down
5 changes: 4 additions & 1 deletion crates/matrix-sdk-crypto/src/olm/group_sessions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@ use ruma::{DeviceKeyAlgorithm, OwnedRoomId};
use serde::{Deserialize, Serialize};

mod inbound;
mod inbound_group_session_sender_data;
mod outbound;
mod sender_data;
mod sender_data_finder;

pub use inbound::{InboundGroupSession, PickledInboundGroupSession};
pub(crate) use outbound::ShareState;
pub use outbound::{
EncryptionSettings, OutboundGroupSession, PickledOutboundGroupSession, ShareInfo,
};
pub use sender_data::{SenderData, SenderDataRetryDetails};
pub(crate) use sender_data_finder::SenderDataFinder;
use thiserror::Error;
pub use vodozemac::megolm::{ExportedSessionKey, SessionKey};
use vodozemac::{megolm::SessionKeyDecodeError, Curve25519PublicKey};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,7 @@ impl OutboundGroupSession {
self.room_id().to_owned(),
self.session_id().to_owned(),
session_key,
None, // AJB
)
.into(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ use crate::types::DeviceKeys;
/// state when we get the device info. Finally, if we can look up the sender
/// using the device info, the session can be moved into `SenderKnown` state.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum InboundGroupSessionSenderData {
pub enum SenderData {
/// We have not yet found the (signed) device info for the sending device
UnknownDevice {
// TODO: we may need to handle unsigned and unknown devices separately, which
// probably necessitates a flag here
/// When we will next try again to find device info for this session,
/// and how many times we have tried
retry_details: RetryDetails,
retry_details: SenderDataRetryDetails,

/// Was this session created before we started collecting trust
/// information about sessions? If so, we may choose to display its
Expand All @@ -47,7 +47,7 @@ pub enum InboundGroupSessionSenderData {
device_keys: DeviceKeys,
/// When we will next try again to find a cross-signing key that signed
/// the device information, and how many times we have tried.
retry_details: RetryDetails,
retry_details: SenderDataRetryDetails,

/// Was this session created before we started collecting trust
/// information about sessions? If so, we may choose to display its
Expand All @@ -72,29 +72,74 @@ pub enum InboundGroupSessionSenderData {
},
}

impl SenderData {
/// Create a [`SenderData`] which contains no device info and will be
/// retried soon.
pub fn new() -> Self {
Self::UnknownDevice {
retry_details: SenderDataRetryDetails::retry_soon(),
// TODO: when we have implemented all of SenderDataFinder,
// legacy_session should be set to false, but for now we leave
// it as true because we might lose device info while
// this code is still in transition.
legacy_session: true,
}
}

/// Create a [`SenderData`] which has the legacy flag set. Caution: messages
/// within sessions with this flag will be displayed in some contexts,
/// even when we are unable to verify the sender.
///
/// The returned struct contains no device info, and will be retried soon.
pub(crate) fn legacy() -> Self {
Self::UnknownDevice {
retry_details: SenderDataRetryDetails::retry_soon(),
legacy_session: true,
}
}

#[cfg(test)]
pub(crate) fn unknown(retry_details: SenderDataRetryDetails) -> Self {
Self::UnknownDevice { retry_details, legacy_session: false }
}
}

/// Used when deserialising and the sender_data property is missing.
/// If we are deserialising an InboundGroupSession session with missing
/// sender_data, this must be a legacy session (i.e. it was created before we
/// started tracking sender data). We set its legacy flag to true, and set it up
/// to be retried soon, so we can populate it with trust information if it is
/// available.
impl Default for InboundGroupSessionSenderData {
impl Default for SenderData {
fn default() -> Self {
Self::UnknownDevice { retry_details: RetryDetails::retry_soon(), legacy_session: true }
Self::legacy()
}
}

/// Tracking information about when we need to try again fetching device or
/// user information, and how many times we have already tried.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RetryDetails {
pub retry_count: u8,
pub next_retry_time_ms: MilliSecondsSinceUnixEpoch,
pub struct SenderDataRetryDetails {
retry_count: u8,
next_retry_time_ms: MilliSecondsSinceUnixEpoch,
}

impl RetryDetails {
impl SenderDataRetryDetails {
/// Create a new RetryDetails with a retry count of zero, and retry time of
/// now.
pub(crate) fn retry_soon() -> Self {
Self { retry_count: 0, next_retry_time_ms: MilliSecondsSinceUnixEpoch::now() }
}

#[cfg(test)]
pub(crate) fn new(retry_count: u8, next_retry_time_ms: u64) -> Self {
use ruma::UInt;

Self {
retry_count,
next_retry_time_ms: MilliSecondsSinceUnixEpoch(
UInt::try_from(next_retry_time_ms).unwrap_or(UInt::from(0u8)),
),
}
}
}
Loading

0 comments on commit d53fe25

Please sign in to comment.