forked from MirrorHub/synapse
Fix key verification when key stored with null valid_until_ms
Some keys are stored in the synapse database with a null valid_until_ms which caused an exception to be thrown when using that key. We fix this by treating nulls as zeroes, i.e. they keys will match verification requests with a minimum_valid_until_ms of zero (i.e. don't validate ts) but will not match requests with a non-zero minimum_valid_until_ms. Fixes #5391.
This commit is contained in:
parent
7c455a86bc
commit
43badd2cd4
2 changed files with 57 additions and 1 deletions
|
@ -80,6 +80,14 @@ class KeyStore(SQLBaseStore):
|
||||||
|
|
||||||
for row in txn:
|
for row in txn:
|
||||||
server_name, key_id, key_bytes, ts_valid_until_ms = row
|
server_name, key_id, key_bytes, ts_valid_until_ms = row
|
||||||
|
|
||||||
|
if ts_valid_until_ms is None:
|
||||||
|
# Old keys may be stored with a ts_valid_until_ms of null,
|
||||||
|
# in which case we treat this as if it was set to `0`, i.e.
|
||||||
|
# it won't match key requests that define a minimum
|
||||||
|
# `ts_valid_until_ms`.
|
||||||
|
ts_valid_until_ms = 0
|
||||||
|
|
||||||
res = FetchKeyResult(
|
res = FetchKeyResult(
|
||||||
verify_key=decode_verify_key_bytes(key_id, bytes(key_bytes)),
|
verify_key=decode_verify_key_bytes(key_id, bytes(key_bytes)),
|
||||||
valid_until_ts=ts_valid_until_ms,
|
valid_until_ts=ts_valid_until_ms,
|
||||||
|
|
|
@ -25,7 +25,11 @@ from twisted.internet import defer
|
||||||
|
|
||||||
from synapse.api.errors import SynapseError
|
from synapse.api.errors import SynapseError
|
||||||
from synapse.crypto import keyring
|
from synapse.crypto import keyring
|
||||||
from synapse.crypto.keyring import PerspectivesKeyFetcher, ServerKeyFetcher
|
from synapse.crypto.keyring import (
|
||||||
|
PerspectivesKeyFetcher,
|
||||||
|
ServerKeyFetcher,
|
||||||
|
StoreKeyFetcher,
|
||||||
|
)
|
||||||
from synapse.storage.keys import FetchKeyResult
|
from synapse.storage.keys import FetchKeyResult
|
||||||
from synapse.util import logcontext
|
from synapse.util import logcontext
|
||||||
from synapse.util.logcontext import LoggingContext
|
from synapse.util.logcontext import LoggingContext
|
||||||
|
@ -219,6 +223,50 @@ class KeyringTestCase(unittest.HomeserverTestCase):
|
||||||
# self.assertFalse(d.called)
|
# self.assertFalse(d.called)
|
||||||
self.get_success(d)
|
self.get_success(d)
|
||||||
|
|
||||||
|
def test_verify_json_for_server_with_null_valid_until_ms(self):
|
||||||
|
"""Tests that we correctly handle key requests for keys we've stored
|
||||||
|
with a null `ts_valid_until_ms`
|
||||||
|
"""
|
||||||
|
mock_fetcher = keyring.KeyFetcher()
|
||||||
|
mock_fetcher.get_keys = Mock(return_value=defer.succeed({}))
|
||||||
|
|
||||||
|
kr = keyring.Keyring(
|
||||||
|
self.hs, key_fetchers=(StoreKeyFetcher(self.hs), mock_fetcher)
|
||||||
|
)
|
||||||
|
|
||||||
|
key1 = signedjson.key.generate_signing_key(1)
|
||||||
|
r = self.hs.datastore.store_server_verify_keys(
|
||||||
|
"server9",
|
||||||
|
time.time() * 1000,
|
||||||
|
[("server9", get_key_id(key1), FetchKeyResult(get_verify_key(key1), None))],
|
||||||
|
)
|
||||||
|
self.get_success(r)
|
||||||
|
|
||||||
|
json1 = {}
|
||||||
|
signedjson.sign.sign_json(json1, "server9", key1)
|
||||||
|
|
||||||
|
# should fail immediately on an unsigned object
|
||||||
|
d = _verify_json_for_server(kr, "server9", {}, 0, "test unsigned")
|
||||||
|
self.failureResultOf(d, SynapseError)
|
||||||
|
|
||||||
|
# should fail on a signed object with a non-zero minimum_valid_until_ms,
|
||||||
|
# as it tries to refetch the keys and fails.
|
||||||
|
d = _verify_json_for_server(
|
||||||
|
kr, "server9", json1, 500, "test signed non-zero min"
|
||||||
|
)
|
||||||
|
self.get_failure(d, SynapseError)
|
||||||
|
|
||||||
|
# We expect the keyring tried to refetch the key once.
|
||||||
|
mock_fetcher.get_keys.assert_called_once_with(
|
||||||
|
{"server9": {get_key_id(key1): 500}}
|
||||||
|
)
|
||||||
|
|
||||||
|
# should succeed on a signed object with a 0 minimum_valid_until_ms
|
||||||
|
d = _verify_json_for_server(
|
||||||
|
kr, "server9", json1, 0, "test signed with zero min"
|
||||||
|
)
|
||||||
|
self.get_success(d)
|
||||||
|
|
||||||
def test_verify_json_dedupes_key_requests(self):
|
def test_verify_json_dedupes_key_requests(self):
|
||||||
"""Two requests for the same key should be deduped."""
|
"""Two requests for the same key should be deduped."""
|
||||||
key1 = signedjson.key.generate_signing_key(1)
|
key1 = signedjson.key.generate_signing_key(1)
|
||||||
|
|
Loading…
Reference in a new issue