Skip to main content

arminius_server_client/handlers/
signatures.rs

1// SPDX-FileCopyrightText: 2025 BWI GmbH
2//
3// SPDX-License-Identifier: Apache-2.0
4
5//! Implements the signature upload endpoint (See
6//! <https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3keyssignaturesupload>).
7//!
8//! This endpoint is quite complex in that it requires many checks in order to
9//! be done properly. This is why it got its dedicated module.
10
11#![allow(
12	clippy::allow_attributes,
13	reason = "This source file contains enums which allow `clippy::missing_docs_in_private_items`. But an exception to this lint will mistakenly report that it's unfulfilled when used with expect, even though it is not."
14)]
15
16use std::collections::BTreeMap;
17
18use arminius_lib_authentication::SessionInfo;
19use arminius_lib_component::{
20	Component, ServerState,
21	error::{
22		BadJson, InputJsonError, InternalServerError, MatrixApiError, ResultExt as _,
23		create_custom_matrix_error,
24	},
25	ruma_requests::ArminiusResponse,
26};
27use arminius_lib_db::{Database as _, DefaultDb};
28use arminius_lib_db_keys::{CrossSigningKeyRow, DeviceKeysRow};
29use arminius_lib_db_signatures::LocalSignatureQueries as _;
30use arminius_lib_model::user_keys::DbKeyType;
31use arminius_lib_user_keys::{
32	identity_keys::get_local_keys,
33	signatures::{RequiredSigners, SignatureVerificationError, verify_signatures},
34	traits::{SignedObject, SigningKey as _},
35};
36use axum::{Router, extract::State, http::StatusCode, routing::post};
37use itertools::Itertools as _;
38use ruma::{
39	Base64PublicKeyOrDeviceId, OwnedCrossSigningOrDeviceSigningKeyId, OwnedDeviceId, OwnedUserId,
40	UserId,
41	api::{
42		client::keys::upload_signatures,
43		error::{Error as MatrixError, ErrorCode, ErrorKind},
44	},
45	encryption::{CrossSigningKey, DeviceKeys, KeyUsage},
46	serde::{Base64, base64},
47	signatures::PublicKeyMap,
48};
49
50use crate::client_request::AuthenticatedClientRequest;
51
52/// Thrown when a signature is not valid
53#[derive(Debug, thiserror::Error)]
54#[error("Invalid signature: {0}")]
55pub struct SignatureError(String);
56
57// Manually implemented, because `ErrorKind` does not agree with custom error
58// codes.
59impl MatrixApiError for SignatureError {
60	fn create_matrix_error(&self) -> MatrixError {
61		create_custom_matrix_error(
62			StatusCode::BAD_REQUEST,
63			"M_INVALID_SIGNATURE",
64			&self.to_string(),
65		)
66	}
67}
68
69/// Converts a [`SignatureVerificationError`] into a [`SignaturesUploadError`]
70/// so that it can be returned as Matrix error.
71impl From<SignatureVerificationError> for SignaturesUploadError {
72	fn from(signature_error: SignatureVerificationError) -> Self {
73		match signature_error {
74			SignatureVerificationError::BadJson(bad_json) => {
75				Self::InputJsonError(InputJsonError::BadJson(bad_json))
76			}
77			other_error => Self::SignatureVerification(SignatureError(other_error.to_string())),
78		}
79	}
80}
81
82#[allow(
83	clippy::missing_docs_in_private_items,
84	reason = "TODO(#2003): This exception predates us enabling `clippy::allow_attributes_without_reason`, so we don't know why it was enabled"
85)]
86#[derive(Debug, thiserror::Error, MatrixApiError)]
87enum SignaturesUploadError {
88	#[error(transparent)]
89	InternalServerError(#[from] InternalServerError),
90
91	#[error(transparent)]
92	InputJsonError(#[from] InputJsonError),
93
94	/// Thrown when a signature is not valid base64
95	#[error("Invalid base64: {0}")]
96	#[matrix_api_error(status_code = StatusCode::BAD_REQUEST, error_kind = ErrorKind::Unknown)]
97	InvalidBase64(#[from] ruma::serde::Base64DecodeError),
98
99	#[error(transparent)]
100	SignatureVerification(#[from] SignatureError),
101}
102
103/// Helper function that generates a [`upload_signatures::v3::Failure`]. These
104/// are returned by the `upload_keys_signature` endpoint.
105fn new_failure(
106	errcode: &ErrorCode,
107	message: &str,
108) -> Result<upload_signatures::v3::Failure, InternalServerError> {
109	serde_json::from_str(&format!("{{\"errcode\":\"{}\",\"error\":\"{}\"}}", errcode, message))
110		.unrecoverable_error("Failed to create Failure")
111}
112
113/// Map from user ID to a map from key ID (string) to failure.
114///
115/// This is a subset of what can be returned by the `upload_keys_signature`
116/// endpoint.
117type Failures = BTreeMap<OwnedUserId, BTreeMap<String, upload_signatures::v3::Failure>>;
118
119/// Since there are three possible signatures being uploaded (See
120/// `upload_keys_signature`), we first separate the request's signed objects
121/// into the three possible cases, and return a 3-tuple containing the uploaded
122/// keys for each cases: (
123///		Key ID and signed device keys belonging to the requester,
124///		Key ID and Master key for the key owned by the requester,
125///		A map from user ID to a map of key ID to cross-signing key
126///	)
127///
128/// This type is returned by [`separate_signatures`].
129///
130/// NOTE: The "self Master key" is an `Option` because there can only be one.
131type SignedKeysList = (
132	Vec<(String, DeviceKeys)>,
133	Option<(String, CrossSigningKey)>,
134	BTreeMap<OwnedUserId, BTreeMap<String, CrossSigningKey>>,
135);
136
137/// Contains a signature to be inserted in the database.
138#[derive(Debug)]
139pub struct ValidSignature {
140	/// Type of key that issued the signature.
141	pub signing_key_type: DbKeyType,
142	/// Key ID of the key that issued the signature.
143	pub signing_key_id: OwnedCrossSigningOrDeviceSigningKeyId,
144	/// Unique ID of the signed key. References an entry of the `user_keys`
145	/// table.
146	pub signed_key_nid: i64,
147	/// The actual signature.
148	pub signature: Vec<u8>,
149}
150
151/// Separates the received signed keys into the three cases (See
152/// [`SignedKeysList`] and `upload_keys_signature`).
153///
154/// # Errors
155///
156/// This function errors if:
157/// - The signed object is not a [CrossSigningKey] nor a [DeviceKeys].
158/// - The signed key is a device keys that is **not owned** by the requesting user.
159/// - The signed key is a cross-signing key but its `usage` field does not contain exactly one
160///   entry.
161/// - The signed key is a cross-signing key that is **not a Master key**.
162fn separate_signatures(
163	request_user_id: &UserId,
164	signed_keys: &BTreeMap<OwnedUserId, upload_signatures::v3::SignedKeys>,
165) -> Result<SignedKeysList, SignaturesUploadError> {
166	let mut self_device_keys_signatures = Vec::new();
167	let mut self_master_key_signatures = None;
168	let mut other_master_key_signatures: BTreeMap<OwnedUserId, BTreeMap<String, CrossSigningKey>> =
169		BTreeMap::new();
170
171	for (signed_user_id, user_signed_keys) in signed_keys {
172		for (key_id, signed_object) in user_signed_keys {
173			let key_id = key_id.to_owned();
174			// First, try to deserialize it as `DeviceKeys`
175			if let Ok(signed_device_keys) = serde_json::from_str::<DeviceKeys>(signed_object.get())
176			{
177				if signed_user_id == request_user_id {
178					self_device_keys_signatures.push((key_id, signed_device_keys));
179				} else {
180					return Err(InputJsonError::BadJson(BadJson(
181						"Cannot upload device-keys signatures for other users".to_owned(),
182					))
183					.into());
184				}
185			}
186			// Else, try to deserialize it as a `CrossSigningKey`
187			else if let Ok(signed_cross_signing_key) =
188				serde_json::from_str::<CrossSigningKey>(signed_object.get())
189			{
190				let Ok(key_usage) = signed_cross_signing_key.usage.iter().exactly_one() else {
191					return Err(InputJsonError::BadJson(BadJson(
192						"Cross-signing key `usage` should contain exactly one entry".to_owned(),
193					))
194					.into());
195				};
196
197				if key_usage != &KeyUsage::Master {
198					return Err(InputJsonError::BadJson(BadJson(
199						"Cannot upload signatures for a cross-signing key that is not a Master key"
200							.to_owned(),
201					))
202					.into());
203				}
204
205				// Put it in the correct output vector, based on if it's that of
206				// the requester, or someone else's
207				if signed_user_id == request_user_id {
208					self_master_key_signatures = Some((key_id, signed_cross_signing_key));
209				} else {
210					let user_keys =
211						other_master_key_signatures.entry(signed_user_id.to_owned()).or_default();
212					user_keys.insert(key_id, signed_cross_signing_key);
213				}
214			}
215			// Error if its neither of the two
216			else {
217				return Err(InputJsonError::BadJson(BadJson(
218					"Signed objects must be either device keys or cross-signing keys.".to_owned(),
219				))
220				.into());
221			}
222		}
223	}
224
225	Ok((self_device_keys_signatures, self_master_key_signatures, other_master_key_signatures))
226}
227
228/// Checks that a signature uploaded in `upload_keys_signature` is
229/// cryptographically correct.
230///
231/// Returns a [`upload_signatures::v3::Failure`] if they the verification fails.
232fn check_signing(
233	keymaps: Vec<&PublicKeyMap>,
234	signed_key: &impl SignedObject<OwnedUserId, Base64PublicKeyOrDeviceId>,
235	required_signers: Option<&RequiredSigners<OwnedUserId, Base64PublicKeyOrDeviceId>>,
236) -> Result<Option<upload_signatures::v3::Failure>, SignaturesUploadError> {
237	if let Err(err) = verify_signatures(keymaps, signed_key, required_signers) {
238		let failure = match err {
239			SignatureVerificationError::BadJson(bad_json) => {
240				new_failure(&ErrorCode::BadJson, &bad_json.0)?
241			}
242			other_error => {
243				new_failure(&ErrorCode::from("M_INVALID_SIGNATURE"), &other_error.to_string())?
244			}
245		};
246
247		return Ok(Some(failure));
248	}
249
250	Ok(None)
251}
252
253/// This function is part of `upload_keys_signature` and processes signatures
254/// uploaded for device keys owned by the requester.
255///
256/// # Failures
257///
258/// Here are the cases that will produce failures to be returned by the
259/// endpoint:
260/// - We do not have any stored self-signing key for the user. Such a key is necessary to check the
261///   uploaded device signatures (See `upload_keys_signature`).
262/// - We do not have the corresponding stored device keys object for an uploaded one (e.g it is not
263///   in the database, or the one we have is different).
264/// - The actual signature is invalid (See <https://spec.matrix.org/v1.16/appendices/#signing-json>).
265#[expect(
266	clippy::too_many_lines,
267	reason = "It is too soon to factor out common lines with other functions"
268)]
269fn process_device_keys_signatures(
270	signing_user_id: &UserId,
271	self_signing_key: Option<&CrossSigningKeyRow>,
272	stored_device_keys: &BTreeMap<OwnedDeviceId, DeviceKeysRow>,
273	new_device_keys: Vec<(String, DeviceKeys)>,
274) -> Result<(Vec<ValidSignature>, Failures), SignaturesUploadError> {
275	// Fail if we are missing the self-signing key to verify signatures
276	let Some(self_signing_key) = self_signing_key else {
277		let failure = new_failure(
278			&ErrorCode::BadJson,
279			"Missing self-signing key to verify device keys signatures",
280		)?;
281
282		let failures = BTreeMap::from([(
283			signing_user_id.to_owned(),
284			BTreeMap::from_iter(
285				new_device_keys.into_iter().map(|(key_id, _key)| (key_id, failure.clone())),
286			),
287		)]);
288
289		return Ok((Vec::new(), failures));
290	};
291
292	let signing_key_id = self_signing_key
293		.key
294		.key_id()
295		.unrecoverable_error("Unable to get key ID from stored self-signing key")?;
296
297	let mut valid_signatures = Vec::new();
298	let mut user_failures = BTreeMap::new();
299
300	for (signed_device_keys_id, mut signed_device_keys) in new_device_keys {
301		// Fail if we don't have the same device keys stored
302		let Some(stored_device_keys) = stored_device_keys.get(&signed_device_keys.device_id) else {
303			user_failures.insert(
304				signed_device_keys_id,
305				new_failure(&ErrorCode::BadJson, "No matching device keys found")?,
306			);
307
308			continue;
309		};
310
311		// Verify that the uploaded one matches the stored one
312		if !stored_device_keys
313			.key
314			.compare(&signed_device_keys)
315			.unrecoverable_error("Failed to compare keys")?
316		{
317			user_failures.insert(
318				signed_device_keys_id,
319				new_failure(&ErrorCode::BadJson, "Signed device keys does not match stored one")?,
320			);
321
322			continue;
323		}
324
325		// Skip it if the stored device keys already contain that signature
326		if stored_device_keys
327			.key
328			.signatures
329			.get(signing_user_id)
330			.map(|user_signatures| user_signatures.contains_key(&signing_key_id))
331			== Some(true)
332		{
333			continue;
334		}
335
336		// Make sure the newly uploaded signature is there and extract it
337		let Some(signature) = signed_device_keys
338			.signatures
339			.get(signing_user_id)
340			.and_then(|user_signatures| user_signatures.get(&signing_key_id))
341			.cloned()
342		else {
343			user_failures.insert(
344				signed_device_keys_id.clone(),
345				new_failure(
346					&ErrorCode::BadJson,
347					&format!(
348						"Device keys '{}' should contain a signature from '{}'",
349						signed_device_keys_id, signing_key_id
350					),
351				)?,
352			);
353
354			continue;
355		};
356
357		let device_keys_id = stored_device_keys
358			.key
359			.key_id()
360			.unrecoverable_error("Failed to get key ID of stored keys")?;
361		if signed_device_keys
362			.signatures
363			.get(&signed_device_keys.user_id)
364			.and_then(|user_sigs| user_sigs.get(&device_keys_id))
365			.is_none()
366		{
367			let self_signature = stored_device_keys
368				.key
369				.signatures
370				.get(&stored_device_keys.key.user_id)
371				.and_then(|user_sigs| user_sigs.get(&device_keys_id))
372				.unrecoverable_error("We store device keys that are not signed by themselves")?;
373
374			signed_device_keys.signatures.insert_signature(
375				signed_device_keys.user_id.clone(),
376				device_keys_id,
377				self_signature.to_owned(),
378			);
379		}
380
381		// Verify the signature is actually correct, and that the device keys
382		// are signed by both themselves and the self-signing keys
383		if let Some(failure) = check_signing(
384			vec![
385				&self_signing_key.key.keymap().map_err(InputJsonError::BadJson)?,
386				&signed_device_keys.keymap().map_err(InputJsonError::BadJson)?,
387			],
388			&signed_device_keys,
389			Some(&BTreeMap::from([(
390				signing_user_id.to_owned(),
391				vec![signed_device_keys.key_id().map_err(InputJsonError::BadJson)?],
392			)])),
393		)? {
394			user_failures.insert(signed_device_keys_id, failure);
395			continue;
396		}
397
398		let signature: Vec<u8> = Base64::<base64::Standard>::parse(signature)?.as_bytes().to_vec();
399
400		valid_signatures.push(ValidSignature {
401			signing_key_type: DbKeyType::SelfSigning,
402			signing_key_id: signing_key_id.clone(),
403			signed_key_nid: stored_device_keys.nid,
404			signature,
405		});
406	}
407
408	if !user_failures.is_empty() {
409		return Ok((
410			valid_signatures,
411			BTreeMap::from([(signing_user_id.to_owned(), user_failures)]),
412		));
413	}
414
415	Ok((valid_signatures, BTreeMap::new()))
416}
417
418/// This function is part of `upload_keys_signature` and processes signatures
419/// uploaded for the Master key owned by the requester.
420///
421/// # Failures
422///
423/// Here are the cases that will produce failures to be returned by the
424/// endpoint:
425/// - We do not have the corresponding stored Master key (e.g it is not in the database, or the one
426///   we have is different).
427/// - We do not have the corresponding stored device keys that was used to sign the Master key.
428/// - The actual signature is invalid (See <https://spec.matrix.org/v1.16/appendices/#signing-json>).
429fn process_self_master_key_signatures(
430	session: &SessionInfo,
431	device_keys: &BTreeMap<OwnedDeviceId, DeviceKeysRow>,
432	stored_master_key: Option<&CrossSigningKeyRow>,
433	new_master_key: &CrossSigningKey,
434) -> Result<(Option<ValidSignature>, Option<upload_signatures::v3::Failure>), SignaturesUploadError>
435{
436	// Get the device keys used to sign the master key or fail if not found
437	let Some(signing_device_keys) = device_keys.get(&session.device_id) else {
438		return Ok((
439			None,
440			Some(new_failure(&ErrorCode::BadJson, "No device keys found to verify signature")?),
441		));
442	};
443
444	// Make sure we found the corresponding stored one
445	let Some(stored_master_key) = stored_master_key else {
446		return Ok((None, Some(new_failure(&ErrorCode::BadJson, "No matching Master key found")?)));
447	};
448
449	// Verify the uploaded one matches the stored one
450	if !stored_master_key
451		.key
452		.compare(new_master_key)
453		.unrecoverable_error("Failed to compare keys")?
454	{
455		return Ok((
456			None,
457			Some(new_failure(&ErrorCode::BadJson, "Signed Master key does not match stored one")?),
458		));
459	}
460
461	let signing_key_id =
462		signing_device_keys.key.key_id().unrecoverable_error("Failed to get key ID")?;
463
464	// Skip that signature if the stored one already has it
465	if stored_master_key
466		.key
467		.signatures
468		.get(&session.user_id)
469		.map(|user_signatures| user_signatures.contains_key(&signing_key_id))
470		== Some(true)
471	{
472		return Ok((None, None));
473	}
474
475	// Make sure the newly uploaded signature is there and extract it
476	let Some(signature) = new_master_key
477		.signatures
478		.get(&session.user_id)
479		.and_then(|user_signatures| user_signatures.get(&signing_key_id))
480	else {
481		return Ok((
482			None,
483			Some(new_failure(
484				&ErrorCode::BadJson,
485				"Master key is not signed by the requesting user's device",
486			)?),
487		));
488	};
489
490	// Verify the signature is actually correct
491	if let Some(failure) = check_signing(
492		vec![&signing_device_keys.key.keymap().map_err(InputJsonError::BadJson)?],
493		new_master_key,
494		None,
495	)? {
496		return Ok((None, Some(failure)));
497	}
498
499	let signature: Vec<u8> = Base64::<base64::Standard>::parse(signature)?.as_bytes().to_vec();
500
501	Ok((
502		Some(ValidSignature {
503			signing_key_type: DbKeyType::Device,
504			signing_key_id,
505			signed_key_nid: stored_master_key.nid,
506			signature,
507		}),
508		None,
509	))
510}
511
512/// This function is part of `upload_keys_signature` and processes signatures
513/// uploaded for Master keys owned by other users.
514///
515/// # Failures
516///
517/// Here are the cases that will produce failures to be returned by the
518/// endpoint:
519/// - We do not have any stored user-signing key for the user. Such a key is necessary to check the
520///   uploaded device signatures (See `upload_keys_signature`).
521/// - We do not have the corresponding Master key object for an uploaded one (e.g it is not in the
522///   database, or the one we have is different).
523/// - The actual signature is invalid (See <https://spec.matrix.org/v1.16/appendices/#signing-json>).
524fn process_other_master_key_signatures(
525	signing_user_id: &UserId,
526	user_signing_key: Option<&CrossSigningKeyRow>,
527	stored_master_keys: &BTreeMap<OwnedUserId, CrossSigningKeyRow>,
528	new_master_keys: &BTreeMap<OwnedUserId, BTreeMap<String, CrossSigningKey>>,
529) -> Result<(Vec<ValidSignature>, Failures), SignaturesUploadError> {
530	// Fail if we are missing the user-signing key to verify signatures
531	let Some(user_signing_key) = user_signing_key else {
532		let failure = new_failure(
533			&ErrorCode::BadJson,
534			"Missing user-signing key to verify other user master key signatures",
535		)?;
536
537		let failures = BTreeMap::from_iter(new_master_keys.iter().map(|(user_id, user_keys)| {
538			(
539				user_id.to_owned(),
540				BTreeMap::from_iter(
541					user_keys.keys().cloned().map(|key_id| (key_id, failure.clone())),
542				),
543			)
544		}));
545
546		return Ok((Vec::new(), failures));
547	};
548
549	let signing_key_id =
550		user_signing_key.key.key_id().unrecoverable_error("Failed to get key ID")?;
551
552	let mut valid_signatures = Vec::new();
553	let mut failures = BTreeMap::new();
554
555	for (signed_user_id, signed_keys) in new_master_keys {
556		// Fail if we don't know the master key of that user
557		let Some(stored_master_key) = stored_master_keys.get(signed_user_id) else {
558			let failure = new_failure(&ErrorCode::BadJson, "Missing matching master key")?;
559			failures.insert(
560				signed_user_id.to_owned(),
561				BTreeMap::from_iter(
562					signed_keys.keys().cloned().map(|key_id| (key_id, failure.clone())),
563				),
564			);
565
566			continue;
567		};
568
569		for (signed_key_id, signed_master_key) in signed_keys {
570			// Verify that the uploaded master key matches the stored one
571			if !stored_master_key
572				.key
573				.compare(signed_master_key)
574				.unrecoverable_error("Failed to compare keys")?
575			{
576				failures.insert(
577					signed_user_id.to_owned(),
578					BTreeMap::from([(
579						signed_key_id.to_owned(),
580						new_failure(&ErrorCode::BadJson, "Master key does not match stored one")?,
581					)]),
582				);
583
584				continue;
585			}
586
587			// Make sure the newly uploaded signature is there and extract it
588			let Some(signature) = signed_master_key
589				.signatures
590				.get(signing_user_id)
591				.and_then(|user_signatures| user_signatures.get(&signing_key_id))
592				.cloned()
593			else {
594				failures.insert(
595					signed_user_id.to_owned(),
596					BTreeMap::from([(
597						signed_key_id.to_owned(),
598						new_failure(
599							&ErrorCode::BadJson,
600							&format!(
601								"Master key '{}' is missing a signature from '{}'",
602								signed_key_id, signing_key_id
603							),
604						)?,
605					)]),
606				);
607
608				continue;
609			};
610
611			// Verify the signature is actually correct
612			if let Some(failure) = check_signing(
613				vec![&user_signing_key.key.keymap().map_err(InputJsonError::BadJson)?],
614				signed_master_key,
615				None,
616			)? {
617				failures.insert(
618					signed_user_id.to_owned(),
619					BTreeMap::from([(signed_key_id.to_owned(), failure)]),
620				);
621
622				continue;
623			}
624
625			let signature: Vec<u8> =
626				Base64::<base64::Standard>::parse(signature)?.as_bytes().to_vec();
627
628			valid_signatures.push(ValidSignature {
629				signing_key_type: DbKeyType::UserSigning,
630				signing_key_id: signing_key_id.clone(),
631				signed_key_nid: stored_master_key.nid,
632				signature,
633			});
634		}
635	}
636
637	Ok((valid_signatures, failures))
638}
639
640/// Handler for `POST /_matrix/client/v3/keys/signatures/upload` (See
641/// <https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3keyssignaturesupload>).
642///
643/// There are 3 possible signatures being uploaded via this endpoint:
644/// - Signatures for the user's device keys, emitted by their Self-Signing key
645/// - Signature for the user's Master key, emitted by their device keys
646/// - Signatures for other users' Master keys, emitted by the requester's User-Signing key
647///
648/// We therefore split and process each of these three cases separately, and
649/// then we return a map from user ID to key ID to an error for any signatures
650/// that failed being verified.
651async fn upload_signatures_handler(
652	mut database: State<DefaultDb>,
653	AuthenticatedClientRequest(claims, request): AuthenticatedClientRequest<
654		upload_signatures::v3::Request,
655	>,
656) -> Result<ArminiusResponse<upload_signatures::v3::Response>, SignaturesUploadError> {
657	// 1. Separate the uploaded signatures into the 3 possible categories
658	let (self_device_keys_signatures, self_master_key_signatures, other_users_master_keys) =
659		separate_signatures(&claims.user_id, &request.signed_keys)?;
660
661	// 2. Fetch every possibly involved signing keys
662	let stored_keys = get_local_keys(
663		&mut database,
664		Some(&claims.user_id.clone()),
665		std::iter::once((claims.user_id.clone(), Vec::new()))
666			.chain(
667				other_users_master_keys
668					.keys()
669					.map(|other_user_id| (other_user_id.clone(), Vec::new())),
670			)
671			.collect(),
672	)
673	.await?;
674
675	let mut valid_signatures = Vec::new();
676	let mut failures = BTreeMap::new();
677
678	// 3. Process device keys signed by the user's self-signing key.
679	if !self_device_keys_signatures.is_empty() {
680		let (new_valid_signatures, new_failures) = process_device_keys_signatures(
681			&claims.user_id,
682			stored_keys.self_signing_keys.get(&claims.user_id),
683			stored_keys.device_keys.get(&claims.user_id).unwrap_or(&BTreeMap::new()),
684			self_device_keys_signatures,
685		)?;
686		valid_signatures.extend(new_valid_signatures);
687		failures.extend(new_failures);
688	}
689
690	// 4. Process (if any) the user's Master key signed by their device keys.
691	if let Some((signed_master_key_id, signed_master_key)) = self_master_key_signatures {
692		let (new_valid_signature, new_invalid_signature) = process_self_master_key_signatures(
693			&claims,
694			stored_keys.device_keys.get(&claims.user_id).unwrap_or(&BTreeMap::new()),
695			stored_keys.master_keys.get(&claims.user_id),
696			&signed_master_key,
697		)?;
698
699		if let Some(valid_signature) = new_valid_signature {
700			valid_signatures.push(valid_signature);
701		}
702		if let Some(failure) = new_invalid_signature {
703			failures
704				.insert(claims.user_id.clone(), BTreeMap::from([(signed_master_key_id, failure)]));
705		}
706	}
707
708	// 5. Process other users Master keys signed by the requester's user-signing key.
709	if !other_users_master_keys.is_empty() {
710		let (new_valid_signatures, new_failures) = process_other_master_key_signatures(
711			&claims.user_id,
712			stored_keys.user_signing_keys.get(&claims.user_id),
713			&stored_keys.master_keys,
714			&other_users_master_keys,
715		)?;
716		valid_signatures.extend(new_valid_signatures);
717		failures.extend(new_failures);
718	}
719
720	// 6. Store all the valid signatures
721	let mut transaction =
722		database.begin_transaction().await.unrecoverable_error("Failed to start transaction")?;
723	for ValidSignature { signing_key_type, signing_key_id, signed_key_nid, signature } in
724		valid_signatures
725	{
726		transaction
727			.upsert_local_signature(
728				&claims.user_id,
729				signing_key_type,
730				&signing_key_id,
731				signed_key_nid,
732				&signature,
733			)
734			.await
735			.unrecoverable_error("Failed to insert valid cross-signing signatures")?;
736	}
737	transaction.commit().await.unrecoverable_error("Failed to commit transaction")?;
738
739	// 7. Return all the failing signatures.
740	let mut response = upload_signatures::v3::Response::new();
741	response.failures = failures;
742	Ok(response.into())
743}
744
745/// Component implementing endpoints for signatures.
746#[derive(Debug)]
747pub struct SignaturesComponent;
748
749impl Component for SignaturesComponent {
750	fn router() -> Router<ServerState> {
751		Router::new()
752			.route("/_matrix/client/v3/keys/signatures/upload", post(upload_signatures_handler))
753	}
754}