Exemple #1
0
        def get_key_from_perspectives(response):
            fetcher = PerspectivesKeyFetcher(self.hs)
            keys_to_fetch = {SERVER_NAME: {"key1": 0}}

            def post_json(destination, path, data, **kwargs):
                self.assertEqual(destination, self.mock_perspective_server.server_name)
                self.assertEqual(path, "/_matrix/key/v2/query")
                return {"server_keys": [response]}

            self.http_client.post_json.side_effect = post_json

            return self.get_success(fetcher.get_keys(keys_to_fetch))
Exemple #2
0
    def test_get_perspectives_own_key(self):
        """Check that we can get the perspectives server's own keys

        This is slightly complicated by the fact that the perspectives server may
        use different keys for signing notary responses.
        """

        # arbitrarily advance the clock a bit
        self.reactor.advance(100)

        fetcher = PerspectivesKeyFetcher(self.hs)

        SERVER_NAME = self.mock_perspective_server.server_name
        testkey = signedjson.key.generate_signing_key("ver1")
        testverifykey = signedjson.key.get_verify_key(testkey)
        testverifykey_id = "ed25519:ver1"
        VALID_UNTIL_TS = 200 * 1000

        response = self.build_perspectives_response(
            SERVER_NAME, testkey, VALID_UNTIL_TS
        )

        self.expect_outgoing_key_query(SERVER_NAME, "key1", response)

        keys_to_fetch = {SERVER_NAME: {"key1": 0}}
        keys = self.get_success(fetcher.get_keys(keys_to_fetch))
        self.assertIn(SERVER_NAME, keys)
        k = keys[SERVER_NAME][testverifykey_id]
        self.assertEqual(k.valid_until_ts, VALID_UNTIL_TS)
        self.assertEqual(k.verify_key, testverifykey)
        self.assertEqual(k.verify_key.alg, "ed25519")
        self.assertEqual(k.verify_key.version, "ver1")

        # check that the perspectives store is correctly updated
        lookup_triplet = (SERVER_NAME, testverifykey_id, None)
        key_json = self.get_success(
            self.hs.get_datastore().get_server_keys_json([lookup_triplet])
        )
        res = key_json[lookup_triplet]
        self.assertEqual(len(res), 1)
        res = res[0]
        self.assertEqual(res["key_id"], testverifykey_id)
        self.assertEqual(res["from_server"], self.mock_perspective_server.server_name)
        self.assertEqual(res["ts_added_ms"], self.reactor.seconds() * 1000)
        self.assertEqual(res["ts_valid_until_ms"], VALID_UNTIL_TS)

        self.assertEqual(
            bytes(res["key_json"]), canonicaljson.encode_canonical_json(response)
        )
    def test_get_notary_keyserver_key(self):
        """Fetch the notary's keyserver key"""
        # we expect hs1 to make a regular key request to itself
        self.expect_outgoing_key_request(self.hs.hostname, self.hs_signing_key)
        keyid = "ed25519:%s" % (self.hs_signing_key.version,)

        fetcher = PerspectivesKeyFetcher(self.hs2)
        d = fetcher.get_keys({self.hs.hostname: {keyid: 1000}})
        res = self.get_success(d)
        self.assertIn(self.hs.hostname, res)
        keyres = res[self.hs.hostname][keyid]
        assert isinstance(keyres, FetchKeyResult)
        self.assertEqual(
            signedjson.key.encode_verify_key_base64(keyres.verify_key),
            signedjson.key.encode_verify_key_base64(self.hs_signing_key.verify_key),
        )
Exemple #4
0
    def test_get_keys_from_perspectives(self):
        # arbitrarily advance the clock a bit
        self.reactor.advance(100)

        fetcher = PerspectivesKeyFetcher(self.hs)

        SERVER_NAME = "server2"
        testkey = signedjson.key.generate_signing_key("ver1")
        testverifykey = signedjson.key.get_verify_key(testkey)
        testverifykey_id = "ed25519:ver1"
        VALID_UNTIL_TS = 200 * 1000

        response = self.build_perspectives_response(
            SERVER_NAME,
            testkey,
            VALID_UNTIL_TS,
        )

        self.expect_outgoing_key_query(SERVER_NAME, "key1", response)

        keys = self.get_success(fetcher.get_keys(SERVER_NAME, ["key1"], 0))
        self.assertIn(testverifykey_id, keys)
        k = keys[testverifykey_id]
        self.assertEqual(k.valid_until_ts, VALID_UNTIL_TS)
        self.assertEqual(k.verify_key, testverifykey)
        self.assertEqual(k.verify_key.alg, "ed25519")
        self.assertEqual(k.verify_key.version, "ver1")

        # check that the perspectives store is correctly updated
        lookup_triplet = (SERVER_NAME, testverifykey_id, None)
        key_json = self.get_success(
            self.hs.get_datastores().main.get_server_keys_json(
                [lookup_triplet]))
        res = key_json[lookup_triplet]
        self.assertEqual(len(res), 1)
        res = res[0]
        self.assertEqual(res["key_id"], testverifykey_id)
        self.assertEqual(res["from_server"],
                         self.mock_perspective_server.server_name)
        self.assertEqual(res["ts_added_ms"], self.reactor.seconds() * 1000)
        self.assertEqual(res["ts_valid_until_ms"], VALID_UNTIL_TS)

        self.assertEqual(bytes(res["key_json"]),
                         canonicaljson.encode_canonical_json(response))
Exemple #5
0
    def test_get_key(self):
        """Fetch a key belonging to a random server"""
        # make up a key to be fetched.
        testkey = signedjson.key.generate_signing_key("abc")

        # we expect hs1 to make a regular key request to the target server
        self.expect_outgoing_key_request("targetserver", testkey)
        keyid = "ed25519:%s" % (testkey.version, )

        fetcher = PerspectivesKeyFetcher(self.hs2)
        d = fetcher.get_keys({"targetserver": {keyid: 1000}})
        res = self.get_success(d)
        self.assertIn("targetserver", res)
        keyres = res["targetserver"][keyid]
        assert isinstance(keyres, FetchKeyResult)
        self.assertEqual(
            signedjson.key.encode_verify_key_base64(keyres.verify_key),
            signedjson.key.encode_verify_key_base64(testkey.verify_key),
        )
Exemple #6
0
    def test_get_notary_key(self):
        """Fetch a key belonging to the notary server"""
        # make up a key to be fetched. We randomise the keyid to try to get it to
        # appear before the key server signing key sometimes (otherwise we bail out
        # before fetching its signature)
        testkey = signedjson.key.generate_signing_key(random_string(5))

        # we expect hs1 to make a regular key request to itself
        self.expect_outgoing_key_request(self.hs.hostname, testkey)
        keyid = "ed25519:%s" % (testkey.version, )

        fetcher = PerspectivesKeyFetcher(self.hs2)
        d = fetcher.get_keys({self.hs.hostname: {keyid: 1000}})
        res = self.get_success(d)
        self.assertIn(self.hs.hostname, res)
        keyres = res[self.hs.hostname][keyid]
        assert isinstance(keyres, FetchKeyResult)
        self.assertEqual(
            signedjson.key.encode_verify_key_base64(keyres.verify_key),
            signedjson.key.encode_verify_key_base64(testkey.verify_key),
        )
Exemple #7
0
    def test_get_keys_from_perspectives(self):
        # arbitrarily advance the clock a bit
        self.reactor.advance(100)

        fetcher = PerspectivesKeyFetcher(self.hs)

        SERVER_NAME = "server2"
        testkey = signedjson.key.generate_signing_key("ver1")
        testverifykey = signedjson.key.get_verify_key(testkey)
        testverifykey_id = "ed25519:ver1"
        VALID_UNTIL_TS = 200 * 1000

        # valid response
        response = {
            "server_name": SERVER_NAME,
            "old_verify_keys": {},
            "valid_until_ts": VALID_UNTIL_TS,
            "verify_keys": {
                testverifykey_id: {
                    "key": signedjson.key.encode_verify_key_base64(testverifykey)
                }
            },
        }

        # the response must be signed by both the origin server and the perspectives
        # server.
        signedjson.sign.sign_json(response, SERVER_NAME, testkey)
        self.mock_perspective_server.sign_response(response)

        def post_json(destination, path, data, **kwargs):
            self.assertEqual(destination, self.mock_perspective_server.server_name)
            self.assertEqual(path, "/_matrix/key/v2/query")

            # check that the request is for the expected key
            q = data["server_keys"]
            self.assertEqual(list(q[SERVER_NAME].keys()), ["key1"])
            return {"server_keys": [response]}

        self.http_client.post_json.side_effect = post_json

        keys_to_fetch = {SERVER_NAME: {"key1": 0}}
        keys = self.get_success(fetcher.get_keys(keys_to_fetch))
        self.assertIn(SERVER_NAME, keys)
        k = keys[SERVER_NAME][testverifykey_id]
        self.assertEqual(k.valid_until_ts, VALID_UNTIL_TS)
        self.assertEqual(k.verify_key, testverifykey)
        self.assertEqual(k.verify_key.alg, "ed25519")
        self.assertEqual(k.verify_key.version, "ver1")

        # check that the perspectives store is correctly updated
        lookup_triplet = (SERVER_NAME, testverifykey_id, None)
        key_json = self.get_success(
            self.hs.get_datastore().get_server_keys_json([lookup_triplet])
        )
        res = key_json[lookup_triplet]
        self.assertEqual(len(res), 1)
        res = res[0]
        self.assertEqual(res["key_id"], testverifykey_id)
        self.assertEqual(res["from_server"], self.mock_perspective_server.server_name)
        self.assertEqual(res["ts_added_ms"], self.reactor.seconds() * 1000)
        self.assertEqual(res["ts_valid_until_ms"], VALID_UNTIL_TS)

        self.assertEqual(
            bytes(res["key_json"]), canonicaljson.encode_canonical_json(response)
        )
Exemple #8
0
 def get_key_from_perspectives(response):
     fetcher = PerspectivesKeyFetcher(self.hs)
     self.expect_outgoing_key_query(SERVER_NAME, "key1", response)
     return self.get_success(fetcher.get_keys(SERVER_NAME, ["key1"], 0))
Exemple #9
0
    def test_get_multiple_keys_from_perspectives(self):
        """Check that we can correctly request multiple keys for the same server"""

        fetcher = PerspectivesKeyFetcher(self.hs)

        SERVER_NAME = "server2"

        testkey1 = signedjson.key.generate_signing_key("ver1")
        testverifykey1 = signedjson.key.get_verify_key(testkey1)
        testverifykey1_id = "ed25519:ver1"

        testkey2 = signedjson.key.generate_signing_key("ver2")
        testverifykey2 = signedjson.key.get_verify_key(testkey2)
        testverifykey2_id = "ed25519:ver2"

        VALID_UNTIL_TS = 200 * 1000

        response1 = self.build_perspectives_response(
            SERVER_NAME,
            testkey1,
            VALID_UNTIL_TS,
        )
        response2 = self.build_perspectives_response(
            SERVER_NAME,
            testkey2,
            VALID_UNTIL_TS,
        )

        async def post_json(destination, path, data, **kwargs):
            self.assertEqual(destination,
                             self.mock_perspective_server.server_name)
            self.assertEqual(path, "/_matrix/key/v2/query")

            # check that the request is for the expected keys
            q = data["server_keys"]

            self.assertEqual(list(q[SERVER_NAME].keys()),
                             [testverifykey1_id, testverifykey2_id])
            return {"server_keys": [response1, response2]}

        self.http_client.post_json.side_effect = post_json

        # fire off two separate requests; they should get merged together into a
        # single HTTP hit.
        request1_d = defer.ensureDeferred(
            fetcher.get_keys(SERVER_NAME, [testverifykey1_id], 0))
        request2_d = defer.ensureDeferred(
            fetcher.get_keys(SERVER_NAME, [testverifykey2_id], 0))

        keys1 = self.get_success(request1_d)
        self.assertIn(testverifykey1_id, keys1)
        k = keys1[testverifykey1_id]
        self.assertEqual(k.valid_until_ts, VALID_UNTIL_TS)
        self.assertEqual(k.verify_key, testverifykey1)
        self.assertEqual(k.verify_key.alg, "ed25519")
        self.assertEqual(k.verify_key.version, "ver1")

        keys2 = self.get_success(request2_d)
        self.assertIn(testverifykey2_id, keys2)
        k = keys2[testverifykey2_id]
        self.assertEqual(k.valid_until_ts, VALID_UNTIL_TS)
        self.assertEqual(k.verify_key, testverifykey2)
        self.assertEqual(k.verify_key.alg, "ed25519")
        self.assertEqual(k.verify_key.version, "ver2")

        # finally, ensure that only one request was sent
        self.assertEqual(self.http_client.post_json.call_count, 1)
Exemple #10
0
 def get_key_from_perspectives(response):
     fetcher = PerspectivesKeyFetcher(self.hs)
     keys_to_fetch = {SERVER_NAME: {"key1": 0}}
     self.expect_outgoing_key_query(SERVER_NAME, "key1", response)
     return self.get_success(fetcher.get_keys(keys_to_fetch))