#!/usr/bin/env python # -*- coding: utf-8 -*- # # Copyright (c) 2017, NORDUnet A/S. # See LICENSE for licensing information. # # Initialise a new CT log. # import sys import os import argparse import yaml import errno from time import time from base64 import b64encode from certtools import build_merkle_tree, write_file, generate_tree_head_signature from mergetools import get_sth, perm, get_logorder def parse_args(): parser = argparse.ArgumentParser(description="") parser.add_argument('--config', help="System configuration", required=True) parser.add_argument('--localconfig', help="Local configuration", required=True) args = parser.parse_args() config = yaml.load(open(args.config)) localconfig = yaml.load(open(args.localconfig)) return (args, config, localconfig) def main(): """ Initialise a log by creating - sth file - must not exist before - consulting 'logorder' if it exists - perm database if it doesn't exist """ args, config, localconfig = parse_args() signingnodes = config["signingnodes"] paths = localconfig["paths"] own_key = (localconfig["nodename"], "%s/%s-private.pem" % (paths["privatekeys"], localconfig["nodename"])) mergedb = paths["mergedb"] logorderfile = mergedb + "/logorder" sthfile = mergedb + "/sth" # Don't do anything if there's already an sth file. sth = get_sth(sthfile) if sth['tree_size'] >= 0: print >>sys.stderr, \ "This log has an STH file with tree size %s." % sth['tree_size'] print >>sys.stderr, "I refuse to destroy this log." return 1 # Ensure that we can find our keyfile. try: os.stat(own_key[1]) except OSError, e: if e.errno == errno.ENOENT: print >>sys.stderr, "Unable to open keyfile: %s" % own_key[1] return 1 raise # Create a chains database. chainsdb = perm(localconfig.get("dbbackend", "filedb"), mergedb + "/chains") # Create sth file. tree_size = 0 root_hash = build_merkle_tree('')[-1][0] try: logorder = get_logorder(logorderfile) tree_size = len(logorder) root_hash = build_merkle_tree(logorder[:tree_size])[-1][0] except IOError, e: if e.errno == errno.ENOENT: pass timestamp = int(time() * 1000) tree_head_signature = \ generate_tree_head_signature(signingnodes, own_key, tree_size, timestamp, root_hash) if tree_head_signature == None: return 1 sth = {"tree_size": tree_size, "timestamp": timestamp, "sha256_root_hash": b64encode(root_hash), "tree_head_signature": b64encode(tree_head_signature)} print "Creating sth file with tree size", tree_size, \ "and timestamp", timestamp write_file(sthfile, sth) return 0 if __name__ == '__main__': sys.exit(main())