mirror of
https://mau.dev/maunium/synapse.git
synced 2024-10-01 01:36:05 -04:00
Check sender_key matches on inbound encrypted events. (#6850)
If they don't then the device lists are probably out of sync.
This commit is contained in:
parent
60d0672426
commit
a58860e480
1
changelog.d/6850.misc
Normal file
1
changelog.d/6850.misc
Normal file
@ -0,0 +1 @@
|
||||
Detect unexpected sender keys on inbound encrypted events and resync device lists.
|
@ -598,7 +598,13 @@ class DeviceListUpdater(object):
|
||||
# happens if we've missed updates.
|
||||
resync = yield self._need_to_do_resync(user_id, pending_updates)
|
||||
|
||||
logger.debug("Need to re-sync devices for %r? %r", user_id, resync)
|
||||
if logger.isEnabledFor(logging.INFO):
|
||||
logger.info(
|
||||
"Received device list update for %s, requiring resync: %s. Devices: %s",
|
||||
user_id,
|
||||
resync,
|
||||
", ".join(u[0] for u in pending_updates),
|
||||
)
|
||||
|
||||
if resync:
|
||||
yield self.user_device_resync(user_id)
|
||||
|
@ -754,27 +754,73 @@ class FederationHandler(BaseHandler):
|
||||
# if we don't then we mark the device cache for that user as stale.
|
||||
if event.type == EventTypes.Encrypted:
|
||||
device_id = event.content.get("device_id")
|
||||
sender_key = event.content.get("sender_key")
|
||||
|
||||
cached_devices = await self.store.get_cached_devices_for_user(event.sender)
|
||||
|
||||
resync = False # Whether we should resync device lists.
|
||||
|
||||
device = None
|
||||
if device_id is not None:
|
||||
cached_devices = await self.store.get_cached_devices_for_user(
|
||||
event.sender
|
||||
)
|
||||
if device_id not in cached_devices:
|
||||
device = cached_devices.get(device_id)
|
||||
if device is None:
|
||||
logger.info(
|
||||
"Received event from remote device not in our cache: %s %s",
|
||||
event.sender,
|
||||
device_id,
|
||||
)
|
||||
await self.store.mark_remote_user_device_cache_as_stale(
|
||||
event.sender
|
||||
resync = True
|
||||
|
||||
# We also check if the `sender_key` matches what we expect.
|
||||
if sender_key is not None:
|
||||
# Figure out what sender key we're expecting. If we know the
|
||||
# device and recognize the algorithm then we can work out the
|
||||
# exact key to expect. Otherwise check it matches any key we
|
||||
# have for that device.
|
||||
if device:
|
||||
keys = device.get("keys", {}).get("keys", {})
|
||||
|
||||
if event.content.get("algorithm") == "m.megolm.v1.aes-sha2":
|
||||
# For this algorithm we expect a curve25519 key.
|
||||
key_name = "curve25519:%s" % (device_id,)
|
||||
current_keys = [keys.get(key_name)]
|
||||
else:
|
||||
# We don't know understand the algorithm, so we just
|
||||
# check it matches a key for the device.
|
||||
current_keys = keys.values()
|
||||
elif device_id:
|
||||
# We don't have any keys for the device ID.
|
||||
current_keys = []
|
||||
else:
|
||||
# The event didn't include a device ID, so we just look for
|
||||
# keys across all devices.
|
||||
current_keys = (
|
||||
key
|
||||
for device in cached_devices
|
||||
for key in device.get("keys", {}).get("keys", {}).values()
|
||||
)
|
||||
|
||||
# Immediately attempt a resync in the background
|
||||
if self.config.worker_app:
|
||||
return run_in_background(self._user_device_resync, event.sender)
|
||||
else:
|
||||
return run_in_background(
|
||||
self._device_list_updater.user_device_resync, event.sender
|
||||
)
|
||||
# We now check that the sender key matches (one of) the expected
|
||||
# keys.
|
||||
if sender_key not in current_keys:
|
||||
logger.info(
|
||||
"Received event from remote device with unexpected sender key: %s %s: %s",
|
||||
event.sender,
|
||||
device_id or "<no device_id>",
|
||||
sender_key,
|
||||
)
|
||||
resync = True
|
||||
|
||||
if resync:
|
||||
await self.store.mark_remote_user_device_cache_as_stale(event.sender)
|
||||
|
||||
# Immediately attempt a resync in the background
|
||||
if self.config.worker_app:
|
||||
return run_in_background(self._user_device_resync, event.sender)
|
||||
else:
|
||||
return run_in_background(
|
||||
self._device_list_updater.user_device_resync, event.sender
|
||||
)
|
||||
|
||||
@log_function
|
||||
async def backfill(self, dest, room_id, limit, extremities):
|
||||
|
Loading…
Reference in New Issue
Block a user