crypto: get_most_recent_session: return None for unknown device (#4846)

If we have a device whose Curve25519 key we don't know, then
self-evidently we can't have any active Olm sessions with that device.
Currently, we return an `EventError::MissingSenderKey` in this case, but
(a) the definition of that error doesn't match this situation, and (b)
it complicates handling in methods that call `DeviceData::encrypt`
(currently only `DeviceData::maybe_encrypt_room_key`, but I want to add
a second).

Other than `DeviceData::encrypt`, the only place where
`get_most_recent_session` is called is `mark_device_as_wedged`. In that
case, we have just looked up the device by its Curve25519 key, so we
know it must have one.

We can therefore be reasonably certain that this change is a no-op.
This commit is contained in:
Richard van der Hoff
2025-03-26 14:42:24 +00:00
committed by GitHub
parent e60cf18337
commit 6e480271d3
3 changed files with 60 additions and 13 deletions

View File

@@ -31,14 +31,14 @@ use ruma::{
};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use tracing::{instrument, trace, warn};
use tracing::{instrument, trace};
use vodozemac::{olm::SessionConfig, Curve25519PublicKey, Ed25519PublicKey};
use super::{atomic_bool_deserializer, atomic_bool_serializer};
#[cfg(any(test, feature = "testing", doc))]
use crate::OlmMachine;
use crate::{
error::{EventError, MismatchedIdentityKeysError, OlmError, OlmResult, SignatureError},
error::{MismatchedIdentityKeysError, OlmError, OlmResult, SignatureError},
identities::{OwnUserIdentityData, UserIdentityData},
olm::{
InboundGroupSession, OutboundGroupSession, Session, ShareInfo, SignedJsonObject, VerifyJson,
@@ -695,12 +695,7 @@ impl DeviceData {
Ok(None)
}
} else {
warn!(
"Trying to find an Olm session of a device, but the device doesn't have a \
Curve25519 key",
);
Err(EventError::MissingSenderKey.into())
Ok(None)
}
}
@@ -846,7 +841,7 @@ impl DeviceData {
message: encrypted.cast(),
}),
Err(OlmError::MissingSession | OlmError::EventError(EventError::MissingSenderKey)) => {
Err(OlmError::MissingSession) => {
Ok(MaybeEncryptedRoomKey::Withheld { code: WithheldCode::NoOlm })
}
Err(e) => Err(e),

View File

@@ -12,22 +12,29 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::time::{Duration, SystemTime};
use std::{
collections::BTreeMap,
time::{Duration, SystemTime},
};
use assert_matches2::assert_let;
use matrix_sdk_test::async_test;
use ruma::{
device_id,
events::{dummy::ToDeviceDummyEventContent, AnyToDeviceEvent},
SecondsSinceUnixEpoch,
user_id, DeviceKeyAlgorithm, DeviceKeyId, SecondsSinceUnixEpoch,
};
use vodozemac::Ed25519SecretKey;
use crate::{
machine::{
test_helpers::{create_session, get_machine_pair, get_machine_pair_with_session},
tests,
},
olm::utility::SignJson,
store::Changes,
types::events::ToDeviceEvent,
types::{events::ToDeviceEvent, DeviceKeys},
DeviceData, OlmMachine,
};
#[async_test]
@@ -136,6 +143,51 @@ async fn test_getting_most_recent_session() {
);
}
#[async_test]
async fn test_get_most_recent_session_of_device_with_no_curve_key() {
let alice_machine =
OlmMachine::new(user_id!("@alice:example.org"), device_id!("ALICE_DEVICE")).await;
let bob_user_id = user_id!("@bob:example.com");
let bob_device_id = device_id!("BOB_DEVICE");
let bob_device_data = {
// Create a device with no Curve25519 key. It has to have an Ed25519 key, and be
// signed, for us to accept it
let bob_signing_key = Ed25519SecretKey::new();
// Generate the unsigned structure
let mut bob_device_keys = DeviceKeys::new(
bob_user_id.to_owned(),
bob_device_id.to_owned(),
vec![],
BTreeMap::from([(
DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, bob_device_id),
bob_signing_key.public_key().into(),
)]),
Default::default(),
);
// Add the signature
bob_device_keys.signatures.add_signature(
bob_user_id.to_owned(),
DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, bob_device_id),
bob_signing_key
.sign_json(serde_json::to_value(&bob_device_keys).unwrap())
.expect("Could not sign device data"),
);
DeviceData::try_from(&bob_device_keys).unwrap()
};
alice_machine.store().save_device_data(&[bob_device_data]).await.unwrap();
// Now, fetch the device from the store, and the most recent session should be
// None.
let device = alice_machine.get_device(bob_user_id, bob_device_id, None).await.unwrap().unwrap();
let newest_session = device.get_most_recent_session().await.unwrap();
assert!(newest_session.is_none());
}
async fn olm_encryption_test_helper(use_fallback_key: bool) {
let (alice, bob) =
get_machine_pair_with_session(tests::alice_id(), tests::user_id(), use_fallback_key).await;

View File

@@ -21,7 +21,7 @@ mod account;
mod group_sessions;
mod session;
mod signing;
mod utility;
pub(crate) mod utility;
pub use account::{Account, OlmMessageHash, PickledAccount, StaticAccountData};
pub(crate) use account::{OlmDecryptionInfo, SessionType};