Example #1
0
 def verify_json_for_server(self, server_name, json_object):
     logger.debug("Verifying for %s", server_name)
     key_ids = signature_ids(json_object, server_name)
     if not key_ids:
         raise SynapseError(
             400,
             "Not signed with a supported algorithm",
             Codes.UNAUTHORIZED,
         )
     try:
         verify_key = yield self.get_server_verify_key(server_name, key_ids)
     except IOError:
         raise SynapseError(
             502,
             "Error downloading keys for %s" % (server_name,),
             Codes.UNAUTHORIZED,
         )
     except:
         raise SynapseError(
             401,
             "No key for %s with id %s" % (server_name, key_ids),
             Codes.UNAUTHORIZED,
         )
     try:
         verify_signed_json(json_object, server_name, verify_key)
     except:
         raise SynapseError(
             401,
             "Invalid signature for server %s with key %s:%s" % (
                 server_name, verify_key.alg, verify_key.version
             ),
             Codes.UNAUTHORIZED,
         )
Example #2
0
 def test_sign_and_verify(self):
     self.assertIn('signatures', self.signed)
     self.assertIn('Alice', self.signed['signatures'])
     self.assertIn('mock:test', self.signed['signatures']['Alice'])
     self.assertEqual(self.signed['signatures']['Alice']['mock:test'],
                      encode_base64('x_______'))
     verify_signed_json(self.signed, 'Alice', self.verkey)
Example #3
0
def main():

    parser = argparse.ArgumentParser()
    parser.add_argument("signature_name")
    parser.add_argument("input_json",
                        nargs="?",
                        type=argparse.FileType('r'),
                        default=sys.stdin)

    args = parser.parse_args()
    logging.basicConfig()

    server_name = args.signature_name
    keys = {}
    for target, port in get_targets(server_name):
        try:
            keys = get_server_keys(server_name, target, port)
            print "Using keys from https://%s:%s/_matrix/key/v1" % (target,
                                                                    port)
            write_signing_keys(sys.stdout, keys.values())
            break
        except:
            logging.exception("Error talking to %s:%s", target, port)

    json_to_check = json.load(args.input_json)
    print "Checking JSON:"
    for key_id in json_to_check["signatures"][args.signature_name]:
        try:
            key = keys[key_id]
            verify_signed_json(json_to_check, args.signature_name, key)
            print "PASS %s" % (key_id, )
        except:
            logging.exception("Check for key %s failed" % (key_id, ))
            print "FAIL %s" % (key_id, )
Example #4
0
def main():

    parser = argparse.ArgumentParser()
    parser.add_argument("signature_name")
    parser.add_argument("input_json", nargs="?", type=argparse.FileType('r'),
                        default=sys.stdin)

    args = parser.parse_args()
    logging.basicConfig()

    server_name = args.signature_name
    keys = {}
    for target, port in get_targets(server_name):
        try:
            keys = get_server_keys(server_name, target, port)
            print "Using keys from https://%s:%s/_matrix/key/v1" % (target, port)
            write_signing_keys(sys.stdout, keys.values())
            break
        except:
            logging.exception("Error talking to %s:%s", target, port)

    json_to_check = json.load(args.input_json)
    print "Checking JSON:"
    for key_id in json_to_check["signatures"][args.signature_name]:
        try:
            key = keys[key_id]
            verify_signed_json(json_to_check, args.signature_name, key)
            print "PASS %s" % (key_id,)
        except:
            logging.exception("Check for key %s failed" % (key_id,))
            print "FAIL %s" % (key_id,)
Example #5
0
 def verify_json_for_server(self, server_name, json_object):
     logger.debug("Verifying for %s", server_name)
     key_ids = signature_ids(json_object, server_name)
     if not key_ids:
         raise SynapseError(
             400,
             "Not signed with a supported algorithm",
             Codes.UNAUTHORIZED,
         )
     try:
         verify_key = yield self.get_server_verify_key(server_name, key_ids)
     except IOError:
         raise SynapseError(
             502,
             "Error downloading keys for %s" % (server_name, ),
             Codes.UNAUTHORIZED,
         )
     except:
         raise SynapseError(
             401,
             "No key for %s with id %s" % (server_name, key_ids),
             Codes.UNAUTHORIZED,
         )
     try:
         verify_signed_json(json_object, server_name, verify_key)
     except:
         raise SynapseError(
             401,
             "Invalid signature for server %s with key %s:%s" %
             (server_name, verify_key.alg, verify_key.version),
             Codes.UNAUTHORIZED,
         )
Example #6
0
    def test_verify_fail(self):
        self.signed['signatures']['Alice']['mock:test'] = encode_base64(
            'not a signature')
        print self.signed
        verkey = MockVerifyKey()

        with self.assertRaises(SignatureVerifyException):
            verify_signed_json(self.signed, 'Alice', self.verkey)
Example #7
0
    def _do_invite(self, roomid, userstring):
        if (not userstring.startswith('@')
                and self._is_on("complete_usernames")):
            url = self._identityServerUrl() + "/_matrix/identity/api/v1/lookup"

            json_res = yield self.http_client.do_request("GET",
                                                         url,
                                                         qparams={
                                                             'medium': 'email',
                                                             'address':
                                                             userstring
                                                         })

            mxid = None

            if 'mxid' in json_res and 'signatures' in json_res:
                url = self._identityServerUrl(
                ) + "/_matrix/identity/api/v1/pubkey/ed25519"

                pubKey = None
                pubKeyObj = yield self.http_client.do_request("GET", url)
                if 'public_key' in pubKeyObj:
                    pubKey = nacl.signing.VerifyKey(
                        pubKeyObj['public_key'],
                        encoder=nacl.encoding.HexEncoder)
                else:
                    print "No public key found in pubkey response!"

                sigValid = False

                if pubKey:
                    for signame in json_res['signatures']:
                        if signame not in TRUSTED_ID_SERVERS:
                            print "Ignoring signature from untrusted server %s" % (
                                signame)
                        else:
                            try:
                                verify_signed_json(json_res, signame, pubKey)
                                sigValid = True
                                print "Mapping %s -> %s correctly signed by %s" % (
                                    userstring, json_res['mxid'], signame)
                                break
                            except SignatureVerifyException as e:
                                print "Invalid signature from %s" % (signame)
                                print e

                if sigValid:
                    print "Resolved 3pid %s to %s" % (userstring,
                                                      json_res['mxid'])
                    mxid = json_res['mxid']
                else:
                    print "Got association for %s but couldn't verify signature" % (
                        userstring)

            if not mxid:
                mxid = "@" + userstring + ":" + self._domain()

            self._do_membership_change(roomid, "invite", mxid)
Example #8
0
    def test_verify_fail(self):
        self.signed['signatures']['Alice']['mock:test'] = encode_base64(
            'not a signature'
        )
        print self.signed
        verkey = MockVerifyKey()

        with self.assertRaises(SignatureVerifyException):
            verify_signed_json(self.signed, 'Alice', self.verkey)
Example #9
0
 def test_sign_and_verify(self):
     self.assertIn('signatures', self.signed)
     self.assertIn('Alice', self.signed['signatures'])
     self.assertIn('mock:test', self.signed['signatures']['Alice'])
     self.assertEqual(
         self.signed['signatures']['Alice']['mock:test'],
         encode_base64('x_______')
     )
     verify_signed_json(self.signed, 'Alice', self.verkey)
Example #10
0
def get_server_keys(server_name, target, port):
    url = "https://%s:%i/_matrix/key/v1" % (target, port)
    keys = json.load(urllib2.urlopen(url))
    verify_keys = {}
    for key_id, key_base64 in keys["verify_keys"].items():
        verify_key = decode_verify_key_bytes(key_id, decode_base64(key_base64))
        verify_signed_json(keys, server_name, verify_key)
        verify_keys[key_id] = verify_key
    return verify_keys
Example #11
0
def get_server_keys(server_name, target, port):
    url = "https://%s:%i/_matrix/key/v1" % (target, port)
    keys = json.load(urllib2.urlopen(url))
    verify_keys = {}
    for key_id, key_base64 in keys["verify_keys"].items():
        verify_key = decode_verify_key_bytes(key_id, decode_base64(key_base64))
        verify_signed_json(keys, server_name, verify_key)
        verify_keys[key_id] = verify_key
    return verify_keys
Example #12
0
    def _do_invite(self, roomid, userstring):
        if (not userstring.startswith('@') and
                    self._is_on("complete_usernames")):
            url = self._identityServerUrl()+"/_matrix/identity/api/v1/lookup"

            json_res = yield self.http_client.do_request("GET", url, qparams={'medium':'email','address':userstring})

            mxid = None

            if 'mxid' in json_res and 'signatures' in json_res:
                url = self._identityServerUrl()+"/_matrix/identity/api/v1/pubkey/ed25519"

                pubKey = None
                pubKeyObj = yield self.http_client.do_request("GET", url)
                if 'public_key' in pubKeyObj:
                    pubKey = nacl.signing.VerifyKey(pubKeyObj['public_key'], encoder=nacl.encoding.HexEncoder)
                else:
                    print "No public key found in pubkey response!"

                sigValid = False

                if pubKey:
                    for signame in json_res['signatures']:
                        if signame not in TRUSTED_ID_SERVERS:
                            print "Ignoring signature from untrusted server %s" % (signame)
                        else:
                            try:
                                verify_signed_json(json_res, signame, pubKey)
                                sigValid = True
                                print "Mapping %s -> %s correctly signed by %s" % (userstring, json_res['mxid'], signame)
                                break
                            except SignatureVerifyException as e:
                                print "Invalid signature from %s" % (signame)
                                print e

                if sigValid:
                    print "Resolved 3pid %s to %s" % (userstring, json_res['mxid'])
                    mxid = json_res['mxid']
                else:
                    print "Got association for %s but couldn't verify signature" % (userstring)

            if not mxid:
                mxid = "@" + userstring + ":" + self._domain()

            self._do_membership_change(roomid, "invite", mxid)
Example #13
0
        def handle_key_deferred(group, deferred):
            server_name = group.server_name
            try:
                _, _, key_id, verify_key = yield deferred
            except IOError as e:
                logger.warn(
                    "Got IOError when downloading keys for %s: %s %s",
                    server_name,
                    type(e).__name__,
                    str(e.message),
                )
                raise SynapseError(
                    502,
                    "Error downloading keys for %s" % (server_name, ),
                    Codes.UNAUTHORIZED,
                )
            except Exception as e:
                logger.exception(
                    "Got Exception when downloading keys for %s: %s %s",
                    server_name,
                    type(e).__name__,
                    str(e.message),
                )
                raise SynapseError(
                    401,
                    "No key for %s with id %s" % (server_name, key_ids),
                    Codes.UNAUTHORIZED,
                )

            json_object = group_id_to_json[group.group_id]

            try:
                verify_signed_json(json_object, server_name, verify_key)
            except:
                raise SynapseError(
                    401,
                    "Invalid signature for server %s with key %s:%s" %
                    (server_name, verify_key.alg, verify_key.version),
                    Codes.UNAUTHORIZED,
                )
Example #14
0
    def _async_render_GET(self, request):
        try:
            server_keys, certificate = yield fetch_server_key(
                self.server_name,
                self.key_server.ssl_context_factory
            )

            resp_server_name = server_keys[u"server_name"]
            verify_key_b64 = server_keys[u"signature_verify_key"]
            tls_certificate_b64 = server_keys[u"tls_certificate"]
            verify_key = VerifyKey(decode_base64(verify_key_b64))

            if resp_server_name != self.server_name:
                raise ValueError("Wrong server name '%s' != '%s'" %
                                 (resp_server_name, self.server_name))

            x509_certificate_bytes = crypto.dump_certificate(
                crypto.FILETYPE_ASN1,
                certificate
            )

            if encode_base64(x509_certificate_bytes) != tls_certificate_b64:
                raise ValueError("TLS certificate doesn't match")

            verify_signed_json(server_keys, self.server_name, verify_key)

            signed_json = sign_json(
                server_keys,
                self.key_server.server_name,
                self.key_server.signing_key
            )

            json_bytes = encode_canonical_json(signed_json)
            respond_with_json_bytes(request, 200, json_bytes)

        except Exception as e:
            json_bytes = encode_canonical_json({
                u"error": {u"code": 502, u"message": e.message}
            })
            respond_with_json_bytes(request, 502, json_bytes)
Example #15
0
        def handle_key_deferred(group, deferred):
            server_name = group.server_name
            try:
                _, _, key_id, verify_key = yield deferred
            except IOError as e:
                logger.warn(
                    "Got IOError when downloading keys for %s: %s %s",
                    server_name, type(e).__name__, str(e.message),
                )
                raise SynapseError(
                    502,
                    "Error downloading keys for %s" % (server_name,),
                    Codes.UNAUTHORIZED,
                )
            except Exception as e:
                logger.exception(
                    "Got Exception when downloading keys for %s: %s %s",
                    server_name, type(e).__name__, str(e.message),
                )
                raise SynapseError(
                    401,
                    "No key for %s with id %s" % (server_name, key_ids),
                    Codes.UNAUTHORIZED,
                )

            json_object = group_id_to_json[group.group_id]

            try:
                verify_signed_json(json_object, server_name, verify_key)
            except:
                raise SynapseError(
                    401,
                    "Invalid signature for server %s with key %s:%s" % (
                        server_name, verify_key.alg, verify_key.version
                    ),
                    Codes.UNAUTHORIZED,
                )
Example #16
0
def reinsert_events(cursor, server_name, signing_key):
    print "Running delta: v10"

    cursor.executescript(delta_sql)

    cursor.execute(
        "SELECT * FROM events ORDER BY rowid ASC"
    )

    print "Getting events..."

    rows = store.cursor_to_dict(cursor)

    events = store._generate_event_json(cursor, rows)

    print "Got events from DB."

    algorithms = {
        "sha256": hashlib.sha256,
    }

    key_id = "%s:%s" % (signing_key.alg, signing_key.version)
    verify_key = signing_key.verify_key
    verify_key.alg = signing_key.alg
    verify_key.version = signing_key.version

    server_keys = {
        server_name: {
            key_id: verify_key
        }
    }

    i = 0
    N = len(events)

    for event in events:
        if i % 100 == 0:
            print "Processed: %d/%d events" % (i,N,)
        i += 1

        # for alg_name in event.hashes:
        #     if check_event_content_hash(event, algorithms[alg_name]):
        #         pass
        #     else:
        #         pass
        #         print "FAIL content hash %s %s" % (alg_name, event.event_id, )

        have_own_correctly_signed = False
        for host, sigs in event.signatures.items():
            pruned = prune_event(event)

            for key_id in sigs:
                if host not in server_keys:
                    server_keys[host] = {}  # get_key(host)
                if key_id in server_keys[host]:
                    try:
                        verify_signed_json(
                            pruned.get_pdu_json(),
                            host,
                            server_keys[host][key_id]
                        )

                        if host == server_name:
                            have_own_correctly_signed = True
                    except SignatureVerifyException:
                        print "FAIL signature check %s %s" % (
                            key_id, event.event_id
                        )

        # TODO: Re sign with our own server key
        if not have_own_correctly_signed:
            sigs = compute_event_signature(event, server_name, signing_key)
            event.signatures.update(sigs)

            pruned = prune_event(event)

            for key_id in event.signatures[server_name]:
                verify_signed_json(
                    pruned.get_pdu_json(),
                    server_name,
                    server_keys[server_name][key_id]
                )

        event_json = encode_canonical_json(
            event.get_dict()
        ).decode("UTF-8")

        metadata_json = encode_canonical_json(
            event.internal_metadata.get_dict()
        ).decode("UTF-8")

        store._simple_insert_txn(
            cursor,
            table="event_json",
            values={
                "event_id": event.event_id,
                "room_id": event.room_id,
                "internal_metadata": metadata_json,
                "json": event_json,
            },
            or_replace=True,
        )
Example #17
0
    def get_server_verify_key_v1_direct(self, server_name, key_ids):
        """Finds a verification key for the server with one of the key ids.
        Args:
            server_name (str): The name of the server to fetch a key for.
            keys_ids (list of str): The key_ids to check for.
        """

        # Try to fetch the key from the remote server.

        (response,
         tls_certificate) = yield fetch_server_key(server_name,
                                                   self.hs.tls_context_factory)

        # Check the response.

        x509_certificate_bytes = crypto.dump_certificate(
            crypto.FILETYPE_ASN1, tls_certificate)

        if ("signatures" not in response
                or server_name not in response["signatures"]):
            raise ValueError("Key response not signed by remote server")

        if "tls_certificate" not in response:
            raise ValueError("Key response missing TLS certificate")

        tls_certificate_b64 = response["tls_certificate"]

        if encode_base64(x509_certificate_bytes) != tls_certificate_b64:
            raise ValueError("TLS certificate doesn't match")

        # Cache the result in the datastore.

        time_now_ms = self.clock.time_msec()

        verify_keys = {}
        for key_id, key_base64 in response["verify_keys"].items():
            if is_signing_algorithm_supported(key_id):
                key_bytes = decode_base64(key_base64)
                verify_key = decode_verify_key_bytes(key_id, key_bytes)
                verify_key.time_added = time_now_ms
                verify_keys[key_id] = verify_key

        for key_id in response["signatures"][server_name]:
            if key_id not in response["verify_keys"]:
                raise ValueError(
                    "Key response must include verification keys for all"
                    " signatures")
            if key_id in verify_keys:
                verify_signed_json(response, server_name, verify_keys[key_id])

        yield self.store.store_server_certificate(
            server_name,
            server_name,
            time_now_ms,
            tls_certificate,
        )

        yield self.store_keys(
            server_name=server_name,
            from_server=server_name,
            verify_keys=verify_keys,
        )

        defer.returnValue(verify_keys)
Example #18
0
    def get_server_verify_key(self, server_name, key_ids):
        """Finds a verification key for the server with one of the key ids.
        Args:
            server_name (str): The name of the server to fetch a key for.
            keys_ids (list of str): The key_ids to check for.
        """

        # Check the datastore to see if we have one cached.
        cached = yield self.store.get_server_verify_keys(server_name, key_ids)

        if cached:
            defer.returnValue(cached[0])
            return

        # Try to fetch the key from the remote server.

        limiter = yield get_retry_limiter(
            server_name,
            self.clock,
            self.store,
        )

        with limiter:
            (response, tls_certificate) = yield fetch_server_key(
                server_name, self.hs.tls_context_factory
            )

        # Check the response.

        x509_certificate_bytes = crypto.dump_certificate(
            crypto.FILETYPE_ASN1, tls_certificate
        )

        if ("signatures" not in response
                or server_name not in response["signatures"]):
            raise ValueError("Key response not signed by remote server")

        if "tls_certificate" not in response:
            raise ValueError("Key response missing TLS certificate")

        tls_certificate_b64 = response["tls_certificate"]

        if encode_base64(x509_certificate_bytes) != tls_certificate_b64:
            raise ValueError("TLS certificate doesn't match")

        verify_keys = {}
        for key_id, key_base64 in response["verify_keys"].items():
            if is_signing_algorithm_supported(key_id):
                key_bytes = decode_base64(key_base64)
                verify_key = decode_verify_key_bytes(key_id, key_bytes)
                verify_keys[key_id] = verify_key

        for key_id in response["signatures"][server_name]:
            if key_id not in response["verify_keys"]:
                raise ValueError(
                    "Key response must include verification keys for all"
                    " signatures"
                )
            if key_id in verify_keys:
                verify_signed_json(
                    response,
                    server_name,
                    verify_keys[key_id]
                )

        # Cache the result in the datastore.

        time_now_ms = self.clock.time_msec()

        yield self.store.store_server_certificate(
            server_name,
            server_name,
            time_now_ms,
            tls_certificate,
        )

        for key_id, key in verify_keys.items():
            yield self.store.store_server_verify_key(
                server_name, server_name, time_now_ms, key
            )

        for key_id in key_ids:
            if key_id in verify_keys:
                defer.returnValue(verify_keys[key_id])
                return

        raise ValueError("No verification key found for given key ids")
Example #19
0
    def get_server_verify_key_v2_indirect(self, server_name, key_ids,
                                          perspective_name, perspective_keys):
        limiter = yield get_retry_limiter(perspective_name, self.clock,
                                          self.store)

        with limiter:
            # TODO(mark): Set the minimum_valid_until_ts to that needed by
            # the events being validated or the current time if validating
            # an incoming request.
            responses = yield self.client.post_json(
                destination=perspective_name,
                path=b"/_matrix/key/v2/query",
                data={
                    u"server_keys": {
                        server_name: {
                            key_id: {
                                u"minimum_valid_until_ts": 0
                            }
                            for key_id in key_ids
                        }
                    }
                },
            )

        keys = {}

        for response in responses:
            if (u"signatures" not in response
                    or perspective_name not in response[u"signatures"]):
                raise ValueError(
                    "Key response not signed by perspective server"
                    " %r" % (perspective_name, ))

            verified = False
            for key_id in response[u"signatures"][perspective_name]:
                if key_id in perspective_keys:
                    verify_signed_json(response, perspective_name,
                                       perspective_keys[key_id])
                    verified = True

            if not verified:
                logging.info(
                    "Response from perspective server %r not signed with a"
                    " known key, signed with: %r, known keys: %r",
                    perspective_name,
                    list(response[u"signatures"][perspective_name]),
                    list(perspective_keys))
                raise ValueError(
                    "Response not signed with a known key for perspective"
                    " server %r" % (perspective_name, ))

            response_keys = yield self.process_v2_response(
                server_name, perspective_name, response)

            keys.update(response_keys)

        yield self.store_keys(
            server_name=server_name,
            from_server=perspective_name,
            verify_keys=keys,
        )

        defer.returnValue(keys)
Example #20
0
    def process_v2_response(self,
                            server_name,
                            from_server,
                            response_json,
                            requested_id=None):
        time_now_ms = self.clock.time_msec()
        response_keys = {}
        verify_keys = {}
        for key_id, key_data in response_json["verify_keys"].items():
            if is_signing_algorithm_supported(key_id):
                key_base64 = key_data["key"]
                key_bytes = decode_base64(key_base64)
                verify_key = decode_verify_key_bytes(key_id, key_bytes)
                verify_key.time_added = time_now_ms
                verify_keys[key_id] = verify_key

        old_verify_keys = {}
        for key_id, key_data in response_json["old_verify_keys"].items():
            if is_signing_algorithm_supported(key_id):
                key_base64 = key_data["key"]
                key_bytes = decode_base64(key_base64)
                verify_key = decode_verify_key_bytes(key_id, key_bytes)
                verify_key.expired = key_data["expired_ts"]
                verify_key.time_added = time_now_ms
                old_verify_keys[key_id] = verify_key

        for key_id in response_json["signatures"][server_name]:
            if key_id not in response_json["verify_keys"]:
                raise ValueError(
                    "Key response must include verification keys for all"
                    " signatures")
            if key_id in verify_keys:
                verify_signed_json(response_json, server_name,
                                   verify_keys[key_id])

        signed_key_json = sign_json(
            response_json,
            self.config.server_name,
            self.config.signing_key[0],
        )

        signed_key_json_bytes = encode_canonical_json(signed_key_json)
        ts_valid_until_ms = signed_key_json[u"valid_until_ts"]

        updated_key_ids = set()
        if requested_id is not None:
            updated_key_ids.add(requested_id)
        updated_key_ids.update(verify_keys)
        updated_key_ids.update(old_verify_keys)

        response_keys.update(verify_keys)
        response_keys.update(old_verify_keys)

        for key_id in updated_key_ids:
            yield self.store.store_server_keys_json(
                server_name=server_name,
                key_id=key_id,
                from_server=server_name,
                ts_now_ms=time_now_ms,
                ts_expires_ms=ts_valid_until_ms,
                key_json_bytes=signed_key_json_bytes,
            )

        defer.returnValue(response_keys)

        raise ValueError("No verification key found for given key ids")
Example #21
0
def reinsert_events(cursor, server_name, signing_key):
    print "Running delta: v10"

    cursor.executescript(delta_sql)

    cursor.execute("SELECT * FROM events ORDER BY rowid ASC")

    print "Getting events..."

    rows = store.cursor_to_dict(cursor)

    events = store._generate_event_json(cursor, rows)

    print "Got events from DB."

    algorithms = {
        "sha256": hashlib.sha256,
    }

    key_id = "%s:%s" % (signing_key.alg, signing_key.version)
    verify_key = signing_key.verify_key
    verify_key.alg = signing_key.alg
    verify_key.version = signing_key.version

    server_keys = {server_name: {key_id: verify_key}}

    i = 0
    N = len(events)

    for event in events:
        if i % 100 == 0:
            print "Processed: %d/%d events" % (
                i,
                N,
            )
        i += 1

        # for alg_name in event.hashes:
        #     if check_event_content_hash(event, algorithms[alg_name]):
        #         pass
        #     else:
        #         pass
        #         print "FAIL content hash %s %s" % (alg_name, event.event_id, )

        have_own_correctly_signed = False
        for host, sigs in event.signatures.items():
            pruned = prune_event(event)

            for key_id in sigs:
                if host not in server_keys:
                    server_keys[host] = {}  # get_key(host)
                if key_id in server_keys[host]:
                    try:
                        verify_signed_json(pruned.get_pdu_json(), host,
                                           server_keys[host][key_id])

                        if host == server_name:
                            have_own_correctly_signed = True
                    except SignatureVerifyException:
                        print "FAIL signature check %s %s" % (key_id,
                                                              event.event_id)

        # TODO: Re sign with our own server key
        if not have_own_correctly_signed:
            sigs = compute_event_signature(event, server_name, signing_key)
            event.signatures.update(sigs)

            pruned = prune_event(event)

            for key_id in event.signatures[server_name]:
                verify_signed_json(pruned.get_pdu_json(), server_name,
                                   server_keys[server_name][key_id])

        event_json = encode_canonical_json(event.get_dict()).decode("UTF-8")

        metadata_json = encode_canonical_json(
            event.internal_metadata.get_dict()).decode("UTF-8")

        store._simple_insert_txn(
            cursor,
            table="event_json",
            values={
                "event_id": event.event_id,
                "room_id": event.room_id,
                "internal_metadata": metadata_json,
                "json": event_json,
            },
            or_replace=True,
        )
Example #22
0
    def process_v2_response(self, server_name, from_server, response_json,
                            requested_id=None):
        time_now_ms = self.clock.time_msec()
        response_keys = {}
        verify_keys = {}
        for key_id, key_data in response_json["verify_keys"].items():
            if is_signing_algorithm_supported(key_id):
                key_base64 = key_data["key"]
                key_bytes = decode_base64(key_base64)
                verify_key = decode_verify_key_bytes(key_id, key_bytes)
                verify_key.time_added = time_now_ms
                verify_keys[key_id] = verify_key

        old_verify_keys = {}
        for key_id, key_data in response_json["old_verify_keys"].items():
            if is_signing_algorithm_supported(key_id):
                key_base64 = key_data["key"]
                key_bytes = decode_base64(key_base64)
                verify_key = decode_verify_key_bytes(key_id, key_bytes)
                verify_key.expired = key_data["expired_ts"]
                verify_key.time_added = time_now_ms
                old_verify_keys[key_id] = verify_key

        for key_id in response_json["signatures"].get(server_name, {}):
            if key_id not in response_json["verify_keys"]:
                raise ValueError(
                    "Key response must include verification keys for all"
                    " signatures"
                )
            if key_id in verify_keys:
                verify_signed_json(
                    response_json,
                    server_name,
                    verify_keys[key_id]
                )

        signed_key_json = sign_json(
            response_json,
            self.config.server_name,
            self.config.signing_key[0],
        )

        signed_key_json_bytes = encode_canonical_json(signed_key_json)
        ts_valid_until_ms = signed_key_json[u"valid_until_ts"]

        updated_key_ids = set()
        if requested_id is not None:
            updated_key_ids.add(requested_id)
        updated_key_ids.update(verify_keys)
        updated_key_ids.update(old_verify_keys)

        response_keys.update(verify_keys)
        response_keys.update(old_verify_keys)

        for key_id in updated_key_ids:
            yield self.store.store_server_keys_json(
                server_name=server_name,
                key_id=key_id,
                from_server=server_name,
                ts_now_ms=time_now_ms,
                ts_expires_ms=ts_valid_until_ms,
                key_json_bytes=signed_key_json_bytes,
            )

        defer.returnValue(response_keys)

        raise ValueError("No verification key found for given key ids")
Example #23
0
    def get_server_verify_key_v2_indirect(self, server_name, key_ids,
                                          perspective_name,
                                          perspective_keys):
        limiter = yield get_retry_limiter(
            perspective_name, self.clock, self.store
        )

        with limiter:
            # TODO(mark): Set the minimum_valid_until_ts to that needed by
            # the events being validated or the current time if validating
            # an incoming request.
            query_response = yield self.client.post_json(
                destination=perspective_name,
                path=b"/_matrix/key/v2/query",
                data={
                    u"server_keys": {
                        server_name: {
                            key_id: {
                                u"minimum_valid_until_ts": 0
                            } for key_id in key_ids
                        }
                    }
                },
            )

        keys = {}

        responses = query_response["server_keys"]

        for response in responses:
            if (u"signatures" not in response
                    or perspective_name not in response[u"signatures"]):
                raise ValueError(
                    "Key response not signed by perspective server"
                    " %r" % (perspective_name,)
                )

            verified = False
            for key_id in response[u"signatures"][perspective_name]:
                if key_id in perspective_keys:
                    verify_signed_json(
                        response,
                        perspective_name,
                        perspective_keys[key_id]
                    )
                    verified = True

            if not verified:
                logging.info(
                    "Response from perspective server %r not signed with a"
                    " known key, signed with: %r, known keys: %r",
                    perspective_name,
                    list(response[u"signatures"][perspective_name]),
                    list(perspective_keys)
                )
                raise ValueError(
                    "Response not signed with a known key for perspective"
                    " server %r" % (perspective_name,)
                )

            response_keys = yield self.process_v2_response(
                server_name, perspective_name, response
            )

            keys.update(response_keys)

        yield self.store_keys(
            server_name=server_name,
            from_server=perspective_name,
            verify_keys=keys,
        )

        defer.returnValue(keys)
Example #24
0
    def process_v2_response(self, from_server, response_json,
                            requested_ids=[]):
        time_now_ms = self.clock.time_msec()
        response_keys = {}
        verify_keys = {}
        for key_id, key_data in response_json["verify_keys"].items():
            if is_signing_algorithm_supported(key_id):
                key_base64 = key_data["key"]
                key_bytes = decode_base64(key_base64)
                verify_key = decode_verify_key_bytes(key_id, key_bytes)
                verify_key.time_added = time_now_ms
                verify_keys[key_id] = verify_key

        old_verify_keys = {}
        for key_id, key_data in response_json["old_verify_keys"].items():
            if is_signing_algorithm_supported(key_id):
                key_base64 = key_data["key"]
                key_bytes = decode_base64(key_base64)
                verify_key = decode_verify_key_bytes(key_id, key_bytes)
                verify_key.expired = key_data["expired_ts"]
                verify_key.time_added = time_now_ms
                old_verify_keys[key_id] = verify_key

        results = {}
        server_name = response_json["server_name"]
        for key_id in response_json["signatures"].get(server_name, {}):
            if key_id not in response_json["verify_keys"]:
                raise ValueError(
                    "Key response must include verification keys for all"
                    " signatures"
                )
            if key_id in verify_keys:
                verify_signed_json(
                    response_json,
                    server_name,
                    verify_keys[key_id]
                )

        signed_key_json = sign_json(
            response_json,
            self.config.server_name,
            self.config.signing_key[0],
        )

        signed_key_json_bytes = encode_canonical_json(signed_key_json)
        ts_valid_until_ms = signed_key_json[u"valid_until_ts"]

        updated_key_ids = set(requested_ids)
        updated_key_ids.update(verify_keys)
        updated_key_ids.update(old_verify_keys)

        response_keys.update(verify_keys)
        response_keys.update(old_verify_keys)

        yield defer.gatherResults(
            [
                self.store.store_server_keys_json(
                    server_name=server_name,
                    key_id=key_id,
                    from_server=server_name,
                    ts_now_ms=time_now_ms,
                    ts_expires_ms=ts_valid_until_ms,
                    key_json_bytes=signed_key_json_bytes,
                )
                for key_id in updated_key_ids
            ],
            consumeErrors=True,
        ).addErrback(unwrapFirstError)

        results[server_name] = response_keys

        defer.returnValue(results)
Example #25
0
    def process_v2_response(self,
                            from_server,
                            response_json,
                            requested_ids=[]):
        time_now_ms = self.clock.time_msec()
        response_keys = {}
        verify_keys = {}
        for key_id, key_data in response_json["verify_keys"].items():
            if is_signing_algorithm_supported(key_id):
                key_base64 = key_data["key"]
                key_bytes = decode_base64(key_base64)
                verify_key = decode_verify_key_bytes(key_id, key_bytes)
                verify_key.time_added = time_now_ms
                verify_keys[key_id] = verify_key

        old_verify_keys = {}
        for key_id, key_data in response_json["old_verify_keys"].items():
            if is_signing_algorithm_supported(key_id):
                key_base64 = key_data["key"]
                key_bytes = decode_base64(key_base64)
                verify_key = decode_verify_key_bytes(key_id, key_bytes)
                verify_key.expired = key_data["expired_ts"]
                verify_key.time_added = time_now_ms
                old_verify_keys[key_id] = verify_key

        results = {}
        server_name = response_json["server_name"]
        for key_id in response_json["signatures"].get(server_name, {}):
            if key_id not in response_json["verify_keys"]:
                raise ValueError(
                    "Key response must include verification keys for all"
                    " signatures")
            if key_id in verify_keys:
                verify_signed_json(response_json, server_name,
                                   verify_keys[key_id])

        signed_key_json = sign_json(
            response_json,
            self.config.server_name,
            self.config.signing_key[0],
        )

        signed_key_json_bytes = encode_canonical_json(signed_key_json)
        ts_valid_until_ms = signed_key_json[u"valid_until_ts"]

        updated_key_ids = set(requested_ids)
        updated_key_ids.update(verify_keys)
        updated_key_ids.update(old_verify_keys)

        response_keys.update(verify_keys)
        response_keys.update(old_verify_keys)

        yield defer.gatherResults(
            [
                self.store.store_server_keys_json(
                    server_name=server_name,
                    key_id=key_id,
                    from_server=server_name,
                    ts_now_ms=time_now_ms,
                    ts_expires_ms=ts_valid_until_ms,
                    key_json_bytes=signed_key_json_bytes,
                ) for key_id in updated_key_ids
            ],
            consumeErrors=True,
        ).addErrback(unwrapFirstError)

        results[server_name] = response_keys

        defer.returnValue(results)