#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (c) 2014 Kungliga Tekniska Högskolan # (KTH Royal Institute of Technology, Stockholm, Sweden). # See LICENSE for licensing information. import json import base64 import urllib import urllib2 import sys import time from certtools import build_merkle_tree, create_sth_signature, check_sth_signature ctbaseurl = "https://127.0.0.1:8080/" frontendnodes = ["https://127.0.0.1:8082/"] storagenodes = ["https://127.0.0.1:8081/"] chainsdir = "../rel/mergedb/chains" logorderfile = "../rel/mergedb/logorder" def parselogrow(row): return base64.b16decode(row) def get_logorder(): f = open(logorderfile, "r") return [parselogrow(row.rstrip()) for row in f] def write_chain(key, value): f = open(chainsdir + "/" + base64.b16encode(key), "w") f.write(value) f.close() def read_chain(key): f = open(chainsdir + "/" + base64.b16encode(key), "r") value = f.read() f.close() return value def add_to_logorder(key): f = open(logorderfile, "a") f.write(base64.b16encode(key) + "\n") f.close() def get_new_entries(baseurl): try: result = urllib2.urlopen(baseurl + "ct/storage/fetchnewentries").read() parsed_result = json.loads(result) if parsed_result.get(u"result") == u"ok": return parsed_result[u"entries"] print "ERROR: fetchnewentries", parsed_result sys.exit(1) except urllib2.HTTPError, e: print "ERROR: fetchnewentries", e.read() sys.exit(1) def get_curpos(baseurl): try: result = urllib2.urlopen(baseurl + "ct/frontend/currentposition").read() parsed_result = json.loads(result) if parsed_result.get(u"result") == u"ok": return parsed_result[u"position"] print "ERROR: currentposition", parsed_result sys.exit(1) except urllib2.HTTPError, e: print "ERROR: currentposition", e.read() sys.exit(1) def sendlog(baseurl, submission): try: result = urllib2.urlopen(baseurl + "ct/frontend/sendlog", json.dumps(submission)).read() return json.loads(result) except urllib2.HTTPError, e: print "ERROR: sendlog", e.read() sys.exit(1) except ValueError, e: print "==== FAILED REQUEST ====" print submission print "======= RESPONSE =======" print result print "========================" raise e def sendentry(baseurl, entry, hash): try: result = urllib2.urlopen(baseurl + "ct/frontend/sendentry", json.dumps({"entry":base64.b64encode(entry), "treeleafhash":base64.b64encode(hash)})).read() return json.loads(result) except urllib2.HTTPError, e: print "ERROR: sendentry", e.read() sys.exit(1) except ValueError, e: print "==== FAILED REQUEST ====" print hash print "======= RESPONSE =======" print result print "========================" raise e def sendsth(baseurl, submission): try: result = urllib2.urlopen(baseurl + "ct/frontend/sendsth", json.dumps(submission)).read() return json.loads(result) except urllib2.HTTPError, e: print "ERROR: sendsth", e.read() sys.exit(1) except ValueError, e: print "==== FAILED REQUEST ====" print submission print "======= RESPONSE =======" print result print "========================" raise e def get_missingentries(baseurl): try: result = urllib2.urlopen(baseurl + "ct/frontend/missingentries").read() parsed_result = json.loads(result) if parsed_result.get(u"result") == u"ok": return parsed_result[u"entries"] print "ERROR: missingentries", parsed_result sys.exit(1) except urllib2.HTTPError, e: print "ERROR: missingentries", e.read() sys.exit(1) logorder = get_logorder() certsinlog = set(logorder) new_entries = [entry for storagenode in storagenodes for entry in get_new_entries(storagenode)] print "adding entries" added_entries = 0 for new_entry in new_entries: hash = base64.b64decode(new_entry["hash"]) entry = base64.b64decode(new_entry["entry"]) if hash not in certsinlog: write_chain(hash, entry) add_to_logorder(hash) logorder.append(hash) certsinlog.add(hash) added_entries += 1 print "added", added_entries, "entries" tree = build_merkle_tree(logorder) tree_size = len(logorder) root_hash = tree[-1][0] timestamp = int(time.time() * 1000) privatekey = base64.decodestring( "MHcCAQEEIMM/FjZ4FSzfENTTwGpTve6CP+IVr" "Y7p8OKV634uJI/foAoGCCqGSM49AwEHoUQDQg" "AE4qWq6afhBUi0OdcWUYhyJLNXTkGqQ9PMS5l" "qoCgkV2h1ZvpNjBH2u8UbgcOQwqDo66z6BWQJ" "GolozZYmNHE2kQ==") tree_head_signature = create_sth_signature(tree_size, timestamp, root_hash, privatekey) sth = {"tree_size": tree_size, "timestamp": timestamp, "sha256_root_hash": base64.b64encode(root_hash), "tree_head_signature": base64.b64encode(tree_head_signature)} check_sth_signature(ctbaseurl, sth) print "root hash", base64.b16encode(root_hash) for frontendnode in frontendnodes: print "distributing for node", frontendnode curpos = get_curpos(frontendnode) print "current position", curpos entries = [base64.b64encode(entry) for entry in logorder[curpos:]] sendlog(frontendnode, {"start": curpos, "hashes": entries}) print "log sent" missingentries = get_missingentries(frontendnode) print "missing entries:", missingentries for missingentry in missingentries: hash = base64.b64decode(missingentry) sendentry(frontendnode, read_chain(hash), hash) sendsth(frontendnode, sth)