Compare commits

...

6 Commits

Author SHA1 Message Date
Andrew Morgan de29d1f106 Merge branch 'anoa/query_cross_signing_keys_key_upload' of github.com:matrix-org/synapse into anoa/query_cross_signing_keys_key_upload
* 'anoa/query_cross_signing_keys_key_upload' of github.com:matrix-org/synapse:
  Update changelog.d/7289.bugfix
2020-04-21 15:51:27 +01:00
Andrew Morgan b08b7c71fc lint 2020-04-21 15:46:59 +01:00
Andrew Morgan 74eaac0052 Improve details of query_client_keys and query_user_devices docstrings 2020-04-21 15:45:57 +01:00
Andrew Morgan 7cb1e4846a Refactor and add validation to _retrieve_cross_signing_keys_for_remote_user 2020-04-21 15:35:01 +01:00
Andrew Morgan 1b4dda5a8d Refactor _get_e2e_cross_signing_verify_key 2020-04-21 14:37:26 +01:00
Andrew Morgan 6d559bab03
Update changelog.d/7289.bugfix
Co-Authored-By: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2020-04-21 12:23:29 +01:00
3 changed files with 73 additions and 47 deletions

View File

@ -1 +1 @@
Fix a bug with cross-signing devices with remote users when they did not share a room with any user on the local homeserver. Fix a bug with cross-signing devices belonging to remote users who did not share a room with any user on the local homeserver.

View File

@ -407,12 +407,12 @@ class TransportLayerClient(object):
"<user_id>": { "<user_id>": {
"<device_id>": {...} "<device_id>": {...}
} } } }
"master_keys": { "master_key": {
"<user_id>": {...} "<user_id>": {...}
} } } }
"self_signing_keys": { "self_signing_key": {
"<user_id>": {...} "<user_id>": {...}
} } } } }
Args: Args:
destination(str): The server to query. destination(str): The server to query.
@ -436,9 +436,22 @@ class TransportLayerClient(object):
{ {
"stream_id": "...", "stream_id": "...",
"devices": [ { ... } ], "devices": [ { ... } ],
"master_key": { ... }, "master_key": {
"self_signing_key: { ... } "user_id": "<user_id>",
"usage": [...],
"keys": {...},
"signatures": {
"<user_id>": {...}
} }
},
"self_signing_key": {
"user_id": "<user_id>",
"usage": [...],
"keys": {...},
"signatures": {
"<user_id>": {...}
}
} }
Args: Args:
destination(str): The server to query. destination(str): The server to query.

View File

@ -989,20 +989,24 @@ class E2eKeysHandler(object):
user_id, key_type, from_user_id user_id, key_type, from_user_id
) )
if key:
# We found a copy of this key in our database. Decode and return it
key_id, verify_key = get_verify_key_from_cross_signing_key(key)
return key, key_id, verify_key
# If we couldn't find the key locally, and we're looking for keys of # If we couldn't find the key locally, and we're looking for keys of
# another user then attempt to fetch the missing key from the remote # another user then attempt to fetch the missing key from the remote
# user's server. # user's server.
# #
# We may run into this in possible edge cases where a user tries to # We may run into this in possible edge cases where a user tries to
# cross-sign a remote user, but does not share any rooms with them yet. # cross-sign a remote user, but does not share any rooms with them yet.
# Thus, we would not have their key list yet. We fetch the key here, # Thus, we would not have their key list yet. We instead fetch the key,
# store it and notify clients of new, associated device IDs. # store it and notify clients of new, associated device IDs.
if ( if self.is_mine(user) or key_type not in ["master", "self_signing"]:
key is None # Note that master and self_signing keys are the only cross-signing keys we
and not self.is_mine(user) # can request over federation
# We only get "master" and "self_signing" keys from remote servers return
and key_type in ["master", "self_signing"]
):
( (
key, key,
key_id, key_id,
@ -1010,19 +1014,8 @@ class E2eKeysHandler(object):
) = yield self._retrieve_cross_signing_keys_for_remote_user(user, key_type) ) = yield self._retrieve_cross_signing_keys_for_remote_user(user, key_type)
if key is None: if key is None:
logger.warning("No %s key found for %s", key_type, user_id)
raise NotFoundError("No %s key found for %s" % (key_type, user_id)) raise NotFoundError("No %s key found for %s" % (key_type, user_id))
try:
key_id, verify_key = get_verify_key_from_cross_signing_key(key)
except ValueError as e:
logger.warning(
"Invalid %s key retrieved: %s - %s %s", key_type, key, type(e), e,
)
raise SynapseError(
502, "Invalid %s key retrieved from remote server" % (key_type,)
)
return key, key_id, verify_key return key, key_id, verify_key
@defer.inlineCallbacks @defer.inlineCallbacks
@ -1058,22 +1051,33 @@ class E2eKeysHandler(object):
return None, None, None return None, None, None
# Process each of the retrieved cross-signing keys # Process each of the retrieved cross-signing keys
final_key = None desired_key = None
final_key_id = None desired_key_id = None
final_verify_key = None desired_verify_key = None
device_ids = [] retrieved_device_ids = []
for key_type in ["master", "self_signing"]: for key_type in ["master", "self_signing"]:
key_content = remote_result.get(key_type + "_key") key_content = remote_result.get(key_type + "_key")
if not key_content: if not key_content:
continue continue
# At the same time, store this key in the db for # Ensure these keys belong to the correct user
# subsequent queries if "user_id" not in key_content:
yield self.store.set_e2e_cross_signing_key( logger.warning(
user.to_string(), key_type, key_content "Invalid %s key retrieved, missing user_id field: %s",
key_type,
key_content,
) )
continue
if user.to_string() != key_content["user_id"]:
logger.warning(
"Found %s key of user %s when querying for keys of user %s",
key_type,
key_content["user_id"],
user.to_string(),
)
continue
# Note down the device ID attached to this key # Validate the key contents
try: try:
# verify_key is a VerifyKey from signedjson, which uses # verify_key is a VerifyKey from signedjson, which uses
# .version to denote the portion of the key ID after the # .version to denote the portion of the key ID after the
@ -1088,19 +1092,28 @@ class E2eKeysHandler(object):
e, e,
) )
continue continue
device_ids.append(verify_key.version)
# Note down the device ID attached to this key
retrieved_device_ids.append(verify_key.version)
# If this is the desired key type, save it and its ID/VerifyKey # If this is the desired key type, save it and its ID/VerifyKey
if key_type == desired_key_type: if key_type == desired_key_type:
final_key = key_content desired_key = key_content
final_verify_key = verify_key desired_verify_key = verify_key
final_key_id = key_id desired_key_id = key_id
# At the same time, store this key in the db for subsequent queries
yield self.store.set_e2e_cross_signing_key(
user.to_string(), key_type, key_content
)
# Notify clients that new devices for this user have been discovered # Notify clients that new devices for this user have been discovered
if device_ids: if retrieved_device_ids:
yield self.device_handler.notify_device_update(user.to_string(), device_ids) yield self.device_handler.notify_device_update(
user.to_string(), retrieved_device_ids
)
return final_key, final_key_id, final_verify_key return desired_key, desired_key_id, desired_verify_key
def _check_cross_signing_key(key, user_id, key_type, signing_key=None): def _check_cross_signing_key(key, user_id, key_type, signing_key=None):