mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2025-01-22 23:11:01 -05:00
Verify third party ID server certificates
This commit is contained in:
parent
6ffbcf45c6
commit
b8dd5b1a2d
@ -397,13 +397,24 @@ class Auth(object):
|
|||||||
(EventTypes.ThirdPartyInvite, token,)
|
(EventTypes.ThirdPartyInvite, token,)
|
||||||
)
|
)
|
||||||
if not invite_event:
|
if not invite_event:
|
||||||
|
logger.info("Failing 3pid invite because no invite found for token %s", token)
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
public_key = join_third_party_invite["public_key"]
|
public_key = join_third_party_invite["public_key"]
|
||||||
key_validity_url = join_third_party_invite["key_validity_url"]
|
key_validity_url = join_third_party_invite["key_validity_url"]
|
||||||
if invite_event.content["public_key"] != public_key:
|
if invite_event.content["public_key"] != public_key:
|
||||||
|
logger.info(
|
||||||
|
"Failing 3pid invite because public key invite: %s != join: %s",
|
||||||
|
invite_event.content["public_key"],
|
||||||
|
public_key
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
if invite_event.content["key_validity_url"] != key_validity_url:
|
if invite_event.content["key_validity_url"] != key_validity_url:
|
||||||
|
logger.info(
|
||||||
|
"Failing 3pid invite because key_validity_url invite: %s != join: %s",
|
||||||
|
invite_event.content["key_validity_url"],
|
||||||
|
key_validity_url
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
verify_key = nacl.signing.VerifyKey(decode_base64(public_key))
|
verify_key = nacl.signing.VerifyKey(decode_base64(public_key))
|
||||||
encoded_signature = join_third_party_invite["signature"]
|
encoded_signature = join_third_party_invite["signature"]
|
||||||
|
@ -22,11 +22,16 @@ from synapse.types import UserID, RoomAlias, RoomID
|
|||||||
from synapse.api.constants import (
|
from synapse.api.constants import (
|
||||||
EventTypes, Membership, JoinRules, RoomCreationPreset,
|
EventTypes, Membership, JoinRules, RoomCreationPreset,
|
||||||
)
|
)
|
||||||
from synapse.api.errors import StoreError, SynapseError
|
from synapse.api.errors import AuthError, StoreError, SynapseError
|
||||||
from synapse.util import stringutils, unwrapFirstError
|
from synapse.util import stringutils, unwrapFirstError
|
||||||
from synapse.util.async import run_on_reactor
|
from synapse.util.async import run_on_reactor
|
||||||
|
|
||||||
|
from signedjson.sign import verify_signed_json
|
||||||
|
from signedjson.key import decode_verify_key_bytes
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
from unpaddedbase64 import decode_base64
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import string
|
import string
|
||||||
|
|
||||||
@ -614,12 +619,34 @@ class RoomMemberHandler(BaseHandler):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if "mxid" in data:
|
if "mxid" in data:
|
||||||
# TODO: Validate the response signature and such
|
if "signatures" not in data:
|
||||||
|
raise AuthError(401, "No signatures on 3pid binding")
|
||||||
|
self.verify_any_signature(data, id_server)
|
||||||
defer.returnValue(data["mxid"])
|
defer.returnValue(data["mxid"])
|
||||||
|
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
logger.warn("Error from identity server lookup: %s" % (e,))
|
logger.warn("Error from identity server lookup: %s" % (e,))
|
||||||
defer.returnValue(None)
|
defer.returnValue(None)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def verify_any_signature(self, data, server_hostname):
|
||||||
|
if server_hostname not in data["signatures"]:
|
||||||
|
raise AuthError(401, "No signature from server %s" % (server_hostname,))
|
||||||
|
for key_name, signature in data["signatures"][server_hostname].items():
|
||||||
|
key_data = yield self.hs.get_simple_http_client().get_json(
|
||||||
|
"https://%s/_matrix/identity/api/v1/pubkey/%s" %
|
||||||
|
(server_hostname, key_name,),
|
||||||
|
)
|
||||||
|
if "public_key" not in key_data:
|
||||||
|
raise AuthError(401, "No public key named %s from %s" %
|
||||||
|
(key_name, server_hostname,))
|
||||||
|
verify_signed_json(
|
||||||
|
data,
|
||||||
|
server_hostname,
|
||||||
|
decode_verify_key_bytes(key_name, decode_base64(key_data["public_key"]))
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def _make_and_store_3pid_invite(
|
def _make_and_store_3pid_invite(
|
||||||
self,
|
self,
|
||||||
|
@ -24,7 +24,6 @@ from canonicaljson import encode_canonical_json
|
|||||||
from twisted.internet import defer, reactor, ssl
|
from twisted.internet import defer, reactor, ssl
|
||||||
from twisted.web.client import (
|
from twisted.web.client import (
|
||||||
Agent, readBody, FileBodyProducer, PartialDownloadError,
|
Agent, readBody, FileBodyProducer, PartialDownloadError,
|
||||||
HTTPConnectionPool,
|
|
||||||
)
|
)
|
||||||
from twisted.web.http_headers import Headers
|
from twisted.web.http_headers import Headers
|
||||||
|
|
||||||
@ -59,11 +58,8 @@ class SimpleHttpClient(object):
|
|||||||
# The default context factory in Twisted 14.0.0 (which we require) is
|
# The default context factory in Twisted 14.0.0 (which we require) is
|
||||||
# BrowserLikePolicyForHTTPS which will do regular cert validation
|
# BrowserLikePolicyForHTTPS which will do regular cert validation
|
||||||
# 'like a browser'
|
# 'like a browser'
|
||||||
pool = HTTPConnectionPool(reactor)
|
|
||||||
pool.maxPersistentPerHost = 10
|
|
||||||
self.agent = Agent(
|
self.agent = Agent(
|
||||||
reactor,
|
reactor,
|
||||||
pool=pool,
|
|
||||||
connectTimeout=15,
|
connectTimeout=15,
|
||||||
contextFactory=hs.get_http_client_context_factory()
|
contextFactory=hs.get_http_client_context_factory()
|
||||||
)
|
)
|
||||||
|
@ -63,7 +63,7 @@ def check_key_valid(http_client, event):
|
|||||||
event.content["third_party_invite"]["key_validity_url"],
|
event.content["third_party_invite"]["key_validity_url"],
|
||||||
{"public_key": event.content["third_party_invite"]["public_key"]}
|
{"public_key": event.content["third_party_invite"]["public_key"]}
|
||||||
)
|
)
|
||||||
if not response["valid"]:
|
except Exception:
|
||||||
raise AuthError(403, "Third party certificate was invalid")
|
|
||||||
except IOError:
|
|
||||||
raise AuthError(502, "Third party certificate could not be checked")
|
raise AuthError(502, "Third party certificate could not be checked")
|
||||||
|
if "valid" not in response or not response["valid"]:
|
||||||
|
raise AuthError(403, "Third party certificate was invalid")
|
||||||
|
Loading…
Reference in New Issue
Block a user