summary refs log tree commit diff
diff options
context:
space:
mode:
authorJonas Jelten <jj@sft.lol>2020-10-26 19:37:47 +0100
committerGitHub <noreply@github.com>2020-10-26 18:37:47 +0000
commit2e380f0f1802e5310f5a19b5cac314ce742aaecd (patch)
treeac49855e8f394a1b59183dac4f2320b5a04c625d
parentAdd type hints for account validity handler (#8620) (diff)
downloadsynapse-2e380f0f1802e5310f5a19b5cac314ce742aaecd.tar.xz
e2e: ensure we have both master and self-signing key (#8455)
it seems to be possible that only one of them ends up to be cached.
when this was the case, the missing one was not fetched via federation,
and clients then failed to validate cross-signed devices.

Signed-off-by: Jonas Jelten <jj@sft.lol>
-rw-r--r--changelog.d/8455.bugfix1
-rw-r--r--synapse/handlers/e2e_keys.py27
2 files changed, 23 insertions, 5 deletions
diff --git a/changelog.d/8455.bugfix b/changelog.d/8455.bugfix
new file mode 100644
index 0000000000..561e73f5e0
--- /dev/null
+++ b/changelog.d/8455.bugfix
@@ -0,0 +1 @@
+Fix fetching of E2E cross signing keys over federation when only one of the master key and device signing key is cached already.
diff --git a/synapse/handlers/e2e_keys.py b/synapse/handlers/e2e_keys.py
index 611742ae72..929752150d 100644
--- a/synapse/handlers/e2e_keys.py
+++ b/synapse/handlers/e2e_keys.py
@@ -129,6 +129,11 @@ class E2eKeysHandler:
                 if user_id in local_query:
                     results[user_id] = keys
 
+        # Get cached cross-signing keys
+        cross_signing_keys = await self.get_cross_signing_keys_from_cache(
+            device_keys_query, from_user_id
+        )
+
         # Now attempt to get any remote devices from our local cache.
         remote_queries_not_in_cache = {}
         if remote_queries:
@@ -155,16 +160,28 @@ class E2eKeysHandler:
                             unsigned["device_display_name"] = device_display_name
                         user_devices[device_id] = result
 
+            # check for missing cross-signing keys.
+            for user_id in remote_queries.keys():
+                cached_cross_master = user_id in cross_signing_keys["master_keys"]
+                cached_cross_selfsigning = (
+                    user_id in cross_signing_keys["self_signing_keys"]
+                )
+
+                # check if we are missing only one of cross-signing master or
+                # self-signing key, but the other one is cached.
+                # as we need both, this will issue a federation request.
+                # if we don't have any of the keys, either the user doesn't have
+                # cross-signing set up, or the cached device list
+                # is not (yet) updated.
+                if cached_cross_master ^ cached_cross_selfsigning:
+                    user_ids_not_in_cache.add(user_id)
+
+            # add those users to the list to fetch over federation.
             for user_id in user_ids_not_in_cache:
                 domain = get_domain_from_id(user_id)
                 r = remote_queries_not_in_cache.setdefault(domain, {})
                 r[user_id] = remote_queries[user_id]
 
-        # Get cached cross-signing keys
-        cross_signing_keys = await self.get_cross_signing_keys_from_cache(
-            device_keys_query, from_user_id
-        )
-
         # Now fetch any devices that we don't have in our cache
         @trace
         async def do_remote_query(destination):