crypto: Check the recipient and recipient keys for decrypted events.
parent
0eab02a941
commit
27ae8bccb9
|
@ -655,13 +655,13 @@ impl OlmMachine {
|
||||||
|
|
||||||
async fn try_decrypt_olm_event(
|
async fn try_decrypt_olm_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
sender: &str,
|
sender: &UserId,
|
||||||
sender_key: &str,
|
sender_key: &str,
|
||||||
message: &OlmMessage,
|
message: &OlmMessage,
|
||||||
) -> Result<Option<String>> {
|
) -> Result<Option<String>> {
|
||||||
let s = self.store.get_sessions(sender_key).await?;
|
let s = self.store.get_sessions(sender_key).await?;
|
||||||
|
|
||||||
/// We don't have any existing sessions, return early.
|
// We don't have any existing sessions, return early.
|
||||||
let sessions = if let Some(s) = s {
|
let sessions = if let Some(s) = s {
|
||||||
s
|
s
|
||||||
} else {
|
} else {
|
||||||
|
@ -708,10 +708,10 @@ impl OlmMachine {
|
||||||
|
|
||||||
async fn decrypt_olm_message(
|
async fn decrypt_olm_message(
|
||||||
&mut self,
|
&mut self,
|
||||||
sender: &str,
|
sender: &UserId,
|
||||||
sender_key: &str,
|
sender_key: &str,
|
||||||
message: OlmMessage,
|
message: OlmMessage,
|
||||||
) -> Result<EventResult<ToDeviceEvent>> {
|
) -> Result<(EventResult<ToDeviceEvent>, String)> {
|
||||||
// First try to decrypt using an existing session.
|
// First try to decrypt using an existing session.
|
||||||
let plaintext = if let Some(p) = self
|
let plaintext = if let Some(p) = self
|
||||||
.try_decrypt_olm_event(sender, sender_key, &message)
|
.try_decrypt_olm_event(sender, sender_key, &message)
|
||||||
|
@ -724,8 +724,8 @@ impl OlmMachine {
|
||||||
// Decryption failed with every known session, let's try to create a
|
// Decryption failed with every known session, let's try to create a
|
||||||
// new session.
|
// new session.
|
||||||
let mut session = match &message {
|
let mut session = match &message {
|
||||||
/// A new session can only be created using a pre-key message,
|
// A new session can only be created using a pre-key message,
|
||||||
/// return with an error if it isn't one.
|
// return with an error if it isn't one.
|
||||||
OlmMessage::Message(_) => {
|
OlmMessage::Message(_) => {
|
||||||
warn!(
|
warn!(
|
||||||
"Failed to decrypt a non-pre-key message with all
|
"Failed to decrypt a non-pre-key message with all
|
||||||
|
@ -736,7 +736,7 @@ impl OlmMachine {
|
||||||
}
|
}
|
||||||
|
|
||||||
OlmMessage::PreKey(m) => {
|
OlmMessage::PreKey(m) => {
|
||||||
/// Create the new session.
|
// Create the new session.
|
||||||
let session = match self
|
let session = match self
|
||||||
.account
|
.account
|
||||||
.create_inbound_session(sender_key, m.clone())
|
.create_inbound_session(sender_key, m.clone())
|
||||||
|
@ -753,32 +753,79 @@ impl OlmMachine {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Save the account since we remove the one-time key that
|
// Save the account since we remove the one-time key that
|
||||||
/// was used to create this session.
|
// was used to create this session.
|
||||||
self.store.save_account(self.account.clone()).await?;
|
self.store.save_account(self.account.clone()).await?;
|
||||||
session
|
session
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Decrypt our message, this shouldn't fail since we're using a
|
// Decrypt our message, this shouldn't fail since we're using a
|
||||||
/// newly created Session.
|
// newly created Session.
|
||||||
let plaintext = session.decrypt(message).await?;
|
let plaintext = session.decrypt(message).await?;
|
||||||
|
|
||||||
/// Save the new ratcheted state of the session.
|
// Save the new ratcheted state of the session.
|
||||||
self.store.save_session(session).await?;
|
self.store.save_session(session).await?;
|
||||||
plaintext
|
plaintext
|
||||||
};
|
};
|
||||||
|
|
||||||
trace!("Successfully decrypted a Olm message: {}", plaintext);
|
trace!("Successfully decrypted a Olm message: {}", plaintext);
|
||||||
|
|
||||||
// TODO get the recipient, recipient_keys, and keys out of here
|
Ok(self.parse_decrypted_to_device_event(sender, &plaintext)?)
|
||||||
// separately.
|
}
|
||||||
// TODO verify that the recipient, recipient_keys match with us.
|
|
||||||
// TODO verify that the sender in the decrypted event matches the one in
|
fn parse_decrypted_to_device_event(
|
||||||
// the unencrypted one.
|
&self,
|
||||||
Ok(serde_json::from_str::<EventResult<ToDeviceEvent>>(
|
sender: &UserId,
|
||||||
&plaintext,
|
plaintext: &str,
|
||||||
)?)
|
) -> Result<(EventResult<ToDeviceEvent>, String)> {
|
||||||
|
// TODO make the errors a bit more specific.
|
||||||
|
let decrypted_json: Value = serde_json::from_str(&plaintext)?;
|
||||||
|
|
||||||
|
let encrytped_sender = decrypted_json
|
||||||
|
.get("sender")
|
||||||
|
.cloned()
|
||||||
|
.ok_or(OlmError::MissingCiphertext)?;
|
||||||
|
let encrytped_sender: UserId = serde_json::from_value(encrytped_sender)?;
|
||||||
|
let recipient = decrypted_json
|
||||||
|
.get("recipient")
|
||||||
|
.cloned()
|
||||||
|
.ok_or(OlmError::MissingCiphertext)?;
|
||||||
|
let recipient: UserId = serde_json::from_value(recipient)?;
|
||||||
|
|
||||||
|
let recipient_keys: HashMap<KeyAlgorithm, String> = serde_json::from_value(
|
||||||
|
decrypted_json
|
||||||
|
.get("recipient_keys")
|
||||||
|
.cloned()
|
||||||
|
.ok_or(OlmError::MissingCiphertext)?,
|
||||||
|
)?;
|
||||||
|
let keys: HashMap<KeyAlgorithm, String> = serde_json::from_value(
|
||||||
|
decrypted_json
|
||||||
|
.get("keys")
|
||||||
|
.cloned()
|
||||||
|
.ok_or(OlmError::MissingCiphertext)?,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if recipient != self.user_id || sender != &encrytped_sender {
|
||||||
|
return Err(OlmError::MissingCiphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.account.identity_keys().ed25519()
|
||||||
|
!= recipient_keys
|
||||||
|
.get(&KeyAlgorithm::Ed25519)
|
||||||
|
.ok_or(OlmError::MissingCiphertext)?
|
||||||
|
{
|
||||||
|
return Err(OlmError::MissingCiphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
let signing_key = keys
|
||||||
|
.get(&KeyAlgorithm::Ed25519)
|
||||||
|
.ok_or(OlmError::MissingSigningKey)?;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
serde_json::from_value::<EventResult<ToDeviceEvent>>(decrypted_json)?,
|
||||||
|
signing_key.to_owned(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decrypt a to-device event.
|
/// Decrypt a to-device event.
|
||||||
|
@ -820,15 +867,19 @@ impl OlmMachine {
|
||||||
.map_err(|_| OlmError::UnsupportedOlmType)?;
|
.map_err(|_| OlmError::UnsupportedOlmType)?;
|
||||||
|
|
||||||
// Decrypt the OlmMessage and get a Ruma event out of it.
|
// Decrypt the OlmMessage and get a Ruma event out of it.
|
||||||
let mut decrypted_event = self
|
let (mut decrypted_event, signing_key) = self
|
||||||
.decrypt_olm_message(&event.sender.to_string(), &content.sender_key, message)
|
.decrypt_olm_message(&event.sender, &content.sender_key, message)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
debug!("Decrypted a to-device event {:?}", decrypted_event);
|
debug!("Decrypted a to-device event {:?}", decrypted_event);
|
||||||
|
|
||||||
// Handle the decrypted event, e.g. fetch out megolm sessions out of
|
// Handle the decrypted event, e.g. fetch out megolm sessions out of
|
||||||
// the event.
|
// the event.
|
||||||
self.handle_decrypted_to_device_event(&content.sender_key, &mut decrypted_event)
|
self.handle_decrypted_to_device_event(
|
||||||
|
&content.sender_key,
|
||||||
|
&signing_key,
|
||||||
|
&mut decrypted_event,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(decrypted_event)
|
Ok(decrypted_event)
|
||||||
|
@ -838,14 +889,14 @@ impl OlmMachine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_room_key(&mut self, sender_key: &str, event: &mut ToDeviceRoomKey) -> Result<()> {
|
async fn add_room_key(
|
||||||
|
&mut self,
|
||||||
|
sender_key: &str,
|
||||||
|
signing_key: &str,
|
||||||
|
event: &mut ToDeviceRoomKey,
|
||||||
|
) -> Result<()> {
|
||||||
match event.content.algorithm {
|
match event.content.algorithm {
|
||||||
Algorithm::MegolmV1AesSha2 => {
|
Algorithm::MegolmV1AesSha2 => {
|
||||||
let signing_key = event
|
|
||||||
.keys
|
|
||||||
.get("ed25519")
|
|
||||||
.ok_or(OlmError::MissingSigningKey)?;
|
|
||||||
|
|
||||||
let session_key = GroupSessionKey(mem::take(&mut event.content.session_key));
|
let session_key = GroupSessionKey(mem::take(&mut event.content.session_key));
|
||||||
|
|
||||||
let session = InboundGroupSession::new(
|
let session = InboundGroupSession::new(
|
||||||
|
@ -1101,6 +1152,7 @@ impl OlmMachine {
|
||||||
fn add_forwarded_room_key(
|
fn add_forwarded_room_key(
|
||||||
&self,
|
&self,
|
||||||
_sender_key: &str,
|
_sender_key: &str,
|
||||||
|
_signing_key: &str,
|
||||||
_event: &ToDeviceForwardedRoomKey,
|
_event: &ToDeviceForwardedRoomKey,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1110,6 +1162,7 @@ impl OlmMachine {
|
||||||
async fn handle_decrypted_to_device_event(
|
async fn handle_decrypted_to_device_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
sender_key: &str,
|
sender_key: &str,
|
||||||
|
signing_key: &str,
|
||||||
event: &mut EventResult<ToDeviceEvent>,
|
event: &mut EventResult<ToDeviceEvent>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let event = if let EventResult::Ok(e) = event {
|
let event = if let EventResult::Ok(e) = event {
|
||||||
|
@ -1120,8 +1173,10 @@ impl OlmMachine {
|
||||||
};
|
};
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
ToDeviceEvent::RoomKey(e) => self.add_room_key(sender_key, e).await,
|
ToDeviceEvent::RoomKey(e) => self.add_room_key(sender_key, signing_key, e).await,
|
||||||
ToDeviceEvent::ForwardedRoomKey(e) => self.add_forwarded_room_key(sender_key, e),
|
ToDeviceEvent::ForwardedRoomKey(e) => {
|
||||||
|
self.add_forwarded_room_key(sender_key, signing_key, e)
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
warn!("Received a unexpected encrypted to-device event");
|
warn!("Received a unexpected encrypted to-device event");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in New Issue