diff options
author | Linus Nordberg <linus@nordberg.se> | 2021-06-16 10:17:42 +0200 |
---|---|---|
committer | Linus Nordberg <linus@nordberg.se> | 2021-06-16 10:17:42 +0200 |
commit | 3629f925b06d9d789e6942876aaf2c0ef875353f (patch) | |
tree | 7bd3555613ece3b29597fe70d6a11ef7d1a87f24 | |
parent | e4e8216eff7bff1449c12979c9da4c67eafb4499 (diff) |
validate tree heads harder
Disallow time travel, tree shrinkage, new tree hash for same sized
tree, new tree size with same tree hash.
Consider an STH seen iff all three attributes -- timestamp, size,
hash -- are identical.
-rwxr-xr-x | siglog-witness.py | 43 |
1 files changed, 37 insertions, 6 deletions
diff --git a/siglog-witness.py b/siglog-witness.py index 2c9862e..c1152ef 100755 --- a/siglog-witness.py +++ b/siglog-witness.py @@ -416,22 +416,52 @@ def main(args): if not cur_tree_head.signature_valid(log_verification_key): return ERR_TREEHEAD_SIGNATURE_INVALID, "ERROR: signature of current tree head invalid" + # TODO: move to TreeHead.validate_history() ts_sec = new_tree_head.timestamp() ts_asc = time.ctime(ts_sec) if ts_sec < now - 12 * 3600: return (ERR_OK, - "WARNING: timestamp too old: {} ({})".format(ts_sec, ts_asc)) + "WARNING: Tree head timestamp too old: {} ({})".format(ts_sec, ts_asc)) if ts_sec > now + 12 * 3600: return (ERR_OK, - "WARNING: timestamp too new: {} ({})".format(ts_sec, ts_asc)) + "WARNING: Tree head timestamp too new: {} ({})".format(ts_sec, ts_asc)) - # TODO: Needs more thought: size, hash, timestamp -- what may change and what may not? - if new_tree_head.tree_size() <= cur_tree_head.tree_size(): - return 0, "INFO: Fetched head of tree of size {} already seen".format(cur_tree_head.tree_size()) + if new_tree_head.tree_size() < cur_tree_head.tree_size(): + return (ERR_TREEHEAD_INVALID, + "ERROR: Log is shrinking: {} < {} ".format(new_tree_head.tree_size(), + cur_tree_head.tree_size())) + + if new_tree_head.timestamp() < cur_tree_head.timestamp(): + return (ERR_TREEHEAD_INVALID, + "ERROR: Log is time traveling: {} < {} ".format(time.ctime(new_tree_head.timestamp()), + time.ctime(cur_tree_head.timestamp()))) + + if new_tree_head.timestamp() == cur_tree_head.timestamp() and \ + new_tree_head.root_hash() == cur_tree_head.root_hash() and \ + new_tree_head.tree_size() == cur_tree_head.tree_size(): + return (ERR_OK, + "INFO: Fetched head of tree of size {} already seen".format(cur_tree_head.tree_size())) + + if new_tree_head.root_hash() == cur_tree_head.root_hash() and \ + new_tree_head.tree_size() != cur_tree_head.tree_size(): + return (ERR_TREEHEAD_INVALID, + "ERROR: Tree size has changed but hash has not: " + "{}: {} != {}".format(new_tree_head.root_hash(), + new_tree_head.tree_size(), + cur_tree_head.tree_size())) + + if new_tree_head.root_hash() != cur_tree_head.root_hash() and \ + new_tree_head.tree_size() == cur_tree_head.tree_size(): + return (ERR_TREEHEAD_INVALID, + "ERROR: Hash has changed but tree size has not: " + "{}: {} != {}".format(new_tree_head.tree_size(), + new_tree_head.root_hash(), + cur_tree_head.root_hash())) + + # Same hash and size, new timestamp is ok. proof, err = fetch_consistency_proof(cur_tree_head.tree_size(), new_tree_head.tree_size()) if err: return err - if not consistency_proof_valid(cur_tree_head, new_tree_head, proof): errmsg = "ERROR: failing consistency proof check for {}->{}\n".format(cur_tree_head.tree_size(), new_tree_head.tree_size()) @@ -441,6 +471,7 @@ def main(args): new_tree_head.root_hash(), proof.path()) return ERR_CONSISTENCYPROOF_INVALID, errmsg + # TODO: end move err = sign_send_store_tree_head(signing_key, new_tree_head) if err: return err |