diff --git a/synapse/config/experimental.py b/synapse/config/experimental.py
index bc38fae0b6..7c81f055b6 100644
--- a/synapse/config/experimental.py
+++ b/synapse/config/experimental.py
@@ -194,3 +194,6 @@ class ExperimentalConfig(Config):
self.msc3966_exact_event_property_contains = experimental.get(
"msc3966_exact_event_property_contains", False
)
+
+ # MSC3967: Do not require UIA when first uploading cross signing keys
+ self.msc3967_enabled = experimental.get("msc3967_enabled", False)
diff --git a/synapse/handlers/e2e_keys.py b/synapse/handlers/e2e_keys.py
index 43cbece21b..4e9c8d8db0 100644
--- a/synapse/handlers/e2e_keys.py
+++ b/synapse/handlers/e2e_keys.py
@@ -1301,6 +1301,20 @@ class E2eKeysHandler:
return desired_key_data
+ async def is_cross_signing_set_up_for_user(self, user_id: str) -> bool:
+ """Checks if the user has cross-signing set up
+
+ Args:
+ user_id: The user to check
+
+ Returns:
+ True if the user has cross-signing set up, False otherwise
+ """
+ existing_master_key = await self.store.get_e2e_cross_signing_key(
+ user_id, "master"
+ )
+ return existing_master_key is not None
+
def _check_cross_signing_key(
key: JsonDict, user_id: str, key_type: str, signing_key: Optional[VerifyKey] = None
diff --git a/synapse/rest/client/keys.py b/synapse/rest/client/keys.py
index 7873b363c0..32bb8b9a91 100644
--- a/synapse/rest/client/keys.py
+++ b/synapse/rest/client/keys.py
@@ -312,15 +312,29 @@ class SigningKeyUploadServlet(RestServlet):
user_id = requester.user.to_string()
body = parse_json_object_from_request(request)
- await self.auth_handler.validate_user_via_ui_auth(
- requester,
- request,
- body,
- "add a device signing key to your account",
- # Allow skipping of UI auth since this is frequently called directly
- # after login and it is silly to ask users to re-auth immediately.
- can_skip_ui_auth=True,
- )
+ if self.hs.config.experimental.msc3967_enabled:
+ if await self.e2e_keys_handler.is_cross_signing_set_up_for_user(user_id):
+ # If we already have a master key then cross signing is set up and we require UIA to reset
+ await self.auth_handler.validate_user_via_ui_auth(
+ requester,
+ request,
+ body,
+ "reset the device signing key on your account",
+ # Do not allow skipping of UIA auth.
+ can_skip_ui_auth=False,
+ )
+ # Otherwise we don't require UIA since we are setting up cross signing for first time
+ else:
+ # Previous behaviour is to always require UIA but allow it to be skipped
+ await self.auth_handler.validate_user_via_ui_auth(
+ requester,
+ request,
+ body,
+ "add a device signing key to your account",
+ # Allow skipping of UI auth since this is frequently called directly
+ # after login and it is silly to ask users to re-auth immediately.
+ can_skip_ui_auth=True,
+ )
result = await self.e2e_keys_handler.upload_signing_keys_for_user(user_id, body)
return 200, result
|