Skip to content

Commit 536ba51

Browse files
committed
feat(crypto): Check sender data before accepting room key bundles
1 parent 917c46b commit 536ba51

File tree

2 files changed

+67
-55
lines changed

2 files changed

+67
-55
lines changed

crates/matrix-sdk-crypto/src/store/mod.rs

Lines changed: 62 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ use thiserror::Error;
6060
use tokio::sync::{Mutex, Notify, OwnedRwLockWriteGuard, RwLock};
6161
use tokio_stream::wrappers::errors::BroadcastStreamRecvError;
6262
use tracing::{error, info, instrument, trace, warn};
63-
use types::RoomKeyBundleInfo;
63+
use types::{RoomKeyBundleInfo, StoredRoomKeyBundleData};
6464
use vodozemac::{megolm::SessionOrdering, Curve25519PublicKey};
6565

6666
use self::types::{
@@ -1341,14 +1341,11 @@ impl Store {
13411341
///
13421342
/// while let Some(bundle_info) = bundle_stream.next().await {
13431343
/// // Try to find the bundle content in the store and if it's valid accept it.
1344-
/// if let Some(bundle_content) = machine.store().get_received_room_key_bundle_data(&bundle_info.room_id, &bundle_info.sender).await? {
1345-
/// let StoredRoomKeyBundleData { sender_user, sender_data, bundle_data, .. } = bundle_content;
1344+
/// if let Some(bundle_data) = machine.store().get_received_room_key_bundle_data(&bundle_info.room_id, &bundle_info.sender).await? {
13461345
/// // Download the bundle now and import it.
13471346
/// let bundle: RoomKeyBundle = todo!("Download the bundle");
13481347
/// machine.store().receive_room_key_bundle(
1349-
/// &bundle_info.room_id,
1350-
/// &sender_user,
1351-
/// &sender_data,
1348+
/// &bundle_data,
13521349
/// bundle,
13531350
/// |_, _| {},
13541351
/// ).await?;
@@ -1611,66 +1608,86 @@ impl Store {
16111608
///
16121609
/// # Arguments
16131610
///
1611+
/// * `bundle_info` - The [`StoredRoomKeyBundleData`] of the bundle that is
1612+
/// being received.
16141613
/// * `bundle` - The decrypted and deserialized bundle itself.
1615-
/// * `room_id` - The room that we expect this bundle to correspond to.
1616-
/// * `sender_user` - The user that sent us the to-device message pointing
1617-
/// to this data.
1618-
/// * `sender_data` - Information on the sending device at the time we
1619-
/// received that message.
16201614
///
16211615
/// [MSC4268]: https://github.com/matrix-org/matrix-spec-proposals/pull/4268
1622-
#[instrument(skip(self, bundle, progress_listener), fields(bundle_size = bundle.room_keys.len()))]
1616+
#[instrument(skip(self, bundle, progress_listener), fields(bundle_size = bundle.room_keys.len(), sender_data))]
16231617
pub async fn receive_room_key_bundle(
16241618
&self,
1625-
room_id: &RoomId,
1626-
sender_user: &UserId,
1627-
sender_data: &SenderData,
1619+
bundle_info: &StoredRoomKeyBundleData,
16281620
bundle: RoomKeyBundle,
16291621
progress_listener: impl Fn(usize, usize),
16301622
) -> Result<(), CryptoStoreError> {
1631-
let (good, bad): (Vec<_>, Vec<_>) = bundle.room_keys.iter().partition_map(|key| {
1632-
if key.room_id != room_id {
1633-
trace!("Ignoring key for incorrect room {} in bundle", key.room_id);
1634-
Either::Right(key)
1635-
} else {
1636-
Either::Left(key)
1637-
}
1638-
});
1623+
let sender_data = if bundle_info.sender_data.should_recalculate() {
1624+
let device = self
1625+
.get_device_from_curve_key(&bundle_info.sender_user, bundle_info.sender_key)
1626+
.await?;
16391627

1640-
match (bad.is_empty(), good.is_empty()) {
1641-
// Case 1: Completely empty bundle.
1642-
(true, true) => {
1643-
warn!("Received a completely empty room key bundle");
1628+
device
1629+
.as_ref()
1630+
.map(SenderData::from_device)
1631+
.unwrap_or_else(|| bundle_info.sender_data.clone())
1632+
} else {
1633+
bundle_info.sender_data.clone()
1634+
};
1635+
1636+
tracing::Span::current().record("sender_data", tracing::field::debug(&sender_data));
1637+
1638+
match sender_data {
1639+
SenderData::UnknownDevice { .. }
1640+
| SenderData::VerificationViolation(_)
1641+
| SenderData::DeviceInfo { .. } => {
1642+
warn!("Not accepting a historic room key bundle due to insufficient trust in the sender");
1643+
Ok(())
16441644
}
1645+
SenderData::SenderUnverified(_) | SenderData::SenderVerified(_) => {
1646+
let (good, bad): (Vec<_>, Vec<_>) = bundle.room_keys.iter().partition_map(|key| {
1647+
if key.room_id != bundle_info.bundle_data.room_id {
1648+
trace!("Ignoring key for incorrect room {} in bundle", key.room_id);
1649+
Either::Right(key)
1650+
} else {
1651+
Either::Left(key)
1652+
}
1653+
});
1654+
1655+
match (bad.is_empty(), good.is_empty()) {
1656+
// Case 1: Completely empty bundle.
1657+
(true, true) => {
1658+
warn!("Received a completely empty room key bundle");
1659+
}
16451660

1646-
// Case 2: A bundle for the wrong room.
1647-
(false, true) => {
1648-
let bad_keys: Vec<_> =
1649-
bad.iter().map(|&key| (&key.room_id, &key.session_id)).collect();
1661+
// Case 2: A bundle for the wrong room.
1662+
(false, true) => {
1663+
let bad_keys: Vec<_> =
1664+
bad.iter().map(|&key| (&key.room_id, &key.session_id)).collect();
16501665

1651-
warn!(
1666+
warn!(
16521667
?bad_keys,
16531668
"Received a room key bundle for the wrong room, ignoring all room keys from the bundle"
16541669
);
1655-
}
1670+
}
16561671

1657-
// Case 3: A bundle containing useful room keys.
1658-
(_, false) => {
1659-
// We have at least some good keys, if we also have some bad ones let's mention
1660-
// that here.
1661-
if !bad.is_empty() {
1662-
warn!(
1663-
bad_key_count = bad.len(),
1664-
"The room key bundle contained some room keys \
1672+
// Case 3: A bundle containing useful room keys.
1673+
(_, false) => {
1674+
// We have at least some good keys, if we also have some bad ones let's
1675+
// mention that here.
1676+
if !bad.is_empty() {
1677+
warn!(
1678+
bad_key_count = bad.len(),
1679+
"The room key bundle contained some room keys \
16651680
that were meant for a different room"
1666-
);
1681+
);
1682+
}
1683+
1684+
self.import_sessions_impl(good, None, progress_listener).await?;
1685+
}
16671686
}
16681687

1669-
self.import_sessions_impl(good, None, progress_listener).await?;
1688+
Ok(())
16701689
}
16711690
}
1672-
1673-
Ok(())
16741691
}
16751692
}
16761693

crates/matrix-sdk/src/room/shared_room_history.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@
1414

1515
use std::iter;
1616

17-
use matrix_sdk_base::{
18-
crypto::store::types::StoredRoomKeyBundleData,
19-
media::{MediaFormat, MediaRequestParameters},
20-
};
17+
use matrix_sdk_base::media::{MediaFormat, MediaRequestParameters};
2118
use ruma::{events::room::MediaSource, OwnedUserId, UserId};
2219
use tracing::{info, instrument, warn};
2320

@@ -124,20 +121,20 @@ pub(crate) async fn maybe_accept_key_bundle(room: &Room, inviter: &UserId) -> Re
124121
return Ok(());
125122
};
126123

127-
let Some(StoredRoomKeyBundleData { sender_user, sender_data, bundle_data, .. }) =
124+
let Some(bundle_info) =
128125
olm_machine.store().get_received_room_key_bundle_data(room.room_id(), inviter).await?
129126
else {
130127
// No bundle received (yet).
131128
return Ok(());
132129
};
133130

134-
tracing::Span::current().record("bundle_sender", sender_user.as_str());
131+
tracing::Span::current().record("bundle_sender", bundle_info.sender_user.as_str());
135132

136133
let bundle_content = client
137134
.media()
138135
.get_media_content(
139136
&MediaRequestParameters {
140-
source: MediaSource::Encrypted(Box::new(bundle_data.file)),
137+
source: MediaSource::Encrypted(Box::new(bundle_info.bundle_data.file.clone())),
141138
format: MediaFormat::File,
142139
},
143140
false,
@@ -149,9 +146,7 @@ pub(crate) async fn maybe_accept_key_bundle(room: &Room, inviter: &UserId) -> Re
149146
olm_machine
150147
.store()
151148
.receive_room_key_bundle(
152-
room.room_id(),
153-
&sender_user,
154-
&sender_data,
149+
&bundle_info,
155150
bundle,
156151
// TODO: Use the progress listener and expose an argument for it.
157152
|_, _| {},

0 commit comments

Comments
 (0)