mirror of
https://github.com/element-hq/synapse
synced 2024-09-10 16:35:10 +00:00
Only check event ID domain for signatures for V1 events
In future version events won't have an event ID, so we won't be able to do this check.
This commit is contained in:
parent
8e3d34e3c5
commit
840068bd78
3 changed files with 44 additions and 31 deletions
|
@ -20,7 +20,7 @@ import six
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
from twisted.internet.defer import DeferredList
|
from twisted.internet.defer import DeferredList
|
||||||
|
|
||||||
from synapse.api.constants import MAX_DEPTH, EventTypes, Membership
|
from synapse.api.constants import KNOWN_ROOM_VERSIONS, MAX_DEPTH, EventTypes, Membership
|
||||||
from synapse.api.errors import Codes, SynapseError
|
from synapse.api.errors import Codes, SynapseError
|
||||||
from synapse.crypto.event_signing import check_event_content_hash
|
from synapse.crypto.event_signing import check_event_content_hash
|
||||||
from synapse.events import event_type_from_format_version
|
from synapse.events import event_type_from_format_version
|
||||||
|
@ -66,7 +66,7 @@ class FederationBase(object):
|
||||||
Returns:
|
Returns:
|
||||||
Deferred : A list of PDUs that have valid signatures and hashes.
|
Deferred : A list of PDUs that have valid signatures and hashes.
|
||||||
"""
|
"""
|
||||||
deferreds = self._check_sigs_and_hashes(pdus)
|
deferreds = self._check_sigs_and_hashes(room_version, pdus)
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def handle_check_result(pdu, deferred):
|
def handle_check_result(pdu, deferred):
|
||||||
|
@ -121,16 +121,17 @@ class FederationBase(object):
|
||||||
else:
|
else:
|
||||||
defer.returnValue([p for p in valid_pdus if p])
|
defer.returnValue([p for p in valid_pdus if p])
|
||||||
|
|
||||||
def _check_sigs_and_hash(self, pdu):
|
def _check_sigs_and_hash(self, room_version, pdu):
|
||||||
return logcontext.make_deferred_yieldable(
|
return logcontext.make_deferred_yieldable(
|
||||||
self._check_sigs_and_hashes([pdu])[0],
|
self._check_sigs_and_hashes(room_version, [pdu])[0],
|
||||||
)
|
)
|
||||||
|
|
||||||
def _check_sigs_and_hashes(self, pdus):
|
def _check_sigs_and_hashes(self, room_version, pdus):
|
||||||
"""Checks that each of the received events is correctly signed by the
|
"""Checks that each of the received events is correctly signed by the
|
||||||
sending server.
|
sending server.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
room_version (str): The room version of the PDUs
|
||||||
pdus (list[FrozenEvent]): the events to be checked
|
pdus (list[FrozenEvent]): the events to be checked
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
@ -141,7 +142,7 @@ class FederationBase(object):
|
||||||
* throws a SynapseError if the signature check failed.
|
* throws a SynapseError if the signature check failed.
|
||||||
The deferreds run their callbacks in the sentinel logcontext.
|
The deferreds run their callbacks in the sentinel logcontext.
|
||||||
"""
|
"""
|
||||||
deferreds = _check_sigs_on_pdus(self.keyring, pdus)
|
deferreds = _check_sigs_on_pdus(self.keyring, room_version, pdus)
|
||||||
|
|
||||||
ctx = logcontext.LoggingContext.current_context()
|
ctx = logcontext.LoggingContext.current_context()
|
||||||
|
|
||||||
|
@ -203,16 +204,17 @@ class FederationBase(object):
|
||||||
|
|
||||||
|
|
||||||
class PduToCheckSig(namedtuple("PduToCheckSig", [
|
class PduToCheckSig(namedtuple("PduToCheckSig", [
|
||||||
"pdu", "redacted_pdu_json", "event_id_domain", "sender_domain", "deferreds",
|
"pdu", "redacted_pdu_json", "sender_domain", "deferreds",
|
||||||
])):
|
])):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _check_sigs_on_pdus(keyring, pdus):
|
def _check_sigs_on_pdus(keyring, room_version, pdus):
|
||||||
"""Check that the given events are correctly signed
|
"""Check that the given events are correctly signed
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
keyring (synapse.crypto.Keyring): keyring object to do the checks
|
keyring (synapse.crypto.Keyring): keyring object to do the checks
|
||||||
|
room_version (str): the room version of the PDUs
|
||||||
pdus (Collection[EventBase]): the events to be checked
|
pdus (Collection[EventBase]): the events to be checked
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
@ -243,32 +245,22 @@ def _check_sigs_on_pdus(keyring, pdus):
|
||||||
#
|
#
|
||||||
# let's start by getting the domain for each pdu, and flattening the event back
|
# let's start by getting the domain for each pdu, and flattening the event back
|
||||||
# to JSON.
|
# to JSON.
|
||||||
|
|
||||||
pdus_to_check = [
|
pdus_to_check = [
|
||||||
PduToCheckSig(
|
PduToCheckSig(
|
||||||
pdu=p,
|
pdu=p,
|
||||||
redacted_pdu_json=prune_event(p).get_pdu_json(),
|
redacted_pdu_json=prune_event(p).get_pdu_json(),
|
||||||
event_id_domain=get_domain_from_id(p.event_id),
|
|
||||||
sender_domain=get_domain_from_id(p.sender),
|
sender_domain=get_domain_from_id(p.sender),
|
||||||
deferreds=[],
|
deferreds=[],
|
||||||
)
|
)
|
||||||
for p in pdus
|
for p in pdus
|
||||||
]
|
]
|
||||||
|
|
||||||
# first make sure that the event is signed by the event_id's domain
|
# First we check that the sender event is signed by the sender's domain
|
||||||
deferreds = keyring.verify_json_objects_for_server([
|
# (except if its a 3pid invite, in which case it may be sent by any server)
|
||||||
(p.event_id_domain, p.redacted_pdu_json)
|
|
||||||
for p in pdus_to_check
|
|
||||||
])
|
|
||||||
|
|
||||||
for p, d in zip(pdus_to_check, deferreds):
|
|
||||||
p.deferreds.append(d)
|
|
||||||
|
|
||||||
# now let's look for events where the sender's domain is different to the
|
|
||||||
# event id's domain (normally only the case for joins/leaves), and add additional
|
|
||||||
# checks.
|
|
||||||
pdus_to_check_sender = [
|
pdus_to_check_sender = [
|
||||||
p for p in pdus_to_check
|
p for p in pdus_to_check
|
||||||
if p.sender_domain != p.event_id_domain and not _is_invite_via_3pid(p.pdu)
|
if not _is_invite_via_3pid(p.pdu)
|
||||||
]
|
]
|
||||||
|
|
||||||
more_deferreds = keyring.verify_json_objects_for_server([
|
more_deferreds = keyring.verify_json_objects_for_server([
|
||||||
|
@ -279,19 +271,37 @@ def _check_sigs_on_pdus(keyring, pdus):
|
||||||
for p, d in zip(pdus_to_check_sender, more_deferreds):
|
for p, d in zip(pdus_to_check_sender, more_deferreds):
|
||||||
p.deferreds.append(d)
|
p.deferreds.append(d)
|
||||||
|
|
||||||
|
# now let's look for events where the sender's domain is different to the
|
||||||
|
# event id's domain (normally only the case for joins/leaves), and add additional
|
||||||
|
# checks. Only do this if the room version has a concept of event ID domain
|
||||||
|
if room_version in KNOWN_ROOM_VERSIONS:
|
||||||
|
pdus_to_check_event_id = [
|
||||||
|
p for p in pdus_to_check
|
||||||
|
if p.sender_domain != get_domain_from_id(p.pdu.event_id)
|
||||||
|
]
|
||||||
|
|
||||||
|
more_deferreds = keyring.verify_json_objects_for_server([
|
||||||
|
(get_domain_from_id(p.pdu.event_id), p.redacted_pdu_json)
|
||||||
|
for p in pdus_to_check_event_id
|
||||||
|
])
|
||||||
|
|
||||||
|
for p, d in zip(pdus_to_check_event_id, more_deferreds):
|
||||||
|
p.deferreds.append(d)
|
||||||
|
|
||||||
# replace lists of deferreds with single Deferreds
|
# replace lists of deferreds with single Deferreds
|
||||||
return [_flatten_deferred_list(p.deferreds) for p in pdus_to_check]
|
return [_flatten_deferred_list(p.deferreds) for p in pdus_to_check]
|
||||||
|
|
||||||
|
|
||||||
def _flatten_deferred_list(deferreds):
|
def _flatten_deferred_list(deferreds):
|
||||||
"""Given a list of one or more deferreds, either return the single deferred, or
|
"""Given a list of deferreds, either return the single deferred,
|
||||||
combine into a DeferredList.
|
combine into a DeferredList, or return an already resolved deferred.
|
||||||
"""
|
"""
|
||||||
if len(deferreds) > 1:
|
if len(deferreds) > 1:
|
||||||
return DeferredList(deferreds, fireOnOneErrback=True, consumeErrors=True)
|
return DeferredList(deferreds, fireOnOneErrback=True, consumeErrors=True)
|
||||||
else:
|
elif len(deferreds) == 1:
|
||||||
assert len(deferreds) == 1
|
|
||||||
return deferreds[0]
|
return deferreds[0]
|
||||||
|
else:
|
||||||
|
return defer.succeed(None)
|
||||||
|
|
||||||
|
|
||||||
def _is_invite_via_3pid(event):
|
def _is_invite_via_3pid(event):
|
||||||
|
@ -319,7 +329,7 @@ def event_from_pdu_json(pdu_json, event_format_version, outlier=False):
|
||||||
"""
|
"""
|
||||||
# we could probably enforce a bunch of other fields here (room_id, sender,
|
# we could probably enforce a bunch of other fields here (room_id, sender,
|
||||||
# origin, etc etc)
|
# origin, etc etc)
|
||||||
assert_params_in_dict(pdu_json, ('event_id', 'type', 'depth'))
|
assert_params_in_dict(pdu_json, ('type', 'depth'))
|
||||||
|
|
||||||
depth = pdu_json['depth']
|
depth = pdu_json['depth']
|
||||||
if not isinstance(depth, six.integer_types):
|
if not isinstance(depth, six.integer_types):
|
||||||
|
|
|
@ -205,7 +205,7 @@ class FederationClient(FederationBase):
|
||||||
|
|
||||||
# FIXME: We should handle signature failures more gracefully.
|
# FIXME: We should handle signature failures more gracefully.
|
||||||
pdus[:] = yield logcontext.make_deferred_yieldable(defer.gatherResults(
|
pdus[:] = yield logcontext.make_deferred_yieldable(defer.gatherResults(
|
||||||
self._check_sigs_and_hashes(pdus),
|
self._check_sigs_and_hashes(room_version, pdus),
|
||||||
consumeErrors=True,
|
consumeErrors=True,
|
||||||
).addErrback(unwrapFirstError))
|
).addErrback(unwrapFirstError))
|
||||||
|
|
||||||
|
@ -268,7 +268,7 @@ class FederationClient(FederationBase):
|
||||||
pdu = pdu_list[0]
|
pdu = pdu_list[0]
|
||||||
|
|
||||||
# Check signatures are correct.
|
# Check signatures are correct.
|
||||||
signed_pdu = yield self._check_sigs_and_hash(pdu)
|
signed_pdu = yield self._check_sigs_and_hash(room_version, pdu)
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -757,7 +757,7 @@ class FederationClient(FederationBase):
|
||||||
pdu = event_from_pdu_json(pdu_dict, format_ver)
|
pdu = event_from_pdu_json(pdu_dict, format_ver)
|
||||||
|
|
||||||
# Check signatures are correct.
|
# Check signatures are correct.
|
||||||
pdu = yield self._check_sigs_and_hash(pdu)
|
pdu = yield self._check_sigs_and_hash(room_version, pdu)
|
||||||
|
|
||||||
# FIXME: We should handle signature failures more gracefully.
|
# FIXME: We should handle signature failures more gracefully.
|
||||||
|
|
||||||
|
|
|
@ -645,9 +645,12 @@ class FederationServer(FederationBase):
|
||||||
pdu.event_id, origin
|
pdu.event_id, origin
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# We've already checked that we know the room version by this point
|
||||||
|
room_version = yield self.store.get_room_version(pdu.room_id)
|
||||||
|
|
||||||
# Check signature.
|
# Check signature.
|
||||||
try:
|
try:
|
||||||
pdu = yield self._check_sigs_and_hash(pdu)
|
pdu = yield self._check_sigs_and_hash(room_version, pdu)
|
||||||
except SynapseError as e:
|
except SynapseError as e:
|
||||||
raise FederationError(
|
raise FederationError(
|
||||||
"ERROR",
|
"ERROR",
|
||||||
|
|
Loading…
Reference in a new issue