Skip to main content

tuwunel_service/server_keys/
get.rs

1//! Retrieval of cached and remote federation verify keys.
2//!
3//! Event signature requirements are translated into ruma public-key maps.
4//! Individual keys can fall back from the cache to trusted notaries and the
5//! origin server according to configuration.
6
7use std::borrow::Borrow;
8
9use ruma::{
10	CanonicalJsonObject, ServerName, ServerSigningKeyId, api::federation::discovery::VerifyKey,
11	room_version_rules::RoomVersionRules,
12};
13use tuwunel_core::{Err, Result, implement};
14
15use super::{PubKeyMap, PubKeys, extract_key};
16
17/// Resolves the public keys required to verify an event.
18///
19/// Invalid signature metadata returns an error. Fetch failures for individual
20/// keys are omitted, so a successful result can still be a partial key map.
21#[implement(super::Service)]
22pub async fn get_event_keys(
23	&self,
24	object: &CanonicalJsonObject,
25	version: &RoomVersionRules,
26) -> Result<PubKeyMap> {
27	use ruma::signatures::required_keys;
28
29	let required = match required_keys(object, &version.signatures) {
30		| Ok(required) => required,
31		| Err(e) => {
32			return Err!(BadServerResponse("Failed to determine keys required to verify: {e}"));
33		},
34	};
35
36	let batch = required
37		.iter()
38		.map(|(s, ids)| (s.borrow(), ids.iter().map(Borrow::borrow)));
39
40	Ok(self.get_pubkeys(batch).await)
41}
42
43/// Resolves public-key sets for a batch of servers and key IDs.
44///
45/// Every requested server is inserted, even when its key set is empty.
46/// Individual key errors are suppressed by [`Self::get_pubkeys_for`].
47#[implement(super::Service)]
48pub async fn get_pubkeys<'a, S, K>(&self, batch: S) -> PubKeyMap
49where
50	S: Iterator<Item = (&'a ServerName, K)> + Send,
51	K: Iterator<Item = &'a ServerSigningKeyId> + Send,
52{
53	let mut keys = PubKeyMap::new();
54	for (server, key_ids) in batch {
55		let pubkeys = self.get_pubkeys_for(server, key_ids).await;
56		keys.insert(server.as_str().into(), pubkeys);
57	}
58
59	keys
60}
61
62/// Resolves the requested public keys for one server.
63///
64/// Keys that cannot be loaded or fetched are omitted, making the returned set
65/// intentionally partial rather than failing the whole request.
66#[implement(super::Service)]
67pub async fn get_pubkeys_for<'a, I>(&self, origin: &ServerName, key_ids: I) -> PubKeys
68where
69	I: Iterator<Item = &'a ServerSigningKeyId> + Send,
70{
71	let mut keys = PubKeys::new();
72	for key_id in key_ids {
73		if let Ok(verify_key) = self.get_verify_key(origin, key_id).await {
74			keys.insert(key_id.as_str().into(), verify_key.key);
75		}
76	}
77
78	keys
79}
80
81/// Retrieves one current or retired verify key for a server.
82///
83/// The cache is checked first. Trusted notaries and the origin are then queried
84/// in configured order, with origin requests disabled in notary-only mode.
85#[implement(super::Service)]
86pub async fn get_verify_key(
87	&self,
88	origin: &ServerName,
89	key_id: &ServerSigningKeyId,
90) -> Result<VerifyKey> {
91	let notary_first = self
92		.services
93		.server
94		.config
95		.query_trusted_key_servers_first;
96
97	let notary_only = self
98		.services
99		.server
100		.config
101		.only_query_trusted_key_servers;
102
103	if let Some(result) = self.verify_keys_for(origin).await.remove(key_id) {
104		return Ok(result);
105	}
106
107	if notary_first
108		&& let Ok(result) = self
109			.get_verify_key_from_notaries(origin, key_id)
110			.await
111	{
112		return Ok(result);
113	}
114
115	if !notary_only
116		&& let Ok(result) = self
117			.get_verify_key_from_origin(origin, key_id)
118			.await
119	{
120		return Ok(result);
121	}
122
123	if !notary_first
124		&& let Ok(result) = self
125			.get_verify_key_from_notaries(origin, key_id)
126			.await
127	{
128		return Ok(result);
129	}
130
131	Err!(BadServerResponse(debug_error!(
132		?key_id,
133		?origin,
134		"Failed to fetch federation signing-key"
135	)))
136}
137
138#[implement(super::Service)]
139async fn get_verify_key_from_notaries(
140	&self,
141	origin: &ServerName,
142	key_id: &ServerSigningKeyId,
143) -> Result<VerifyKey> {
144	for notary in &self.services.config.trusted_servers {
145		if let Ok(server_keys) = self.notary_request(notary, origin).await {
146			for server_key in server_keys.clone() {
147				self.add_signing_keys(server_key).await;
148			}
149
150			for server_key in server_keys {
151				if let Some(result) = extract_key(server_key, key_id) {
152					return Ok(result);
153				}
154			}
155		}
156	}
157
158	Err!(Request(NotFound("Failed to fetch signing-key from notaries")))
159}
160
161#[implement(super::Service)]
162async fn get_verify_key_from_origin(
163	&self,
164	origin: &ServerName,
165	key_id: &ServerSigningKeyId,
166) -> Result<VerifyKey> {
167	if let Ok(server_key) = self.server_request(origin).await {
168		self.add_signing_keys(server_key.clone()).await;
169		if let Some(result) = extract_key(server_key, key_id) {
170			return Ok(result);
171		}
172	}
173
174	Err!(Request(NotFound("Failed to fetch signing-key from origin")))
175}