fix: SEC8

Reviewed-By: Ginger <ginger@gingershaped.computer>
Reviewed-By: Jade <jade@ellis.link>
Reviewed-By: Jacob Taylor <jacob@explodie.org>
This commit is contained in:
timedout committed 2026-09-28 02:00:37 +01:00
1 parent c0ad864d57
commit 550dd0160a
33 files changed
+1420 -848

No files matched your search

-4
View File
@@ -200,10 +200,6 @@ pub fn build(router: Router<State>, state: State) -> Router<State> {
router = router
.ruma_route(&server::get_server_version_route)
.route("/_matrix/key/v2/server", get(server::get_server_keys_route))
.route(
"/_matrix/key/v2/server/{key_id}",
get(server::get_server_keys_deprecated_route),
)
.ruma_route(&server::get_public_rooms_route)
.ruma_route(&server::get_public_rooms_filtered_route)
.ruma_route(&server::send_transaction_message_route)
+18 -7
View File
@@ -1,9 +1,13 @@
use std::any::{Any, TypeId};
use conduwuit::{Err, Error, Result, err, utils::IterStream};
use conduwuit::{
Err, Error, Result, err,
utils::{IterStream, millis_since_unix_epoch},
};
use http::StatusCode;
use ruma::{
DeviceId, OwnedDeviceId, OwnedServerName, OwnedUserId, UserId,
DeviceId, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedServerName, OwnedUserId, UInt,
UserId,
api::{
IncomingRequest,
auth_scheme::{
@@ -127,12 +131,18 @@ impl CheckAuth for ServerSignatures {
return Err!(Request(Unauthorized("Destination mismatch.")));
}
let min_valid_ts =
MilliSecondsSinceUnixEpoch(UInt::new_saturating(millis_since_unix_epoch()));
let key = services
.server_keys
.get_verify_key(&output.origin, &output.key)
.get_single_verify_key(&output.origin, &output.key, min_valid_ts)
.await
.map_err(|e| {
err!(Request(Unauthorized(warn!("Failed to fetch signing keys: {e}"))))
.ok_or_else(|| {
err!(Request(Unauthorized(debug_warn!(
origin=%output.origin,
"Unable to acquire your signing key (ID: {})",
output.key
))))
})?;
let keys: PubKeys = [(output.key.to_string(), key.key)].into();
@@ -160,8 +170,9 @@ impl CheckAuth for ServerSignatures {
Ok(output.origin)
},
| Err(err) =>
Err!(Request(Unauthorized(warn!("Failed to verify X-Matrix header: {err}")))),
| Err(err) => Err!(Request(Unauthorized(debug_warn!(
"Failed to verify X-Matrix header: {err}"
)))),
}
}
}
+1 -1
View File
@@ -324,7 +324,7 @@ async fn validate_invite_state(
services
.server_keys
.verify_event(&state_event_json, room_version_rules)
.verify_event_json(&state_event_json, room_version_rules)
.await
.map_err(|e| {
err!(Request(InvalidParam("Signature verification failed on invite event: {e}")))
+48 -38
View File
@@ -1,10 +1,8 @@
use std::{
mem::take,
time::{Duration, SystemTime},
};
use std::{collections::BTreeMap, mem::take, time::Duration};
use axum::{Json, extract::State, response::IntoResponse};
use conduwuit::{Result, utils::timepoint_from_now};
use futures::StreamExt;
use ruma::{
MilliSecondsSinceUnixEpoch,
api::{
@@ -14,33 +12,62 @@ use ruma::{
assign,
serde::Raw,
};
use service::{server_keys, server_keys::in_one_week};
/// # `GET /_matrix/key/v2/server`
///
/// Gets the public signing keys of this server.
///
/// - Matrix does not support invalidating public keys, so the key returned by
/// this will be valid forever.
// Response type for this endpoint is Json because we need to calculate a
// signature for the response
pub(crate) async fn get_server_keys_route(
State(services): State<crate::State>,
) -> Result<impl IntoResponse> {
let server_name = services.globals.server_name();
let active_key_id = services.server_keys.active_key_id();
let mut all_keys = services.server_keys.verify_keys_for(server_name).await;
let verify_keys = BTreeMap::from([services.server_keys.active_verify_key()]);
let verify_keys = all_keys
.remove_entry(active_key_id)
.expect("active verify_key is missing");
let old_verify_keys = all_keys
.into_iter()
.map(|(id, key)| (id, OldVerifyKey::new(expires_ts(), key.key)))
.collect();
let old_verify_keys = if let Some(k) = &services.config.old_verify_keys {
k.to_owned()
} else {
// We need to figure out any old signing keys we've acquired from
// notaries.
let mut keys = services.server_keys.signing_keys_for(server_name);
let mut old_keys = BTreeMap::new();
while let Some(resp) = keys.next().await {
// We need to verify that this response is still trusted based on
// the current configuration. It's possible we got this response
// from a notary who we no longer trust.
if resp.valid_until_ts > in_one_week() {
continue;
}
let trusted = services.config.trusted_servers.iter().any(|notary| {
server_keys::Service::verify_server_keys_response(
&resp,
Some((notary.server_name(), notary.verify_keys())),
)
.is_ok()
});
if !trusted {
continue;
}
for (old_key_id, old_key) in resp.old_verify_keys {
if old_key.expired_ts > resp.valid_until_ts {
// This key expired in the future which is probably illegal
continue;
}
old_keys
.entry(old_key_id)
.and_modify(|current_old_key: &mut OldVerifyKey| {
// Use the lowest expiry timestamp
if current_old_key.expired_ts > old_key.expired_ts {
*current_old_key = old_key.clone();
}
})
.or_insert(old_key);
}
}
old_keys
};
let server_key = assign!(ServerSigningKeys::new(server_name.to_owned(), valid_until_ts()), {
verify_keys: [verify_keys].into(),
verify_keys,
old_verify_keys,
});
@@ -56,24 +83,7 @@ pub(crate) async fn get_server_keys_route(
}
fn valid_until_ts() -> MilliSecondsSinceUnixEpoch {
let dur = Duration::from_hours(168);
let dur = Duration::from_hours(12);
let timepoint = timepoint_from_now(dur).expect("SystemTime should not overflow");
MilliSecondsSinceUnixEpoch::from_system_time(timepoint).expect("UInt should not overflow")
}
fn expires_ts() -> MilliSecondsSinceUnixEpoch {
let timepoint = SystemTime::now();
MilliSecondsSinceUnixEpoch::from_system_time(timepoint).expect("UInt should not overflow")
}
/// # `GET /_matrix/key/v2/server/{keyId}`
///
/// Gets the public signing keys of this server.
///
/// - Matrix does not support invalidating public keys, so the key returned by
/// this will be valid forever.
pub(crate) async fn get_server_keys_deprecated_route(
State(services): State<crate::State>,
) -> impl IntoResponse {
get_server_keys_route(State(services)).await
}
+1 -1
View File
@@ -142,7 +142,7 @@ pub(crate) async fn validate_any_membership_event(
services
.server_keys
.verify_event(&pdu, room_version_rules)
.verify_event_json(&pdu, room_version_rules)
.await
.map_err(|e| {
err!(Request(InvalidParam("Signature verification failed on membership event: {e}")))