crypto: Ignore key verification requests that have an invalid timestamp

master
Damir Jelić 2021-06-08 14:54:20 +02:00
parent c4b1d3bc44
commit 533a5b92b0
2 changed files with 64 additions and 12 deletions

View File

@ -35,6 +35,7 @@ use ruma::{
}, },
identifiers::{DeviceId, RoomId, UserId}, identifiers::{DeviceId, RoomId, UserId},
serde::CanonicalJsonValue, serde::CanonicalJsonValue,
MilliSecondsSinceUnixEpoch,
}; };
use super::FlowId; use super::FlowId;
@ -53,6 +54,16 @@ impl AnyEvent<'_> {
} }
} }
pub fn timestamp(&self) -> Option<&MilliSecondsSinceUnixEpoch> {
match self {
AnyEvent::Room(e) => Some(e.origin_server_ts()),
AnyEvent::ToDevice(e) => match e {
AnyToDeviceEvent::KeyVerificationRequest(e) => Some(&e.content.timestamp),
_ => None,
},
}
}
pub fn verification_content(&self) -> Option<AnyVerificationContent> { pub fn verification_content(&self) -> Option<AnyVerificationContent> {
match self { match self {
AnyEvent::Room(e) => match e { AnyEvent::Room(e) => match e {

View File

@ -16,8 +16,8 @@ use std::{convert::TryFrom, sync::Arc};
use dashmap::DashMap; use dashmap::DashMap;
use matrix_sdk_common::{locks::Mutex, uuid::Uuid}; use matrix_sdk_common::{locks::Mutex, uuid::Uuid};
use ruma::{DeviceId, UserId}; use ruma::{uint, DeviceId, MilliSecondsSinceUnixEpoch, UInt, UserId};
use tracing::{info, warn}; use tracing::{info, trace, warn};
use super::{ use super::{
cache::VerificationCache, cache::VerificationCache,
@ -98,6 +98,30 @@ impl VerificationMachine {
self.verifications.get_sas(transaction_id) self.verifications.get_sas(transaction_id)
} }
#[cfg(not(target_arch = "wasm32"))]
fn is_timestamp_valid(timestamp: &MilliSecondsSinceUnixEpoch) -> bool {
// The event should be ignored if the event is older than 10 minutes
let old_timestamp_threshold: UInt = uint!(600);
// The event should be ignored if the event is 5 minutes or more into the
// future.
let timestamp_threshold: UInt = uint!(300);
let timestamp = timestamp.as_secs();
let now = MilliSecondsSinceUnixEpoch::now().as_secs();
!(now.saturating_sub(timestamp) > old_timestamp_threshold
|| timestamp.saturating_sub(now) > timestamp_threshold)
}
#[cfg(target_arch = "wasm32")]
fn is_timestamp_valid(timestamp: &MilliSecondsSinceUnixEpoch) -> bool {
// TODO the non-wasm method with the same name uses
// `MilliSecondsSinceUnixEpoch::now()` which internally uses
// `SystemTime::now()` this panics under WASM, thus we're returning here
// true for now.
true
}
fn queue_up_content( fn queue_up_content(
&self, &self,
recipient: &UserId, recipient: &UserId,
@ -184,6 +208,8 @@ impl VerificationMachine {
"Received a new verification request", "Received a new verification request",
); );
if let Some(timestamp) = event.timestamp() {
if Self::is_timestamp_valid(timestamp) {
let request = VerificationRequest::from_request( let request = VerificationRequest::from_request(
self.verifications.clone(), self.verifications.clone(),
self.account.clone(), self.account.clone(),
@ -195,6 +221,21 @@ impl VerificationMachine {
); );
self.requests.insert(request.flow_id().as_str().to_owned(), request); self.requests.insert(request.flow_id().as_str().to_owned(), request);
} else {
trace!(
sender = event.sender().as_str(),
from_device = r.from_device().as_str(),
timestamp =? timestamp,
"The received verification request was too old or too far into the future",
);
}
} else {
warn!(
sender = event.sender().as_str(),
from_device = r.from_device().as_str(),
"The key verification request didn't contain a valid timestamp"
);
}
} }
AnyVerificationContent::Cancel(c) => { AnyVerificationContent::Cancel(c) => {
if let Some(verification) = self.get_request(flow_id.as_str()) { if let Some(verification) = self.get_request(flow_id.as_str()) {