Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

task(crypto): Support receiving stable identifier for MSC4147 #4420

Merged
merged 1 commit into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/matrix-sdk-crypto/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ All notable changes to this project will be documented in this file.

## [Unreleased] - ReleaseDate

- Accept stable identifier `sender_device_keys` for MSC4147 (Including device
keys with Olm-encrypted events).
([#4420](https://github.com/matrix-org/matrix-rust-sdk/pull/4420))

## [0.9.0] - 2024-12-18

- Expose new API `DehydratedDevices::get_dehydrated_device_pickle_key`, `DehydratedDevices::save_dehydrated_device_pickle_key`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ impl<'a> SenderDataFinder<'a> {
room_key_event: &'a DecryptedRoomKeyEvent,
) -> Result<SenderData, SessionDeviceKeysCheckError> {
// Does the to-device message contain the device_keys property from MSC4147?
if let Some(sender_device_keys) = &room_key_event.device_keys {
if let Some(sender_device_keys) = &room_key_event.sender_device_keys {
// Yes: use the device keys to continue.

// Validate the signature of the DeviceKeys supplied.
Expand Down
2 changes: 1 addition & 1 deletion crates/matrix-sdk-crypto/src/olm/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,6 @@ mod tests {
// DecryptedOlmV1Event
let event: DecryptedOlmV1Event<DummyEventContent> =
serde_json::from_str(&bob_session_result.plaintext).unwrap();
assert_eq!(event.device_keys.unwrap(), alice.device_keys());
assert_eq!(event.sender_device_keys.unwrap(), alice.device_keys());
}
}
2 changes: 1 addition & 1 deletion crates/matrix-sdk-crypto/src/store/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1027,7 +1027,7 @@ macro_rules! cryptostore_integration_tests {
recipient_keys: OlmV1Keys {
ed25519: account.identity_keys().ed25519,
},
device_keys: None,
sender_device_keys: None,
content: SecretSendContent::new(id.to_owned(), secret.to_owned()),
};

Expand Down
137 changes: 129 additions & 8 deletions crates/matrix-sdk-crypto/src/types/events/olm_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,10 @@ impl AnyDecryptedOlmEvent {
pub fn sender_device_keys(&self) -> Option<&DeviceKeys> {
match self {
AnyDecryptedOlmEvent::Custom(_) => None,
AnyDecryptedOlmEvent::RoomKey(e) => e.device_keys.as_ref(),
AnyDecryptedOlmEvent::ForwardedRoomKey(e) => e.device_keys.as_ref(),
AnyDecryptedOlmEvent::SecretSend(e) => e.device_keys.as_ref(),
AnyDecryptedOlmEvent::Dummy(e) => e.device_keys.as_ref(),
AnyDecryptedOlmEvent::RoomKey(e) => e.sender_device_keys.as_ref(),
AnyDecryptedOlmEvent::ForwardedRoomKey(e) => e.sender_device_keys.as_ref(),
AnyDecryptedOlmEvent::SecretSend(e) => e.sender_device_keys.as_ref(),
AnyDecryptedOlmEvent::Dummy(e) => e.sender_device_keys.as_ref(),
}
}
}
Expand All @@ -176,8 +176,8 @@ where
/// The recipient's signing keys of the encrypted event.
pub recipient_keys: OlmV1Keys,
/// The device keys if supplied as per MSC4147
#[serde(rename = "org.matrix.msc4147.device_keys")]
pub device_keys: Option<DeviceKeys>,
#[serde(alias = "org.matrix.msc4147.device_keys")]
pub sender_device_keys: Option<DeviceKeys>,
/// The type of the event.
pub content: C,
}
Expand All @@ -201,7 +201,7 @@ impl<C: EventType + Debug + Sized + Serialize> DecryptedOlmV1Event<C> {
recipient: recipient.to_owned(),
keys: OlmV1Keys { ed25519: key },
recipient_keys: OlmV1Keys { ed25519: key },
device_keys,
sender_device_keys: device_keys,
content,
}
}
Expand Down Expand Up @@ -264,10 +264,18 @@ impl<'de> Deserialize<'de> for AnyDecryptedOlmEvent {

#[cfg(test)]
mod tests {
use std::collections::BTreeMap;

use assert_matches::assert_matches;
use ruma::{device_id, owned_user_id, KeyId};
use serde_json::{json, Value};
use vodozemac::{Curve25519PublicKey, Ed25519PublicKey, Ed25519Signature};

use super::AnyDecryptedOlmEvent;
use crate::types::{
events::olm_v1::DecryptedRoomKeyEvent, DeviceKey, DeviceKeys, EventEncryptionAlgorithm,
Signatures,
};

const ED25519_KEY: &str = "aOfOnlaeMb5GW1TxkZ8pXnblkGMgAvps+lAukrdYaZk";

Expand Down Expand Up @@ -363,6 +371,80 @@ mod tests {
})
}

/// Return the JSON for creating sender device keys, and the matching
/// `DeviceKeys` object that should be created when the JSON is
/// deserialized.
fn sender_device_keys() -> (Value, DeviceKeys) {
let sender_device_keys_json = json!({
"user_id": "@u:s.co",
"device_id": "DEV",
"algorithms": [
"m.olm.v1.curve25519-aes-sha2"
],
"keys": {
"curve25519:DEV": "c29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb28",
"ed25519:DEV": "b29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb28"
},
"signatures": {
"@u:s.co": {
"ed25519:DEV": "mia28GKixFzOWKJ0h7Bdrdy2fjxiHCsst1qpe467FbW85H61UlshtKBoAXfTLlVfi0FX+/noJ8B3noQPnY+9Cg",
"ed25519:ssk": "mia28GKixFzOWKJ0h7Bdrdy2fjxiHCsst1qpe467FbW85H61UlshtKBoAXfTLlVfi0FX+/noJ8B3noQPnY+9Cg"
}
}
}
);

let user_id = owned_user_id!("@u:s.co");
let device_id = device_id!("DEV");
let ssk_id = device_id!("ssk");

let ed25519_device_key_id = KeyId::from_parts(ruma::DeviceKeyAlgorithm::Ed25519, device_id);
let curve25519_device_key_id =
KeyId::from_parts(ruma::DeviceKeyAlgorithm::Curve25519, device_id);
let ed25519_ssk_id = KeyId::from_parts(ruma::DeviceKeyAlgorithm::Ed25519, ssk_id);

let mut keys = BTreeMap::new();
keys.insert(
ed25519_device_key_id.clone(),
DeviceKey::Ed25519(
Ed25519PublicKey::from_base64("b29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb28")
.unwrap(),
),
);
keys.insert(
curve25519_device_key_id,
DeviceKey::Curve25519(
Curve25519PublicKey::from_base64("c29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb28")
.unwrap(),
),
);

let mut signatures = Signatures::new();
signatures.add_signature(
user_id.clone(),
ed25519_device_key_id,
Ed25519Signature::from_base64(
"mia28GKixFzOWKJ0h7Bdrdy2fjxiHCsst1qpe467FbW85H61UlshtKBoAXfTLlVfi0FX+/noJ8B3noQPnY+9Cg"
).unwrap()
);
signatures. add_signature(
user_id.clone(),
ed25519_ssk_id,
Ed25519Signature::from_base64(
"mia28GKixFzOWKJ0h7Bdrdy2fjxiHCsst1qpe467FbW85H61UlshtKBoAXfTLlVfi0FX+/noJ8B3noQPnY+9Cg"
).unwrap()
);
let sender_device_keys = DeviceKeys::new(
user_id,
device_id.to_owned(),
vec![EventEncryptionAlgorithm::OlmV1Curve25519AesSha2],
keys,
signatures,
);

(sender_device_keys_json, sender_device_keys)
}

#[test]
fn deserialization() -> Result<(), serde_json::Error> {
macro_rules! assert_deserialization_result {
Expand All @@ -377,7 +459,7 @@ mod tests {
}

assert_deserialization_result!(
// `m.room_key
// `m.room_key`
room_key_event => RoomKey,

// `m.forwarded_room_key`
Expand All @@ -392,4 +474,43 @@ mod tests {

Ok(())
}

#[test]
fn sender_device_keys_are_deserialized_unstable() {
let (sender_device_keys_json, sender_device_keys) = sender_device_keys();

// Given JSON for a room key event with sender_device_keys using the unstable
// prefix
let mut event_json = room_key_event();
event_json
.as_object_mut()
.unwrap()
.insert("org.matrix.msc4147.device_keys".to_owned(), sender_device_keys_json);

// When we deserialize it
let event: DecryptedRoomKeyEvent = serde_json::from_value(event_json)
.expect("JSON should deserialize to the right event type");

// Then it contains the sender_device_keys
assert_eq!(event.sender_device_keys, Some(sender_device_keys));
}

#[test]
fn sender_device_keys_are_deserialized() {
let (sender_device_keys_json, sender_device_keys) = sender_device_keys();

// Given JSON for a room key event with sender_device_keys
let mut event_json = room_key_event();
event_json
.as_object_mut()
.unwrap()
.insert("sender_device_keys".to_owned(), sender_device_keys_json);

// When we deserialize it
let event: DecryptedRoomKeyEvent = serde_json::from_value(event_json)
.expect("JSON should deserialize to the right event type");

// Then it contains the sender_device_keys
assert_eq!(event.sender_device_keys, Some(sender_device_keys));
}
}
Loading