Add expire tests

Fixes wrong signature generation in server-side `expire` endpoint.
This commit is contained in:
Jason Rhinelander 2021-06-21 14:16:25 -03:00
parent 2134b22dfa
commit 40e3489f62
3 changed files with 111 additions and 2 deletions

View file

@ -706,7 +706,7 @@ void RequestHandler::process_client_req(
return cb(Response{http::UNAUTHORIZED, "expire_all timestamp should be >= current time"sv});
}
if (!verify_signature(req.pubkey, req.pubkey_ed25519, req.signature, "expire", req.messages)) {
if (!verify_signature(req.pubkey, req.pubkey_ed25519, req.signature, "expire", req.expiry, req.messages)) {
OXEN_LOG(debug, "expire_msgs: signature verification failed");
return cb(Response{http::UNAUTHORIZED, "expire_msgs signature verification failed"sv});
}

View file

@ -27,7 +27,6 @@ def sns(omq):
def random_sn(omq, sns):
sn = random.choice(sns['service_node_states'])
addr = "curve://{}:{}/{}".format(sn['public_ip'], sn['storage_lmq_port'], sn['pubkey_x25519'])
print(addr)
conn = omq.connect_remote(addr)
return conn

110
tests/test_expire.py Normal file
View file

@ -0,0 +1,110 @@
import pyoxenmq
import ss
import time
import base64
import json
from nacl.encoding import HexEncoder, Base64Encoder
from nacl.hash import blake2b
from nacl.signing import VerifyKey
import nacl.exceptions
def test_expire_all(omq, random_sn, sk, exclude):
swarm = ss.get_swarm(omq, random_sn, sk)
sns = ss.random_swarm_members(swarm, 2, exclude)
conns = [omq.connect_remote("curve://{}:{}/{}".format(sn['ip'], sn['port_omq'], sn['pubkey_x25519']))
for sn in sns]
msgs = ss.store_n(omq, conns[0], sk, b"omg123", 5)
my_ss_id = '05' + sk.verify_key.encode().hex()
ts = msgs[2]['req']['expiry']
to_sign = "expire_all{}".format(ts).encode()
sig = sk.sign(to_sign, encoder=Base64Encoder).signature.decode()
params = json.dumps({
"pubkey": my_ss_id,
"expiry": ts,
"signature": sig
}).encode()
resp = omq.request(conns[1], 'storage.expire_all', [params])
assert len(resp) == 1
r = json.loads(resp[0])
assert set(r['swarm'].keys()) == {x['pubkey_ed25519'] for x in swarm['snodes']}
# 0 and 1 have later expiries than 2, so they should get updated; 2's expiry is already the
# given value, and 3/4 are <= so shouldn't get updated.
msg_hashes = sorted(msgs[i]['hash'] for i in (0, 1))
# signature of ( PUBKEY_HEX || EXPIRY || UPDATED[0] || ... || UPDATED[N] )
expected_signed = "".join((my_ss_id, str(ts), *msg_hashes)).encode()
for k, v in r['swarm'].items():
assert v['updated'] == msg_hashes
edpk = VerifyKey(k, encoder=HexEncoder)
edpk.verify(expected_signed, base64.b64decode(v['signature']))
r = json.loads(omq.request(conns[0], 'storage.retrieve',
[json.dumps({ "pubkey": my_ss_id }).encode()]
)[0])
assert len(r['messages']) == 5
assert r['messages'][0]['expiration'] == ts
assert r['messages'][1]['expiration'] == ts
assert r['messages'][2]['expiration'] == ts
assert r['messages'][3]['expiration'] == msgs[3]['req']['expiry']
assert r['messages'][4]['expiration'] == msgs[4]['req']['expiry']
def test_expire(omq, random_sn, sk, exclude):
swarm = ss.get_swarm(omq, random_sn, sk)
sns = ss.random_swarm_members(swarm, 2, exclude)
conns = [omq.connect_remote("curve://{}:{}/{}".format(sn['ip'], sn['port_omq'], sn['pubkey_x25519']))
for sn in sns]
msgs = ss.store_n(omq, conns[0], sk, b"omg123", 10)
my_ss_id = '05' + sk.verify_key.encode().hex()
ts = msgs[6]['req']['expiry']
hashes = [msgs[i]['hash'] for i in (0, 1, 5, 6, 7, 9)] + ['bepQtTaYrzcuCXO3fZkmk/h3xkMQ3vCh94i5HzLmj3I']
actual_update_msgs = sorted(msgs[i]['hash'] for i in (0, 1, 5))
hashes = sorted(hashes, reverse=True)
to_sign = ("expire" + str(ts) + "".join(hashes)).encode()
sig = sk.sign(to_sign, encoder=Base64Encoder).signature.decode()
params = json.dumps({
"pubkey": my_ss_id,
"messages": hashes,
"expiry": ts,
"signature": sig
}).encode()
resp = omq.request(conns[1], 'storage.expire', [params])
assert len(resp) == 1
r = json.loads(resp[0])
assert set(r['swarm'].keys()) == {x['pubkey_ed25519'] for x in swarm['snodes']}
# ( PUBKEY_HEX || EXPIRY || RMSG[0] || ... || RMSG[N] || UMSG[0] || ... || UMSG[M] )
expected_signed = "".join((my_ss_id, str(ts), *hashes, *actual_update_msgs)).encode()
for k, v in r['swarm'].items():
assert v['updated'] == actual_update_msgs
edpk = VerifyKey(k, encoder=HexEncoder)
try:
edpk.verify(expected_signed, base64.b64decode(v['signature']))
except nacl.exceptions.BadSignatureError as e:
print("Bad signature from swarm member {}".format(k))
raise e
r = json.loads(omq.request(conns[0], 'storage.retrieve',
[json.dumps({ "pubkey": my_ss_id }).encode()]
)[0])
assert len(r['messages']) == 10
for i in range(10):
assert r['messages'][i]['expiration'] == ts if i in (0, 1, 5, 6) else msgs[i]['req']['expiry']