1use axum::extract::State;
2use ruma::{
3 UserId,
4 api::client::{
5 keys::upload_signing_keys,
6 uiaa::{AuthFlow, AuthType, UiaaInfo},
7 },
8 encryption::{CrossSigningKey, KeyUsage},
9 serde::Raw,
10};
11use serde_json::{json, value::to_raw_value};
12use tuwunel_core::{
13 Err, Error, Result, debug, debug_error, err,
14 result::NotFound,
15 utils,
16 utils::{BoolExt, OptionExt},
17};
18use tuwunel_service::{Services, uiaa::SESSION_ID_LENGTH, users::parse_master_key};
19
20use crate::{Ruma, router::auth_uiaa};
21
22struct Keys<'a> {
23 user_id: &'a UserId,
24 master_key: &'a Option<Raw<CrossSigningKey>>,
25 self_signing_key: &'a Option<Raw<CrossSigningKey>>,
26 user_signing_key: &'a Option<Raw<CrossSigningKey>>,
27}
28
29struct ValidatedKeys<'a>(Keys<'a>);
30
31pub(crate) async fn upload_signing_keys_route(
40 State(services): State<crate::State>,
41 body: Ruma<upload_signing_keys::v3::Request>,
42) -> Result<upload_signing_keys::v3::Response> {
43 let sender_user = body.sender_user();
44
45 if body
46 .auth
47 .as_ref()
48 .is_some_and(|auth| auth.session().is_some())
49 && body.master_key.is_none()
50 && body.self_signing_key.is_none()
51 && body.user_signing_key.is_none()
52 {
53 return Err!(Request(MissingParam(
54 "Signing keys are unavailable. Retry with the full request body."
55 )));
56 }
57
58 let keys = validate_keys(Keys {
59 user_id: sender_user,
60 master_key: &body.master_key,
61 self_signing_key: &body.self_signing_key,
62 user_signing_key: &body.user_signing_key,
63 })?;
64
65 if let Ok(exists) = check_for_new_keys(
68 &services,
69 sender_user,
70 body.self_signing_key.as_ref(),
71 body.user_signing_key.as_ref(),
72 body.master_key.as_ref(),
73 )
74 .await
75 .inspect_err(|e| debug_error!(?e))
76 {
77 if let Some(result) = exists {
78 return Ok(result);
81 }
82
83 debug!("Skipping UIA as per MSC3967: user had no existing keys");
85 return persist_signing_keys(&services, keys).await;
86 }
87
88 if body
91 .appservice_info
92 .as_ref()
93 .is_some_and(|appservice| appservice.registration.device_management)
94 {
95 debug!(
96 "Skipping UIAA for {sender_user} as this is from an appservice and MSC4190 is \
97 enabled"
98 );
99
100 return persist_signing_keys(&services, keys).await;
101 }
102
103 let is_oidc = body
104 .sender_device()
105 .ok()
106 .map_async(|sender_device| {
107 services
108 .users
109 .is_oidc_device(sender_user, sender_device)
110 })
111 .await
112 .unwrap_or(false);
113
114 if is_oidc
117 && services
118 .users
119 .can_replace_cross_signing_keys(sender_user)
120 .await
121 {
122 return persist_signing_keys(&services, keys).await;
123 }
124
125 if is_oidc && body.auth.is_none() {
127 return Err(Error::Uiaa(create_oauth_uiaa(&services, sender_user, &body)?));
128 }
129
130 let authed_user = auth_uiaa(&services, &body).await?;
131
132 assert_eq!(sender_user, authed_user, "Expected UIAA of {sender_user} and not {authed_user}");
133 persist_signing_keys(&services, keys).await
134}
135
136fn validate_keys(keys: Keys<'_>) -> Result<ValidatedKeys<'_>> {
137 [
138 (keys.master_key.as_ref(), KeyUsage::Master),
139 (keys.self_signing_key.as_ref(), KeyUsage::SelfSigning),
140 (keys.user_signing_key.as_ref(), KeyUsage::UserSigning),
141 ]
142 .into_iter()
143 .try_for_each(|(key, usage)| validate_key(keys.user_id, key, &usage))?;
144
145 Ok(ValidatedKeys(keys))
146}
147
148fn validate_key(
149 user_id: &UserId,
150 key: Option<&Raw<CrossSigningKey>>,
151 usage: &KeyUsage,
152) -> Result {
153 let Some(key) = key else {
154 return Ok(());
155 };
156
157 let key = key
158 .deserialize()
159 .map_err(|error| err!(Request(InvalidParam("Invalid cross-signing key: {error}"))))?;
160
161 if key.user_id != user_id {
162 return Err!(Request(InvalidParam("Cross-signing key belongs to another user.")));
163 }
164
165 if !key.usage.contains(usage) {
166 return Err!(Request(InvalidParam(
167 "Cross-signing key does not include the required usage."
168 )));
169 }
170
171 if key.keys.len() != 1 {
172 return Err!(Request(InvalidParam("Cross-signing key must contain exactly one key.")));
173 }
174
175 Ok(())
176}
177
178async fn persist_signing_keys(
179 services: &Services,
180 keys: ValidatedKeys<'_>,
181) -> Result<upload_signing_keys::v3::Response> {
182 let ValidatedKeys(keys) = keys;
183
184 services
185 .users
186 .add_cross_signing_keys(
187 keys.user_id,
188 keys.master_key,
189 keys.self_signing_key,
190 keys.user_signing_key,
191 true, )
193 .await?;
194
195 Ok(upload_signing_keys::v3::Response {})
196}
197
198fn create_oauth_uiaa(
199 services: &Services,
200 sender_user: &UserId,
201 body: &Ruma<upload_signing_keys::v3::Request>,
202) -> Result<UiaaInfo> {
203 let session = utils::random_string(SESSION_ID_LENGTH);
204 let issuer = services.oauth.get_server()?.issuer_url()?;
205 let base = issuer.trim_end_matches('/');
206 let url = format!("{base}/_tuwunel/oidc/account?action=org.matrix.cross_signing_reset");
207
208 let uiaainfo = UiaaInfo {
209 flows: vec![AuthFlow { stages: vec![AuthType::OAuth] }],
210 params: Some(to_raw_value(&json!({"m.oauth": { "url": url }}))?),
211 session: Some(session),
212 ..Default::default()
213 };
214
215 services.uiaa.create(
216 sender_user,
217 body.sender_device()?,
218 &uiaainfo,
219 body.json_body
220 .as_ref()
221 .ok_or_else(|| err!(Request(NotJson("JSON body is not valid"))))?,
222 );
223
224 Ok(uiaainfo)
225}
226
227async fn check_for_new_keys(
228 services: &Services,
229 user_id: &UserId,
230 self_signing_key: Option<&Raw<CrossSigningKey>>,
231 user_signing_key: Option<&Raw<CrossSigningKey>>,
232 master_signing_key: Option<&Raw<CrossSigningKey>>,
233) -> Result<Option<upload_signing_keys::v3::Response>> {
234 debug!("checking for existing keys");
235
236 let empty = match master_signing_key {
237 | Some(new_master) => !master_key_matches(services, user_id, new_master).await?,
238 | None => false,
239 };
240
241 if let Some(new_user_signing) = user_signing_key {
242 let fetched = services.users.get_user_signing_key(user_id).await;
243
244 if fetched.is_not_found() {
245 if !empty {
246 return Err!(Request(Forbidden(
247 "Tried to update an existing user signing key, UIA required"
248 )));
249 }
250 } else if fetched?.deserialize()? != new_user_signing.deserialize()? {
251 return Err!(Request(Forbidden(
252 "Tried to change an existing user signing key, UIA required"
253 )));
254 }
255 }
256
257 if let Some(new_self_signing) = self_signing_key {
258 let fetched = services
259 .users
260 .get_self_signing_key(None, user_id, &|_| true)
261 .await;
262
263 if fetched.is_not_found() {
264 if !empty {
265 return Err!(Request(Forbidden(
266 "Tried to add a new signing key independently from the master key"
267 )));
268 }
269 } else if fetched?.deserialize()? != new_self_signing.deserialize()? {
270 return Err!(Request(Forbidden(
271 "Tried to update an existing self signing key, UIA required"
272 )));
273 }
274 }
275
276 Ok(empty
277 .is_false()
278 .into_option()
279 .map(|()| upload_signing_keys::v3::Response {}))
280}
281
282async fn master_key_matches(
286 services: &Services,
287 user_id: &UserId,
288 new_master_key: &Raw<CrossSigningKey>,
289) -> Result<bool> {
290 let (new_row_key, new_value) = parse_master_key(user_id, new_master_key)?;
291 let existing = services
292 .users
293 .get_master_key(None, user_id, &|_| true)
294 .await;
295
296 if existing.is_not_found() {
297 return Ok(false);
298 }
299
300 let (existing_row_key, existing_value) = parse_master_key(user_id, &existing?)?;
301
302 if existing_row_key != new_row_key || existing_value != new_value {
303 return Err!(Request(Forbidden("Tried to change an existing master key, UIA required")));
304 }
305
306 Ok(true)
307}
308
309#[cfg(test)]
310mod tests {
311 use ruma::{api::error::ErrorKind::InvalidParam, user_id};
312 use serde_json::Map;
313
314 use super::*;
315
316 #[test]
317 fn accepts_valid_unsigned_keys_and_additional_usages() {
318 let user_id = user_id!("@alice:example.com");
319 let master_key =
320 Some(signing_key(user_id, &["master", "self_signing"], &["ed25519:master"]));
321
322 let self_signing_key =
323 Some(signing_key(user_id, &["self_signing", "user_signing"], &["ed25519:self"]));
324
325 let user_signing_key =
326 Some(signing_key(user_id, &["user_signing", "master"], &["ed25519:user"]));
327
328 validate_keys(Keys {
329 user_id,
330 master_key: &master_key,
331 self_signing_key: &self_signing_key,
332 user_signing_key: &user_signing_key,
333 })
334 .expect("valid unsigned keys should pass structural validation");
335 }
336
337 #[test]
338 fn rejects_wrong_owner_for_each_role() {
339 let user_id = user_id!("@alice:example.com");
340 let other_user = user_id!("@mallory:elsewhere.example");
341 let none = None;
342 let master_key = Some(signing_key(other_user, &["master"], &["ed25519:master"]));
343 let self_signing_key =
344 Some(signing_key(other_user, &["self_signing"], &["ed25519:self"]));
345
346 let user_signing_key =
347 Some(signing_key(other_user, &["user_signing"], &["ed25519:user"]));
348
349 assert_invalid(&validate_keys(Keys {
350 user_id,
351 master_key: &master_key,
352 self_signing_key: &none,
353 user_signing_key: &none,
354 }));
355
356 assert_invalid(&validate_keys(Keys {
357 user_id,
358 master_key: &none,
359 self_signing_key: &self_signing_key,
360 user_signing_key: &none,
361 }));
362
363 assert_invalid(&validate_keys(Keys {
364 user_id,
365 master_key: &none,
366 self_signing_key: &none,
367 user_signing_key: &user_signing_key,
368 }));
369 }
370
371 #[test]
372 fn rejects_missing_usage_for_each_role() {
373 let user_id = user_id!("@alice:example.com");
374 let none = None;
375 let master_key = Some(signing_key(user_id, &["self_signing"], &["ed25519:master"]));
376 let self_signing_key = Some(signing_key(user_id, &["master"], &["ed25519:self"]));
377 let user_signing_key = Some(signing_key(user_id, &["master"], &["ed25519:user"]));
378
379 assert_invalid(&validate_keys(Keys {
380 user_id,
381 master_key: &master_key,
382 self_signing_key: &none,
383 user_signing_key: &none,
384 }));
385
386 assert_invalid(&validate_keys(Keys {
387 user_id,
388 master_key: &none,
389 self_signing_key: &self_signing_key,
390 user_signing_key: &none,
391 }));
392
393 assert_invalid(&validate_keys(Keys {
394 user_id,
395 master_key: &none,
396 self_signing_key: &none,
397 user_signing_key: &user_signing_key,
398 }));
399 }
400
401 #[test]
402 fn rejects_invalid_key_counts() {
403 let user_id = user_id!("@alice:example.com");
404 let none = None;
405 let empty = Some(signing_key(user_id, &["master"], &[]));
406 let multiple =
407 Some(signing_key(user_id, &["self_signing"], &["ed25519:first", "ed25519:second"]));
408
409 assert_invalid(&validate_keys(Keys {
410 user_id,
411 master_key: &empty,
412 self_signing_key: &none,
413 user_signing_key: &none,
414 }));
415
416 assert_invalid(&validate_keys(Keys {
417 user_id,
418 master_key: &none,
419 self_signing_key: &multiple,
420 user_signing_key: &none,
421 }));
422 }
423
424 #[test]
425 fn rejects_a_malformed_later_key_before_persistence() {
426 let user_id = user_id!("@alice:example.com");
427 let master_key = Some(signing_key(user_id, &["master"], &["ed25519:master"]));
428 let self_signing_key = Some(signing_key(user_id, &["self_signing"], &["ed25519:self"]));
429 let user_signing_key = Some(signing_key(user_id, &["master"], &["ed25519:user"]));
430
431 assert_invalid(&validate_keys(Keys {
432 user_id,
433 master_key: &master_key,
434 self_signing_key: &self_signing_key,
435 user_signing_key: &user_signing_key,
436 }));
437 }
438
439 fn signing_key(user_id: &UserId, usage: &[&str], key_ids: &[&str]) -> Raw<CrossSigningKey> {
440 let keys: Map<_, _> = key_ids
441 .iter()
442 .map(|key_id| ((*key_id).to_owned(), json!("public-key")))
443 .collect();
444
445 let key = json!({
446 "user_id": user_id,
447 "usage": usage,
448 "keys": keys,
449 });
450
451 Raw::from_json(to_raw_value(&key).expect("cross-signing key should serialize"))
452 }
453
454 fn assert_invalid(result: &Result<ValidatedKeys<'_>>) {
455 assert!(matches!(result, Err(Error::Request(InvalidParam, ..))));
456 }
457}