summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Nordberg <linus@nordberg.se>2021-06-16 10:17:42 +0200
committerLinus Nordberg <linus@nordberg.se>2021-06-16 10:17:42 +0200
commit3629f925b06d9d789e6942876aaf2c0ef875353f (patch)
tree7bd3555613ece3b29597fe70d6a11ef7d1a87f24
parente4e8216eff7bff1449c12979c9da4c67eafb4499 (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-xsiglog-witness.py43
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