summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rwxr-xr-xtools/check-sth.py138
-rwxr-xr-xtools/comparecert.py78
-rwxr-xr-xtools/compileconfig.py372
-rw-r--r--tools/convertdb.py71
-rwxr-xr-xtools/create-key.sh4
-rwxr-xr-xtools/fetchacert.py22
-rwxr-xr-xtools/fetchallcerts.py182
-rwxr-xr-xtools/josef_auditor.py398
-rwxr-xr-xtools/josef_experimental.py128
-rwxr-xr-xtools/josef_experimental_auditor.py476
-rwxr-xr-xtools/josef_nagios_auditor.py11
-rwxr-xr-xtools/merge.py518
-rw-r--r--tools/mergetools.py96
-rw-r--r--tools/precerttools.py102
-rw-r--r--tools/rfc2459.py927
-rwxr-xr-xtools/storagegc.py85
-rwxr-xr-xtools/submitcert.py219
-rwxr-xr-xtools/testcase1.py264
-rw-r--r--tools/testcerts/cert1.txt86
-rw-r--r--tools/testcerts/cert2.txt138
-rw-r--r--tools/testcerts/cert3.txt108
-rw-r--r--tools/testcerts/cert4.txt120
-rw-r--r--tools/testcerts/cert5.txt145
-rw-r--r--tools/testcerts/pre1.txt79
-rw-r--r--tools/testcerts/pre2.txt106
-rw-r--r--tools/testcerts/roots/root1.pem23
-rw-r--r--tools/testcerts/roots/root2.pem21
-rw-r--r--tools/testcerts/roots/root3.pem19
-rw-r--r--tools/testcerts/roots/root4.pem19
-rw-r--r--tools/testcerts/roots/root5.pem29
-rwxr-xr-xtools/to_catlfish.py25
-rwxr-xr-xtools/treeinfo.py123
-rwxr-xr-xtools/validatestore.py96
-rwxr-xr-xtools/verifysct.py123
-rwxr-xr-xtools/verifysecondary.py36
-rwxr-xr-xtools/verifysecondary.sh4
36 files changed, 0 insertions, 5391 deletions
diff --git a/tools/check-sth.py b/tools/check-sth.py
deleted file mode 100755
index dacd8e6..0000000
--- a/tools/check-sth.py
+++ /dev/null
@@ -1,138 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2015, NORDUnet A/S.
-# See LICENSE for licensing information.
-
-import sys
-import argparse
-import json
-import errno
-import shutil
-import base64
-from datetime import datetime, timedelta, tzinfo
-import time
-from certtools import get_sth, create_ssl_context, check_sth_signature, get_public_key_from_file, get_consistency_proof, verify_consistency_proof
-
-NAGIOS_OK = 0
-NAGIOS_WARN = 1
-NAGIOS_CRIT = 2
-NAGIOS_UNKNOWN = 3
-
-DEFAULT_CUR_FILE = 'cur-sth.json'
-
-parser = argparse.ArgumentParser(description="")
-parser.add_argument('--cur-sth',
- metavar='file',
- default=DEFAULT_CUR_FILE,
- help="File containing current STH (default=%s)" % DEFAULT_CUR_FILE)
-parser.add_argument('baseurl', help="Base URL for CT log")
-parser.add_argument('--publickey', default=None, metavar='file', help='Public key for the CT log')
-parser.add_argument('--cafile', default=None, metavar='file', help='File containing the CA cert')
-parser.add_argument('--allow-lag', action='store_true', help='Allow node to lag behind previous STH')
-parser.add_argument('--quiet-ok', action='store_true', help="Don't print status if OK")
-
-def print_sth(sth):
- if sth is None:
- print "NONE"
- else:
- print sth['timestamp']
- print sth['sha256_root_hash']
- print sth['tree_size']
- print sth['tree_head_signature']
-
-def get_new_sth(baseurl):
- try:
- sth = get_sth(baseurl)
- except Exception, e:
- print e
- sys.exit(NAGIOS_UNKNOWN)
- return sth
-
-def read_sth(fn):
- try:
- f = open(fn)
- except IOError, e:
- if e.errno == errno.ENOENT:
- return None
- raise e
- return json.loads(f.read())
-
-def mv_file(fromfn, tofn):
- shutil.move(fromfn, tofn)
-
-def write_file(fn, sth):
- tempname = fn + ".new"
- open(tempname, 'w').write(json.dumps(sth))
- mv_file(tempname, fn)
-
-class UTC(tzinfo):
- def utcoffset(self, dt):
- return timedelta(hours=0)
- def dst(self, dt):
- return timedelta(0)
-
-def check_age(sth):
- age = time.time() - sth["timestamp"]/1000
- sth_time = datetime.fromtimestamp(sth['timestamp'] / 1000, UTC()).strftime("%Y-%m-%d %H:%M:%S")
- roothash = b64_to_b16(sth['sha256_root_hash'])
- if age > 6 * 3600:
- print "CRITICAL: %s is older than 6h: %s UTC" % (roothash, sth_time)
- sys.exit(NAGIOS_CRIT)
- if age > 2 * 3600:
- print "WARNING: %s is older than 2h: %s UTC" % (roothash, sth_time)
- sys.exit(NAGIOS_WARN)
- return "%s UTC, %d minutes ago" % (sth_time, age/60)
-
-def check_consistency(newsth, oldsth, baseurl):
- consistency_proof = [base64.decodestring(entry) for entry in get_consistency_proof(baseurl, oldsth["tree_size"], newsth["tree_size"])]
- (old_treehead, new_treehead) = verify_consistency_proof(consistency_proof, oldsth["tree_size"], newsth["tree_size"], base64.b64decode(oldsth["sha256_root_hash"]))
- assert old_treehead == base64.b64decode(oldsth["sha256_root_hash"])
- assert new_treehead == base64.b64decode(newsth["sha256_root_hash"])
-
-def b64_to_b16(s):
- return base64.b16encode(base64.decodestring(s))
-
-def main(args):
- if args.cur_sth is None:
- args.cur_sth = "cur-sth.json"
-
- create_ssl_context(cafile=args.cafile)
-
- logpublickey = get_public_key_from_file(args.publickey) if args.publickey else None
-
- newsth = get_new_sth(args.baseurl)
- check_sth_signature(args.baseurl, newsth, publickey=logpublickey)
-
- oldsth = read_sth(args.cur_sth)
-
- #print_sth(newsth)
- #print_sth(oldsth)
-
- if oldsth:
- if newsth["tree_size"] == oldsth["tree_size"]:
- if oldsth["sha256_root_hash"] != newsth["sha256_root_hash"]:
- print "CRITICAL: root hash is different even though tree size is the same.",
- print "tree size:", newsth["tree_size"],
- print "old hash:", b64_to_b16(oldsth["sha256_root_hash"])
- print "new hash:", b64_to_b16(newsth["sha256_root_hash"])
- sys.exit(NAGIOS_CRIT)
- elif newsth["tree_size"] < oldsth["tree_size"]:
- if not args.allow_lag:
- print "CRITICAL: new tree smaller than previous tree (%d < %d)" % \
- (newsth["tree_size"], oldsth["tree_size"])
- sys.exit(NAGIOS_CRIT)
-
- if oldsth and oldsth["tree_size"] > 0 and oldsth["tree_size"] != newsth["tree_size"]:
- check_consistency(newsth, oldsth, args.baseurl)
-
- age = check_age(newsth)
-
- write_file(args.cur_sth, newsth)
-
- if not args.quiet_ok:
- print "OK: size: %d hash: %s, %s" % (newsth["tree_size"], b64_to_b16(newsth["sha256_root_hash"])[:8], age)
- sys.exit(NAGIOS_OK)
-
-if __name__ == '__main__':
- main(parser.parse_args())
diff --git a/tools/comparecert.py b/tools/comparecert.py
deleted file mode 100755
index 81893f7..0000000
--- a/tools/comparecert.py
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (c) 2014, NORDUnet A/S.
-# See LICENSE for licensing information.
-
-import argparse
-import urllib2
-import urllib
-import json
-import base64
-import sys
-import struct
-import hashlib
-import itertools
-from certtools import *
-from certtools import *
-from precerttools import *
-import os
-import signal
-import select
-import zipfile
-
-def readfile(filename):
- contents = open(filename).read()
- certchain = get_certs_from_string(contents)
- precerts = get_precerts_from_string(contents)
- return (certchain, precerts)
-
-def testcerts(template, test):
- (certchain1, precerts1) = template
- (certchain2, precerts2) = test
-
- if precerts1 != precerts2:
- return (False, "precerts are different")
-
- if certchain1 == certchain2:
- return (True, "")
-
- if len(certchain2) == len(certchain1) + 1:
- if certchain2[:-1] != certchain1:
- return (False, "certchains are different")
- last_issuer = get_cert_info(certchain1[-1])["issuer"]
- root_subject = get_cert_info(certchain2[-1])["subject"]
- if last_issuer == root_subject:
- return (True, "fetched chain has an appended root cert")
- else:
- return (False, "fetched chain has an extra entry")
-
- return (False, "certchains are different")
-
-parser = argparse.ArgumentParser(description='')
-parser.add_argument('templates', help="Test templates, separated with colon")
-parser.add_argument('test', help="Files to test, separated with colon")
-args = parser.parse_args()
-
-templates = [readfile(filename) for filename in args.templates.split(":")]
-
-tests = [readfile(filename) for filename in args.test.split(":")]
-
-
-for test in tests:
- found = False
- errors = []
- for template in templates:
- (result, message) = testcerts(template, test)
- if result:
- print message
- found = True
- templates.remove(template)
- break
- else:
- errors.append(message)
- if not found:
- print "Matching template not found for test"
- for error in errors:
- print error
- sys.exit(1)
-sys.exit(0)
diff --git a/tools/compileconfig.py b/tools/compileconfig.py
deleted file mode 100755
index eb0ddc6..0000000
--- a/tools/compileconfig.py
+++ /dev/null
@@ -1,372 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (c) 2014, NORDUnet A/S.
-# See LICENSE for licensing information.
-
-import argparse
-import sys
-import yaml
-import re
-
-class Symbol(str):
- pass
-
-clean_string = re.compile(r'^[-.:_/A-Za-z0-9 ]*$')
-clean_symbol = re.compile(r'^[_A-Za-z0-9]*$')
-
-def quote_erlang_string(s):
- if clean_string.match(s):
- return '"' + s + '"'
- else:
- return "[" + ",".join([str(ord(c)) for c in s]) + "]"
-
-def quote_erlang_symbol(s):
- if clean_symbol.match(s):
- return s
- elif clean_string.match(s):
- return "'" + s + "'"
- else:
- print >>sys.stderr, "Cannot generate symbol", s
- sys.exit(1)
-
-def gen_erlang(term, level=1):
- indent = " " * level
- separator = ",\n" + indent
- if isinstance(term, Symbol):
- return quote_erlang_symbol(term)
- elif isinstance(term, basestring):
- return quote_erlang_string(term)
- elif isinstance(term, int):
- return str(term)
- elif isinstance(term, tuple):
- tuplecontents = [gen_erlang(e, level=level+1) for e in term]
- if "\n" not in "".join(tuplecontents):
- separator = ", "
- return "{" + separator.join(tuplecontents) + "}"
- elif isinstance(term, list):
- listcontents = [gen_erlang(e, level=level+1) for e in term]
- return "[" + separator.join(listcontents) + "]"
- else:
- print "unknown type", type(term)
- sys.exit(1)
-
-saslconfig = [(Symbol("sasl_error_logger"), Symbol("false")),
- (Symbol("errlog_type"), Symbol("error")),
- (Symbol("error_logger_mf_dir"), "sasl_log"),
- (Symbol("error_logger_mf_maxbytes"), 10485760),
- (Symbol("error_logger_mf_maxfiles"), 10),
- ]
-
-def parse_address(address):
- parsed_address = address.split(":")
- if len(parsed_address) != 2:
- print >>sys.stderr, "Invalid address format", address
- sys.exit(1)
- return (parsed_address[0], int(parsed_address[1]))
-
-def get_node_config(nodename, config):
- nodetype = None
- nodeconfig = None
- for t in ["frontendnodes", "storagenodes", "signingnodes", "mergenodes"]:
- for node in config[t]:
- if node["name"] == nodename:
- nodetype = t
- nodeconfig = node
- if nodeconfig == None:
- print >>sys.stderr, "Cannot find config for node", nodename
- sys.exit(1)
- return (nodetype, nodeconfig)
-
-def gen_http_servers(nodetype, nodeconfig, bind_address, bind_publicaddress, bind_publichttpaddress):
- if bind_address:
- (host, port) = parse_address(bind_address)
- else:
- (_, port) = parse_address(nodeconfig["address"])
- host = "0.0.0.0"
- if nodetype == "frontendnodes":
- if bind_publicaddress:
- (publichost, publicport) = parse_address(bind_publicaddress)
- else:
- (_, publicport) = parse_address(nodeconfig["publicaddress"])
- publichost = "0.0.0.0"
-
- http_servers = []
- https_servers = []
- if bind_publichttpaddress:
- (publichttphost, publichttpport) = parse_address(bind_publichttpaddress)
- http_servers.append((Symbol("external_http_api"), publichttphost, publichttpport, Symbol("v1")))
- https_servers.append((Symbol("external_https_api"), publichost, publicport, Symbol("v1")))
- https_servers.append((Symbol("frontend_https_api"), host, port, Symbol("frontend")))
- return (http_servers,
- https_servers)
-
- elif nodetype == "storagenodes":
- return ([],
- [(Symbol("storage_https_api"), host, port, Symbol("storage"))])
- elif nodetype == "signingnodes":
- return ([],
- [(Symbol("signing_https_api"), host, port, Symbol("signing"))])
- elif nodetype == "mergenodes":
- return ([],
- [(Symbol("frontend_https_api"), host, port, Symbol("frontend"))])
- else:
- print >>sys.stderr, "unknown nodetype", nodetype
- sys.exit(1)
-
-def allowed_clients_frontend(mergenodenames, primarymergenode):
- return [
- ("/plop/v1/frontend/sendentry", mergenodenames),
- ("/plop/v1/frontend/sendlog", mergenodenames),
- ("/plop/v1/frontend/sendsth", [primarymergenode]),
- ("/plop/v1/frontend/currentposition", mergenodenames),
- ("/plop/v1/frontend/missingentries", mergenodenames),
- ]
-
-def allowed_clients_mergesecondary(primarymergenode):
- return [
- ("/plop/v1/merge/sendentry", [primarymergenode]),
- ("/plop/v1/merge/sendlog", [primarymergenode]),
- ("/plop/v1/merge/verifyroot", [primarymergenode]),
- ("/plop/v1/merge/verifiedsize", [primarymergenode]),
- ("/plop/v1/merge/setverifiedsize", [primarymergenode]),
- ("/plop/v1/merge/missingentries", [primarymergenode]),
- ]
-
-def allowed_clients_public():
- noauth = Symbol("noauth")
- return [
- ("/ct/v1/add-chain", noauth),
- ("/ct/v1/add-pre-chain", noauth),
- ("/ct/v1/get-sth", noauth),
- ("/ct/v1/get-sth-consistency", noauth),
- ("/ct/v1/get-proof-by-hash", noauth),
- ("/ct/v1/get-entries", noauth),
- ("/ct/v1/get-entry-and-proof", noauth),
- ("/ct/v1/get-roots", noauth),
- ]
-
-def allowed_clients_signing(frontendnodenames, primarymergenode):
- return [
- ("/plop/v1/signing/sct", frontendnodenames),
- ("/plop/v1/signing/sth", [primarymergenode]),
- ]
-
-def allowed_clients_storage(frontendnodenames, mergenodenames):
- return [
- ("/plop/v1/storage/sendentry", frontendnodenames),
- ("/plop/v1/storage/entrycommitted", frontendnodenames),
- ("/plop/v1/storage/fetchnewentries", mergenodenames),
- ("/plop/v1/storage/getentry", mergenodenames),
- ]
-
-def allowed_servers_frontend(signingnodenames, storagenodenames):
- return [
- ("/plop/v1/storage/sendentry", storagenodenames),
- ("/plop/v1/storage/entrycommitted", storagenodenames),
- ("/plop/v1/signing/sct", signingnodenames),
- ]
-
-def parse_ratelimit_expression(expression):
- if expression == "none":
- return Symbol("none")
- parts = expression.split(" ")
- if not (len(parts) == 3 and parts[1] == 'per' and parts[2] in ["second", "minute", "hour"]):
- print >>sys.stderr, "Ratelimit expressions must have the format \"<frequency> per second|minute|hour\" or \"none\""
- sys.exit(1)
- return (int(parts[0]), Symbol(parts[2]))
-
-def parse_ratelimit((type, description)):
- descriptions = [parse_ratelimit_expression(s.strip()) for s in description.split(",")]
- if len(descriptions) != 1:
- print >>sys.stderr, "%s: Only one ratelimit expression supported right now" % (type,)
- return (Symbol(type), descriptions)
-
-def gen_config(nodename, config, localconfig):
- print "generating config for", nodename
- paths = localconfig["paths"]
- bind_address = localconfig.get("addresses", {}).get(nodename)
- bind_publicaddress = localconfig.get("publicaddresses", {}).get(nodename)
- bind_publichttpaddress = localconfig.get("publichttpaddresses", {}).get(nodename)
- options = localconfig.get("options", [])
-
- configfile = open(paths["configdir"] + "/" + nodename + ".config", "w")
- print >>configfile, "%% catlfish configuration file (-*- erlang -*-)"
-
- (nodetype, nodeconfig) = get_node_config(nodename, config)
- (http_servers, https_servers) = gen_http_servers(nodetype, nodeconfig, bind_address, bind_publicaddress, bind_publichttpaddress=bind_publichttpaddress)
-
- catlfishconfig = []
- plopconfig = []
-
- if nodetype in ("frontendnodes", "mergenodes"):
- catlfishconfig.append((Symbol("known_roots_path"), localconfig["paths"]["knownroots"]))
- if nodetype == "frontendnodes":
- if "sctcaching" in options:
- catlfishconfig.append((Symbol("sctcache_root_path"), paths["db"] + "sctcache/"))
- if "ratelimits" in localconfig:
- ratelimits = map(parse_ratelimit, localconfig["ratelimits"].items())
- catlfishconfig.append((Symbol("ratelimits"), ratelimits))
-
- catlfishconfig += [
- (Symbol("https_servers"), https_servers),
- (Symbol("http_servers"), http_servers),
- (Symbol("https_certfile"), paths["https_certfile"]),
- (Symbol("https_keyfile"), paths["https_keyfile"]),
- (Symbol("https_cacertfile"), paths["https_cacertfile"]),
- ]
-
- catlfishconfig.append((Symbol("mmd"), config["mmd"]))
-
- lagerconfig = [
- (Symbol("handlers"), [
- (Symbol("lager_console_backend"), Symbol("info")),
- (Symbol("lager_file_backend"), [(Symbol("file"), nodename + "-error.log"), (Symbol("level"), Symbol("error"))]),
- (Symbol("lager_file_backend"), [(Symbol("file"), nodename + "-debug.log"), (Symbol("level"), Symbol("debug"))]),
- (Symbol("lager_file_backend"), [(Symbol("file"), nodename + "-console.log"), (Symbol("level"), Symbol("info"))]),
- ])
- ]
-
- if nodetype in ("frontendnodes", "storagenodes"):
- plopconfig += [
- (Symbol("entry_root_path"), paths["db"] + "certentries/"),
- ]
- if nodetype == "frontendnodes":
- plopconfig += [
- (Symbol("index_path"), paths["db"] + "index"),
- ]
- elif nodetype == "storagenodes":
- plopconfig += [
- (Symbol("newentries_path"), paths["db"] + "newentries"),
- (Symbol("lastverifiednewentry_path"), paths["db"] + "lastverifiednewentry"),
- ]
- if nodetype in ("frontendnodes", "storagenodes"):
- plopconfig += [
- (Symbol("entryhash_root_path"), paths["db"] + "entryhash/"),
- (Symbol("indexforhash_root_path"), paths["db"] + "certindex/"),
- ]
- if nodetype == "frontendnodes":
- plopconfig += [
- (Symbol("sth_path"), paths["db"] + "sth"),
- (Symbol("entryhash_from_entry"),
- (Symbol("catlfish"), Symbol("entryhash_from_entry"))),
- ]
- if nodetype in ("frontendnodes", "mergenodes"):
- plopconfig += [
- (Symbol("verify_entry"),
- (Symbol("catlfish"), Symbol("verify_entry"))),
- ]
- if nodetype == "mergenodes":
- plopconfig += [
- (Symbol("verifiedsize_path"), paths["mergedb"] + "/verifiedsize"),
- (Symbol("index_path"), paths["mergedb"] + "/logorder"),
- (Symbol("entry_root_path"), paths["mergedb"] + "/chains/"),
- ]
-
- signingnodes = config["signingnodes"]
- signingnodeaddresses = ["https://%s/plop/v1/signing/" % node["address"] for node in config["signingnodes"]]
- mergenodenames = [node["name"] for node in config["mergenodes"]]
- primarymergenode = config["primarymergenode"]
- storagenodeaddresses = ["https://%s/plop/v1/storage/" % node["address"] for node in config["storagenodes"]]
- frontendnodenames = [node["name"] for node in config["frontendnodes"]]
-
- allowed_clients = []
- allowed_servers = []
-
- if nodetype == "frontendnodes":
- storagenodenames = [node["name"] for node in config["storagenodes"]]
- plopconfig.append((Symbol("storage_nodes"), storagenodeaddresses))
- plopconfig.append((Symbol("storage_nodes_quorum"), config["storage-quorum-size"]))
- services = [Symbol("ht")]
- allowed_clients += allowed_clients_frontend(mergenodenames, primarymergenode)
- allowed_clients += allowed_clients_public()
- allowed_servers += allowed_servers_frontend([node["name"] for node in signingnodes], storagenodenames)
- elif nodetype == "storagenodes":
- allowed_clients += allowed_clients_storage(frontendnodenames, mergenodenames)
- services = []
- elif nodetype == "signingnodes":
- allowed_clients += allowed_clients_signing(frontendnodenames, primarymergenode)
- services = [Symbol("sign")]
- elif nodetype == "mergenodes":
- storagenodenames = [node["name"] for node in config["storagenodes"]]
- plopconfig.append((Symbol("storage_nodes"), storagenodeaddresses))
- plopconfig.append((Symbol("storage_nodes_quorum"), config["storage-quorum-size"]))
- services = [Symbol("ht")]
- allowed_clients += allowed_clients_mergesecondary(primarymergenode)
-
- plopconfig += [
- (Symbol("publickey_path"), paths["publickeys"]),
- (Symbol("services"), services),
- ]
- if nodetype == "signingnodes":
- hsm = localconfig.get("hsm")
- if "logprivatekey" in paths:
- plopconfig.append((Symbol("log_private_key"), paths["logprivatekey"]))
- if hsm:
- plopconfig.append((Symbol("hsm"), [hsm.get("library"), str(hsm.get("slot")), "ecdsa", hsm.get("label"), hsm.get("pin")]))
- if not ("logprivatekey" in paths or hsm):
- print >>sys.stderr, "Neither logprivatekey nor hsm configured for signing node", nodename
- sys.exit(1)
- plopconfig += [
- (Symbol("log_public_key"), paths["logpublickey"]),
- (Symbol("own_key"), (nodename, "%s/%s-private.pem" % (paths["privatekeys"], nodename))),
- ]
- if nodetype == "frontendnodes":
- plopconfig.append((Symbol("signing_nodes"), signingnodeaddresses))
- plopconfig += [
- (Symbol("allowed_clients"), allowed_clients),
- (Symbol("allowed_servers"), allowed_servers),
- ]
-
- erlangconfig = [
- (Symbol("sasl"), saslconfig),
- (Symbol("catlfish"), catlfishconfig),
- (Symbol("lager"), lagerconfig),
- (Symbol("plop"), plopconfig),
- ]
-
- print >>configfile, gen_erlang(erlangconfig) + ".\n"
-
- configfile.close()
-
-
-def gen_testmakefile(config, testmakefile, machines):
- configfile = open(testmakefile, "w")
- frontendnodenames = [node["name"] for node in config["frontendnodes"]]
- storagenodenames = [node["name"] for node in config["storagenodes"]]
- signingnodenames = [node["name"] for node in config["signingnodes"]]
- mergenodenames = [node["name"] for node in config["mergenodes"]]
-
- frontendnodeaddresses = [node["publicaddress"] for node in config["frontendnodes"]]
- storagenodeaddresses = [node["address"] for node in config["storagenodes"]]
- signingnodeaddresses = [node["address"] for node in config["signingnodes"]]
- mergenodeaddresses = [node["address"] for node in config["mergenodes"] if node["name"] != config["primarymergenode"]]
-
- print >>configfile, "NODES=" + " ".join(frontendnodenames+storagenodenames+signingnodenames+mergenodenames)
- print >>configfile, "MACHINES=" + " ".join([str(e) for e in range(1, machines+1)])
- print >>configfile, "TESTURLS=" + " ".join(frontendnodeaddresses+storagenodeaddresses+signingnodeaddresses+mergenodeaddresses)
- print >>configfile, "BASEURL=" + config["baseurl"]
-
- configfile.close()
-
-
-def main():
- parser = argparse.ArgumentParser(description="")
- parser.add_argument('--config', help="System configuration", required=True)
- parser.add_argument('--localconfig', help="Local configuration")
- parser.add_argument("--testmakefile", metavar="file", help="Generate makefile variables for test")
- parser.add_argument("--machines", type=int, metavar="n", help="Number of machines")
- args = parser.parse_args()
-
- config = yaml.load(open(args.config))
- if args.testmakefile and args.machines:
- gen_testmakefile(config, args.testmakefile, args.machines)
- elif args.localconfig:
- localconfig = yaml.load(open(args.localconfig))
- localnodes = localconfig["localnodes"]
- for localnode in localnodes:
- gen_config(localnode, config, localconfig)
- else:
- print >>sys.stderr, "Nothing to do"
- sys.exit(1)
-
-main()
diff --git a/tools/convertdb.py b/tools/convertdb.py
deleted file mode 100644
index c036843..0000000
--- a/tools/convertdb.py
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2014, NORDUnet A/S.
-# See LICENSE for licensing information.
-
-import argparse
-import urllib2
-import urllib
-import json
-import base64
-import sys
-import struct
-import hashlib
-import itertools
-from certtools import *
-from mergetools import *
-import zipfile
-import os
-import time
-import shutil
-
-def write_file(fn, contents):
- tempname = fn + ".new"
- open(tempname, 'w').write(contents)
- shutil.move(tempname, fn)
-
-def unpack_entry(entry):
- pieces = []
- while len(entry):
- (length,) = struct.unpack(">I", entry[0:4])
- data = entry[4:4+length]
- entry = entry[4+length:]
- pieces.append(data)
- return pieces
-
-def read_old_entry(entry, hash):
- unpacked = unpack_entry(entry)
- mtl = unpacked[0]
- assert hash == get_leaf_hash(mtl)
- (leafcert, timestamp, issuer_key_hash) = unpack_mtl(mtl)
- certchain = decode_certificate_chain(unpacked[1])
- if issuer_key_hash:
- leafcert = certchain[0]
- certchain = certchain[1:]
- certtype = "PRC1"
- else:
- certtype = "EEC1"
- return (mtl, leafcert, certtype, certchain)
-
-def convertentry(entry, hash):
- (mtl, leafcert, certtype, chain) = read_old_entry(entry, hash)
- entry = tlv_encodelist([("MTL1", mtl),
- (certtype, leafcert),
- ("CHN1", tlv_encodelist([("X509", cert) for cert in chain]))])
- return wrap_entry(entry)
-
-parser = argparse.ArgumentParser(description='')
-parser.add_argument('path', help="Path to database to convert")
-args = parser.parse_args()
-
-for (dirpath, dirnames, filenames) in os.walk(args.path):
- for filename in filenames:
- fullpath = dirpath + "/" + filename
- entry = open(fullpath).read()
- entry = convertentry(entry, base64.b16decode(filename.upper()))
- if entry != None:
- print "writing new entry for", filename
- write_file(fullpath, entry)
- else:
- print "not writing new entry for", filename
diff --git a/tools/create-key.sh b/tools/create-key.sh
deleted file mode 100755
index 9d29c86..0000000
--- a/tools/create-key.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-
-openssl ecparam -name prime256v1 -genkey -noout -out $1-private.pem
-openssl ec -in $1-private.pem -pubout -out $1.pem
diff --git a/tools/fetchacert.py b/tools/fetchacert.py
deleted file mode 100755
index 82ea7c1..0000000
--- a/tools/fetchacert.py
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-import argparse
-import base64
-from certtools import *
-
-parser = argparse.ArgumentParser(description='')
-parser.add_argument('baseurl', help="Base URL for CT server")
-parser.add_argument('index', type=int, help="Index for entry to fetch")
-args = parser.parse_args()
-
-rawentries = get_entries(args.baseurl, args.index, args.index)["entries"]
-entry = extract_original_entry(rawentries[0])
-(chain, _timestamp, _issuer_key_hash) = entry
-s = ""
-for cert in chain:
- s += "-----BEGIN CERTIFICATE-----\n"
- s += base64.encodestring(cert).rstrip() + "\n"
- s += "-----END CERTIFICATE-----\n"
- s += "\n"
-print s
diff --git a/tools/fetchallcerts.py b/tools/fetchallcerts.py
deleted file mode 100755
index 66fde74..0000000
--- a/tools/fetchallcerts.py
+++ /dev/null
@@ -1,182 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2014, NORDUnet A/S.
-# See LICENSE for licensing information.
-
-import argparse
-import urllib2
-import urllib
-import json
-import base64
-import sys
-import struct
-import hashlib
-import itertools
-from certtools import *
-import zipfile
-import os
-import time
-
-parser = argparse.ArgumentParser(description='')
-parser.add_argument('baseurl', help="Base URL for CT server")
-parser.add_argument('--store', default=None, metavar="dir", help='Store certificates in directory dir')
-parser.add_argument('--write-sth', action='store_true', help='Write STH')
-parser.add_argument('--no-check-signature', action='store_true', help='Don\'t check signature')
-parser.add_argument('--publickey', default=None, metavar="file", help='Public key for the CT log')
-parser.add_argument('--cafile', default=None, metavar="file", help='File containing the CA cert')
-args = parser.parse_args()
-
-create_ssl_context(cafile=args.cafile)
-
-def get_entries_wrapper(baseurl, start, end):
- fetched_entries = 0
- while start + fetched_entries < (end + 1):
- print "fetching from", start + fetched_entries
- entries = get_entries(baseurl, start + fetched_entries, end)["entries"]
- if len(entries) == 0:
- break
- for entry in entries:
- fetched_entries += 1
- yield entry
-
-def print_layer(layer):
- for entry in layer:
- print base64.b16encode(entry)
-
-logpublickey = get_public_key_from_file(args.publickey) if args.publickey else None
-
-sth = get_sth(args.baseurl)
-if not args.no_check_signature:
- check_sth_signature(args.baseurl, sth, publickey=logpublickey)
-tree_size = sth["tree_size"]
-root_hash = base64.decodestring(sth["sha256_root_hash"])
-
-try:
- if args.store:
- oldsth = json.load(open(args.store + "/currentsth"))
- else:
- oldsth = None
-except IOError:
- oldsth = None
-
-sth_timestamp = datetime.datetime.fromtimestamp(sth["timestamp"]/1000)
-since_timestamp = time.time() - sth["timestamp"]/1000
-
-print "Log last updated %s, %d seconds ago" % (sth_timestamp.ctime(), since_timestamp)
-
-print "tree size", tree_size
-print "root hash", base64.b16encode(root_hash)
-
-if oldsth:
- if oldsth["tree_size"] == tree_size:
- print "Tree size has not changed"
- if oldsth["sha256_root_hash"] != sth["sha256_root_hash"]:
- print "Root hash is different even though tree size is the same."
- print "Log has violated the append-only property."
- print "Old hash:", oldsth["sha256_root_hash"]
- print "New hash:", sth["sha256_root_hash"]
- sys.exit(1)
- if oldsth["timestamp"] == sth["timestamp"]:
- print "Timestamp has not changed"
- else:
- print "Tree size changed, old tree size was", oldsth["tree_size"]
-
-merkle_64klayer = []
-
-if args.store:
- ncerts = None
- for blocknumber in range(0, (tree_size / 65536) + 1):
- (resulttype, result) = get_merkle_hash_64k(args.store, blocknumber, write_to_cache=True)
- if resulttype == "incomplete":
- (incompletelength, hash) = result
- ncerts = blocknumber * 65536 + incompletelength
- break
- assert resulttype == "hash"
- hash = result
- merkle_64klayer.append(hash)
- print blocknumber * 65536,
- sys.stdout.flush()
- print
- print "ncerts", ncerts
-else:
- ncerts = 0
-
-entries = get_entries_wrapper(args.baseurl, ncerts, tree_size - 1)
-
-if not args.store:
- layer0 = [get_leaf_hash(base64.decodestring(entry["leaf_input"])) for entry in entries]
-
- tree = build_merkle_tree(layer0)
-
- calculated_root_hash = tree[-1][0]
-
-else:
- currentfilename = None
- zf = None
- for entry, i in itertools.izip(entries, itertools.count(ncerts)):
- try:
- (chain, timestamp, issuer_key_hash) = extract_original_entry(entry)
- zipfilename = args.store + "/" + ("%04d.zip" % (i / 10000))
- if zipfilename != currentfilename:
- if zf:
- zf.close()
- zf = zipfile.ZipFile(zipfilename, "a",
- compression=zipfile.ZIP_DEFLATED)
- currentfilename = zipfilename
- s = ""
- s += "Timestamp: %s\n" % timestamp
- leaf_input = base64.decodestring(entry["leaf_input"])
- leaf_hash = get_leaf_hash(leaf_input)
- s += "Leafhash: %s\n" % base64.b16encode(leaf_hash)
- if issuer_key_hash:
- s += "-----BEGIN PRECERTIFICATE-----\n"
- s += base64.encodestring(chain[0]).rstrip() + "\n"
- s += "-----END PRECERTIFICATE-----\n"
- s += "\n"
- chain = chain[1:]
- for cert in chain:
- s += "-----BEGIN CERTIFICATE-----\n"
- s += base64.encodestring(cert).rstrip() + "\n"
- s += "-----END CERTIFICATE-----\n"
- s += "\n"
- zf.writestr("%08d" % i, s)
- except AssertionError, e:
- print "error for cert", i, e
- if zf:
- zf.close()
-
- for blocknumber in range(ncerts / 65536, (tree_size / 65536) + 1):
- (resulttype, result) = get_merkle_hash_64k(args.store, blocknumber, write_to_cache=True)
- if resulttype == "incomplete":
- (incompletelength, hash) = result
- ncerts = blocknumber * 65536 + incompletelength
- merkle_64klayer.append(hash)
- break
- assert resulttype == "hash"
- hash = result
- merkle_64klayer.append(hash)
- print blocknumber * 65536, base64.b16encode(hash)
-
- tree = build_merkle_tree(merkle_64klayer)
-
- calculated_root_hash = tree[-1][0]
-
- assert ncerts == tree_size
-
-print "calculated root hash", base64.b16encode(calculated_root_hash)
-
-if oldsth and oldsth["tree_size"] > 0 and oldsth["tree_size"] != tree_size:
- consistency_proof = [base64.decodestring(entry) for entry in get_consistency_proof(args.baseurl, oldsth["tree_size"], tree_size)]
- (old_treehead, new_treehead) = verify_consistency_proof(consistency_proof, oldsth["tree_size"], tree_size, base64.b64decode(oldsth["sha256_root_hash"]))
- assert old_treehead == base64.b64decode(oldsth["sha256_root_hash"])
- assert new_treehead == base64.b64decode(sth["sha256_root_hash"])
-
-if calculated_root_hash != root_hash:
- print "fetched root hash and calculated root hash different"
- sys.exit(1)
-
-if args.store and args.write_sth:
- f = open(args.store + "/currentsth", "w")
- f.write(json.dumps(sth))
- f.close()
diff --git a/tools/josef_auditor.py b/tools/josef_auditor.py
deleted file mode 100755
index 710e3da..0000000
--- a/tools/josef_auditor.py
+++ /dev/null
@@ -1,398 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-import time
-import datetime
-import base64
-import argparse
-import errno
-from certtools import *
-
-NAGIOS_OK = 0
-NAGIOS_WARN = 1
-NAGIOS_CRIT = 2
-NAGIOS_UNKNOWN = 3
-
-DEFAULT_CUR_FILE = 'all-sth.json'
-
-base_urls = ["https://plausible.ct.nordu.net/",
- "https://ct1.digicert-ct.com/log/",
- "https://ct.izenpe.com/",
- "https://log.certly.io/",
- "https://ct.googleapis.com/aviator/",
- "https://ct.googleapis.com/pilot/",
- "https://ct.googleapis.com/rocketeer/",
- "https://ct.ws.symantec.com/",
- "https://ctlog.api.venafi.com/",
- ]
-
-logkeys = {}
-logkeys["https://plausible.ct.nordu.net/"] = get_public_key_from_file("../../plausible-logkey.pem")
-logkeys["https://ct.googleapis.com/rocketeer/"] = get_public_key_from_file("../../rocketeer-logkey.pem")
-logkeys["https://ct.googleapis.com/aviator/"] = get_public_key_from_file("../../aviator-logkey.pem")
-logkeys["https://ct.googleapis.com/pilot/"] = get_public_key_from_file("../../pilot-logkey.pem")
-logkeys["https://log.certly.io/"] = get_public_key_from_file("../../certly-logkey.pem")
-logkeys["https://ct.izenpe.com/"] = get_public_key_from_file("../../izenpe-logkey.pem")
-logkeys["https://ct.ws.symantec.com/"] = get_public_key_from_file("../../symantec-logkey.pem")
-logkeys["https://ctlog.api.venafi.com/"] = get_public_key_from_file("../../venafi-logkey.pem")
-logkeys["https://ct1.digicert-ct.com/log/"] = get_public_key_from_file("../../digicert-logkey.pem")
-
-parser = argparse.ArgumentParser(description="")
-parser.add_argument('--audit', action='store_true', help="run lightweight auditor verifying consistency in STH")
-parser.add_argument('--audit2', action='store_true', help="run medium-weight auditor verifying consistency in STH and inclusion proofs of new entries")
-parser.add_argument('--audit3', action='store_true', help="continously run medium-weight auditor verifying consistency in STH and inclusion proofs of new entries")
-parser.add_argument('--build-sth', action='store_true', help="get all entries and construct STH")
-parser.add_argument('--verify-index', default=None, help="Verify a specific index in all logs" )
-# parser.add_argument('--verify-hash', action='store_true', help="Verify an entry hash in all logs" )
-parser.add_argument('--roots', action='store_true', help="Check accepted root certificates for all logs" )
-parser.add_argument('--cur-sth',
- metavar='file',
- default=DEFAULT_CUR_FILE,
- help="File containing current STH (default=%s)" % DEFAULT_CUR_FILE)
-
-timings = {}
-errors = []
-
-class UTC(datetime.tzinfo):
- def utcoffset(self, dt):
- return datetime.timedelta(hours=0)
- def dst(self, dt):
- return datetime.timedelta(0)
-
-def reduce_layer(layer):
- new_layer = []
- while len(layer) > 1:
- e1 = layer.pop(0)
- e2 = layer.pop(0)
- new_layer.append(internal_hash((e1,e2)))
- return new_layer
-
-def reduce_tree(entries, layers):
- if len(entries) == 0 and layers is []:
- return [[hashlib.sha256().digest()]]
-
- layer_idx = 0
- layers[layer_idx] += entries
-
- while len(layers[layer_idx]) > 1:
- if len(layers) == layer_idx + 1:
- layers.append([])
-
- layers[layer_idx + 1] += reduce_layer(layers[layer_idx])
- layer_idx += 1
- return layers
-
-def reduce_subtree_to_root(layers):
- while len(layers) > 1:
- if len(layers[1]) == 0:
- layers[1] = layers[0]
- else:
- layers[1] += next_merkle_layer(layers[0])
- del layers[0]
-
- if len(layers[0]) > 1:
- return next_merkle_layer(layers[0])
- return layers[0]
-
-def fetch_all_sth():
- sths = {}
- for base_url in base_urls:
- # Fetch STH
- try:
- sths[base_url] = get_sth(base_url)
- except:
- sths[base_url] = None
- error_str = time.strftime('%H:%M:%S') + " ERROR: Failed to retrieve STH from " + base_url
- print error_str
- errors.append(error_str)
- continue
-
- # Check signature on the STH
- try:
- check_sth_signature(base_url, sths[base_url], logkeys[base_url])
- except:
- error_str = time.strftime('%H:%M:%S') + " ERROR: Could not verify signature from " + base_url
- print error_str
- errors.append(error_str)
- continue
-
- return sths
-
-def verify_progress(old, new):
- print "Verifying progress"
- for url in new:
- if new and old and new[url] and old[url]:
- if new[url]["tree_size"] == old[url]["tree_size"]:
- if old[url]["sha256_root_hash"] != new[url]["sha256_root_hash"]:
- errors.append(time.strftime('%H:%M:%S') + " CRITICAL: root hash is different for same tree size in " + url)
- # print "tree size:", newsth["tree_size"],
- # print "old hash:", b64_to_b16(oldsth["sha256_root_hash"])
- # print "new hash:", b64_to_b16(newsth["sha256_root_hash"])
- # sys.exit(NAGIOS_CRIT)
- # TODO
- elif new[url]["tree_size"] < old[url]["tree_size"]:
- # if not args.allow_lag:
- errors.append(time.strftime('%H:%M:%S') + " CRITICAL: new tree smaller than previous tree (%d < %d)" % \
- (new[url]["tree_size"], old[url]["tree_size"]))
- # sys.exit(NAGIOS_CRIT)
- if new[url]:
- age = time.time() - new[url]["timestamp"]/1000
- sth_time = datetime.datetime.fromtimestamp(new[url]['timestamp'] / 1000, UTC()).strftime("%Y-%m-%d %H:%M:%S")
- # roothash = b64_to_b16(sth['sha256_root_hash'])
- roothash = new[url]['sha256_root_hash']
- if age > 24 * 3600:
- errors.append(time.strftime('%H:%M:%S') + " CRITICAL: %s is older than 24h: %s UTC" % (url, sth_time))
- elif age > 12 * 3600:
- errors.append(time.strftime('%H:%M:%S') + " WARNING: %s is older than 12h: %s UTC" % (url, sth_time))
- elif age > 6 * 3600:
- errors.append(time.strftime('%H:%M:%S') + " WARNING: %s is older than 6h: %s UTC" % (url, sth_time))
- # elif age > 2 * 3600:
- # errors.append(time.strftime('%H:%M:%S') + " WARNING: %s is older than 2h: %s UTC" % (url, sth_time))
-
-def verify_consistency(old, new):
- for url in old:
- # try:
- if old[url] and new[url] and old[url]["tree_size"]!= new[url]["tree_size"]:
- consistency_proof = get_consistency_proof(url, old[url]["tree_size"], new[url]["tree_size"])
- decoded_consistency_proof = []
- for item in consistency_proof:
- decoded_consistency_proof.append(base64.b64decode(item))
- res = verify_consistency_proof(decoded_consistency_proof, old[url]["tree_size"], new[url]["tree_size"], old[url]["sha256_root_hash"])
-
- if old[url]["sha256_root_hash"] != str(base64.b64encode(res[0])):
- print time.strftime('%H:%M:%S') + " Verification of old hash failed! " + old[url]["sha256_root_hash"], str(base64.b64encode(res[0]))
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Failed to verify consistency for " + url + ", tree size " + old[url]["tree_size"])
- elif new[url]["sha256_root_hash"] != str(base64.b64encode(res[1])):
- print time.strftime('%H:%M:%S') + " Verification of new hash failed! " + new[url]["sha256_root_hash"], str(base64.b64encode(res[1]))
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Failed to verify consistency for " + url + ", tree size " + new[url]["tree_size"])
- else:
- print time.strftime("%H:%M:%S") + " New STH from " + url + ", timestamp: " + \
- str(new[url]["timestamp"]) + ", size: " + str(new[url]["tree_size"]) + "...OK."
-
- # except:
- # print "ERROR: Could not verify consistency for " + url
-
-def verify_inclusion_all(old, new):
- for url in old:
- try:
- if old[url] and new[url]:
- if old[url]["tree_size"]!= new[url]["tree_size"]:
- entries = get_entries(url, old[url]["tree_size"], new[url]["tree_size"] -1)["entries"]
- success = True
- for i in entries:
- h = get_leaf_hash(base64.b64decode(i["leaf_input"]))
- if not verify_inclusion_by_hash(url, h):
- success = False
-
- if success:
- print time.strftime("%H:%M:%S") + " Verifying inclusion for " + str(len(entries)) + " new entries in " + url + " ...OK"
- else:
- print time.strftime('%H:%M:%S') + " ERROR: Failed to prove inclusion of all new entries in " + url
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Failed to prove inclusion of all new entries in " + url)
- except:
- print time.strftime('%H:%M:%S') + " ERROR: Failed to prove inclusion of all new entries in " + url
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Failed to prove inclusion of all new entries in " + url)
-
-def fetch_and_build_tree(old_sth, base_url):
- sth = old_sth[base_url]
- subtree = [[]]
- idx = 0
-
- res_strings = [""]
-
- print time.strftime('%H:%M:%S') + " Getting all entries from " + base_url
- while idx < sth["tree_size"]:
- pre_size = idx
- entries = get_entries(base_url, idx, sth["tree_size"]-1)["entries"]
-
- new_leafs = []
- for item in entries:
- new_leafs.append(get_leaf_hash(base64.b64decode(item["leaf_input"])))
- idx += len(new_leafs)
- print time.strftime('%H:%M:%S') + " Got entries " + str(pre_size) + " to " + str(idx) + " from " + base_url
- subtree = reduce_tree(new_leafs, subtree)
-
- root = base64.b64encode(reduce_subtree_to_root(subtree)[0])
-
- if root == sth["sha256_root_hash"]:
- print time.strftime('%H:%M:%S') + " Verifying root hashes for " + base_url + "...OK."
- res_strings.append("STH for " + base_url + " built successfully.")
- else:
- print time.strftime('%H:%M:%S') + " ERROR: Failed to verify root hashes! STH root: " + sth["sha256_root_hash"] + ", Tree root: " + root
- res_strings.append(time.strftime('%H:%M:%S') + " " + base_url + " Failed! STH root: " + sth["sha256_root_hash"] + " Calculated root: " + root)
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Failed to verify root hash for " + base_url + ", tre size " + sth["tree_size"])
-
- for item in res_strings:
- print item + "\n"
-
-def verify_inclusion_by_hash(base_url, leaf_hash):
- try:
- tmp_sth = get_sth(base_url)
- proof = get_proof_by_hash(base_url, leaf_hash, tmp_sth["tree_size"])
-
- decoded_inclusion_proof = []
- for item in proof["audit_path"]:
- decoded_inclusion_proof.append(base64.b64decode(item))
-
- root = base64.b64encode(verify_inclusion_proof(decoded_inclusion_proof, proof["leaf_index"], tmp_sth["tree_size"], leaf_hash))
-
- if tmp_sth["sha256_root_hash"] == root:
- # print "Verifying inclusion for entry " + str(proof["leaf_index"]) + " in " + base_url + "...OK."
- return True
- else:
- print time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for entry " + str(proof["leaf_index"]) + " in " + base_url
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for entry " + str(proof["leaf_index"]) + " in " + base_url)
- return False
- except:
- print time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for hashed entry in " + base_url
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for hashed entry in " + base_url)
- return False
-
-def verify_inclusion_by_index(base_url, index):
- try:
- tmp_sth = get_sth(base_url)
- proof = get_proof_by_index(base_url, index, tmp_sth["tree_size"])
-
- decoded_inclusion_proof = []
- for item in proof["audit_path"]:
- decoded_inclusion_proof.append(base64.b64decode(item))
-
- root = base64.b64encode(verify_inclusion_proof(decoded_inclusion_proof, index, tmp_sth["tree_size"], get_leaf_hash(base64.b64decode(proof["leaf_input"]))))
-
- if tmp_sth["sha256_root_hash"] == root:
- print time.strftime('%H:%M:%S') + " Verifying inclusion for entry " + str(index) + " in " + base_url + "...OK."
- else:
- print time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for entry " + str(index) + " in " + base_url
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for entry " + str(index) + " in " + base_url)
- except:
- print time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for entry " + str(index) + " in " + base_url
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for entry " + str(index) + " in " + base_url)
-
-def get_proof_by_index(baseurl, index, tree_size):
- try:
- params = urllib.urlencode({"leaf_index":index,
- "tree_size":tree_size})
- result = \
- urlopen(baseurl + "ct/v1/get-entry-and-proof?" + params).read()
- return json.loads(result)
- except urllib2.HTTPError, e:
- print "ERROR:", e.read()
- sys.exit(0)
-
-def get_all_roots(base_url):
- # print "Fetching roots from " + base_url
- result = urlopen(base_url + "ct/v1/get-roots").read()
- certs = json.loads(result)["certificates"]
- print time.strftime('%H:%M:%S') + " Received " + str(len(certs)) + " certs from " + base_url
-
- for accepted_cert in certs:
- subject = get_cert_info(base64.decodestring(accepted_cert))["subject"]
- issuer = get_cert_info(base64.decodestring(accepted_cert))["issuer"]
- if subject == issuer:
- root_cert = base64.decodestring(accepted_cert)
- print get_cert_info(root_cert)["subject"]
-
-def print_errors(errors):
- print "Encountered " + str(len(errors)) + " errors:"
- for item in errors:
- print item
-
-def print_timings(timings):
- for item in timings:
- m,s = divmod(timings[item]["longest"], 60)
- h,m = divmod(m, 60)
- print item + " last seen " + datetime.datetime.fromtimestamp(int(timings[item]["last"])/1000).strftime('%Y-%m-%d %H:%M:%S') \
- + " longest between two STH: " + str(int(h)) + "h " + str(int(m)) + "m "# + str(int(s)) + "s."
-
-
-def read_sth(fn):
- try:
- f = open(fn)
- except IOError, e:
- if e.errno == errno.ENOENT:
- return None
- raise e
- return json.loads(f.read())
-
-
-def write_file(fn, sth):
- tempname = fn + ".new"
- open(tempname, 'w').write(json.dumps(sth))
- mv_file(tempname, fn)
-
-
-def main(args):
-
- # print time.strftime("%H:%M:%S") + " Starting..."
- if args.verify_index is None and not args.build_sth and not args.audit and not args.audit2 \
- and not args.audit3 and not args.verify_hash and not args.roots:
-
- print time.strftime('%H:%M:%S') + " Nothing to do."
- return
- else:
- sth = fetch_all_sth()
-
- if args.verify_index is not None:
- for url in base_urls:
- verify_inclusion_by_index(url, int(args.verify_index))
-
-
- if args.roots:
- print time.strftime('%H:%M:%S') + " Getting accepted Root Certs from all logs..."
- for url in base_urls:
- get_all_roots(url)
-
-
- if args.build_sth:
- print time.strftime('%H:%M:%S') + " Building trees from entries. This may take a while, go get coffee or something..."
- for base_url in base_urls:
- fetch_and_build_tree(sth, base_url)
- # fetch_and_build_tree(sth, base_urls[2])
-
- if args.audit:
- print time.strftime('%H:%M:%S') + " Running auditor1 for " +str(len(base_urls)) + " logs..."
- old_sth = read_sth(args.cur_sth)
- if old_sth:
- verify_consistency(old_sth, sth)
- else:
- print "No old sth found..."
- write_file(args.cur_sth, sth)
-
-
- if args.audit3:
- print time.strftime('%H:%M:%S') + " Running auditor3 for " +str(len(base_urls)) + " logs..."
- while True:
- time.sleep(30)
- new_sth = fetch_all_sth()
- verify_consistency(sth, new_sth)
- verify_inclusion_all(sth, new_sth)
- sth = new_sth
-
- if args.audit2:
- print time.strftime('%H:%M:%S') + " Running auditor2 for " +str(len(base_urls)) + " logs..."
- old_sth = read_sth(args.cur_sth)
- verify_progress(old_sth, sth)
- if old_sth:
- verify_consistency(old_sth, sth)
- verify_inclusion_all(old_sth, sth)
- write_file(args.cur_sth, sth)
-
-
-
-if __name__ == '__main__':
- main(parser.parse_args())
- if len(errors) == 0:
- print time.strftime('%H:%M:%S') + " Everything OK."
- sys.exit(NAGIOS_OK)
- else:
- print_errors(errors)
- sys.exit(NAGIOS_WARN)
-
-
-
-
-
-
-
-
-
diff --git a/tools/josef_experimental.py b/tools/josef_experimental.py
deleted file mode 100755
index 4377b8b..0000000
--- a/tools/josef_experimental.py
+++ /dev/null
@@ -1,128 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-import time
-import base64
-import urllib
-import urllib2
-import sys
-# from pympler.asizeof import asizeof
-from certtools import *
-from Crypto.Signature import PKCS1_v1_5
-
-def reduce_leafs_to_root(layer0):
- if len(layer0) == 0:
- return [[hashlib.sha256().digest()]]
- current_layer = layer0
- while len(current_layer) > 1:
- current_layer = next_merkle_layer(current_layer)
- return current_layer
-
-def reduce_layer(layer):
- new_layer = []
- while len(layer) > 1:
- e1 = layer.pop(0)
- e2 = layer.pop(0)
- new_layer.append(internal_hash((e1,e2)))
- return new_layer
-
-def reduce_tree(entries, layers):
- if len(entries) == 0 and layers is []:
- return [[hashlib.sha256().digest()]]
-
- layer_idx = 0
- layers[layer_idx] += entries
-
- while len(layers[layer_idx]) > 1:
- if len(layers) == layer_idx + 1:
- layers.append([])
-
- layers[layer_idx + 1] += reduce_layer(layers[layer_idx])
- layer_idx += 1
- return layers
-
-def reduce_subtree_to_root(layers):
- while len(layers) > 1:
- layers[1] += next_merkle_layer(layers[0])
- del layers[0]
-
- if len(layers[0]) > 1:
- return next_merkle_layer(layers[0])
- return layers[0]
-
-def get_proof_by_index(baseurl, index, tree_size):
- try:
- params = urllib.urlencode({"leaf_index":index,
- "tree_size":tree_size})
- result = \
- urlopen(baseurl + "ct/v1/get-entry-and-proof?" + params).read()
- return json.loads(result)
- except urllib2.HTTPError, e:
- print "ERROR:", e.read()
- sys.exit(1)
-
-
-base_urls = ["https://plausible.ct.nordu.net/",
- "https://ct1.digicert-ct.com/log/",
- "https://ct.izenpe.com/",
- "https://log.certly.io/",
- "https://ctlog.api.venafi.com/",
- "https://ct.googleapis.com/aviator/",
- "https://ct.googleapis.com/pilot/",
- "https://ct.googleapis.com/rocketeer/",
- ]
-
-logkeys = {}
-logkeys["https://plausible.ct.nordu.net/"] = get_public_key_from_file("../../plausible-logkey.pem")
-logkeys["https://ct.googleapis.com/rocketeer/"] = get_public_key_from_file("../../rocketeer-logkey.pem")
-logkeys["https://ct.googleapis.com/aviator/"] = get_public_key_from_file("../../aviator-logkey.pem")
-logkeys["https://ct.googleapis.com/pilot/"] = get_public_key_from_file("../../pilot-logkey.pem")
-logkeys["https://log.certly.io/"] = get_public_key_from_file("../../certly-logkey.pem")
-logkeys["https://ct.izenpe.com/"] = get_public_key_from_file("../../izenpe-logkey.pem")
-logkeys["https://ct1.digicert-ct.com/log/"] = get_public_key_from_file("../../digicert-logkey.pem")
-logkeys["https://ctlog.api.venafi.com/"] = get_public_key_from_file("../../venafi-logkey.pem")
-
-
-import Crypto.PublicKey.RSA as RSA
-from Crypto.Hash import SHA256
-
-for url in base_urls:
- sth = get_sth(url)
- signature = base64.b64decode(sth["tree_head_signature"])
- key = logkeys[url]
- root_hash = base64.b64decode(sth["sha256_root_hash"])
-
- hash_alg, signature_alg, unpacked_signature = decode_signature(signature)
- if signature_alg == 1:
-
- # rsa_key = RSA.importKey(key)
- # verifier = PKCS1_v1_5.new(rsa_key)
-
- # version = struct.pack(">b", 0)
- # signature_type = struct.pack(">b", 1)
- # timestamp = struct.pack(">Q", sth["timestamp"])
- # tree_size = struct.pack(">Q", sth["tree_size"])
- # hash = base64.decodestring(sth["sha256_root_hash"])
-
- # tree_head = version + signature_type + timestamp + tree_size + hash
- # h = SHA256.new(tree_head)
-
- # print verifier
- # print verifier.verify(h, unpacked_signature)
- print "RSA Signature from " + url
- check_sth_signature(url, sth, key)
-
-
-
- elif signature_alg == 3:
- print "ECDSA signature from " + url
- check_sth_signature(url, sth, key)
- else:
- print "Unknown signature algorithm from " + url
-
-# print sth
-# print "\n\n" + signature
-# print "\n\n" + key
-# print rsa_key
-
-# print "\n\n" + rsa_key.verify(root_hash, signature) \ No newline at end of file
diff --git a/tools/josef_experimental_auditor.py b/tools/josef_experimental_auditor.py
deleted file mode 100755
index 57ef9cb..0000000
--- a/tools/josef_experimental_auditor.py
+++ /dev/null
@@ -1,476 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-import time
-import datetime
-import base64
-import argparse
-import errno
-from certtools import *
-
-NAGIOS_OK = 0
-NAGIOS_WARN = 1
-NAGIOS_CRIT = 2
-NAGIOS_UNKNOWN = 3
-
-DEFAULT_CUR_FILE = 'all-sth.json'
-
-base_urls = [
- "https://plausible.ct.nordu.net/",
- "https://ct1.digicert-ct.com/log/",
- "https://ct.izenpe.com/",
- "https://log.certly.io/",
- "https://ct.googleapis.com/aviator/",
- "https://ct.googleapis.com/pilot/",
- "https://ct.googleapis.com/rocketeer/",
- "https://ct.ws.symantec.com/",
- # "https://ctlog.api.venafi.com/",
- ]
-
-# logkeys = {}
-# logkeys["https://plausible.ct.nordu.net/"] = get_public_key_from_file("../../plausible-logkey.pem")
-# logkeys["https://ct.googleapis.com/rocketeer/"] = get_public_key_from_file("../../rocketeer-logkey.pem")
-# logkeys["https://ct.googleapis.com/aviator/"] = get_public_key_from_file("../../aviator-logkey.pem")
-# logkeys["https://ct.googleapis.com/pilot/"] = get_public_key_from_file("../../pilot-logkey.pem")
-# logkeys["https://log.certly.io/"] = get_public_key_from_file("../../certly-logkey.pem")
-# logkeys["https://ct.izenpe.com/"] = get_public_key_from_file("../../izenpe-logkey.pem")
-# logkeys["https://ct.ws.symantec.com/"] = get_public_key_from_file("../../symantec-logkey.pem")
-# logkeys["https://ctlog.api.venafi.com/"] = get_public_key_from_file("../../venafi-logkey.pem")
-# logkeys["https://ct1.digicert-ct.com/log/"] = get_public_key_from_file("../../digicert-logkey.pem")
-
-parser = argparse.ArgumentParser(description="")
-parser.add_argument('--audit', action='store_true', help="run lightweight auditor verifying consistency in STH")
-parser.add_argument('--audit2', action='store_true', help="run medium-weight auditor verifying consistency in STH and inclusion proofs of new entries")
-parser.add_argument('--audit3', action='store_true', help="continously run medium-weight auditor verifying consistency in STH and inclusion proofs of new entries")
-parser.add_argument('--audit4', action='store_true', help="run one check on one server")
-parser.add_argument('--build-sth', action='store_true', help="get all entries and construct STH")
-parser.add_argument('--verify-index', default=None, help="Verify a specific index in all logs" )
-# parser.add_argument('--verify-hash', action='store_true', help="Verify an entry hash in all logs" )
-parser.add_argument('--host', default=None, help="Base URL for CT log")
-parser.add_argument('--roots', action='store_true', help="Check accepted root certificates for all logs" )
-parser.add_argument('--cur-sth',
- metavar='file',
- default=DEFAULT_CUR_FILE,
- help="File containing current STH (default=%s)" % DEFAULT_CUR_FILE)
-
-timings = {}
-errors = []
-
-class UTC(datetime.tzinfo):
- def utcoffset(self, dt):
- return datetime.timedelta(hours=0)
- def dst(self, dt):
- return datetime.timedelta(0)
-
-def reduce_layer(layer):
- new_layer = []
- while len(layer) > 1:
- e1 = layer.pop(0)
- e2 = layer.pop(0)
- new_layer.append(internal_hash((e1,e2)))
- return new_layer
-
-def reduce_tree(entries, layers):
- if len(entries) == 0 and layers is []:
- return [[hashlib.sha256().digest()]]
-
- layer_idx = 0
- layers[layer_idx] += entries
-
- while len(layers[layer_idx]) > 1:
- if len(layers) == layer_idx + 1:
- layers.append([])
-
- layers[layer_idx + 1] += reduce_layer(layers[layer_idx])
- layer_idx += 1
- return layers
-
-def reduce_subtree_to_root(layers):
- while len(layers) > 1:
- if len(layers[1]) == 0:
- layers[1] = layers[0]
- else:
- layers[1] += next_merkle_layer(layers[0])
- del layers[0]
-
- if len(layers[0]) > 1:
- return next_merkle_layer(layers[0])
- return layers[0]
-
-def fetch_all_sth():
- sths = {}
- for base_url in base_urls:
- # Fetch STH
- try:
- sths[base_url] = get_sth(base_url)
- except:
- sths[base_url] = None
- error_str = time.strftime('%H:%M:%S') + " ERROR: Failed to retrieve STH from " + base_url
- print error_str
- errors.append(error_str)
- continue
-
- # Check signature on the STH
- try:
- # check_sth_signature(base_url, sths[base_url], logkeys[base_url])
- check_sth_signature(base_url, sths[base_url], None)
- except:
- error_str = time.strftime('%H:%M:%S') + " ERROR: Could not verify signature from " + base_url
- print error_str
- errors.append(error_str)
- continue
-
- # Add timing info
- # try:
- # if base_url not in timings:
- # timings[base_url] = {"last":sths[base_url]["timestamp"], "longest":0}
- # else:
- # then = datetime.datetime.fromtimestamp(int(timings[base_url]["last"])/1000)
- # now = datetime.datetime.fromtimestamp(int(sths[base_url]["timestamp"])/1000)
- # tdelta = now - then
-
- # timings[base_url]["last"] = sths[base_url]["timestamp"]
-
- # if tdelta.total_seconds() > timings[base_url]["longest"]:
- # timings[base_url]["longest"] = tdelta.total_seconds()
-
- # except Exception, err:
- # print Exception, err
- # print time.strftime('%H:%M:%S') + "ERROR: Failed to set TIME info for STH"
-
- return sths
-
-def verify_progress(old, new):
- print "Verifying progress"
- try:
- for url in new:
- if new and old and new[url] and old[url]:
- if new[url]["tree_size"] == old[url]["tree_size"]:
- if old[url]["sha256_root_hash"] != new[url]["sha256_root_hash"]:
- errors.append(time.strftime('%H:%M:%S') + " CRITICAL: root hash is different for same tree size in " + url)
- # print "tree size:", newsth["tree_size"],
- # print "old hash:", b64_to_b16(oldsth["sha256_root_hash"])
- # print "new hash:", b64_to_b16(newsth["sha256_root_hash"])
- # sys.exit(NAGIOS_CRIT)
- # TODO
- elif new[url]["tree_size"] < old[url]["tree_size"]:
- # if not args.allow_lag:
- errors.append(time.strftime('%H:%M:%S') + " CRITICAL: new tree smaller than previous tree (%d < %d)" % \
- (new[url]["tree_size"], old[url]["tree_size"]))
- # sys.exit(NAGIOS_CRIT)
- if new[url]:
- age = time.time() - new[url]["timestamp"]/1000
- sth_time = datetime.datetime.fromtimestamp(new[url]['timestamp'] / 1000, UTC()).strftime("%Y-%m-%d %H:%M:%S")
- # roothash = b64_to_b16(sth['sha256_root_hash'])
- roothash = new[url]['sha256_root_hash']
- if age > 24 * 3600:
- errors.append(time.strftime('%H:%M:%S') + " CRITICAL: %s is older than 24h: %s UTC" % (url, sth_time))
- elif age > 12 * 3600:
- errors.append(time.strftime('%H:%M:%S') + " WARNING: %s is older than 12h: %s UTC" % (url, sth_time))
- elif age > 6 * 3600:
- errors.append(time.strftime('%H:%M:%S') + " WARNING: %s is older than 6h: %s UTC" % (url, sth_time))
- # elif age > 2 * 3600:
- # errors.append(time.strftime('%H:%M:%S') + " WARNING: %s is older than 2h: %s UTC" % (url, sth_time))
- except:
- print time.strftime('%H:%M:%S') + " ERROR: Failed to verify progress for " + url
-
-
-def verify_consistency(old, new):
- for url in old:
- try:
- if old[url] and new[url] and old[url]["tree_size"]!= new[url]["tree_size"]:
- consistency_proof = get_consistency_proof(url, old[url]["tree_size"], new[url]["tree_size"])
- decoded_consistency_proof = []
- for item in consistency_proof:
- decoded_consistency_proof.append(base64.b64decode(item))
- res = verify_consistency_proof(decoded_consistency_proof, old[url]["tree_size"], new[url]["tree_size"], old[url]["sha256_root_hash"])
-
- if old[url]["sha256_root_hash"] != str(base64.b64encode(res[0])):
- print time.strftime('%H:%M:%S') + " Verification of old hash failed! " + old[url]["sha256_root_hash"], str(base64.b64encode(res[0]))
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Failed to verify consistency for " + url + ", tree size " + old[url]["tree_size"])
- elif new[url]["sha256_root_hash"] != str(base64.b64encode(res[1])):
- print time.strftime('%H:%M:%S') + " Verification of new hash failed! " + new[url]["sha256_root_hash"], str(base64.b64encode(res[1]))
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Failed to verify consistency for " + url + ", tree size " + new[url]["tree_size"])
- else:
- print time.strftime("%H:%M:%S") + " New STH from " + url + ", timestamp: " + \
- str(new[url]["timestamp"]) + ", size: " + str(new[url]["tree_size"]) + "...OK."
-
- except:
- print "ERROR: Could not verify consistency for " + url
-
-def verify_inclusion_all(old, new):
- for url in old:
- try:
- if old[url] and new[url]:
- if old[url]["tree_size"]!= new[url]["tree_size"]:
- entries = []
-
- while len(entries) + old[url]["tree_size"]!= new[url]["tree_size"]:
- entries += get_entries(url, str(int(old[url]["tree_size"]) + len(entries)), new[url]["tree_size"] -1)["entries"]
- print "Got " + str(len(entries)) + " entries..."
-
- success = True
- for i in entries:
- h = get_leaf_hash(base64.b64decode(i["leaf_input"]))
- if not verify_inclusion_by_hash(url, h):
- success = False
-
- if success:
- print time.strftime("%H:%M:%S") + " Verifying inclusion for " + str(len(entries)) + " new entries in " + url + " ...OK"
- else:
- print time.strftime('%H:%M:%S') + " ERROR: Failed to prove inclusion of all new entries in " + url
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Failed to prove inclusion of all new entries in " + url)
- except:
- print time.strftime('%H:%M:%S') + " ERROR: Failed to prove inclusion of all new entries in " + url
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Failed to prove inclusion of all new entries in " + url)
-
-def fetch_and_build_tree(old_sth, base_url):
- try:
- sth = old_sth[base_url]
- subtree = [[]]
- idx = 0
-
- res_strings = [""]
-
- print time.strftime('%H:%M:%S') + " Getting all entries from " + base_url
- while idx < sth["tree_size"]:
- pre_size = idx
- entries = get_entries(base_url, idx, sth["tree_size"]-1)["entries"]
-
- new_leafs = []
- for item in entries:
- new_leafs.append(get_leaf_hash(base64.b64decode(item["leaf_input"])))
- idx += len(new_leafs)
- print time.strftime('%H:%M:%S') + " Got entries " + str(pre_size) + " to " + str(idx) + " from " + base_url
- subtree = reduce_tree(new_leafs, subtree)
-
- root = base64.b64encode(reduce_subtree_to_root(subtree)[0])
-
- if root == sth["sha256_root_hash"]:
- print time.strftime('%H:%M:%S') + " Verifying root hashes for " + base_url + "...OK."
- res_strings.append("STH for " + base_url + " built successfully.")
- else:
- print time.strftime('%H:%M:%S') + " ERROR: Failed to verify root hashes! STH root: " + sth["sha256_root_hash"] + ", Tree root: " + root
- res_strings.append(time.strftime('%H:%M:%S') + " " + base_url + " Failed! STH root: " + sth["sha256_root_hash"] + " Calculated root: " + root)
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Failed to verify root hash for " + base_url + ", tre size " + sth["tree_size"])
-
- for item in res_strings:
- print item + "\n"
-
- except:
- print time.strftime('%H:%M:%S') + " ERROR: Failed to build STH for " + base_url
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Failed to build STH for " + base_url)
-
-def verify_inclusion_by_hash(base_url, leaf_hash):
- try:
- tmp_sth = get_sth(base_url)
- proof = get_proof_by_hash(base_url, leaf_hash, tmp_sth["tree_size"])
-
- decoded_inclusion_proof = []
- for item in proof["audit_path"]:
- decoded_inclusion_proof.append(base64.b64decode(item))
-
- root = base64.b64encode(verify_inclusion_proof(decoded_inclusion_proof, proof["leaf_index"], tmp_sth["tree_size"], leaf_hash))
-
- if tmp_sth["sha256_root_hash"] == root:
- # print "Verifying inclusion for entry " + str(proof["leaf_index"]) + " in " + base_url + "...OK."
- return True
- else:
- print time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for entry " + str(proof["leaf_index"]) + " in " + base_url
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for entry " + str(proof["leaf_index"]) + " in " + base_url)
- return False
- except:
- print time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for hashed entry in " + base_url
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for hashed entry in " + base_url)
- return False
-
-def verify_inclusion_by_index(base_url, index):
- try:
- tmp_sth = get_sth(base_url)
- proof = get_proof_by_index(base_url, index, tmp_sth["tree_size"])
-
- decoded_inclusion_proof = []
- for item in proof["audit_path"]:
- decoded_inclusion_proof.append(base64.b64decode(item))
-
- root = base64.b64encode(verify_inclusion_proof(decoded_inclusion_proof, index, tmp_sth["tree_size"], get_leaf_hash(base64.b64decode(proof["leaf_input"]))))
-
- if tmp_sth["sha256_root_hash"] == root:
- print time.strftime('%H:%M:%S') + " Verifying inclusion for entry " + str(index) + " in " + base_url + "...OK."
- else:
- print time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for entry " + str(index) + " in " + base_url
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for entry " + str(index) + " in " + base_url)
- except:
- print time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for entry " + str(index) + " in " + base_url
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for entry " + str(index) + " in " + base_url)
-
-def get_proof_by_index(baseurl, index, tree_size):
- try:
- params = urllib.urlencode({"leaf_index":index,
- "tree_size":tree_size})
- result = \
- urlopen(baseurl + "ct/v1/get-entry-and-proof?" + params).read()
- return json.loads(result)
- except urllib2.HTTPError, e:
- print "ERROR:", e.read()
- sys.exit(0)
-
-def get_all_roots(base_url):
- # print "Fetching roots from " + base_url
- result = urlopen(base_url + "ct/v1/get-roots").read()
- certs = json.loads(result)["certificates"]
- print time.strftime('%H:%M:%S') + " Received " + str(len(certs)) + " certs from " + base_url
-
- for accepted_cert in certs:
- subject = get_cert_info(base64.decodestring(accepted_cert))["subject"]
- issuer = get_cert_info(base64.decodestring(accepted_cert))["issuer"]
- if subject == issuer:
- root_cert = base64.decodestring(accepted_cert)
- print get_cert_info(root_cert)["subject"]
-
-def print_errors(errors):
- print "Encountered " + str(len(errors)) + " errors:"
- for item in errors:
- print item
-
-def print_timings(timings):
- for item in timings:
- m,s = divmod(timings[item]["longest"], 60)
- h,m = divmod(m, 60)
- print item + " last seen " + datetime.datetime.fromtimestamp(int(timings[item]["last"])/1000).strftime('%Y-%m-%d %H:%M:%S') \
- + " longest between two STH: " + str(int(h)) + "h " + str(int(m)) + "m "# + str(int(s)) + "s."
-
-
-def read_sth(fn):
- try:
- f = open(fn)
- except IOError, e:
- if e.errno == errno.ENOENT:
- return None
- raise e
- return json.loads(f.read())
-
-
-def write_file(fn, sth):
- tempname = fn + ".new"
- open(tempname, 'w').write(json.dumps(sth))
- mv_file(tempname, fn)
-
-
-def main(args):
-
- # print time.strftime("%H:%M:%S") + " Starting..."
- if args.verify_index is None and not args.build_sth and not args.audit and not args.audit2 \
- and not args.audit3 and not args.audit4 and not args.roots:
-
- print time.strftime('%H:%M:%S') + " Nothing to do."
- return
- elif args.audit4:
- pass
- else:
- sth = fetch_all_sth()
-
- if args.verify_index is not None:
- for url in base_urls:
- verify_inclusion_by_index(url, int(args.verify_index))
-
- # if args.verify_hash:
- # idx = 1337
- # url = base_urls[0]
- # entries = get_entries(url, idx, idx)["entries"]
- # h = get_leaf_hash(base64.b64decode(entries[0]["leaf_input"]))
- # verify_inclusion_by_hash(url, h)
-
- if args.roots:
- print time.strftime('%H:%M:%S') + " Getting accepted Root Certs from all logs..."
- for url in base_urls:
- get_all_roots(url)
-
-
- if args.build_sth:
- print time.strftime('%H:%M:%S') + " Building trees from entries. This may take a while, go get coffee or something..."
- for base_url in base_urls:
- fetch_and_build_tree(sth, base_url)
- # fetch_and_build_tree(sth, base_urls[2])
-
- if args.audit:
- print time.strftime('%H:%M:%S') + " Running auditor1 for " +str(len(base_urls)) + " logs..."
- old_sth = read_sth(args.cur_sth)
- if old_sth:
- verify_consistency(old_sth, sth)
- else:
- print "No old sth found..."
- write_file(args.cur_sth, sth)
-
-
- if args.audit3:
- print time.strftime('%H:%M:%S') + " Running auditor3 for " +str(len(base_urls)) + " logs..."
- while True:
- time.sleep(30)
- new_sth = fetch_all_sth()
- verify_consistency(sth, new_sth)
- verify_inclusion_all(sth, new_sth)
- sth = new_sth
-
- if args.audit2:
- print time.strftime('%H:%M:%S') + " Running auditor2 for " +str(len(base_urls)) + " logs..."
- old_sth = read_sth(args.cur_sth)
- # print "Verifying progress..."
- verify_progress(old_sth, sth)
- if old_sth:
- print "Verifying consistency..."
- verify_consistency(old_sth, sth)
- print "Verifying inclusion..."
- verify_inclusion_all(old_sth, sth)
- write_file(args.cur_sth, sth)
-
- # Experimental for plausible + nagios
- if args.audit4:
- base_url = base_urls[0]
- old_sth = read_sth("plausible-sth.json")
- print "Running auditor4 for " + base_url
- try:
- tmp_sth = get_sth(base_url)
- except:
- # sths[base_url] = None
- error_str = time.strftime('%H:%M:%S') + " ERROR: Failed to retrieve STH from " + base_url
- print error_str
- errors.append(error_str)
- sys.exit(NAGIOS_WARN)
-
- # Check signature on the STH
- try:
- check_sth_signature(base_url, tmp_sth, None)
- write_file("plausible-sth.json", tmp_sth)
- except:
- error_str = time.strftime('%H:%M:%S') + " ERROR: Could not verify signature from " + base_url
- print error_str
- errors.append(error_str)
- sys.exit(NAGIOS_CRIT)
- sys.exit(NAGIOS_OK)
-
-
-if __name__ == '__main__':
- # try:
- main(parser.parse_args())
- if len(errors) == 0:
- print time.strftime('%H:%M:%S') + " Everything OK."
- sys.exit(NAGIOS_OK)
- else:
- # print "errors found!"
- print_errors(errors)
- sys.exit(NAGIOS_WARN)
- # except:
- # pass
- # finally:
- # # print_timings(timings)
- # print_errors(errors)
-
-
-
-
-
-
-
-
-
diff --git a/tools/josef_nagios_auditor.py b/tools/josef_nagios_auditor.py
index db68bbe..74d9256 100755
--- a/tools/josef_nagios_auditor.py
+++ b/tools/josef_nagios_auditor.py
@@ -22,10 +22,6 @@ parser.add_argument('--sthfile',
required=True,
metavar='file',
help="File containing current STH")
-# parser.add_argument('--keyfile',
-# metavar='file',
-# required=True,
-# help="File containing current STH")
class UTC(datetime.tzinfo):
def utcoffset(self, dt):
@@ -78,8 +74,6 @@ def get_and_verify_sth(url):
# Check signature on the STH
try:
check_sth_signature(url, sth, None)
- # check_sth_signature(url, sth, key)
- # write_file("plausible-sth.json", tmp_sth)
except:
error_str = time.strftime('%H:%M:%S') + " ERROR: Could not verify signature from " + url
print error_str
@@ -302,11 +296,6 @@ def write_file(fn, sth):
def main(args):
- # try:
- # log_key = get_public_key_from_file(args.keyfile)
- # except:
- # print time.strftime('%H:%M:%S') + " ERROR: Failed to load keyfile " + args.keyfile
- # sys.exit(NAGIOS_WARN)
old_sth = read_sth(args.sthfile)
new_sth = get_and_verify_sth(args.baseurl)
diff --git a/tools/merge.py b/tools/merge.py
deleted file mode 100755
index 2065a2d..0000000
--- a/tools/merge.py
+++ /dev/null
@@ -1,518 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2014, NORDUnet A/S.
-# See LICENSE for licensing information.
-
-import argparse
-import json
-import base64
-import urllib
-import urllib2
-import sys
-import time
-import ecdsa
-import hashlib
-import urlparse
-import os
-import yaml
-import select
-import struct
-from certtools import build_merkle_tree, create_sth_signature, \
- check_sth_signature, get_eckey_from_file, timing_point, http_request, \
- get_public_key_from_file, get_leaf_hash, decode_certificate_chain, \
- create_ssl_context
-from mergetools import parselogrow, get_logorder, read_chain, \
- verify_entry
-
-parser = argparse.ArgumentParser(description="")
-parser.add_argument('--config', help="System configuration", required=True)
-parser.add_argument('--localconfig', help="Local configuration", required=True)
-parser.add_argument("--nomerge", action='store_true', help="Don't actually do merge")
-parser.add_argument("--timing", action='store_true', help="Print timing information")
-args = parser.parse_args()
-
-config = yaml.load(open(args.config))
-localconfig = yaml.load(open(args.localconfig))
-
-ctbaseurl = config["baseurl"]
-frontendnodes = config["frontendnodes"]
-storagenodes = config["storagenodes"]
-secondaries = config.get("mergenodes", [])
-paths = localconfig["paths"]
-mergedb = paths["mergedb"]
-
-signingnodes = config["signingnodes"]
-create_ssl_context(cafile=paths["https_cacertfile"])
-
-chainsdir = mergedb + "/chains"
-logorderfile = mergedb + "/logorder"
-
-own_key = (localconfig["nodename"], "%s/%s-private.pem" % (paths["privatekeys"], localconfig["nodename"]))
-
-logpublickey = get_public_key_from_file(paths["logpublickey"])
-
-hashed_dir = True
-
-def hexencode(key):
- return base64.b16encode(key).lower()
-
-def write_chain(key, value):
- filename = hexencode(key)
- if hashed_dir:
- path = chainsdir + "/" + filename[0:2] + "/" + filename[2:4] + "/" + filename[4:6]
- try:
- os.makedirs(path)
- except Exception, e:
- pass
- else:
- path = chainsdir
- f = open(path + "/" + filename, "w")
- f.write(value)
- f.close()
-
-def add_to_logorder(key):
- f = open(logorderfile, "a")
- f.write(hexencode(key) + "\n")
- f.close()
-
-def fsync_logorder():
- f = open(logorderfile, "a")
- os.fsync(f.fileno())
- f.close()
-
-def get_new_entries(node, baseurl):
- try:
- result = http_request(baseurl + "plop/v1/storage/fetchnewentries", key=own_key, verifynode=node, publickeydir=paths["publickeys"])
- parsed_result = json.loads(result)
- if parsed_result.get(u"result") == u"ok":
- return [base64.b64decode(entry) for entry in parsed_result[u"entries"]]
- print >>sys.stderr, "ERROR: fetchnewentries", parsed_result
- sys.exit(1)
- except urllib2.HTTPError, e:
- print >>sys.stderr, "ERROR: fetchnewentries", e.read()
- sys.exit(1)
-
-def get_entries(node, baseurl, hashes):
- try:
- params = urllib.urlencode({"hash":[base64.b64encode(hash) for hash in hashes]}, doseq=True)
- result = http_request(baseurl + "plop/v1/storage/getentry?" + params, key=own_key, verifynode=node, publickeydir=paths["publickeys"])
- parsed_result = json.loads(result)
- if parsed_result.get(u"result") == u"ok":
- entries = dict([(base64.b64decode(entry["hash"]), base64.b64decode(entry["entry"])) for entry in parsed_result[u"entries"]])
- assert len(entries) == len(hashes)
- assert set(entries.keys()) == set(hashes)
- return entries
- print >>sys.stderr, "ERROR: getentry", parsed_result
- sys.exit(1)
- except urllib2.HTTPError, e:
- print >>sys.stderr, "ERROR: getentry", e.read()
- sys.exit(1)
-
-def get_curpos(node, baseurl):
- try:
- result = http_request(baseurl + "plop/v1/frontend/currentposition", key=own_key, verifynode=node, publickeydir=paths["publickeys"])
- parsed_result = json.loads(result)
- if parsed_result.get(u"result") == u"ok":
- return parsed_result[u"position"]
- print >>sys.stderr, "ERROR: currentposition", parsed_result
- sys.exit(1)
- except urllib2.HTTPError, e:
- print >>sys.stderr, "ERROR: currentposition", e.read()
- sys.exit(1)
-
-def get_verifiedsize(node, baseurl):
- try:
- result = http_request(baseurl + "plop/v1/merge/verifiedsize", key=own_key, verifynode=node, publickeydir=paths["publickeys"])
- parsed_result = json.loads(result)
- if parsed_result.get(u"result") == u"ok":
- return parsed_result[u"size"]
- print >>sys.stderr, "ERROR: verifiedsize", parsed_result
- sys.exit(1)
- except urllib2.HTTPError, e:
- print >>sys.stderr, "ERROR: verifiedsize", e.read()
- sys.exit(1)
-
-
-
-def sendlog(node, baseurl, submission):
- try:
- result = http_request(baseurl + "plop/v1/frontend/sendlog",
- json.dumps(submission), key=own_key, verifynode=node, publickeydir=paths["publickeys"])
- return json.loads(result)
- except urllib2.HTTPError, e:
- print >>sys.stderr, "ERROR: sendlog", e.read()
- sys.stderr.flush()
- return None
- except ValueError, e:
- print >>sys.stderr, "==== FAILED REQUEST ===="
- print >>sys.stderr, submission
- print >>sys.stderr, "======= RESPONSE ======="
- print >>sys.stderr, result
- print >>sys.stderr, "========================"
- sys.stderr.flush()
- raise e
-
-def backup_sendlog(node, baseurl, submission):
- try:
- result = http_request(baseurl + "plop/v1/merge/sendlog",
- json.dumps(submission), key=own_key, verifynode=node, publickeydir=paths["publickeys"])
- return json.loads(result)
- except urllib2.HTTPError, e:
- print >>sys.stderr, "ERROR: sendlog", e.read()
- sys.stderr.flush()
- return None
- except ValueError, e:
- print >>sys.stderr, "==== FAILED REQUEST ===="
- print >>sys.stderr, submission
- print >>sys.stderr, "======= RESPONSE ======="
- print >>sys.stderr, result
- print >>sys.stderr, "========================"
- sys.stderr.flush()
- raise e
-
-def sendentry(node, baseurl, entry, hash):
- try:
- result = http_request(baseurl + "plop/v1/frontend/sendentry",
- json.dumps({"entry":base64.b64encode(entry), "treeleafhash":base64.b64encode(hash)}), key=own_key,
- verifynode=node, publickeydir=paths["publickeys"])
- return json.loads(result)
- except urllib2.HTTPError, e:
- print >>sys.stderr, "ERROR: sendentry", e.read()
- sys.exit(1)
- except ValueError, e:
- print >>sys.stderr, "==== FAILED REQUEST ===="
- print >>sys.stderr, hash
- print >>sys.stderr, "======= RESPONSE ======="
- print >>sys.stderr, result
- print >>sys.stderr, "========================"
- sys.stderr.flush()
- raise e
-
-def sendentry_merge(node, baseurl, entry, hash):
- try:
- result = http_request(baseurl + "plop/v1/merge/sendentry",
- json.dumps({"entry":base64.b64encode(entry), "treeleafhash":base64.b64encode(hash)}), key=own_key,
- verifynode=node, publickeydir=paths["publickeys"])
- return json.loads(result)
- except urllib2.HTTPError, e:
- print >>sys.stderr, "ERROR: sendentry", e.read()
- sys.exit(1)
- except ValueError, e:
- print >>sys.stderr, "==== FAILED REQUEST ===="
- print >>sys.stderr, hash
- print >>sys.stderr, "======= RESPONSE ======="
- print >>sys.stderr, result
- print >>sys.stderr, "========================"
- sys.stderr.flush()
- raise e
-
-def sendsth(node, baseurl, submission):
- try:
- result = http_request(baseurl + "plop/v1/frontend/sendsth",
- json.dumps(submission), key=own_key, verifynode=node, publickeydir=paths["publickeys"])
- return json.loads(result)
- except urllib2.HTTPError, e:
- print >>sys.stderr, "ERROR: sendsth", e.read()
- sys.exit(1)
- except ValueError, e:
- print >>sys.stderr, "==== FAILED REQUEST ===="
- print >>sys.stderr, submission
- print >>sys.stderr, "======= RESPONSE ======="
- print >>sys.stderr, result
- print >>sys.stderr, "========================"
- sys.stderr.flush()
- raise e
-
-def verifyroot(node, baseurl, treesize):
- try:
- result = http_request(baseurl + "plop/v1/merge/verifyroot",
- json.dumps({"tree_size":treesize}), key=own_key, verifynode=node, publickeydir=paths["publickeys"])
- return json.loads(result)
- except urllib2.HTTPError, e:
- print >>sys.stderr, "ERROR: verifyroot", e.read()
- sys.exit(1)
- except ValueError, e:
- print >>sys.stderr, "==== FAILED REQUEST ===="
- print >>sys.stderr, submission
- print >>sys.stderr, "======= RESPONSE ======="
- print >>sys.stderr, result
- print >>sys.stderr, "========================"
- sys.stderr.flush()
- raise e
-
-def setverifiedsize(node, baseurl, treesize):
- try:
- result = http_request(baseurl + "plop/v1/merge/setverifiedsize",
- json.dumps({"size":treesize}), key=own_key, verifynode=node, publickeydir=paths["publickeys"])
- return json.loads(result)
- except urllib2.HTTPError, e:
- print >>sys.stderr, "ERROR: setverifiedsize", e.read()
- sys.exit(1)
- except ValueError, e:
- print >>sys.stderr, "==== FAILED REQUEST ===="
- print >>sys.stderr, submission
- print >>sys.stderr, "======= RESPONSE ======="
- print >>sys.stderr, result
- print >>sys.stderr, "========================"
- sys.stderr.flush()
- raise e
-
-def get_missingentries(node, baseurl):
- try:
- result = http_request(baseurl + "plop/v1/frontend/missingentries", key=own_key, verifynode=node, publickeydir=paths["publickeys"])
- parsed_result = json.loads(result)
- if parsed_result.get(u"result") == u"ok":
- return parsed_result[u"entries"]
- print >>sys.stderr, "ERROR: missingentries", parsed_result
- sys.exit(1)
- except urllib2.HTTPError, e:
- print >>sys.stderr, "ERROR: missingentries", e.read()
- sys.exit(1)
-
-def get_missingentriesforbackup(node, baseurl):
- try:
- result = http_request(baseurl + "plop/v1/merge/missingentries", key=own_key, verifynode=node, publickeydir=paths["publickeys"])
- parsed_result = json.loads(result)
- if parsed_result.get(u"result") == u"ok":
- return parsed_result[u"entries"]
- print >>sys.stderr, "ERROR: missingentriesforbackup", parsed_result
- sys.exit(1)
- except urllib2.HTTPError, e:
- print >>sys.stderr, "ERROR: missingentriesforbackup", e.read()
- sys.exit(1)
-
-def chunks(l, n):
- return [l[i:i+n] for i in range(0, len(l), n)]
-
-timing = timing_point()
-
-logorder = get_logorder(logorderfile)
-
-timing_point(timing, "get logorder")
-
-certsinlog = set(logorder)
-
-new_entries_per_node = {}
-new_entries = set()
-entries_to_fetch = {}
-
-for storagenode in storagenodes:
- print >>sys.stderr, "getting new entries from", storagenode["name"]
- sys.stderr.flush()
- new_entries_per_node[storagenode["name"]] = set(get_new_entries(storagenode["name"], "https://%s/" % storagenode["address"]))
- new_entries.update(new_entries_per_node[storagenode["name"]])
- entries_to_fetch[storagenode["name"]] = []
-
-import subprocess
-
-timing_point(timing, "get new entries")
-
-new_entries -= certsinlog
-
-print >>sys.stderr, "adding", len(new_entries), "entries"
-sys.stderr.flush()
-
-if args.nomerge:
- sys.exit(0)
-
-for hash in new_entries:
- for storagenode in storagenodes:
- if hash in new_entries_per_node[storagenode["name"]]:
- entries_to_fetch[storagenode["name"]].append(hash)
- break
-
-verifycert = subprocess.Popen([paths["verifycert_bin"], paths["known_roots"]],
- stdin=subprocess.PIPE, stdout=subprocess.PIPE)
-
-added_entries = 0
-for storagenode in storagenodes:
- print >>sys.stderr, "getting %d entries from %s:" % (len(entries_to_fetch[storagenode["name"]]), storagenode["name"]),
- sys.stderr.flush()
- for chunk in chunks(entries_to_fetch[storagenode["name"]], 100):
- entries = get_entries(storagenode["name"], "https://%s/" % storagenode["address"], chunk)
- for hash in chunk:
- entry = entries[hash]
- verify_entry(verifycert, entry, hash)
- write_chain(hash, entry)
- add_to_logorder(hash)
- logorder.append(hash)
- certsinlog.add(hash)
- added_entries += 1
- print >>sys.stderr, added_entries,
- sys.stderr.flush()
- print >>sys.stderr
- sys.stderr.flush()
-fsync_logorder()
-timing_point(timing, "add entries")
-print >>sys.stderr, "added", added_entries, "entries"
-sys.stderr.flush()
-
-verifycert.communicate(struct.pack("I", 0))
-
-tree = build_merkle_tree(logorder)
-tree_size = len(logorder)
-root_hash = tree[-1][0]
-timestamp = int(time.time() * 1000)
-
-for secondary in secondaries:
- if secondary["name"] == config["primarymergenode"]:
- continue
- nodeaddress = "https://%s/" % secondary["address"]
- nodename = secondary["name"]
- timing = timing_point()
- print >>sys.stderr, "backing up to node", nodename
- sys.stderr.flush()
- verifiedsize = get_verifiedsize(nodename, nodeaddress)
- timing_point(timing, "get verified size")
- print >>sys.stderr, "verified size", verifiedsize
- sys.stderr.flush()
- entries = [base64.b64encode(entry) for entry in logorder[verifiedsize:]]
- print >>sys.stderr, "sending log:",
- sys.stderr.flush()
- for chunk in chunks(entries, 1000):
- for trynumber in range(5, 0, -1):
- sendlogresult = backup_sendlog(nodename, nodeaddress, {"start": verifiedsize, "hashes": chunk})
- if sendlogresult == None:
- if trynumber == 1:
- sys.exit(1)
- select.select([], [], [], 10.0)
- print >>sys.stderr, "tries left:", trynumber
- sys.stderr.flush()
- continue
- break
- if sendlogresult["result"] != "ok":
- print >>sys.stderr, "sendlog:", sendlogresult
- sys.exit(1)
- verifiedsize += len(chunk)
- print >>sys.stderr, verifiedsize,
- sys.stderr.flush()
- print >>sys.stderr
- timing_point(timing, "sendlog")
- print >>sys.stderr, "log sent"
- sys.stderr.flush()
- missingentries = get_missingentriesforbackup(nodename, nodeaddress)
- timing_point(timing, "get missing")
- print >>sys.stderr, "missing entries:", len(missingentries)
- sys.stderr.flush()
- fetched_entries = 0
- print >>sys.stderr, "fetching missing entries",
- sys.stderr.flush()
- for missingentry in missingentries:
- hash = base64.b64decode(missingentry)
- sendentryresult = sendentry_merge(nodename, nodeaddress, read_chain(chainsdir, hash), hash)
- if sendentryresult["result"] != "ok":
- print >>sys.stderr, "send sth:", sendentryresult
- sys.exit(1)
- fetched_entries += 1
- if added_entries % 1000 == 0:
- print >>sys.stderr, fetched_entries,
- sys.stderr.flush()
- print >>sys.stderr
- sys.stderr.flush()
- timing_point(timing, "send missing")
- verifyrootresult = verifyroot(nodename, nodeaddress, tree_size)
- if verifyrootresult["result"] != "ok":
- print >>sys.stderr, "verifyroot:", verifyrootresult
- sys.exit(1)
- secondary_root_hash = base64.b64decode(verifyrootresult["root_hash"])
- if root_hash != secondary_root_hash:
- print >>sys.stderr, "secondary root hash was", hexencode(secondary_root_hash)
- print >>sys.stderr, " expected", hexencode(root_hash)
- sys.exit(1)
- timing_point(timing, "verifyroot")
- setverifiedsize(nodename, nodeaddress, tree_size)
- if args.timing:
- print >>sys.stderr, timing["deltatimes"]
- sys.stderr.flush()
-
-tree_head_signature = None
-for signingnode in signingnodes:
- try:
- tree_head_signature = create_sth_signature(tree_size, timestamp,
- root_hash, "https://%s/" % signingnode["address"], key=own_key)
- break
- except urllib2.URLError, e:
- print >>sys.stderr, e
- sys.stderr.flush()
-if tree_head_signature == None:
- print >>sys.stderr, "Could not contact any signing nodes"
- sys.exit(1)
-
-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, publickey=logpublickey)
-
-timing_point(timing, "build sth")
-
-if args.timing:
- print >>sys.stderr, timing["deltatimes"]
- sys.stderr.flush()
-
-print hexencode(root_hash)
-sys.stdout.flush()
-
-for frontendnode in frontendnodes:
- nodeaddress = "https://%s/" % frontendnode["address"]
- nodename = frontendnode["name"]
- timing = timing_point()
- print >>sys.stderr, "distributing for node", nodename
- sys.stderr.flush()
- curpos = get_curpos(nodename, nodeaddress)
- timing_point(timing, "get curpos")
- print >>sys.stderr, "current position", curpos
- sys.stderr.flush()
- entries = [base64.b64encode(entry) for entry in logorder[curpos:]]
- print >>sys.stderr, "sending log:",
- sys.stderr.flush()
- for chunk in chunks(entries, 1000):
- for trynumber in range(5, 0, -1):
- sendlogresult = sendlog(nodename, nodeaddress, {"start": curpos, "hashes": chunk})
- if sendlogresult == None:
- if trynumber == 1:
- sys.exit(1)
- select.select([], [], [], 10.0)
- print >>sys.stderr, "tries left:", trynumber
- sys.stderr.flush()
- continue
- break
- if sendlogresult["result"] != "ok":
- print >>sys.stderr, "sendlog:", sendlogresult
- sys.exit(1)
- curpos += len(chunk)
- print >>sys.stderr, curpos,
- sys.stderr.flush()
- print >>sys.stderr
- timing_point(timing, "sendlog")
- print >>sys.stderr, "log sent"
- sys.stderr.flush()
- missingentries = get_missingentries(nodename, nodeaddress)
- timing_point(timing, "get missing")
- print >>sys.stderr, "missing entries:", len(missingentries)
- sys.stderr.flush()
- fetched_entries = 0
- print >>sys.stderr, "fetching missing entries",
- sys.stderr.flush()
- for missingentry in missingentries:
- hash = base64.b64decode(missingentry)
- sendentryresult = sendentry(nodename, nodeaddress, read_chain(chainsdir, hash), hash)
- if sendentryresult["result"] != "ok":
- print >>sys.stderr, "send sth:", sendentryresult
- sys.exit(1)
- fetched_entries += 1
- if added_entries % 1000 == 0:
- print >>sys.stderr, fetched_entries,
- sys.stderr.flush()
- print >>sys.stderr
- sys.stderr.flush()
- timing_point(timing, "send missing")
- sendsthresult = sendsth(nodename, nodeaddress, sth)
- if sendsthresult["result"] != "ok":
- print >>sys.stderr, "send sth:", sendsthresult
- sys.exit(1)
- timing_point(timing, "send sth")
- if args.timing:
- print >>sys.stderr, timing["deltatimes"]
- sys.stderr.flush()
diff --git a/tools/mergetools.py b/tools/mergetools.py
deleted file mode 100644
index 947d7f4..0000000
--- a/tools/mergetools.py
+++ /dev/null
@@ -1,96 +0,0 @@
-# Copyright (c) 2015, NORDUnet A/S.
-# See LICENSE for licensing information.
-import base64
-import hashlib
-import sys
-import struct
-from certtools import get_leaf_hash
-
-def parselogrow(row):
- return base64.b16decode(row, casefold=True)
-
-def get_logorder(filename):
- f = open(filename, "r")
- return [parselogrow(row.rstrip()) for row in f]
-
-def read_chain_open(chainsdir, filename):
- path = chainsdir + "/" + filename[0:2] + "/" + filename[2:4] + "/" + filename[4:6]
- f = open(path + "/" + filename, "r")
- return f
-
-def read_chain(chainsdir, key):
- filename = base64.b16encode(key).upper()
- try:
- f = read_chain_open(chainsdir, filename)
- except IOError, e:
- f = read_chain_open(chainsdir, filename.lower())
- value = f.read()
- f.close()
- return value
-
-def tlv_decode(data):
- (length,) = struct.unpack(">I", data[0:4])
- type = data[4:8]
- value = data[8:length]
- rest = data[length:]
- return (type, value, rest)
-
-def tlv_encode(type, value):
- assert(len(type) == 4)
- data = struct.pack(">I", len(value) + 8) + type + value
- return data
-
-def tlv_decodelist(data):
- l = []
- while len(data):
- (type, value, rest) = tlv_decode(data)
- l.append((type, value))
- data = rest
- return l
-
-def tlv_encodelist(l):
- data = ""
- for (type, value) in l:
- data += tlv_encode(type, value)
- return data
-
-def unwrap_entry(entry):
- ploplevel = tlv_decodelist(entry)
- assert(len(ploplevel) == 2)
- (ploptype, plopdata) = ploplevel[0]
- (plopchecksumtype, plopchecksum) = ploplevel[1]
- assert(ploptype == "PLOP")
- assert(plopchecksumtype == "S256")
- computedchecksum = hashlib.sha256(plopdata).digest()
- assert(computedchecksum == plopchecksum)
- return plopdata
-
-def wrap_entry(entry):
- return tlv_encodelist([("PLOP", entry),
- ("S256", hashlib.sha256(entry).digest())])
-
-def verify_entry(verifycert, entry, hash):
- packed = unwrap_entry(entry)
- unpacked = tlv_decodelist(packed)
- (mtltype, mtl) = unpacked[0]
- assert hash == get_leaf_hash(mtl)
- assert mtltype == "MTL1"
- s = struct.pack(">I", len(packed)) + packed
- try:
- verifycert.stdin.write(s)
- except IOError, e:
- sys.stderr.write("merge: unable to write to verifycert process: ")
- while 1:
- line = verifycert.stdout.readline()
- if line:
- sys.stderr.write(line)
- else:
- sys.exit(1)
- result_length_packed = verifycert.stdout.read(4)
- (result_length,) = struct.unpack(">I", result_length_packed)
- result = verifycert.stdout.read(result_length)
- assert len(result) == result_length
- (error_code,) = struct.unpack("B", result[0:1])
- if error_code != 0:
- print >>sys.stderr, result[1:]
- sys.exit(1)
diff --git a/tools/precerttools.py b/tools/precerttools.py
deleted file mode 100644
index 13ac572..0000000
--- a/tools/precerttools.py
+++ /dev/null
@@ -1,102 +0,0 @@
-# Copyright (c) 2014, NORDUnet A/S.
-# See LICENSE for licensing information.
-
-import sys
-import hashlib
-import rfc2459
-from pyasn1.type import univ, tag
-from pyasn1.codec.der import encoder, decoder
-
-def cleanextensions(extensions):
- result = rfc2459.Extensions().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))
- for idx in range(len(extensions)):
- extension = extensions.getComponentByPosition(idx)
- if extension.getComponentByName("extnID") == univ.ObjectIdentifier("1.3.6.1.4.1.11129.2.4.3"):
- pass
- else:
- result.setComponentByPosition(len(result), extension)
- return result
-
-def decode_any(anydata, asn1Spec=None):
- (wrapper, _) = decoder.decode(anydata)
- (data, _) = decoder.decode(wrapper, asn1Spec=asn1Spec)
- return data
-
-def get_subject(cert):
- (asn1,rest) = decoder.decode(cert, asn1Spec=rfc2459.Certificate())
- assert rest == ''
- tbsCertificate = asn1.getComponentByName("tbsCertificate")
- subject = tbsCertificate.getComponentByName("subject")
- extensions = tbsCertificate.getComponentByName("extensions")
- keyid_wrapper = get_extension(extensions, rfc2459.id_ce_subjectKeyIdentifier)
- keyid = decode_any(keyid_wrapper, asn1Spec=rfc2459.KeyIdentifier())
- return (subject, keyid)
-
-def cleanprecert(precert, issuer=None):
- (asn1,rest) = decoder.decode(precert, asn1Spec=rfc2459.Certificate())
- assert rest == ''
- tbsCertificate = asn1.getComponentByName("tbsCertificate")
-
- extensions = tbsCertificate.getComponentByName("extensions")
- tbsCertificate.setComponentByName("extensions", cleanextensions(extensions))
-
- if issuer:
- (issuer_subject, keyid) = get_subject(issuer)
- tbsCertificate.setComponentByName("issuer", issuer_subject)
- authkeyid = rfc2459.AuthorityKeyIdentifier()
- authkeyid.setComponentByName("keyIdentifier",
- rfc2459.KeyIdentifier(str(keyid)).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
- authkeyid_wrapper = univ.OctetString(encoder.encode(authkeyid))
- authkeyid_wrapper2 = encoder.encode(authkeyid_wrapper)
- set_extension(extensions, rfc2459.id_ce_authorityKeyIdentifier, authkeyid_wrapper2)
- return encoder.encode(tbsCertificate)
-
-def get_extension(extensions, id):
- for idx in range(len(extensions)):
- extension = extensions.getComponentByPosition(idx)
- if extension.getComponentByName("extnID") == id:
- return extension.getComponentByName("extnValue")
- return None
-
-def set_extension(extensions, id, value):
- result = rfc2459.Extensions().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))
- for idx in range(len(extensions)):
- extension = extensions.getComponentByPosition(idx)
- if extension.getComponentByName("extnID") == id:
- extension.setComponentByName("extnValue", value)
-
-def get_cert_key_hash(cert):
- (asn1,rest) = decoder.decode(cert, asn1Spec=rfc2459.Certificate())
- assert rest == ''
- tbsCertificate = asn1.getComponentByName("tbsCertificate")
- key = encoder.encode(tbsCertificate.getComponentByName("subjectPublicKeyInfo"))
- hash = hashlib.sha256()
- hash.update(key)
- return hash.digest()
-
-def printcert(cert, outfile=sys.stdout):
- (asn1,rest) = decoder.decode(cert, asn1Spec=rfc2459.Certificate())
- assert rest == ''
- print >>outfile, asn1.prettyPrint()
-
-def printtbscert(cert, outfile=sys.stdout):
- (asn1,rest) = decoder.decode(cert, asn1Spec=rfc2459.TBSCertificate())
- assert rest == ''
- print >>outfile, asn1.prettyPrint()
-
-ext_key_usage_precert_signing_cert = univ.ObjectIdentifier("1.3.6.1.4.1.11129.2.4.4")
-
-def get_ext_key_usage(cert):
- (asn1,rest) = decoder.decode(cert, asn1Spec=rfc2459.Certificate())
- assert rest == ''
- tbsCertificate = asn1.getComponentByName("tbsCertificate")
- extensions = tbsCertificate.getComponentByName("extensions")
- for idx in range(len(extensions)):
- extension = extensions.getComponentByPosition(idx)
- if extension.getComponentByName("extnID") == rfc2459.id_ce_extKeyUsage:
- ext_key_usage_wrapper_binary = extension.getComponentByName("extnValue")
- (ext_key_usage_wrapper, _) = decoder.decode(ext_key_usage_wrapper_binary)
- (ext_key_usage, _) = decoder.decode(ext_key_usage_wrapper)#, asn1Spec=rfc2459.ExtKeyUsageSyntax())
- return list(ext_key_usage)
- return []
-
diff --git a/tools/rfc2459.py b/tools/rfc2459.py
deleted file mode 100644
index 0ce9c6d..0000000
--- a/tools/rfc2459.py
+++ /dev/null
@@ -1,927 +0,0 @@
-# Copyright (c) 2005-2013, Ilya Etingof <ilya@glas.net>
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# * Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-#
-# * Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# X.509 message syntax
-#
-# ASN.1 source from:
-# http://www.trl.ibm.com/projects/xml/xss4j/data/asn1/grammars/x509.asn
-# http://www.ietf.org/rfc/rfc2459.txt
-#
-# Sample captures from:
-# http://wiki.wireshark.org/SampleCaptures/
-#
-from pyasn1.type import tag,namedtype,namedval,univ,constraint,char,useful
-
-MAX = 64 # XXX ?
-
-#
-# PKIX1Explicit88
-#
-
-# Upper Bounds
-ub_name = univ.Integer(32768)
-ub_common_name = univ.Integer(64)
-ub_locality_name = univ.Integer(128)
-ub_state_name = univ.Integer(128)
-ub_organization_name = univ.Integer(64)
-ub_organizational_unit_name = univ.Integer(64)
-ub_title = univ.Integer(64)
-ub_match = univ.Integer(128)
-ub_emailaddress_length = univ.Integer(128)
-ub_common_name_length = univ.Integer(64)
-ub_country_name_alpha_length = univ.Integer(2)
-ub_country_name_numeric_length = univ.Integer(3)
-ub_domain_defined_attributes = univ.Integer(4)
-ub_domain_defined_attribute_type_length = univ.Integer(8)
-ub_domain_defined_attribute_value_length = univ.Integer(128)
-ub_domain_name_length = univ.Integer(16)
-ub_extension_attributes = univ.Integer(256)
-ub_e163_4_number_length = univ.Integer(15)
-ub_e163_4_sub_address_length = univ.Integer(40)
-ub_generation_qualifier_length = univ.Integer(3)
-ub_given_name_length = univ.Integer(16)
-ub_initials_length = univ.Integer(5)
-ub_integer_options = univ.Integer(256)
-ub_numeric_user_id_length = univ.Integer(32)
-ub_organization_name_length = univ.Integer(64)
-ub_organizational_unit_name_length = univ.Integer(32)
-ub_organizational_units = univ.Integer(4)
-ub_pds_name_length = univ.Integer(16)
-ub_pds_parameter_length = univ.Integer(30)
-ub_pds_physical_address_lines = univ.Integer(6)
-ub_postal_code_length = univ.Integer(16)
-ub_surname_length = univ.Integer(40)
-ub_terminal_id_length = univ.Integer(24)
-ub_unformatted_address_length = univ.Integer(180)
-ub_x121_address_length = univ.Integer(16)
-
-class UniversalString(char.UniversalString): pass
-class BMPString(char.BMPString): pass
-class UTF8String(char.UTF8String): pass
-
-id_pkix = univ.ObjectIdentifier('1.3.6.1.5.5.7')
-id_pe = univ.ObjectIdentifier('1.3.6.1.5.5.7.1')
-id_qt = univ.ObjectIdentifier('1.3.6.1.5.5.7.2')
-id_kp = univ.ObjectIdentifier('1.3.6.1.5.5.7.3')
-id_ad = univ.ObjectIdentifier('1.3.6.1.5.5.7.48')
-
-id_qt_cps = univ.ObjectIdentifier('1.3.6.1.5.5.7.2.1')
-id_qt_unotice = univ.ObjectIdentifier('1.3.6.1.5.5.7.2.2')
-
-id_ad_ocsp = univ.ObjectIdentifier('1.3.6.1.5.5.7.48.1')
-id_ad_caIssuers = univ.ObjectIdentifier('1.3.6.1.5.5.7.48.2')
-
-class AttributeValue(univ.Any): pass
-
-class AttributeType(univ.ObjectIdentifier): pass
-
-class AttributeTypeAndValue(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('type', AttributeType()),
- namedtype.NamedType('value', AttributeValue())
- )
-
-class Attribute(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('type', AttributeType()),
- namedtype.NamedType('vals', univ.SetOf(componentType=AttributeValue()))
- )
-
-id_at = univ.ObjectIdentifier('2.5.4')
-id_at_name = univ.ObjectIdentifier('2.5.4.41')
-id_at_sutname = univ.ObjectIdentifier('2.5.4.4')
-id_at_givenName = univ.ObjectIdentifier('2.5.4.42')
-id_at_initials = univ.ObjectIdentifier('2.5.4.43')
-id_at_generationQualifier = univ.ObjectIdentifier('2.5.4.44')
-
-class X520name(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_name))),
- namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_name))),
- namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_name))),
- namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_name))),
- namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_name)))
- )
-
-id_at_commonName = univ.ObjectIdentifier('2.5.4.3')
-
-class X520CommonName(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_common_name))),
- namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_common_name))),
- namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_common_name))),
- namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_common_name))),
- namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_common_name)))
- )
-
-id_at_localityName = univ.ObjectIdentifier('2.5.4.7')
-
-class X520LocalityName(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_locality_name))),
- namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_locality_name))),
- namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_locality_name))),
- namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_locality_name))),
- namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_locality_name)))
- )
-
-id_at_stateOrProvinceName = univ.ObjectIdentifier('2.5.4.8')
-
-class X520StateOrProvinceName(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_state_name))),
- namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_state_name))),
- namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_state_name))),
- namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_state_name))),
- namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_state_name)))
- )
-
-id_at_organizationName = univ.ObjectIdentifier('2.5.4.10')
-
-class X520OrganizationName(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organization_name))),
- namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organization_name))),
- namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organization_name))),
- namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organization_name))),
- namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organization_name)))
- )
-
-id_at_organizationalUnitName = univ.ObjectIdentifier('2.5.4.11')
-
-class X520OrganizationalUnitName(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organizational_unit_name))),
- namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organizational_unit_name))),
- namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organizational_unit_name))),
- namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organizational_unit_name))),
- namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organizational_unit_name)))
- )
-
-id_at_title = univ.ObjectIdentifier('2.5.4.12')
-
-class X520Title(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_title))),
- namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_title))),
- namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_title))),
- namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_title))),
- namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_title)))
- )
-
-id_at_dnQualifier = univ.ObjectIdentifier('2.5.4.46')
-
-class X520dnQualifier(char.PrintableString): pass
-
-id_at_countryName = univ.ObjectIdentifier('2.5.4.6')
-
-class X520countryName(char.PrintableString):
- subtypeSpec = char.PrintableString.subtypeSpec + constraint.ValueSizeConstraint(2, 2)
-
-pkcs_9 = univ.ObjectIdentifier('1.2.840.113549.1.9')
-
-emailAddress = univ.ObjectIdentifier('1.2.840.113549.1.9.1')
-
-class Pkcs9email(char.IA5String):
- subtypeSpec = char.IA5String.subtypeSpec + constraint.ValueSizeConstraint(1, ub_emailaddress_length)
-
-# ----
-
-class DSAPrivateKey(univ.Sequence):
- """PKIX compliant DSA private key structure"""
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('version', univ.Integer(namedValues=namedval.NamedValues(('v1', 0)))),
- namedtype.NamedType('p', univ.Integer()),
- namedtype.NamedType('q', univ.Integer()),
- namedtype.NamedType('g', univ.Integer()),
- namedtype.NamedType('public', univ.Integer()),
- namedtype.NamedType('private', univ.Integer())
- )
-
-# ----
-
-class RelativeDistinguishedName(univ.SetOf):
- componentType = AttributeTypeAndValue()
-
-class RDNSequence(univ.SequenceOf):
- componentType = RelativeDistinguishedName()
-
-class Name(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('', RDNSequence())
- )
-
-class DirectoryString(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
- namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
- namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
- namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
- namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
- namedtype.NamedType('ia5String', char.IA5String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))) # hm, this should not be here!? XXX
- )
-
-# certificate and CRL specific structures begin here
-
-class AlgorithmIdentifier(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('algorithm', univ.ObjectIdentifier()),
- namedtype.OptionalNamedType('parameters', univ.Any())
- )
-
-class Extension(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('extnID', univ.ObjectIdentifier()),
- namedtype.DefaultedNamedType('critical', univ.Boolean('False')),
- namedtype.NamedType('extnValue', univ.Any())
- )
-
-class Extensions(univ.SequenceOf):
- componentType = Extension()
- sizeSpec = univ.SequenceOf.sizeSpec + constraint.ValueSizeConstraint(1, MAX)
-
-class SubjectPublicKeyInfo(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('algorithm', AlgorithmIdentifier()),
- namedtype.NamedType('subjectPublicKey', univ.BitString())
- )
-
-class UniqueIdentifier(univ.BitString): pass
-
-class Time(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('utcTime', useful.UTCTime()),
- namedtype.NamedType('generalTime', useful.GeneralizedTime())
- )
-
-class Validity(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('notBefore', Time()),
- namedtype.NamedType('notAfter', Time())
- )
-
-class CertificateSerialNumber(univ.Integer): pass
-
-class Version(univ.Integer):
- namedValues = namedval.NamedValues(
- ('v1', 0), ('v2', 1), ('v3', 2)
- )
-
-class TBSCertificate(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.DefaultedNamedType('version', Version('v1').subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
- namedtype.NamedType('serialNumber', CertificateSerialNumber()),
- namedtype.NamedType('signature', AlgorithmIdentifier()),
- namedtype.NamedType('issuer', Name()),
- namedtype.NamedType('validity', Validity()),
- namedtype.NamedType('subject', Name()),
- namedtype.NamedType('subjectPublicKeyInfo', SubjectPublicKeyInfo()),
- namedtype.OptionalNamedType('issuerUniqueID', UniqueIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
- namedtype.OptionalNamedType('subjectUniqueID', UniqueIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
- namedtype.OptionalNamedType('extensions', Extensions().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)))
- )
-
-class Certificate(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('tbsCertificate', TBSCertificate()),
- namedtype.NamedType('signatureAlgorithm', AlgorithmIdentifier()),
- namedtype.NamedType('signatureValue', univ.BitString())
- )
-
-# CRL structures
-
-class RevokedCertificate(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('userCertificate', CertificateSerialNumber()),
- namedtype.NamedType('revocationDate', Time()),
- namedtype.OptionalNamedType('crlEntryExtensions', Extensions())
- )
-
-class TBSCertList(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.OptionalNamedType('version', Version()),
- namedtype.NamedType('signature', AlgorithmIdentifier()),
- namedtype.NamedType('issuer', Name()),
- namedtype.NamedType('thisUpdate', Time()),
- namedtype.OptionalNamedType('nextUpdate', Time()),
- namedtype.OptionalNamedType('revokedCertificates', univ.SequenceOf(componentType=RevokedCertificate())),
- namedtype.OptionalNamedType('crlExtensions', Extensions().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
- )
-
-class CertificateList(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('tbsCertList', TBSCertList()),
- namedtype.NamedType('signatureAlgorithm', AlgorithmIdentifier()),
- namedtype.NamedType('signature', univ.BitString())
- )
-
-# Algorithm OIDs and parameter structures
-
-pkcs_1 = univ.ObjectIdentifier('1.2.840.113549.1.1')
-rsaEncryption = univ.ObjectIdentifier('1.2.840.113549.1.1.1')
-md2WithRSAEncryption = univ.ObjectIdentifier('1.2.840.113549.1.1.2')
-md5WithRSAEncryption = univ.ObjectIdentifier('1.2.840.113549.1.1.4')
-sha1WithRSAEncryption = univ.ObjectIdentifier('1.2.840.113549.1.1.5')
-id_dsa_with_sha1 = univ.ObjectIdentifier('1.2.840.10040.4.3')
-
-class Dss_Sig_Value(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('r', univ.Integer()),
- namedtype.NamedType('s', univ.Integer())
- )
-
-dhpublicnumber = univ.ObjectIdentifier('1.2.840.10046.2.1')
-
-class ValidationParms(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('seed', univ.BitString()),
- namedtype.NamedType('pgenCounter', univ.Integer())
- )
-
-class DomainParameters(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('p', univ.Integer()),
- namedtype.NamedType('g', univ.Integer()),
- namedtype.NamedType('q', univ.Integer()),
- namedtype.NamedType('j', univ.Integer()),
- namedtype.OptionalNamedType('validationParms', ValidationParms())
- )
-
-id_dsa = univ.ObjectIdentifier('1.2.840.10040.4.1')
-
-class Dss_Parms(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('p', univ.Integer()),
- namedtype.NamedType('q', univ.Integer()),
- namedtype.NamedType('g', univ.Integer())
- )
-
-# x400 address syntax starts here
-
-teletex_domain_defined_attributes = univ.Integer(6)
-
-class TeletexDomainDefinedAttribute(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('type', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_domain_defined_attribute_type_length))),
- namedtype.NamedType('value', char.TeletexString())
- )
-
-class TeletexDomainDefinedAttributes(univ.SequenceOf):
- componentType = TeletexDomainDefinedAttribute()
- subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, ub_domain_defined_attributes)
-
-terminal_type = univ.Integer(23)
-
-class TerminalType(univ.Integer):
- subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueSizeConstraint(0, ub_integer_options)
- namedValues = namedval.NamedValues(
- ('telex', 3),
- ('teletelex', 4),
- ('g3-facsimile', 5),
- ('g4-facsimile', 6),
- ('ia5-terminal', 7),
- ('videotex', 8)
- )
-
-class PresentationAddress(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.OptionalNamedType('pSelector', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
- namedtype.OptionalNamedType('sSelector', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
- namedtype.OptionalNamedType('tSelector', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
- namedtype.OptionalNamedType('nAddresses', univ.SetOf(componentType=univ.OctetString()).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3), subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
- )
-
-extended_network_address = univ.Integer(22)
-
-class E163_4_address(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('number', char.NumericString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_e163_4_number_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
- namedtype.OptionalNamedType('sub-address', char.NumericString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_e163_4_sub_address_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)))
- )
-
-class ExtendedNetworkAddress(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('e163-4-address', E163_4_address()),
- namedtype.NamedType('psap-address', PresentationAddress().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
- )
-
-class PDSParameter(univ.Set):
- componentType = namedtype.NamedTypes(
- namedtype.OptionalNamedType('printable-string', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_pds_parameter_length))),
- namedtype.OptionalNamedType('teletex-string', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_pds_parameter_length)))
- )
-
-local_postal_attributes = univ.Integer(21)
-
-class LocalPostalAttributes(PDSParameter): pass
-
-class UniquePostalName(PDSParameter): pass
-
-unique_postal_name = univ.Integer(20)
-
-poste_restante_address = univ.Integer(19)
-
-class PosteRestanteAddress(PDSParameter): pass
-
-post_office_box_address = univ.Integer(18)
-
-class PostOfficeBoxAddress(PDSParameter): pass
-
-street_address = univ.Integer(17)
-
-class StreetAddress(PDSParameter): pass
-
-class UnformattedPostalAddress(univ.Set):
- componentType = namedtype.NamedTypes(
- namedtype.OptionalNamedType('printable-address', univ.SequenceOf(componentType=char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_pds_parameter_length)).subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_pds_physical_address_lines)))),
- namedtype.OptionalNamedType('teletex-string', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_unformatted_address_length)))
- )
-
-physical_delivery_office_name = univ.Integer(10)
-
-class PhysicalDeliveryOfficeName(PDSParameter): pass
-
-physical_delivery_office_number = univ.Integer(11)
-
-class PhysicalDeliveryOfficeNumber(PDSParameter): pass
-
-extension_OR_address_components = univ.Integer(12)
-
-class ExtensionORAddressComponents(PDSParameter): pass
-
-physical_delivery_personal_name = univ.Integer(13)
-
-class PhysicalDeliveryPersonalName(PDSParameter): pass
-
-physical_delivery_organization_name = univ.Integer(14)
-
-class PhysicalDeliveryOrganizationName(PDSParameter): pass
-
-extension_physical_delivery_address_components = univ.Integer(15)
-
-class ExtensionPhysicalDeliveryAddressComponents(PDSParameter): pass
-
-unformatted_postal_address = univ.Integer(16)
-
-postal_code = univ.Integer(9)
-
-class PostalCode(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('numeric-code', char.NumericString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_postal_code_length))),
- namedtype.NamedType('printable-code', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_postal_code_length)))
- )
-
-class PhysicalDeliveryCountryName(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('x121-dcc-code', char.NumericString().subtype(subtypeSpec=constraint.ValueSizeConstraint(ub_country_name_numeric_length, ub_country_name_numeric_length))),
- namedtype.NamedType('iso-3166-alpha2-code', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(ub_country_name_alpha_length, ub_country_name_alpha_length)))
- )
-
-class PDSName(char.PrintableString):
- subtypeSpec = char.PrintableString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_pds_name_length)
-
-physical_delivery_country_name = univ.Integer(8)
-
-class TeletexOrganizationalUnitName(char.TeletexString):
- subtypeSpec = char.TeletexString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_organizational_unit_name_length)
-
-pds_name = univ.Integer(7)
-
-teletex_organizational_unit_names = univ.Integer(5)
-
-class TeletexOrganizationalUnitNames(univ.SequenceOf):
- componentType = TeletexOrganizationalUnitName()
- subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, ub_organizational_units)
-
-teletex_personal_name = univ.Integer(4)
-
-class TeletexPersonalName(univ.Set):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('surname', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_surname_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
- namedtype.OptionalNamedType('given-name', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_given_name_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
- namedtype.OptionalNamedType('initials', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_initials_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
- namedtype.OptionalNamedType('generation-qualifier', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_generation_qualifier_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)))
- )
-
-teletex_organization_name = univ.Integer(3)
-
-class TeletexOrganizationName(char.TeletexString):
- subtypeSpec = char.TeletexString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_organization_name_length)
-
-teletex_common_name = univ.Integer(2)
-
-class TeletexCommonName(char.TeletexString):
- subtypeSpec = char.TeletexString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_common_name_length)
-
-class CommonName(char.PrintableString):
- subtypeSpec = char.PrintableString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_common_name_length)
-
-common_name = univ.Integer(1)
-
-class ExtensionAttribute(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('extension-attribute-type', univ.Integer().subtype(subtypeSpec=constraint.ValueSizeConstraint(0, ub_extension_attributes), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
- namedtype.NamedType('extension-attribute-value', univ.Any().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)))
- )
-
-class ExtensionAttributes(univ.SetOf):
- componentType = ExtensionAttribute()
- subtypeSpec = univ.SetOf.subtypeSpec + constraint.ValueSizeConstraint(1, ub_extension_attributes)
-
-class BuiltInDomainDefinedAttribute(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('type', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_domain_defined_attribute_type_length))),
- namedtype.NamedType('value', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_domain_defined_attribute_value_length)))
- )
-
-class BuiltInDomainDefinedAttributes(univ.SequenceOf):
- componentType = BuiltInDomainDefinedAttribute()
- subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, ub_domain_defined_attributes)
-
-class OrganizationalUnitName(char.PrintableString):
- subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, ub_organizational_unit_name_length)
-
-class OrganizationalUnitNames(univ.SequenceOf):
- componentType = OrganizationalUnitName()
- subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, ub_organizational_units)
-
-class PersonalName(univ.Set):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('surname', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_surname_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
- namedtype.OptionalNamedType('given-name', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_given_name_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
- namedtype.OptionalNamedType('initials', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_initials_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
- namedtype.OptionalNamedType('generation-qualifier', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_generation_qualifier_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)))
- )
-
-class NumericUserIdentifier(char.NumericString):
- subtypeSpec = char.NumericString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_numeric_user_id_length)
-
-class OrganizationName(char.PrintableString):
- subtypeSpec = char.PrintableString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_organization_name_length)
-
-class PrivateDomainName(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('numeric', char.NumericString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_domain_name_length))),
- namedtype.NamedType('printable', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_domain_name_length)))
- )
-
-class TerminalIdentifier(char.PrintableString):
- subtypeSpec = char.PrintableString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_terminal_id_length)
-
-class X121Address(char.NumericString):
- subtypeSpec = char.NumericString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_x121_address_length)
-
-class NetworkAddress(X121Address): pass
-
-class AdministrationDomainName(univ.Choice):
- tagSet = univ.Choice.tagSet.tagExplicitly(
- tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 2)
- )
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('numeric', char.NumericString().subtype(subtypeSpec=constraint.ValueSizeConstraint(0, ub_domain_name_length))),
- namedtype.NamedType('printable', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(0, ub_domain_name_length)))
- )
-
-class CountryName(univ.Choice):
- tagSet = univ.Choice.tagSet.tagExplicitly(
- tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 1)
- )
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('x121-dcc-code', char.NumericString().subtype(subtypeSpec=constraint.ValueSizeConstraint(ub_country_name_numeric_length, ub_country_name_numeric_length))),
- namedtype.NamedType('iso-3166-alpha2-code', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(ub_country_name_alpha_length, ub_country_name_alpha_length)))
- )
-
-class BuiltInStandardAttributes(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.OptionalNamedType('country-name', CountryName()),
- namedtype.OptionalNamedType('administration-domain-name', AdministrationDomainName()),
- namedtype.OptionalNamedType('network-address', NetworkAddress().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
- namedtype.OptionalNamedType('terminal-identifier', TerminalIdentifier().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
- namedtype.OptionalNamedType('private-domain-name', PrivateDomainName().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
- namedtype.OptionalNamedType('organization-name', OrganizationName().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))),
- namedtype.OptionalNamedType('numeric-user-identifier', NumericUserIdentifier().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4))),
- namedtype.OptionalNamedType('personal-name', PersonalName().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 5))),
- namedtype.OptionalNamedType('organizational-unit-names', OrganizationalUnitNames().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 6)))
- )
-
-class ORAddress(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('built-in-standard-attributes', BuiltInStandardAttributes()),
- namedtype.OptionalNamedType('built-in-domain-defined-attributes', BuiltInDomainDefinedAttributes()),
- namedtype.OptionalNamedType('extension-attributes', ExtensionAttributes())
- )
-
-#
-# PKIX1Implicit88
-#
-
-id_ce_invalidityDate = univ.ObjectIdentifier('2.5.29.24')
-
-class InvalidityDate(useful.GeneralizedTime): pass
-
-id_holdinstruction_none = univ.ObjectIdentifier('2.2.840.10040.2.1')
-id_holdinstruction_callissuer = univ.ObjectIdentifier('2.2.840.10040.2.2')
-id_holdinstruction_reject = univ.ObjectIdentifier('2.2.840.10040.2.3')
-
-holdInstruction = univ.ObjectIdentifier('2.2.840.10040.2')
-
-id_ce_holdInstructionCode = univ.ObjectIdentifier('2.5.29.23')
-
-class HoldInstructionCode(univ.ObjectIdentifier): pass
-
-id_ce_cRLReasons = univ.ObjectIdentifier('2.5.29.21')
-
-class CRLReason(univ.Enumerated):
- namedValues = namedval.NamedValues(
- ('unspecified', 0),
- ('keyCompromise', 1),
- ('cACompromise', 2),
- ('affiliationChanged', 3),
- ('superseded', 4),
- ('cessationOfOperation', 5),
- ('certificateHold', 6),
- ('removeFromCRL', 8)
- )
-
-id_ce_cRLNumber = univ.ObjectIdentifier('2.5.29.20')
-
-class CRLNumber(univ.Integer):
- subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(0, MAX)
-
-class BaseCRLNumber(CRLNumber): pass
-
-id_kp_serverAuth = univ.ObjectIdentifier('1.3.6.1.5.5.7.3.1.1')
-id_kp_clientAuth = univ.ObjectIdentifier('1.3.6.1.5.5.7.3.2')
-id_kp_codeSigning = univ.ObjectIdentifier('1.3.6.1.5.5.7.3.3')
-id_kp_emailProtection = univ.ObjectIdentifier('1.3.6.1.5.5.7.3.4')
-id_kp_ipsecEndSystem = univ.ObjectIdentifier('1.3.6.1.5.5.7.3.5')
-id_kp_ipsecTunnel = univ.ObjectIdentifier('1.3.6.1.5.5.7.3.6')
-id_kp_ipsecUser = univ.ObjectIdentifier('1.3.6.1.5.5.7.3.7')
-id_kp_timeStamping = univ.ObjectIdentifier('1.3.6.1.5.5.7.3.8')
-id_pe_authorityInfoAccess = univ.ObjectIdentifier('1.3.6.1.5.5.7.1.1')
-id_ce_extKeyUsage = univ.ObjectIdentifier('2.5.29.37')
-
-class KeyPurposeId(univ.ObjectIdentifier): pass
-
-class ExtKeyUsageSyntax(univ.SequenceOf):
- componentType = KeyPurposeId()
- subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
-
-class ReasonFlags(univ.BitString):
- namedValues = namedval.NamedValues(
- ('unused', 0),
- ('keyCompromise', 1),
- ('cACompromise', 2),
- ('affiliationChanged', 3),
- ('superseded', 4),
- ('cessationOfOperation', 5),
- ('certificateHold', 6)
- )
-
-
-class SkipCerts(univ.Integer):
- subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueSizeConstraint(0, MAX)
-
-id_ce_policyConstraints = univ.ObjectIdentifier('2.5.29.36')
-
-class PolicyConstraints(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.OptionalNamedType('requireExplicitPolicy', SkipCerts().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
- namedtype.OptionalNamedType('inhibitPolicyMapping', SkipCerts().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
- )
-
-id_ce_basicConstraints = univ.ObjectIdentifier('2.5.29.19')
-
-class BasicConstraints(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('cA', univ.Boolean(False)),
- namedtype.OptionalNamedType('pathLenConstraint', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, MAX)))
- )
-
-id_ce_subjectDirectoryAttributes = univ.ObjectIdentifier('2.5.29.9')
-
-class SubjectDirectoryAttributes(univ.SequenceOf):
- componentType = Attribute()
- subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
-
-class EDIPartyName(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.OptionalNamedType('nameAssigner', DirectoryString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
- namedtype.NamedType('partyName', DirectoryString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)))
- )
-
-class AnotherName(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('type-id', univ.ObjectIdentifier()),
- namedtype.NamedType('value', univ.Any().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
- )
-
-class GeneralName(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('otherName', AnotherName().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
- namedtype.NamedType('rfc822Name', char.IA5String().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
- namedtype.NamedType('dNSName', char.IA5String().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
- namedtype.NamedType('x400Address', ORAddress().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))),
- namedtype.NamedType('directoryName', Name().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4))),
- namedtype.NamedType('ediPartyName', EDIPartyName().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 5))),
- namedtype.NamedType('uniformResourceIdentifier', char.IA5String().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 6))),
- namedtype.NamedType('iPAddress', univ.OctetString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 7))),
- namedtype.NamedType('registeredID', univ.ObjectIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 8)))
- )
-
-class GeneralNames(univ.SequenceOf):
- componentType = GeneralName()
- subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
-
-class AccessDescription(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('accessMethod', univ.ObjectIdentifier()),
- namedtype.NamedType('accessLocation', GeneralName())
- )
-
-class AuthorityInfoAccessSyntax(univ.SequenceOf):
- componentType = AccessDescription()
- subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
-
-id_ce_deltaCRLIndicator = univ.ObjectIdentifier('2.5.29.27')
-
-class DistributionPointName(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('fullName', GeneralNames().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
- namedtype.NamedType('nameRelativeToCRLIssuer', RelativeDistinguishedName().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
- )
-
-class DistributionPoint(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.OptionalNamedType('distributionPoint', DistributionPointName().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
- namedtype.OptionalNamedType('reasons', ReasonFlags().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
- namedtype.OptionalNamedType('cRLIssuer', GeneralNames().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)))
- )
-class BaseDistance(univ.Integer):
- subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueRangeConstraint(0, MAX)
-
-id_ce_cRLDistributionPoints = univ.ObjectIdentifier('2.5.29.31')
-
-class CRLDistPointsSyntax(univ.SequenceOf):
- componentType = DistributionPoint
- subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
-id_ce_issuingDistributionPoint = univ.ObjectIdentifier('2.5.29.28')
-
-class IssuingDistributionPoint(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.OptionalNamedType('distributionPoint', DistributionPointName().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
- namedtype.NamedType('onlyContainsUserCerts', univ.Boolean(False).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
- namedtype.NamedType('onlyContainsCACerts', univ.Boolean(False).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
- namedtype.OptionalNamedType('onlySomeReasons', ReasonFlags().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))),
- namedtype.NamedType('indirectCRL', univ.Boolean(False).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)))
- )
-
-class GeneralSubtree(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('base', GeneralName()),
- namedtype.NamedType('minimum', BaseDistance(0).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
- namedtype.OptionalNamedType('maximum', BaseDistance().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
- )
-
-class GeneralSubtrees(univ.SequenceOf):
- componentType = GeneralSubtree()
- subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
-
-id_ce_nameConstraints = univ.ObjectIdentifier('2.5.29.30')
-
-class NameConstraints(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.OptionalNamedType('permittedSubtrees', GeneralSubtrees().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
- namedtype.OptionalNamedType('excludedSubtrees', GeneralSubtrees().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
- )
-
-
-class DisplayText(univ.Choice):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('visibleString', char.VisibleString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, 200))),
- namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, 200))),
- namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, 200)))
- )
-
-class NoticeReference(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('organization', DisplayText()),
- namedtype.NamedType('noticeNumbers', univ.SequenceOf(componentType=univ.Integer()))
- )
-
-class UserNotice(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.OptionalNamedType('noticeRef', NoticeReference()),
- namedtype.OptionalNamedType('explicitText', DisplayText())
- )
-
-class CPSuri(char.IA5String): pass
-
-class PolicyQualifierId(univ.ObjectIdentifier):
- subtypeSpec = univ.ObjectIdentifier.subtypeSpec + constraint.SingleValueConstraint(id_qt_cps, id_qt_unotice)
-
-class CertPolicyId(univ.ObjectIdentifier): pass
-
-class PolicyQualifierInfo(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('policyQualifierId', PolicyQualifierId()),
- namedtype.NamedType('qualifier', univ.Any())
- )
-
-id_ce_certificatePolicies = univ.ObjectIdentifier('2.5.29.32')
-
-class PolicyInformation(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('policyIdentifier', CertPolicyId()),
- namedtype.OptionalNamedType('policyQualifiers', univ.SequenceOf(componentType=PolicyQualifierInfo()).subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX)))
- )
-
-class CertificatePolicies(univ.SequenceOf):
- componentType = PolicyInformation()
- subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
-
-id_ce_policyMappings = univ.ObjectIdentifier('2.5.29.33')
-
-class PolicyMapping(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('issuerDomainPolicy', CertPolicyId()),
- namedtype.NamedType('subjectDomainPolicy', CertPolicyId())
- )
-
-class PolicyMappings(univ.SequenceOf):
- componentType = PolicyMapping()
- subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
-
-id_ce_privateKeyUsagePeriod = univ.ObjectIdentifier('2.5.29.16')
-
-class PrivateKeyUsagePeriod(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.OptionalNamedType('notBefore', useful.GeneralizedTime().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
- namedtype.OptionalNamedType('notAfter', useful.GeneralizedTime().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)))
- )
-
-id_ce_keyUsage = univ.ObjectIdentifier('2.5.29.15')
-
-class KeyUsage(univ.BitString):
- namedValues = namedval.NamedValues(
- ('digitalSignature', 0),
- ('nonRepudiation', 1),
- ('keyEncipherment', 2),
- ('dataEncipherment', 3),
- ('keyAgreement', 4),
- ('keyCertSign', 5),
- ('cRLSign', 6),
- ('encipherOnly', 7),
- ('decipherOnly', 8)
- )
-
-id_ce = univ.ObjectIdentifier('2.5.29')
-
-id_ce_authorityKeyIdentifier = univ.ObjectIdentifier('2.5.29.35')
-
-class KeyIdentifier(univ.OctetString): pass
-
-id_ce_subjectKeyIdentifier = univ.ObjectIdentifier('2.5.29.14')
-
-class SubjectKeyIdentifier(KeyIdentifier): pass
-
-class AuthorityKeyIdentifier(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.OptionalNamedType('keyIdentifier', KeyIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
- namedtype.OptionalNamedType('authorityCertIssuer', GeneralNames().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
- namedtype.OptionalNamedType('authorityCertSerialNumber', CertificateSerialNumber().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2)))
- )
-
-id_ce_certificateIssuer = univ.ObjectIdentifier('2.5.29.29')
-
-class CertificateIssuer(GeneralNames): pass
-
-id_ce_subjectAltName = univ.ObjectIdentifier('2.5.29.17')
-
-class SubjectAltName(GeneralNames): pass
-
-id_ce_issuerAltName = univ.ObjectIdentifier('2.5.29.18')
-
-class IssuerAltName(GeneralNames): pass
diff --git a/tools/storagegc.py b/tools/storagegc.py
deleted file mode 100755
index a4f15b7..0000000
--- a/tools/storagegc.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (c) 2015, NORDUnet A/S.
-# See LICENSE for licensing information.
-
-import argparse
-import urllib2
-import urllib
-import json
-import base64
-import sys
-import yaml
-from certtools import *
-
-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))
-
-paths = localconfig["paths"]
-db_path = paths["db"]
-create_ssl_context(cafile=paths.get("public_cacertfile", None))
-
-baseurl = config["baseurl"]
-
-sth = get_sth(baseurl)
-
-def verifyleafhash(leaf_hash):
- try:
- proof = get_proof_by_hash(baseurl, leaf_hash, sth["tree_size"])
- except SystemExit:
- return False
-
- leaf_index = proof["leaf_index"]
- inclusion_proof = [base64.b64decode(e) for e in proof["audit_path"]]
-
- calc_root_hash = verify_inclusion_proof(inclusion_proof, leaf_index, sth["tree_size"], leaf_hash)
-
- root_hash = base64.b64decode(sth["sha256_root_hash"])
- if root_hash != calc_root_hash:
- print "sth calculation incorrect:"
- print base64.b16encode(root_hash)
- print base64.b16encode(calc_root_hash)
- sys.exit(1)
-
- return True
-
-starttime = datetime.datetime.now()
-
-
-try:
- lastverifiedstring = open(db_path + "lastverifiednewentry").read()
- lastverified = json.loads(lastverifiedstring)
-except IOError:
- lastverified = {"index": -1, "hash": None}
-print "starting at", lastverified
-
-newentriesfile = open(db_path + "newentries")
-if lastverified["index"] >= 0:
- newentriesfile.seek(lastverified["index"]*65)
- assert(newentriesfile.read(64).lower() == lastverified["hash"])
-newentriesfile.seek((lastverified["index"]+1)*65)
-
-try:
- i = lastverified["index"] + 1
- sincewritten = 0
- for line in newentriesfile:
- leaf_hash = base64.b16decode(line.strip(), casefold=True)
- result = verifyleafhash(leaf_hash)
- if not result:
- break
- lastverified = {"index": i, "hash": base64.b16encode(leaf_hash).lower()}
- i += 1
- sincewritten += 1
- if sincewritten > 1000:
- write_file(db_path + "lastverifiednewentry", lastverified)
- sincewritten = 0
- if lastverified["index"] >= 0:
- write_file(db_path + "lastverifiednewentry", lastverified)
- print "lastverified", lastverified
-except KeyboardInterrupt:
- pass
diff --git a/tools/submitcert.py b/tools/submitcert.py
deleted file mode 100755
index 3b14912..0000000
--- a/tools/submitcert.py
+++ /dev/null
@@ -1,219 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (c) 2014, NORDUnet A/S.
-# See LICENSE for licensing information.
-
-import argparse
-import urllib2
-import urllib
-import json
-import base64
-import sys
-import struct
-import hashlib
-import itertools
-from certtools import *
-from certtools import *
-from precerttools import *
-import os
-import signal
-import select
-import zipfile
-
-parser = argparse.ArgumentParser(description='')
-parser.add_argument('baseurl', help="Base URL for CT server")
-parser.add_argument('--store', default=None, metavar="dir", help='Get certificates from directory dir')
-parser.add_argument('--sct-file', default=None, metavar="file", help='Store SCT:s in file')
-parser.add_argument('--parallel', type=int, default=16, metavar="n", help="Number of parallel submits")
-parser.add_argument('--check-sct', action='store_true', help="Check SCT signature")
-parser.add_argument('--pre-warm', action='store_true', help="Wait 3 seconds after first submit")
-parser.add_argument('--publickey', default=None, metavar="file", help='Public key for the CT log')
-parser.add_argument('--cafile', default=None, metavar="file", help='File containing the CA cert')
-args = parser.parse_args()
-
-create_ssl_context(cafile=args.cafile)
-
-from multiprocessing import Pool
-
-baseurl = args.baseurl
-certfilepath = args.store
-
-logpublickey = get_public_key_from_file(args.publickey) if args.publickey else None
-
-lookup_in_log = False
-
-if certfilepath[-1] == "/":
- certfiles = [certfilepath + filename for filename in sorted(os.listdir(certfilepath)) if os.path.isfile(certfilepath + filename)]
-else:
- certfiles = [certfilepath]
-
-sth = get_sth(baseurl)
-
-def submitcert((certfile, cert)):
- timing = timing_point()
- certchain = get_certs_from_string(cert)
- precerts = get_precerts_from_string(cert)
- assert len(precerts) == 0 or len(precerts) == 1
- precert = precerts[0] if precerts else None
- timing_point(timing, "readcerts")
-
- try:
- if precert:
- if ext_key_usage_precert_signing_cert in get_ext_key_usage(certchain[0]):
- issuer_key_hash = get_cert_key_hash(certchain[1])
- issuer = certchain[1]
- else:
- issuer_key_hash = get_cert_key_hash(certchain[0])
- issuer = None
- cleanedcert = cleanprecert(precert, issuer=issuer)
- signed_entry = pack_precert(cleanedcert, issuer_key_hash)
- leafcert = cleanedcert
- result = add_prechain(baseurl, {"chain":map(base64.b64encode, [precert] + certchain)})
- else:
- signed_entry = pack_cert(certchain[0])
- leafcert = certchain[0]
- issuer_key_hash = None
- result = add_chain(baseurl, {"chain":map(base64.b64encode, certchain)})
- except SystemExit:
- print "EXIT:", certfile
- select.select([], [], [], 1.0)
- return (None, None)
-
- timing_point(timing, "addchain")
-
- if result == None:
- print "ERROR for certfile", certfile
- return (None, timing["deltatimes"])
-
- try:
- if args.check_sct:
- check_sct_signature(baseurl, signed_entry, result, precert=precert, publickey=logpublickey)
- timing_point(timing, "checksig")
- except AssertionError, e:
- print "ERROR:", certfile, e
- return (None, None)
- except urllib2.HTTPError, e:
- print "ERROR:", certfile, e
- return (None, None)
- except ecdsa.keys.BadSignatureError, e:
- print "ERROR: bad signature", certfile
- return (None, None)
-
- if lookup_in_log:
-
- merkle_tree_leaf = pack_mtl(result["timestamp"], leafcert)
-
- leaf_hash = get_leaf_hash(merkle_tree_leaf)
-
- proof = get_proof_by_hash(baseurl, leaf_hash, sth["tree_size"])
-
- leaf_index = proof["leaf_index"]
-
- entries = get_entries(baseurl, leaf_index, leaf_index)
-
- fetched_entry = entries["entries"][0]
-
- print "does the leaf_input of the fetched entry match what we calculated:", \
- base64.decodestring(fetched_entry["leaf_input"]) == merkle_tree_leaf
-
- extra_data = fetched_entry["extra_data"]
-
- certchain = decode_certificate_chain(base64.decodestring(extra_data))
-
- submittedcertchain = certchain[1:]
-
- for (submittedcert, fetchedcert, i) in zip(submittedcertchain,
- certchain, itertools.count(1)):
- print "cert", i, "in chain is the same:", submittedcert == fetchedcert
-
- if len(certchain) == len(submittedcertchain) + 1:
- last_issuer = get_cert_info(certchain[-1])["issuer"]
- root_subject = get_cert_info(certchain[-1])["subject"]
- print "issuer of last cert in submitted chain and " \
- "subject of last cert in fetched chain is the same:", \
- last_issuer == root_subject
- elif len(certchain) == len(submittedcertchain):
- print "cert chains are the same length"
- else:
- print "ERROR: fetched cert chain has length", len(certchain),
- print "and submitted chain has length", len(submittedcertchain)
-
- timing_point(timing, "lookup")
- return ((leafcert, issuer_key_hash, result), timing["deltatimes"])
-
-def get_ncerts(certfiles):
- n = 0
- for certfile in certfiles:
- if certfile.endswith(".zip"):
- zf = zipfile.ZipFile(certfile)
- n += len(zf.namelist())
- zf.close()
- else:
- n += 1
- return n
-
-def get_all_certificates(certfiles):
- for certfile in certfiles:
- if certfile.endswith(".zip"):
- zf = zipfile.ZipFile(certfile)
- for name in zf.namelist():
- yield (name, zf.read(name))
- zf.close()
- else:
- yield (certfile, open(certfile).read())
-
-def save_sct(sct, sth, leafcert, issuer_key_hash):
- sctlog = open(args.sct_file, "a")
- sctentry = {"leafcert": base64.b64encode(leafcert), "sct": sct, "sth": sth}
- if issuer_key_hash:
- sctentry["issuer_key_hash"] = base64.b64encode(issuer_key_hash)
- json.dump(sctentry, sctlog)
- sctlog.write("\n")
- sctlog.close()
-
-p = Pool(args.parallel, lambda: signal.signal(signal.SIGINT, signal.SIG_IGN))
-
-nsubmitted = 0
-lastprinted = 0
-
-print "listing certs"
-ncerts = get_ncerts(certfiles)
-
-print ncerts, "certs"
-
-certs = get_all_certificates(certfiles)
-
-(result, timing) = submitcert(certs.next())
-if result != None:
- nsubmitted += 1
- (leafcert, issuer_key_hash, sct) = result
- save_sct(sct, sth, leafcert, issuer_key_hash)
-
-if args.pre_warm:
- select.select([], [], [], 3.0)
-
-starttime = datetime.datetime.now()
-
-try:
- for result, timing in p.imap_unordered(submitcert, certs):
- if timing == None:
- print "error"
- print "submitted", nsubmitted
- p.terminate()
- p.join()
- sys.exit(1)
- if result != None:
- nsubmitted += 1
- (leafcert, issuer_key_hash, sct) = result
- save_sct(sct, sth, leafcert, issuer_key_hash)
- deltatime = datetime.datetime.now() - starttime
- deltatime_f = deltatime.seconds + deltatime.microseconds / 1000000.0
- rate = nsubmitted / deltatime_f
- if nsubmitted > lastprinted + ncerts / 10:
- print nsubmitted, "rate %.1f" % rate
- lastprinted = nsubmitted
- #print timing, "rate %.1f" % rate
- print "submitted", nsubmitted
-except KeyboardInterrupt:
- p.terminate()
- p.join()
diff --git a/tools/testcase1.py b/tools/testcase1.py
deleted file mode 100755
index c66d976..0000000
--- a/tools/testcase1.py
+++ /dev/null
@@ -1,264 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2014, NORDUnet A/S.
-# See LICENSE for licensing information.
-
-import urllib2
-import urllib
-import json
-import base64
-import sys
-import struct
-import hashlib
-import itertools
-from certtools import *
-
-baseurls = [sys.argv[1]]
-logpublickeyfile = sys.argv[2]
-cacertfile = sys.argv[3]
-
-certfiles = ["../tools/testcerts/cert1.txt", "../tools/testcerts/cert2.txt",
- "../tools/testcerts/cert3.txt", "../tools/testcerts/cert4.txt",
- "../tools/testcerts/cert5.txt"]
-
-cc1 = get_certs_from_file(certfiles[0])
-cc2 = get_certs_from_file(certfiles[1])
-cc3 = get_certs_from_file(certfiles[2])
-cc4 = get_certs_from_file(certfiles[3])
-cc5 = get_certs_from_file(certfiles[4])
-
-create_ssl_context(cafile=cacertfile)
-
-failures = 0
-indentation = ""
-
-logpublickey = get_public_key_from_file(logpublickeyfile)
-
-def testgroup(name):
- global indentation
- print name + ":"
- indentation = " "
-
-def print_error(message, *args):
- global failures, indentation
- print indentation + "ERROR:", message % args
- failures += 1
-
-def print_success(message, *args):
- print indentation + message % args
-
-def assert_equal(actual, expected, name, quiet=False, nodata=False, fatal=False):
- global failures
- if actual != expected:
- if nodata:
- print_error("%s differs", name)
- else:
- print_error("%s expected %s got %s", name, expected, actual)
- if fatal:
- sys.exit(1)
- elif not quiet:
- print_success("%s was correct", name)
-
-def print_and_check_tree_size(expected, baseurl):
- global failures
- sth = get_sth(baseurl)
- try:
- check_sth_signature(baseurl, sth, publickey=logpublickey)
- except AssertionError, e:
- print_error("%s", e)
- except ecdsa.keys.BadSignatureError, e:
- print_error("bad STH signature")
- tree_size = sth["tree_size"]
- assert_equal(tree_size, expected, "tree size", quiet=True)
-
-def do_add_chain(chain, baseurl):
- global failures
- try:
- result = add_chain(baseurl, {"chain":map(base64.b64encode, chain)})
- except ValueError, e:
- print_error("%s", e)
- try:
- signed_entry = pack_cert(chain[0])
- check_sct_signature(baseurl, signed_entry, result, publickey=logpublickey)
- print_success("signature check succeeded")
- except AssertionError, e:
- print_error("%s", e)
- except ecdsa.keys.BadSignatureError, e:
- print e
- print_error("bad SCT signature")
- return result
-
-def get_and_validate_proof(timestamp, chain, leaf_index, nentries, baseurl):
- cert = chain[0]
- merkle_tree_leaf = pack_mtl(timestamp, cert)
- leaf_hash = get_leaf_hash(merkle_tree_leaf)
- sth = get_sth(baseurl)
- proof = get_proof_by_hash(baseurl, leaf_hash, sth["tree_size"])
- leaf_index = proof["leaf_index"]
- inclusion_proof = [base64.b64decode(e) for e in proof["audit_path"]]
- assert_equal(leaf_index, leaf_index, "leaf_index", quiet=True)
- assert_equal(len(inclusion_proof), nentries, "audit_path length", quiet=True)
-
- calc_root_hash = verify_inclusion_proof(inclusion_proof, leaf_index, sth["tree_size"], leaf_hash)
- root_hash = base64.b64decode(sth["sha256_root_hash"])
-
- assert_equal(root_hash, calc_root_hash, "verified root hash", nodata=True, quiet=True)
- get_and_check_entry(timestamp, chain, leaf_index, baseurl)
-
-def get_and_validate_consistency_proof(sth1, sth2, size1, size2, baseurl):
- consistency_proof = [base64.decodestring(entry) for entry in get_consistency_proof(baseurl, size1, size2)]
- (old_treehead, new_treehead) = verify_consistency_proof(consistency_proof, size1, size2, sth1)
- #print repr(sth1), repr(old_treehead)
- #print repr(sth2), repr(new_treehead)
- assert_equal(old_treehead, sth1, "sth1", nodata=True, quiet=True)
- assert_equal(new_treehead, sth2, "sth2", nodata=True, quiet=True)
-
-
-def get_and_check_entry(timestamp, chain, leaf_index, baseurl):
- entries = get_entries(baseurl, leaf_index, leaf_index)
- assert_equal(len(entries), 1, "get_entries", quiet=True)
- fetched_entry = entries["entries"][0]
- merkle_tree_leaf = pack_mtl(timestamp, chain[0])
- leaf_input = base64.decodestring(fetched_entry["leaf_input"])
- assert_equal(leaf_input, merkle_tree_leaf, "entry", nodata=True, quiet=True)
- extra_data = base64.decodestring(fetched_entry["extra_data"])
- certchain = decode_certificate_chain(extra_data)
-
- submittedcertchain = chain[1:]
-
- for (submittedcert, fetchedcert, i) in zip(submittedcertchain,
- certchain, itertools.count(1)):
- assert_equal(fetchedcert, submittedcert, "cert %d in chain" % (i,), quiet=True)
-
- if len(certchain) == len(submittedcertchain) + 1:
- last_issuer = get_cert_info(submittedcertchain[-1])["issuer"]
- root_subject = get_cert_info(certchain[-1])["subject"]
- if last_issuer == root_subject:
- print_success("fetched chain has an appended root cert")
- else:
- print_error("fetched chain has an extra entry")
- elif len(certchain) == len(submittedcertchain):
- print_success("cert chains are the same length")
- else:
- print_error("cert chain length %d expected %d or %d",
- len(certchain),
- len(submittedcertchain),
- len(submittedcertchain))
-
-def merge():
- return subprocess.call(["../tools/merge.py", "--config", "../test/catlfish-test.cfg",
- "--localconfig", "../test/catlfish-test-local-merge.cfg"])
-
-mergeresult = merge()
-assert_equal(mergeresult, 0, "merge", quiet=True, fatal=True)
-
-for baseurl in baseurls:
- print_and_check_tree_size(0, baseurl)
-
-testgroup("cert1")
-
-result1 = do_add_chain(cc1, baseurls[0])
-
-mergeresult = merge()
-assert_equal(mergeresult, 0, "merge", quiet=True, fatal=True)
-
-size_sth = {}
-
-for baseurl in baseurls:
- print_and_check_tree_size(1, baseurl)
-size_sth[1] = base64.b64decode(get_sth(baseurls[0])["sha256_root_hash"])
-
-result2 = do_add_chain(cc1, baseurls[0])
-
-assert_equal(result2["timestamp"], result1["timestamp"], "timestamp")
-
-mergeresult = merge()
-assert_equal(mergeresult, 0, "merge", quiet=True, fatal=True)
-
-for baseurl in baseurls:
- print_and_check_tree_size(1, baseurl)
-size1_v2_sth = base64.b64decode(get_sth(baseurls[0])["sha256_root_hash"])
-
-assert_equal(size_sth[1], size1_v2_sth, "sth", nodata=True)
-
-# TODO: add invalid cert and check that it generates an error
-# and that treesize still is 1
-
-get_and_validate_proof(result1["timestamp"], cc1, 0, 0, baseurls[0])
-
-testgroup("cert2")
-
-result3 = do_add_chain(cc2, baseurls[0])
-
-mergeresult = merge()
-assert_equal(mergeresult, 0, "merge", quiet=True, fatal=True)
-
-for baseurl in baseurls:
- print_and_check_tree_size(2, baseurl)
-size_sth[2] = base64.b64decode(get_sth(baseurls[0])["sha256_root_hash"])
-
-get_and_validate_proof(result1["timestamp"], cc1, 0, 1, baseurls[0])
-get_and_validate_proof(result3["timestamp"], cc2, 1, 1, baseurls[0])
-
-testgroup("cert3")
-
-result4 = do_add_chain(cc3, baseurls[0])
-
-mergeresult = merge()
-assert_equal(mergeresult, 0, "merge", quiet=True, fatal=True)
-
-for baseurl in baseurls:
- print_and_check_tree_size(3, baseurl)
-size_sth[3] = base64.b64decode(get_sth(baseurls[0])["sha256_root_hash"])
-
-get_and_validate_proof(result1["timestamp"], cc1, 0, 2, baseurls[0])
-get_and_validate_proof(result3["timestamp"], cc2, 1, 2, baseurls[0])
-get_and_validate_proof(result4["timestamp"], cc3, 2, 1, baseurls[0])
-
-testgroup("cert4")
-
-result5 = do_add_chain(cc4, baseurls[0])
-
-mergeresult = merge()
-assert_equal(mergeresult, 0, "merge", quiet=True, fatal=True)
-
-for baseurl in baseurls:
- print_and_check_tree_size(4, baseurl)
-size_sth[4] = base64.b64decode(get_sth(baseurls[0])["sha256_root_hash"])
-
-get_and_validate_proof(result1["timestamp"], cc1, 0, 2, baseurls[0])
-get_and_validate_proof(result3["timestamp"], cc2, 1, 2, baseurls[0])
-get_and_validate_proof(result4["timestamp"], cc3, 2, 2, baseurls[0])
-get_and_validate_proof(result5["timestamp"], cc4, 3, 2, baseurls[0])
-
-testgroup("cert5")
-
-result6 = do_add_chain(cc5, baseurls[0])
-
-mergeresult = merge()
-assert_equal(mergeresult, 0, "merge", quiet=True, fatal=True)
-
-for baseurl in baseurls:
- print_and_check_tree_size(5, baseurl)
-size_sth[5] = base64.b64decode(get_sth(baseurls[0])["sha256_root_hash"])
-
-get_and_validate_proof(result1["timestamp"], cc1, 0, 3, baseurls[0])
-get_and_validate_proof(result3["timestamp"], cc2, 1, 3, baseurls[0])
-get_and_validate_proof(result4["timestamp"], cc3, 2, 3, baseurls[0])
-get_and_validate_proof(result5["timestamp"], cc4, 3, 3, baseurls[0])
-get_and_validate_proof(result6["timestamp"], cc5, 4, 1, baseurls[0])
-
-mergeresult = merge()
-assert_equal(mergeresult, 0, "merge", quiet=True, fatal=True)
-
-for first_size in range(1, 5):
- for second_size in range(first_size + 1, 6):
- get_and_validate_consistency_proof(size_sth[first_size], size_sth[second_size], first_size, second_size, baseurls[0])
-
-print "-------"
-if failures:
- print failures, "failed tests" if failures != 1 else "failed test"
- sys.exit(1)
-else:
- print "all tests succeeded"
diff --git a/tools/testcerts/cert1.txt b/tools/testcerts/cert1.txt
deleted file mode 100644
index 4871b22..0000000
--- a/tools/testcerts/cert1.txt
+++ /dev/null
@@ -1,86 +0,0 @@
-CONNECTED(00000003)
----
-Certificate chain
- 0 s:/C=SE/2.5.4.17=114 27/ST=Stockholms l\xC3\xA4n/L=Stockholm/2.5.4.9=Valhallav\xC3\xA4gen 79/O=Kungliga Tekniska H\xC3\xB6gskolan/OU=ITA/CN=ns-vip-01.sys.kth.se
- i:/C=NL/O=TERENA/CN=TERENA SSL CA
------BEGIN CERTIFICATE-----
-MIIFBTCCA+2gAwIBAgIRAN/MrgvfgxMmWUPdGv/VYEgwDQYJKoZIhvcNAQEFBQAw
-NjELMAkGA1UEBhMCTkwxDzANBgNVBAoTBlRFUkVOQTEWMBQGA1UEAxMNVEVSRU5B
-IFNTTCBDQTAeFw0xNDA3MDMwMDAwMDBaFw0xNzA3MDIyMzU5NTlaMIG8MQswCQYD
-VQQGEwJTRTEPMA0GA1UEERMGMTE0IDI3MRgwFgYDVQQIDA9TdG9ja2hvbG1zIGzD
-pG4xEjAQBgNVBAcTCVN0b2NraG9sbTEaMBgGA1UECQwRVmFsaGFsbGF2w6RnZW4g
-NzkxJTAjBgNVBAoMHEt1bmdsaWdhIFRla25pc2thIEjDtmdza29sYW4xDDAKBgNV
-BAsTA0lUQTEdMBsGA1UEAxMUbnMtdmlwLTAxLnN5cy5rdGguc2UwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmIUMi8T6Mf+ku/h7d0bYsi8/oKySKTpkS
-rzeAbuUNhmnT+VTMvb2w538KcPKnOhFGFRF3Lzfa1j70vKuLWbfLqQHOXa0Yq0zb
-mvVNFH9Uthtpmv7uj5o8uK7kTSNF2FzaWnm3gg6QckxYAAS1eG9wjRvfSSSwzbw0
-e/y3tvhN+vxerzZX8oiY4dFWmtmPRf9xE18LkQus41AJPLH+4SCXbpuJn4Vo3kTk
-rZp2MZo4bZ6PB/y257FowNOokkQG/Qg6wOX+9WW/zHCj8RqofaEhmpgtVyOklgJk
-DTLN8Z8869Zo+Nt2TeDyPWRr+IxFSVZCXAnEL0qCMYDrHAzZKJkDAgMBAAGjggGF
-MIIBgTAfBgNVHSMEGDAWgBQMvZNoDPPeq6NJays3V0fqkOO57TAdBgNVHQ4EFgQU
-3BVAdQu5ifzshxwoM7LxZfO3KnEwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQC
-MAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYL
-KwYBBAGyMQECAh0wCAYGZ4EMAQICMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly9j
-cmwudGNzLnRlcmVuYS5vcmcvVEVSRU5BU1NMQ0EuY3JsMG0GCCsGAQUFBwEBBGEw
-XzA1BggrBgEFBQcwAoYpaHR0cDovL2NydC50Y3MudGVyZW5hLm9yZy9URVJFTkFT
-U0xDQS5jcnQwJgYIKwYBBQUHMAGGGmh0dHA6Ly9vY3NwLnRjcy50ZXJlbmEub3Jn
-MDMGA1UdEQQsMCqCFG5zLXZpcC0wMS5zeXMua3RoLnNlggZrdGguc2WCCnd3dy5r
-dGguc2UwDQYJKoZIhvcNAQEFBQADggEBAK7O5ycJffAYElE0wXYDyRIakFWHbouO
-0l9D+npPMz8pKzIeLEZ46/sCK9E+Nd3AkCIpL0hZftlSKsDg3mppAgMhMLn2/Tux
-HelMlEqdwN7/7fiNPGzsBYu4fBqpGddbI69RWf/1JzR2Xeo76kQ6UCwg3EirYfw7
-zpeV81ct9fxYcFEyabiG18l7hmYEm/3SeKeRDcYWauk+hB/kg7lzCJ2qZFIk/sQM
-EEmI7JvoNuAfrWYwfr9hG39CawNQ0beGnlAAKxJeU2IC1Sbl9ccBu1JFRcsMRTr+
-Y8IfG+gNlh5a/vDJ98MnSJZp8QZo1TXDinEk+2tSHVR5iin1oOH1D60=
------END CERTIFICATE-----
- 1 s:/C=NL/O=TERENA/CN=TERENA SSL CA
- i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
------BEGIN CERTIFICATE-----
-MIIEmDCCA4CgAwIBAgIQS8gUAy8H+mqk8Nop32F5ujANBgkqhkiG9w0BAQUFADCB
-lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
-Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
-SGFyZHdhcmUwHhcNMDkwNTE4MDAwMDAwWhcNMjAwNTMwMTA0ODM4WjA2MQswCQYD
-VQQGEwJOTDEPMA0GA1UEChMGVEVSRU5BMRYwFAYDVQQDEw1URVJFTkEgU1NMIENB
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw+NIxC9cwcupmf0booNd
-ij2tOtDipEMfTQ7+NSUwpWkbxOjlwY9UfuFqoppcXN49/ALOlrhfj4NbzGBAkPjk
-tjolnF8UUeyx56+eUKExVccCvaxSin81joL6hK0V/qJ/gxA6VVOULAEWdJRUYyij
-8lspPZSIgCDiFFkhGbSkmOFg5vLrooCDQ+CtaPN5GYtoQ1E/iptBhQw1jF218bbl
-p8ODtWsjb9Sl61DllPFKX+4nSxQSFSRMDc9ijbcAIa06Mg9YC18em9HfnY6pGTVQ
-L0GprTvG4EWyUzl/Ib8iGodcNK5Sbwd9ogtOnyt5pn0T3fV/g3wvWl13eHiRoBS/
-fQIDAQABo4IBPjCCATowHwYDVR0jBBgwFoAUoXJfJhsomEOVXQc31YWWnUvSw0Uw
-HQYDVR0OBBYEFAy9k2gM896ro0lrKzdXR+qQ47ntMA4GA1UdDwEB/wQEAwIBBjAS
-BgNVHRMBAf8ECDAGAQH/AgEAMBgGA1UdIAQRMA8wDQYLKwYBBAGyMQECAh0wRAYD
-VR0fBD0wOzA5oDegNYYzaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VS
-Rmlyc3QtSGFyZHdhcmUuY3JsMHQGCCsGAQUFBwEBBGgwZjA9BggrBgEFBQcwAoYx
-aHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VUTkFkZFRydXN0U2VydmVyX0NBLmNy
-dDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG
-9w0BAQUFAAOCAQEATiPuSJz2hYtxxApuc5NywDqOgIrZs8qy1AGcKM/yXA4hRJML
-thoh45gBlA5nSYEevj0NTmDa76AxTpXv8916WoIgQ7ahY0OzUGlDYktWYrA0irkT
-Q1mT7BR5iPNIk+idyfqHcgxrVqDDFY1opYcfcS3mWm08aXFABFXcoEOUIEU4eNe9
-itg5xt8Jt1qaqQO4KBB4zb8BG1oRPjj02Bs0ec8z0gH9rJjNbUcRkEy7uVvYcOfV
-r7bMxIbmdcCeKbYrDyqlaQIN4+mitF3A884saoU4dmHGSYKrUbOCprlBmCiY+2v+
-ihb/MX5UR6g83EMmqZsFt57ANEORMNQywxFa4Q==
------END CERTIFICATE-----
----
-Server certificate
-subject=/C=SE/2.5.4.17=114 27/ST=Stockholms l\xC3\xA4n/L=Stockholm/2.5.4.9=Valhallav\xC3\xA4gen 79/O=Kungliga Tekniska H\xC3\xB6gskolan/OU=ITA/CN=ns-vip-01.sys.kth.se
-issuer=/C=NL/O=TERENA/CN=TERENA SSL CA
----
-No client certificate CA names sent
----
-SSL handshake has read 2608 bytes and written 452 bytes
----
-New, TLSv1/SSLv3, Cipher is RC4-MD5
-Server public key is 2048 bit
-SSL-Session:
- Protocol : TLSv1
- Cipher : RC4-MD5
- Session-ID: 1CB6F52D821C229181597FA36C61A4DAB2AB0330A5157E1C8094AA73D475C123
- Session-ID-ctx:
- Master-Key: E01E6B7F470205A7BAE7CCB5290A57E59DE52D822E5AFC5BFFC1DD28C5CA9D4D55CD2308CCB7E302641BF5B352E6AB11
- Key-Arg : None
- Krb5 Principal: None
- Start Time: 1406768584
- Timeout : 300 (sec)
- Verify return code: 20 (unable to get local issuer certificate)
----
diff --git a/tools/testcerts/cert2.txt b/tools/testcerts/cert2.txt
deleted file mode 100644
index 011caf5..0000000
--- a/tools/testcerts/cert2.txt
+++ /dev/null
@@ -1,138 +0,0 @@
-CONNECTED(00000003)
----
-Certificate chain
- 0 s:/C=SE/O=Kungliga Tekniska H\xC3\xB6gskolan/OU=ITA/CN=www.lan.kth.se
- i:/C=NL/O=TERENA/CN=TERENA SSL CA
------BEGIN CERTIFICATE-----
-MIIEfzCCA2egAwIBAgIRALtnWx1jbyJqNiquRFaHsxwwDQYJKoZIhvcNAQEFBQAw
-NjELMAkGA1UEBhMCTkwxDzANBgNVBAoTBlRFUkVOQTEWMBQGA1UEAxMNVEVSRU5B
-IFNTTCBDQTAeFw0xMzAxMTYwMDAwMDBaFw0xNjAxMTYyMzU5NTlaMFsxCzAJBgNV
-BAYTAlNFMSUwIwYDVQQKDBxLdW5nbGlnYSBUZWtuaXNrYSBIw7Znc2tvbGFuMQww
-CgYDVQQLEwNJVEExFzAVBgNVBAMTDnd3dy5sYW4ua3RoLnNlMIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2fC9NwlmMN9ja8S9sMRdPXTY9XMutGDbVStq
-VQbflK1A4Ap3ODAEIsTFz1xn5OvrxSPFyphbDwNDlfvnB9lWQQvG6EZ003zExbiY
-g2WrUk74IsGEgvjw3u+1DIRJCO/mKXlg1a/8wkzINXvnra+yTMDO8VLmiLmUrvn+
-yYi8gr7ekUgFr+3rm9J25tfHyan9p15RMcI//WQTfjq3X/EnyImOiZpMyh0OjSif
-LnwHrE0M3grivYP6PZN3mJjKJNFGL9zh5S/Wt4Q65t9wXhO5oAkDA9XS6bk1yOv2
-V81qRANaBdP/ieHghko2UV/mGeHeJhHYB02XFg5mpxxIndBcxwIDAQABo4IBYTCC
-AV0wHwYDVR0jBBgwFoAUDL2TaAzz3qujSWsrN1dH6pDjue0wHQYDVR0OBBYEFDAA
-juxftrwLBCSto5PE6PBYMX1RMA4GA1UdDwEB/wQEAwIFoDAMBgNVHRMBAf8EAjAA
-MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAYBgNVHSAEETAPMA0GCysG
-AQQBsjEBAgIdMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly9jcmwudGNzLnRlcmVu
-YS5vcmcvVEVSRU5BU1NMQ0EuY3JsMG0GCCsGAQUFBwEBBGEwXzA1BggrBgEFBQcw
-AoYpaHR0cDovL2NydC50Y3MudGVyZW5hLm9yZy9URVJFTkFTU0xDQS5jcnQwJgYI
-KwYBBQUHMAGGGmh0dHA6Ly9vY3NwLnRjcy50ZXJlbmEub3JnMBkGA1UdEQQSMBCC
-Dnd3dy5sYW4ua3RoLnNlMA0GCSqGSIb3DQEBBQUAA4IBAQCrfiHdIwVEVO1HwZXb
-Hi5KsOFDcHS+MH5tvo2Cj6uXzDOMFWSoLm31MR4TK55Hzz7oMkpO+rxchqpvoUtl
-m2ma9phntzvCppeOcob2dZt6lyqzg4uIxlgV6ucULQ27KlwGZPAp46ZdK1M3qVMR
-gQ2kOXc0wMAKFXu4qvrj2JsWFnZKn233Cg2iS6ixDjqZvSxzC23buhN48dzCdYI/
-mWaisULtkd95O+WhtQPp5tP5QqGmwGoM6+Q1StOo4068CG1TRDoQWnjVHHt5yU2O
-gG3YSEwpMe/FJS4UcojdAkWewbv4ArP72/LEBkqubicFib6ALkQ7WfuUf8XN4Ky3
-vVwW
------END CERTIFICATE-----
- 1 s:/C=NL/O=TERENA/CN=TERENA SSL CA
- i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
------BEGIN CERTIFICATE-----
-MIIEmDCCA4CgAwIBAgIQS8gUAy8H+mqk8Nop32F5ujANBgkqhkiG9w0BAQUFADCB
-lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
-Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
-SGFyZHdhcmUwHhcNMDkwNTE4MDAwMDAwWhcNMjAwNTMwMTA0ODM4WjA2MQswCQYD
-VQQGEwJOTDEPMA0GA1UEChMGVEVSRU5BMRYwFAYDVQQDEw1URVJFTkEgU1NMIENB
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw+NIxC9cwcupmf0booNd
-ij2tOtDipEMfTQ7+NSUwpWkbxOjlwY9UfuFqoppcXN49/ALOlrhfj4NbzGBAkPjk
-tjolnF8UUeyx56+eUKExVccCvaxSin81joL6hK0V/qJ/gxA6VVOULAEWdJRUYyij
-8lspPZSIgCDiFFkhGbSkmOFg5vLrooCDQ+CtaPN5GYtoQ1E/iptBhQw1jF218bbl
-p8ODtWsjb9Sl61DllPFKX+4nSxQSFSRMDc9ijbcAIa06Mg9YC18em9HfnY6pGTVQ
-L0GprTvG4EWyUzl/Ib8iGodcNK5Sbwd9ogtOnyt5pn0T3fV/g3wvWl13eHiRoBS/
-fQIDAQABo4IBPjCCATowHwYDVR0jBBgwFoAUoXJfJhsomEOVXQc31YWWnUvSw0Uw
-HQYDVR0OBBYEFAy9k2gM896ro0lrKzdXR+qQ47ntMA4GA1UdDwEB/wQEAwIBBjAS
-BgNVHRMBAf8ECDAGAQH/AgEAMBgGA1UdIAQRMA8wDQYLKwYBBAGyMQECAh0wRAYD
-VR0fBD0wOzA5oDegNYYzaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VS
-Rmlyc3QtSGFyZHdhcmUuY3JsMHQGCCsGAQUFBwEBBGgwZjA9BggrBgEFBQcwAoYx
-aHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VUTkFkZFRydXN0U2VydmVyX0NBLmNy
-dDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG
-9w0BAQUFAAOCAQEATiPuSJz2hYtxxApuc5NywDqOgIrZs8qy1AGcKM/yXA4hRJML
-thoh45gBlA5nSYEevj0NTmDa76AxTpXv8916WoIgQ7ahY0OzUGlDYktWYrA0irkT
-Q1mT7BR5iPNIk+idyfqHcgxrVqDDFY1opYcfcS3mWm08aXFABFXcoEOUIEU4eNe9
-itg5xt8Jt1qaqQO4KBB4zb8BG1oRPjj02Bs0ec8z0gH9rJjNbUcRkEy7uVvYcOfV
-r7bMxIbmdcCeKbYrDyqlaQIN4+mitF3A884saoU4dmHGSYKrUbOCprlBmCiY+2v+
-ihb/MX5UR6g83EMmqZsFt57ANEORMNQywxFa4Q==
------END CERTIFICATE-----
- 2 s:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
- i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
------BEGIN CERTIFICATE-----
-MIIEPDCCAySgAwIBAgIQSEus8arH1xND0aJ0NUmXJTANBgkqhkiG9w0BAQUFADBv
-MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
-ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
-eHRlcm5hbCBDQSBSb290MB4XDTA1MDYwNzA4MDkxMFoXDTIwMDUzMDEwNDgzOFow
-gZcxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtl
-IENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMY
-aHR0cDovL3d3dy51c2VydHJ1c3QuY29tMR8wHQYDVQQDExZVVE4tVVNFUkZpcnN0
-LUhhcmR3YXJlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsffDOD+0
-qH/POYJRZ9Btn9L/WPPnnyvsDYlUmbk4mRb34CF5SMK7YXQSlh08anLVPBBnOjnt
-KxPNZuuVCTOkbJex6MbswXV5nEZejavQav25KlUXEFSzGfCa9vGxXbanbfvgcRdr
-ooj7AN/+GjF3DJoBerEy4ysBBzhuw6VeI7xFm3tQwckwj9vlK3rTW/szQB6g1ZgX
-vIuHw4nTXaCOsqqq9o5piAbF+okh8widaS4JM5spDUYPjMxJNLBpUb35Bs1orWZM
-vD6sYb0KiA7I3z3ufARMnQpea5HW7sftKI2rTYeJc9BupNAeFosU4XZEA39jrOTN
-SZzFkvSrMqFIWwIDAQABo4GqMIGnMB8GA1UdIwQYMBaAFK29mHo0tCb3+sQmVO8D
-veAky1QaMB0GA1UdDgQWBBShcl8mGyiYQ5VdBzfVhZadS9LDRTAOBgNVHQ8BAf8E
-BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8v
-Y3JsLnVzZXJ0cnVzdC5jb20vQWRkVHJ1c3RFeHRlcm5hbENBUm9vdC5jcmwwDQYJ
-KoZIhvcNAQEFBQADggEBADzse+Cuow6WbTDXhcbSaFtFWoKmNA+wyZIjXhFtCBGy
-dAkjOjUlc1heyrl8KPpH7PmgA1hQtlPvjNs55Gfp2MooRtSn4PU4dfjny1y/HRE8
-akCbLURW0/f/BSgyDBXIZEWT6CEkjy3aeoR7T8/NsiV8dxDTlNEEkaglHAkiD31E
-NREU768A/l7qX46w2ZJZuvwTlqAYAVbO2vYoC7Gv3VxPXLLzj1pxz+0YrWOIHY6V
-9+qV5x+tkLiECEeFfyIvGh1IMNZMCNg3GWcyK+tc0LL8blefBDVekAB+EcfeEyrN
-pG1FJseIVqDwavfY5/wnfmcI0L36tsNhAgFlubgvz1o=
------END CERTIFICATE-----
- 3 s:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
- i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
------BEGIN CERTIFICATE-----
-MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
-MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
-IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
-MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
-FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
-bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
-H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
-uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
-mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
-a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
-E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
-WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
-VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
-Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
-cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
-IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
-AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
-YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
-6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
-Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
-c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
-mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
------END CERTIFICATE-----
----
-Server certificate
-subject=/C=SE/O=Kungliga Tekniska H\xC3\xB6gskolan/OU=ITA/CN=www.lan.kth.se
-issuer=/C=NL/O=TERENA/CN=TERENA SSL CA
----
-No client certificate CA names sent
----
-SSL handshake has read 5205 bytes and written 340 bytes
----
-New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
-Server public key is 2048 bit
-SSL-Session:
- Protocol : TLSv1
- Cipher : DHE-RSA-AES256-SHA
- Session-ID: 6389C01938F30B55DE1970773DAF16F5F0577712DCC25140FC5B09E60712DF4C
- Session-ID-ctx:
- Master-Key: 0ABCD607E10E921BDF9D0D5439972F8789517C18318AF2FA5CEFF7F45A74F246C27D25ED9E6CE97500156803DA037BDA
- Key-Arg : None
- Krb5 Principal: None
- Start Time: 1411388821
- Timeout : 300 (sec)
- Verify return code: 19 (self signed certificate in certificate chain)
----
diff --git a/tools/testcerts/cert3.txt b/tools/testcerts/cert3.txt
deleted file mode 100644
index a776b58..0000000
--- a/tools/testcerts/cert3.txt
+++ /dev/null
@@ -1,108 +0,0 @@
-CONNECTED(00000003)
----
-Certificate chain
- 0 s:/OU=Domain Control Validated/CN=*.nordu.net
- i:/C=NL/O=TERENA/CN=TERENA SSL CA
- 1 s:/C=NL/O=TERENA/CN=TERENA SSL CA
- i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
- 2 s:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
- i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
----
-Server certificate
------BEGIN CERTIFICATE-----
-MIIEZDCCA0ygAwIBAgIRALmfsKN7LvrBTlo9bsrluT0wDQYJKoZIhvcNAQEFBQAw
-NjELMAkGA1UEBhMCTkwxDzANBgNVBAoTBlRFUkVOQTEWMBQGA1UEAxMNVEVSRU5B
-IFNTTCBDQTAeFw0xMzAzMjEwMDAwMDBaFw0xNjA0MDIyMzU5NTlaMDkxITAfBgNV
-BAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDEUMBIGA1UEAxQLKi5ub3JkdS5u
-ZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQClir/sHXJpaMQ8SpK1
-giyizJhK9GSuZkoTaIKiK2hXkHUbxJ09w6pspWXPbUwLK8ZFn32vHMabshKxe4fL
-d0kR/AEr9okwfnABK7+u4CBEs10D2oVrRFS2GFAUtri8v+5+n/mWDoqGc2XybQNs
-CoYyVdSYs6YO/+b8dEGfOrRD2XFoTtP32T35YIlejwpg72f9lUnvOi6Jh+s6jV8P
-hIJV6w3exVQojDiEPSQ3fV/KF6FAaQK4XyEspHL4TH0mtaJhEjnAvHDmN1Bw4WhV
-0Bm86alryZxYNTmpPXDD5AFNBIuL+5FfQgZm+s7QzZriguRGDv8L+YKePFvhiaPV
-AagTAgMBAAGjggFoMIIBZDAfBgNVHSMEGDAWgBQMvZNoDPPeq6NJays3V0fqkOO5
-7TAdBgNVHQ4EFgQU6YkL0qj0tSK5bsZfjDUNLwXUlFgwDgYDVR0PAQH/BAQDAgWg
-MAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIG
-A1UdIAQbMBkwDQYLKwYBBAGyMQECAh0wCAYGZ4EMAQIBMDoGA1UdHwQzMDEwL6At
-oCuGKWh0dHA6Ly9jcmwudGNzLnRlcmVuYS5vcmcvVEVSRU5BU1NMQ0EuY3JsMG0G
-CCsGAQUFBwEBBGEwXzA1BggrBgEFBQcwAoYpaHR0cDovL2NydC50Y3MudGVyZW5h
-Lm9yZy9URVJFTkFTU0xDQS5jcnQwJgYIKwYBBQUHMAGGGmh0dHA6Ly9vY3NwLnRj
-cy50ZXJlbmEub3JnMBYGA1UdEQQPMA2CCyoubm9yZHUubmV0MA0GCSqGSIb3DQEB
-BQUAA4IBAQAdj2R0qT47oLIMnYw69qU58VZB/rnejwhNVdzLtLZ+vQ1YwcXoabOi
-9LmSOZ019ESWxZ415/FjvoLXYKpkq8w96bDw/jqPhUWwK2U6EpD/MlYUKWyAH9XP
-ZLBaYewZEBjkwxYIlroUboPWXUYJIDwotvNgSE9N8Xy1XZ4oi0UVfxxyo3XRpS49
-Ch1az16jKS5rF5R1Q/t6UxYrnfx4XMZHFx56ks6kpucxch37JJ/2i1O84/T9lX17
-7qwk+SO93EmtgxE40wtvL1i2cTZaNHcybyClV6N3Bm8Hu2L4e35SF761CMc4rzlu
-SbDmRK4Rxa5UmgfZnezD0snHVUCrzKzP
------END CERTIFICATE-----
-subject=/OU=Domain Control Validated/CN=*.nordu.net
-issuer=/C=NL/O=TERENA/CN=TERENA SSL CA
----
-
-Manually added intermediate certificate:
------BEGIN CERTIFICATE-----
-MIIEmDCCA4CgAwIBAgIQS8gUAy8H+mqk8Nop32F5ujANBgkqhkiG9w0BAQUFADCB
-lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
-Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
-SGFyZHdhcmUwHhcNMDkwNTE4MDAwMDAwWhcNMjAwNTMwMTA0ODM4WjA2MQswCQYD
-VQQGEwJOTDEPMA0GA1UEChMGVEVSRU5BMRYwFAYDVQQDEw1URVJFTkEgU1NMIENB
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw+NIxC9cwcupmf0booNd
-ij2tOtDipEMfTQ7+NSUwpWkbxOjlwY9UfuFqoppcXN49/ALOlrhfj4NbzGBAkPjk
-tjolnF8UUeyx56+eUKExVccCvaxSin81joL6hK0V/qJ/gxA6VVOULAEWdJRUYyij
-8lspPZSIgCDiFFkhGbSkmOFg5vLrooCDQ+CtaPN5GYtoQ1E/iptBhQw1jF218bbl
-p8ODtWsjb9Sl61DllPFKX+4nSxQSFSRMDc9ijbcAIa06Mg9YC18em9HfnY6pGTVQ
-L0GprTvG4EWyUzl/Ib8iGodcNK5Sbwd9ogtOnyt5pn0T3fV/g3wvWl13eHiRoBS/
-fQIDAQABo4IBPjCCATowHwYDVR0jBBgwFoAUoXJfJhsomEOVXQc31YWWnUvSw0Uw
-HQYDVR0OBBYEFAy9k2gM896ro0lrKzdXR+qQ47ntMA4GA1UdDwEB/wQEAwIBBjAS
-BgNVHRMBAf8ECDAGAQH/AgEAMBgGA1UdIAQRMA8wDQYLKwYBBAGyMQECAh0wRAYD
-VR0fBD0wOzA5oDegNYYzaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VS
-Rmlyc3QtSGFyZHdhcmUuY3JsMHQGCCsGAQUFBwEBBGgwZjA9BggrBgEFBQcwAoYx
-aHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VUTkFkZFRydXN0U2VydmVyX0NBLmNy
-dDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG
-9w0BAQUFAAOCAQEATiPuSJz2hYtxxApuc5NywDqOgIrZs8qy1AGcKM/yXA4hRJML
-thoh45gBlA5nSYEevj0NTmDa76AxTpXv8916WoIgQ7ahY0OzUGlDYktWYrA0irkT
-Q1mT7BR5iPNIk+idyfqHcgxrVqDDFY1opYcfcS3mWm08aXFABFXcoEOUIEU4eNe9
-itg5xt8Jt1qaqQO4KBB4zb8BG1oRPjj02Bs0ec8z0gH9rJjNbUcRkEy7uVvYcOfV
-r7bMxIbmdcCeKbYrDyqlaQIN4+mitF3A884saoU4dmHGSYKrUbOCprlBmCiY+2v+
-ihb/MX5UR6g83EMmqZsFt57ANEORMNQywxFa4Q==
------END CERTIFICATE-----
-
-No client certificate CA names sent
----
-SSL handshake has read 4093 bytes and written 434 bytes
----
-New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
-Server public key is 2048 bit
-Secure Renegotiation IS supported
-Compression: NONE
-Expansion: NONE
-SSL-Session:
- Protocol : TLSv1.2
- Cipher : ECDHE-RSA-AES256-GCM-SHA384
- Session-ID: 1A247C94557A7847AA13E2EFD64ECE3C2DD142B15ABB7BF78BFE43F28BB2C144
- Session-ID-ctx:
- Master-Key: D714373C285767FD040C497DFA59C81AA43BCF62AB9199F5FAB2C34211F7FB767922047DD758441C5493B238E716B477
- Key-Arg : None
- PSK identity: None
- PSK identity hint: None
- SRP username: None
- TLS session ticket lifetime hint: 300 (seconds)
- TLS session ticket:
- 0000 - 7d 26 51 e1 11 16 18 15-b2 1c 21 51 10 10 f0 0d }&Q.......!Q....
- 0010 - 29 f5 24 13 c8 a5 dd 34-87 c1 36 6a 97 12 cc f3 ).$....4..6j....
- 0020 - e4 bb 50 db 39 94 3b b3-8e 52 df 73 89 a2 30 91 ..P.9.;..R.s..0.
- 0030 - 4e a5 8c 80 97 49 79 0f-ce a9 1a eb a8 a0 2d fa N....Iy.......-.
- 0040 - 53 90 fe f1 29 1b 43 5d-09 cc 6c 81 de f8 41 e7 S...).C]..l...A.
- 0050 - dc c3 57 b5 66 e0 03 2b-fd e7 82 5b b6 c4 6a fe ..W.f..+...[..j.
- 0060 - 15 55 55 cd ea af a6 b8-c5 80 2f c8 2d dd bf a0 .UU......./.-...
- 0070 - 1b 23 4c 60 67 70 1c 39-2c 9a 39 1d e0 a4 f7 c0 .#L`gp.9,.9.....
- 0080 - 6e c9 8b 59 c2 cc 2b 12-ee 5d 8f 8c 4a 8e ab 07 n..Y..+..]..J...
- 0090 - 9e be d3 89 9d c1 1e 17-a5 65 19 41 14 63 32 62 .........e.A.c2b
- 00a0 - ce 51 ce ee c0 0c 01 49-b0 0b da 41 29 67 21 e0 .Q.....I...A)g!.
- 00b0 - 2f 77 e2 35 44 35 ba 78-47 fc 3c 11 24 57 8d e3 /w.5D5.xG.<.$W..
-
- Start Time: 1411743389
- Timeout : 300 (sec)
- Verify return code: 20 (unable to get local issuer certificate)
----
diff --git a/tools/testcerts/cert4.txt b/tools/testcerts/cert4.txt
deleted file mode 100644
index 57559e9..0000000
--- a/tools/testcerts/cert4.txt
+++ /dev/null
@@ -1,120 +0,0 @@
-CONNECTED(00000003)
----
-Certificate chain
- 0 s:/businessCategory=Private Organization/1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=Delaware/serialNumber=3359300/street=16 Allen Rd/postalCode=03894-4801/C=US/ST=NH/L=Wolfeboro,/O=Python Software Foundation/CN=www.python.org
- i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert SHA2 Extended Validation Server CA
- 1 s:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert SHA2 Extended Validation Server CA
- i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA
----
-Server certificate
------BEGIN CERTIFICATE-----
-MIIG2jCCBcKgAwIBAgIQAbtvABIrF382yrSc6otrJjANBgkqhkiG9w0BAQsFADB1
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVk
-IFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE0MDkwNTAwMDAwMFoXDTE2MDkwOTEy
-MDAwMFowgfkxHTAbBgNVBA8TFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYB
-BAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMRAwDgYDVQQF
-EwczMzU5MzAwMRQwEgYDVQQJEwsxNiBBbGxlbiBSZDETMBEGA1UEERMKMDM4OTQt
-NDgwMTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk5IMRMwEQYDVQQHEwpXb2xmZWJv
-cm8sMSMwIQYDVQQKExpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEXMBUGA1UE
-AxMOd3d3LnB5dGhvbi5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
-AQCtUnfHpOteoIqZxGsaR/2tIenj0+pBtNBiWT6PlYLLXC6MNRjFwtnhRzEVanAm
-GEEOEQwUokYZHw8kCL2SIZ1DFI5IIFyhTFql1dqiKtoQse0LAZlUHscVxn9OZyWM
-DA4JZ6A4c3/j5SA9hGO3+KyTc95GfiEXqkSkmjH3aBtY2flr+H1fvatQA8AIAD5k
-weQLFbbqi33Uvf4sJ3OhY63Kf1ZWteXSeCT+FRMlFTaYbauo86AmU9X2/b85wold
-naUO3VjcGjTSoSuaxtWuHFRxpOTBG7bqPbtWk+X5l+rjsIoGJ6ZrRFbAtHqG+S3v
-luEG9FtgGAo+3hKm99U8UKKVAgMBAAGjggLfMIIC2zAfBgNVHSMEGDAWgBQ901Cl
-1qCt7vNKYApl0yHU+PjWDzAdBgNVHQ4EFgQUTWfmKThuIBhkZX4B3yNf+DpBqokw
-ggEUBgNVHREEggELMIIBB4IOd3d3LnB5dGhvbi5vcmeCCnB5dGhvbi5vcmeCD3B5
-cGkucHl0aG9uLm9yZ4IPZG9jcy5weXRob24ub3JnghN0ZXN0cHlwaS5weXRob24u
-b3Jngg9idWdzLnB5dGhvbi5vcmeCD3dpa2kucHl0aG9uLm9yZ4INaGcucHl0aG9u
-Lm9yZ4IPbWFpbC5weXRob24ub3JnghRwYWNrYWdpbmcucHl0aG9uLm9yZ4IQcHl0
-aG9uaG9zdGVkLm9yZ4IUd3d3LnB5dGhvbmhvc3RlZC5vcmeCFXRlc3QucHl0aG9u
-aG9zdGVkLm9yZ4IMdXMucHljb24ub3Jngg1pZC5weXRob24ub3JnMA4GA1UdDwEB
-/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0fBG4w
-bDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItZXYtc2VydmVy
-LWcxLmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItZXYt
-c2VydmVyLWcxLmNybDBCBgNVHSAEOzA5MDcGCWCGSAGG/WwCATAqMCgGCCsGAQUF
-BwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGIBggrBgEFBQcBAQR8
-MHowJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBSBggrBgEF
-BQcwAoZGaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkV4
-dGVuZGVkVmFsaWRhdGlvblNlcnZlckNBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqG
-SIb3DQEBCwUAA4IBAQBsTgMOFUP8wHVpgCzm/fQTrKp4nxcb9m9gkTW1aRKuhlAY
-g/CUQ8DC0Ii1XqOolTmGi6NIyX2Xf+RWqh7UzK+Q30Y2RGGb/47uZaif9WaIlKGn
-40D1mzzyGjrfTMSSFlrtwyg/3yM8KN800Cz5HgXnHD2qIuYcYqXRRS6E7PEHB1Dm
-h72iCAHYwUTgfcfqUWVEZ26EQhP4Lk4+hs2UJsAUnMWj7/bnk8LR/KZumLuuv3RK
-lmR1Qg+9AChafiCCFra1UxfgznvF5ocJzr6nNmYc6k1ImaipRq7c/OuwUTTqNqR2
-FceHmpqlkA2AvjdvSvwnODux3QPbMucIaJXrUUwf
------END CERTIFICATE-----
-subject=/businessCategory=Private Organization/1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=Delaware/serialNumber=3359300/street=16 Allen Rd/postalCode=03894-4801/C=US/ST=NH/L=Wolfeboro,/O=Python Software Foundation/CN=www.python.org
-issuer=/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert SHA2 Extended Validation Server CA
----
-
-Manually added intermediate certificate:
------BEGIN CERTIFICATE-----
-MIIEtjCCA56gAwIBAgIQDHmpRLCMEZUgkmFf4msdgzANBgkqhkiG9w0BAQsFADBs
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
-ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowdTEL
-MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
-LmRpZ2ljZXJ0LmNvbTE0MDIGA1UEAxMrRGlnaUNlcnQgU0hBMiBFeHRlbmRlZCBW
-YWxpZGF0aW9uIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBANdTpARR+JmmFkhLZyeqk0nQOe0MsLAAh/FnKIaFjI5j2ryxQDji0/XspQUY
-uD0+xZkXMuwYjPrxDKZkIYXLBxA0sFKIKx9om9KxjxKws9LniB8f7zh3VFNfgHk/
-LhqqqB5LKw2rt2O5Nbd9FLxZS99RStKh4gzikIKHaq7q12TWmFXo/a8aUGxUvBHy
-/Urynbt/DvTVvo4WiRJV2MBxNO723C3sxIclho3YIeSwTQyJ3DkmF93215SF2AQh
-cJ1vb/9cuhnhRctWVyh+HA1BV6q3uCe7seT6Ku8hI3UarS2bhjWMnHe1c63YlC3k
-8wyd7sFOYn4XwHGeLN7x+RAoGTMCAwEAAaOCAUkwggFFMBIGA1UdEwEB/wQIMAYB
-Af8CAQAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF
-BQcDAjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp
-Z2ljZXJ0LmNvbTBLBgNVHR8ERDBCMECgPqA8hjpodHRwOi8vY3JsNC5kaWdpY2Vy
-dC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMD0GA1UdIAQ2
-MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j
-b20vQ1BTMB0GA1UdDgQWBBQ901Cl1qCt7vNKYApl0yHU+PjWDzAfBgNVHSMEGDAW
-gBSxPsNpA/i/RwHUmCYaCALvY2QrwzANBgkqhkiG9w0BAQsFAAOCAQEAnbbQkIbh
-hgLtxaDwNBx0wY12zIYKqPBKikLWP8ipTa18CK3mtlC4ohpNiAexKSHc59rGPCHg
-4xFJcKx6HQGkyhE6V6t9VypAdP3THYUYUN9XR3WhfVUgLkc3UHKMf4Ib0mKPLQNa
-2sPIoc4sUqIAY+tzunHISScjl2SFnjgOrWNoPLpSgVh5oywM395t6zHyuqB8bPEs
-1OG9d4Q3A84ytciagRpKkk47RpqF/oOi+Z6Mo8wNXrM9zwR4jxQUezKcxwCmXMS1
-oVWNWlZopCJwqjyBcdmdqEU79OX2olHdx3ti6G8MdOu42vi/hw15UJGQmxg7kVkn
-8TUoE6smftX3eg==
------END CERTIFICATE-----
-
-No client certificate CA names sent
----
-SSL handshake has read 3662 bytes and written 434 bytes
----
-New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
-Server public key is 2048 bit
-Secure Renegotiation IS supported
-Compression: NONE
-Expansion: NONE
-SSL-Session:
- Protocol : TLSv1.2
- Cipher : ECDHE-RSA-AES128-GCM-SHA256
- Session-ID: 1DE0E69544F8883ADCF023857A02135C5332AB1D514A30DAB522FCF6F23E1DB6
- Session-ID-ctx:
- Master-Key: 5959095AB05ED21709F503091DFCEAFDBD8C3ED809DA5BC8886A6E25A7D66D78F8528A20C900F288E77852C311E881EF
- Key-Arg : None
- PSK identity: None
- PSK identity hint: None
- SRP username: None
- TLS session ticket lifetime hint: 14400 (seconds)
- TLS session ticket:
- 0000 - 63 cc 77 4a 00 db 2c 42-2e 8f 76 23 dd a9 ae 53 c.wJ..,B..v#...S
- 0010 - f0 ac 9f 96 82 bb 06 da-a2 8b 3a 44 cb 66 77 d2 ..........:D.fw.
- 0020 - 01 7d 5a b4 0e bd 63 d0-38 f4 86 b4 05 76 68 9f .}Z...c.8....vh.
- 0030 - 6f 76 1a 2e 06 93 3d d2-05 7e 0e 57 1a 0d a0 22 ov....=..~.W..."
- 0040 - f5 17 e5 1b a7 9d b9 02-95 d8 08 cb 10 31 fb e9 .............1..
- 0050 - 63 26 8c 6e 52 76 cb 7f-64 cc bc c6 43 52 cf 0f c&.nRv..d...CR..
- 0060 - 8e ba 6a 6d b2 30 43 c5-0c 6b 5c 7d 86 90 ad 02 ..jm.0C..k\}....
- 0070 - 8a 71 3b 17 22 ae 4f a6-0e 1b d8 5a fa 86 f1 3c .q;.".O....Z...<
- 0080 - c4 bd 56 7d 6d 40 ed 06-f5 12 56 ff 15 ab 39 69 ..V}m@....V...9i
- 0090 - 20 21 84 e5 15 ac 52 58-8b 13 d0 f3 db 89 a7 c6 !....RX........
- 00a0 - fd 35 6b ec 94 19 99 e1-cb 28 89 3d aa bb ba 52 .5k......(.=...R
- 00b0 - 13 1a 7b c8 39 04 7d cc-49 34 99 52 88 ce ac 8d ..{.9.}.I4.R....
-
- Start Time: 1411736151
- Timeout : 300 (sec)
- Verify return code: 20 (unable to get local issuer certificate)
----
diff --git a/tools/testcerts/cert5.txt b/tools/testcerts/cert5.txt
deleted file mode 100644
index 14af5fd..0000000
--- a/tools/testcerts/cert5.txt
+++ /dev/null
@@ -1,145 +0,0 @@
-CONNECTED(00000003)
----
-Certificate chain
- 0 s:/C=US/ST=California/L=San Francisco/O=Wikimedia Foundation, Inc./CN=*.wikipedia.org
- i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance CA-3
- 1 s:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance CA-3
- i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA
----
-Server certificate
------BEGIN CERTIFICATE-----
-MIIKMzCCCRugAwIBAgIQDfxZHyWomiN2WUOBQIituTANBgkqhkiG9w0BAQUFADBm
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSUwIwYDVQQDExxEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
-ZSBDQS0zMB4XDTEyMTAyMjAwMDAwMFoXDTE2MDEyMDEyMDAwMFoweTELMAkGA1UE
-BhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lz
-Y28xIzAhBgNVBAoTGldpa2ltZWRpYSBGb3VuZGF0aW9uLCBJbmMuMRgwFgYDVQQD
-DA8qLndpa2lwZWRpYS5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
-AQDCuToIC6iqulFKeu4DD5l336SonDpCEiVPqSyopch4fm+Zz2Da0KsCROq1AX5K
-9kb7WXbSSpnVbXaaDDF/dxD65kD+keNJONqEAVdylW/G16Sa89agTVdgLTjZK2dI
-99Q7ws9ijH2psHOUHRJLaJdySLO97OkGwcttd8UGDlCS98A7mN9icvpF4XMl6Oqw
-q1/mj624a1BmAzhQaBLPNKsZcJmadACRL7LJ6sNr/SZV1SENlRLHnkmW/c4T2lSp
-ikvIyJaOFLlt9J0aqCB+Tb0LwO4gNtrMaJ+fjBBJrMVRtLojrukc/yOdGBlTCx7x
-JK5ER9VTf/sb1RViqSKMtSojAgMBAAGjggbIMIIGxDAfBgNVHSMEGDAWgBRQ6nOJ
-2yn7EI+e5QEg1N55mUiD9zAdBgNVHQ4EFgQUAouBfESp0dUaQhWaXSogknV7Q3cw
-ggObBgNVHREEggOSMIIDjoIPKi53aWtpcGVkaWEub3Jngg13aWtpcGVkaWEub3Jn
-gg9tLndpa2lwZWRpYS5vcmeCEnplcm8ud2lraXBlZGlhLm9yZ4IRKi5tLndpa2lw
-ZWRpYS5vcmeCDXdpa2lib29rcy5vcmeCD20ud2lraWJvb2tzLm9yZ4IPKi53aWtp
-Ym9va3Mub3JnghEqLm0ud2lraWJvb2tzLm9yZ4IMd2lraWRhdGEub3Jngg5tLndp
-a2lkYXRhLm9yZ4IOKi53aWtpZGF0YS5vcmeCECoubS53aWtpZGF0YS5vcmeCDXdp
-a2ltZWRpYS5vcmeCD20ud2lraW1lZGlhLm9yZ4IPKi53aWtpbWVkaWEub3JnghEq
-Lm0ud2lraW1lZGlhLm9yZ4IXd2lraW1lZGlhZm91bmRhdGlvbi5vcmeCGW0ud2lr
-aW1lZGlhZm91bmRhdGlvbi5vcmeCGSoud2lraW1lZGlhZm91bmRhdGlvbi5vcmeC
-GyoubS53aWtpbWVkaWFmb3VuZGF0aW9uLm9yZ4IMd2lraW5ld3Mub3Jngg5tLndp
-a2luZXdzLm9yZ4IOKi53aWtpbmV3cy5vcmeCECoubS53aWtpbmV3cy5vcmeCDXdp
-a2lxdW90ZS5vcmeCD20ud2lraXF1b3RlLm9yZ4IPKi53aWtpcXVvdGUub3JnghEq
-Lm0ud2lraXF1b3RlLm9yZ4IOd2lraXNvdXJjZS5vcmeCEG0ud2lraXNvdXJjZS5v
-cmeCECoud2lraXNvdXJjZS5vcmeCEioubS53aWtpc291cmNlLm9yZ4IPd2lraXZl
-cnNpdHkub3JnghFtLndpa2l2ZXJzaXR5Lm9yZ4IRKi53aWtpdmVyc2l0eS5vcmeC
-EyoubS53aWtpdmVyc2l0eS5vcmeCDndpa2l2b3lhZ2Uub3JnghBtLndpa2l2b3lh
-Z2Uub3JnghAqLndpa2l2b3lhZ2Uub3JnghIqLm0ud2lraXZveWFnZS5vcmeCDndp
-a3Rpb25hcnkub3JnghBtLndpa3Rpb25hcnkub3JnghAqLndpa3Rpb25hcnkub3Jn
-ghIqLm0ud2lrdGlvbmFyeS5vcmeCDW1lZGlhd2lraS5vcmeCDyoubWVkaWF3aWtp
-Lm9yZ4IPbS5tZWRpYXdpa2kub3JnghEqLm0ubWVkaWF3aWtpLm9yZ4IUKi56ZXJv
-Lndpa2lwZWRpYS5vcmcwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjBhBgNVHR8EWjBYMCqgKKAmhiRodHRwOi8vY3JsMy5kaWdp
-Y2VydC5jb20vY2EzLWcyOC5jcmwwKqAooCaGJGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0
-LmNvbS9jYTMtZzI4LmNybDCCAcQGA1UdIASCAbswggG3MIIBswYJYIZIAYb9bAEB
-MIIBpDA6BggrBgEFBQcCARYuaHR0cDovL3d3dy5kaWdpY2VydC5jb20vc3NsLWNw
-cy1yZXBvc2l0b3J5Lmh0bTCCAWQGCCsGAQUFBwICMIIBVh6CAVIAQQBuAHkAIAB1
-AHMAZQAgAG8AZgAgAHQAaABpAHMAIABDAGUAcgB0AGkAZgBpAGMAYQB0AGUAIABj
-AG8AbgBzAHQAaQB0AHUAdABlAHMAIABhAGMAYwBlAHAAdABhAG4AYwBlACAAbwBm
-ACAAdABoAGUAIABEAGkAZwBpAEMAZQByAHQAIABDAFAALwBDAFAAUwAgAGEAbgBk
-ACAAdABoAGUAIABSAGUAbAB5AGkAbgBnACAAUABhAHIAdAB5ACAAQQBnAHIAZQBl
-AG0AZQBuAHQAIAB3AGgAaQBjAGgAIABsAGkAbQBpAHQAIABsAGkAYQBiAGkAbABp
-AHQAeQAgAGEAbgBkACAAYQByAGUAIABpAG4AYwBvAHIAcABvAHIAYQB0AGUAZAAg
-AGgAZQByAGUAaQBuACAAYgB5ACAAcgBlAGYAZQByAGUAbgBjAGUALjB7BggrBgEF
-BQcBAQRvMG0wJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBF
-BggrBgEFBQcwAoY5aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0
-SGlnaEFzc3VyYW5jZUNBLTMuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEF
-BQADggEBAFBllO9JfipPjol+w1hrrwbJ2ZdT1l09ZkjdmvcIhyv54XxaW8NDsjjp
-5IIMc28q3JvuERxBnbKiwcrco/JGqwsywTSkYam9pS5ALhP4EXB773cfpYXEeyOC
-LyXQgp79CZXe1q5l3DDKtWXRWyuZ8WZw3dd4y8qPJ9JvkIw4ZFgZgo7NV+Fa0HtY
-vTe7D68o+EbYdmOLRkxKTEldv7A8f6WAWf5KRFE9dIsQvDD96zTYzdfzOCnonDuz
-wJwsJ4BJB8uIs3jFNg05e+6ZrENL/QBEDFe8H09auNHSBuwy4gxEVdfZwgxgrKlf
-uMko54p5i2QMvXtvIr/a3Nzlx6CiavI=
------END CERTIFICATE-----
-subject=/C=US/ST=California/L=San Francisco/O=Wikimedia Foundation, Inc./CN=*.wikipedia.org
-issuer=/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance CA-3
----
-
-Manually added intermediate certificate:
------BEGIN CERTIFICATE-----
-MIIGWDCCBUCgAwIBAgIQCl8RTQNbF5EX0u/UA4w/OzANBgkqhkiG9w0BAQUFADBs
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
-ZSBFViBSb290IENBMB4XDTA4MDQwMjEyMDAwMFoXDTIyMDQwMzAwMDAwMFowZjEL
-MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
-LmRpZ2ljZXJ0LmNvbTElMCMGA1UEAxMcRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
-Q0EtMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9hCikQH17+NDdR
-CPge+yLtYb4LDXBMUGMmdRW5QYiXtvCgFbsIYOBC6AUpEIc2iihlqO8xB3RtNpcv
-KEZmBMcqeSZ6mdWOw21PoF6tvD2Rwll7XjZswFPPAAgyPhBkWBATaccM7pxCUQD5
-BUTuJM56H+2MEb0SqPMV9Bx6MWkBG6fmXcCabH4JnudSREoQOiPkm7YDr6ictFuf
-1EutkozOtREqqjcYjbTCuNhcBoz4/yO9NV7UfD5+gw6RlgWYw7If48hl66l7XaAs
-zPw82W3tzPpLQ4zJ1LilYRyyQLYoEt+5+F/+07LJ7z20Hkt8HEyZNp496+ynaF4d
-32duXvsCAwEAAaOCAvowggL2MA4GA1UdDwEB/wQEAwIBhjCCAcYGA1UdIASCAb0w
-ggG5MIIBtQYLYIZIAYb9bAEDAAIwggGkMDoGCCsGAQUFBwIBFi5odHRwOi8vd3d3
-LmRpZ2ljZXJ0LmNvbS9zc2wtY3BzLXJlcG9zaXRvcnkuaHRtMIIBZAYIKwYBBQUH
-AgIwggFWHoIBUgBBAG4AeQAgAHUAcwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQBy
-AHQAaQBmAGkAYwBhAHQAZQAgAGMAbwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBj
-AGUAcAB0AGEAbgBjAGUAIABvAGYAIAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAg
-AEMAUAAvAEMAUABTACAAYQBuAGQAIAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQ
-AGEAcgB0AHkAIABBAGcAcgBlAGUAbQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBt
-AGkAdAAgAGwAaQBhAGIAaQBsAGkAdAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBj
-AG8AcgBwAG8AcgBhAHQAZQBkACAAaABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBl
-AHIAZQBuAGMAZQAuMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAm
-MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wgY8GA1UdHwSB
-hzCBhDBAoD6gPIY6aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGln
-aEFzc3VyYW5jZUVWUm9vdENBLmNybDBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNl
-cnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDAfBgNVHSME
-GDAWgBSxPsNpA/i/RwHUmCYaCALvY2QrwzAdBgNVHQ4EFgQUUOpzidsp+xCPnuUB
-INTeeZlIg/cwDQYJKoZIhvcNAQEFBQADggEBAB7ipUiebNtTOA/vphoqrOIDQ+2a
-vD6OdRvw/S4iWawTwGHi5/rpmc2HCXVUKL9GYNy+USyS8xuRfDEIcOI3ucFbqL2j
-CwD7GhX9A61YasXHJJlIR0YxHpLvtF9ONMeQvzHB+LGEhtCcAarfilYGzjrpDq6X
-dF3XcZpCdF/ejUN83ulV7WkAywXgemFhM9EZTfkI7qA5xSU1tyvED7Ld8aW3DiTE
-JiiNeXf1L/BXunwH1OH8zVowV36GEEfdMR/X/KLCvzB8XSSq6PmuX2p0ws5rs0bY
-Ib4p1I5eFdZCSucyb6Sxa1GDWL4/bcf72gMhy2oWGU4K8K2Eyl2Us1p292E=
------END CERTIFICATE-----
-
-
-No client certificate CA names sent
----
-SSL handshake has read 4905 bytes and written 434 bytes
----
-New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
-Server public key is 2048 bit
-Secure Renegotiation IS supported
-Compression: NONE
-Expansion: NONE
-SSL-Session:
- Protocol : TLSv1.2
- Cipher : ECDHE-RSA-AES128-GCM-SHA256
- Session-ID: 2022CC0AC2A1FCAB925F6511FCC28ACB27DDA644586ED6502753A3AA9FD70109
- Session-ID-ctx:
- Master-Key: 81B1182E9E133115CE67AD77ED3429F907601B7C5B30A9D5EE66F08652264B06F8576B6943369C92F6734DA8C146B4E8
- Key-Arg : None
- PSK identity: None
- PSK identity hint: None
- SRP username: None
- TLS session ticket lifetime hint: 300 (seconds)
- TLS session ticket:
- 0000 - 4f bd 82 9c 08 63 6f 2c-6f a1 09 b9 33 a3 66 b0 O....co,o...3.f.
- 0010 - 5f 4f 74 38 3a fc 89 a5-e6 88 42 ab 58 7f d6 ba _Ot8:.....B.X...
- 0020 - 30 1f 13 da 7e 7d 31 a3-0d 87 85 67 1b 86 5d 66 0...~}1....g..]f
- 0030 - e0 8e 14 03 c9 89 73 60-38 60 87 a0 0d 48 dd dd ......s`8`...H..
- 0040 - 1d b9 c3 8f 91 ed 92 2d-48 02 fb f0 79 25 4f 56 .......-H...y%OV
- 0050 - 5a ce 68 23 08 78 bc 86-1b ad 7a b7 58 41 04 19 Z.h#.x....z.XA..
- 0060 - 29 0c b6 66 72 f1 27 36-83 18 4b b4 9c 41 64 bb )..fr.'6..K..Ad.
- 0070 - 6f 52 0b df 03 f6 cc c2-b2 37 c2 c9 0e f9 df 9f oR.......7......
- 0080 - 13 af d6 d0 35 e8 e9 ac-f3 a6 02 07 9b 2f a2 e6 ....5......../..
- 0090 - 48 c6 1c c0 12 b2 ec 55-36 ad a0 c0 3c f5 cc db H......U6...<...
-
- Start Time: 1411743946
- Timeout : 300 (sec)
- Verify return code: 20 (unable to get local issuer certificate)
----
diff --git a/tools/testcerts/pre1.txt b/tools/testcerts/pre1.txt
deleted file mode 100644
index 776c38e..0000000
--- a/tools/testcerts/pre1.txt
+++ /dev/null
@@ -1,79 +0,0 @@
-Timestamp: 1383337821156
-Leafhash: A4892155FE9929177BCA785A73C15351A3EE2AF6F163DE40C15802BDE0F41302
------BEGIN PRECERTIFICATE-----
-MIIGqDCCBZCgAwIBAgIQCxvJV1NZEuon0JIojHqH+DANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG
-EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5EaWdpQ2VydCBTSEEyIFNlY3Vy
-ZSBTZXJ2ZXIgQ0EwHhcNMTMxMTAxMDAwMDAwWhcNMTQxMTA2MTIwMDAwWjBkMQswCQYDVQQGEwJV
-UzENMAsGA1UECBMEVXRhaDENMAsGA1UEBxMETGVoaTEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4x
-HjAcBgNVBAMTFWVtYmVkLmN0LmRpZ2ljZXJ0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
-AQoCggEBANExEGl1kTCQJNWXQuTH3m4DWx7xh9Tq+EXHlhorVtgUmHLmBPn7FGC3MH51q0MXN6K7
-huQVXa9LRmCdPRNlNPSkWUqpCVTEqBZrTPuAGEs01+XgXsyhP3uwBxWZkkKJ0FJ4tu7RVHXXgmSC
-+JQkSgI4MUNuMaIHvWEpEKsmov9kcQZGUTPnwEg90PyVLlbKypRoFM0dynpslh6FUH4OEAuCx4h1
-tsAN2KHk/ajYE0ND+FN0gBf5qXuY+njUEsDaGiAVKgAb16wOk//0xWy4cTWeHnyLObrsZ3F11GVl
-8cK1x0dNGxgeVfH6yTB8BJu/2wqaQSAdzf14Cie5D8YUXf0CAwEAAaOCA2swggNnMB8GA1UdIwQY
-MBaAFA+AYRyCMWHVLyjnjUY4tCzhxtniMB0GA1UdDgQWBBT8yxF+UXTw/RIW5igB3ZSRrSSkFzAg
-BgNVHREEGTAXghVlbWJlZC5jdC5kaWdpY2VydC5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
-MBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8EZDBiMC+gLaArhilodHRwOi8vY3JsMy5kaWdp
-Y2VydC5jb20vc3NjYS1zaGEyLWcxLmNybDAvoC2gK4YpaHR0cDovL2NybDQuZGlnaWNlcnQuY29t
-L3NzY2Etc2hhMi1nMS5jcmwwggHEBgNVHSAEggG7MIIBtzCCAbMGCWCGSAGG/WwBATCCAaQwOgYI
-KwYBBQUHAgEWLmh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL3NzbC1jcHMtcmVwb3NpdG9yeS5odG0w
-ggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0AGgAaQBzACAAQwBl
-AHIAdABpAGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1AHQAZQBzACAAYQBjAGMAZQBwAHQA
-YQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABpAGcAaQBDAGUAcgB0ACAAQwBQAC8AQwBQAFMAIABh
-AG4AZAAgAHQAaABlACAAUgBlAGwAeQBpAG4AZwAgAFAAYQByAHQAeQAgAEEAZwByAGUAZQBtAGUA
-bgB0ACAAdwBoAGkAYwBoACAAbABpAG0AaQB0ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAg
-AGEAcgBlACAAaQBuAGMAbwByAHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAgAGIAeQAgAHIA
-ZQBmAGUAcgBlAG4AYwBlAC4wfAYIKwYBBQUHAQEEcDBuMCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz
-cC5kaWdpY2VydC5jb20wRgYIKwYBBQUHMAKGOmh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E
-aWdpQ2VydFNIQTJTZWN1cmVTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADATBgorBgEEAdZ5AgQD
-AQH/BAIFADANBgkqhkiG9w0BAQsFAAOCAQEAbHgFxzrmkXjRdQdlHj4Ey2U8rTOetMqjddrXR1DZ
-9E12vp8yWB+LkSVASutpgzxNawj/rv1w1ODdJWMTra12R1MnxqoVytSEmbE0gjgxahdWWiV8yTFB
-4tMFRHvCCwmIJqhRwjufnRs1q1+9YMxZ6reCG4kg29qgtQhh8V9vCrGfQja/4cBHa6O7w407FPra
-b2NIqtJB/47fOdACkVdFjbOVSWielDtTv7QNPi3OUfNwNE/Qqh1k5MOBDP1gif1AFzl5Z7plUos5
-3533VCBjrcOWp8WXUtNlIedlxjarUaTKSRpZVdRzY9ugvou9JLVF1SuDIAXQ3+tN44bjAjERug==
------END PRECERTIFICATE-----
-
------BEGIN CERTIFICATE-----
-MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG
-EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
-HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgx
-MjAwMDBaME0xCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRp
-Z2lDZXJ0IFNIQTIgU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83nf36QYSv
-x6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bdKpPDkC55gIDvEwRqFDu1
-m5K+wgdlTvza/P96rtxcflUxDOg5B6TXvi/TC2rSsd9f/ld0Uzs1gN2ujkSYs58O09rg1/RrKatE
-p0tYhG2SS4HD2nOLEpdIkARFdRrdNzGXkujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJ
-TvOX6+guqw9ypzAO+sf0/RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQI
-MAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0
-cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj
-ZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwN6A1oDOGMWh0dHA6Ly9jcmw0LmRpZ2lj
-ZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYI
-KwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA+AYRyCMWHV
-LyjnjUY4tCzhxtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0GCSqGSIb3DQEB
-CwUAA4IBAQAjPt9L0jFCpbZ+QlwaRMxp0Wi0XUvgBCFsS+JtzLHgl4+mUwnNqipl5TlPHoOlblyY
-oiQm5vuh7ZPHLgLGTUq/sELfeNqzqPlt/yGFUzZgTHbO7Djc1lGA8MXW5dRNJ2Srm8c+cftIl7gz
-bckTB+6WohsYFfZcTEDts8Ls/3HB40f/1LkAtDdC2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8s
-jX7tN8Cp1Tm5gr8ZDOo0rwAhaPitc+LJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopY
-JeS4d60tbvVS3bR0j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz
------END CERTIFICATE-----
-
------BEGIN CERTIFICATE-----
-MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG
-EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
-HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw
-MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
-dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq
-hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn
-TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5
-BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H
-4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y
-7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB
-o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm
-8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF
-BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr
-EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt
-tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886
-UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
-CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
------END CERTIFICATE-----
-
diff --git a/tools/testcerts/pre2.txt b/tools/testcerts/pre2.txt
deleted file mode 100644
index 4c86537..0000000
--- a/tools/testcerts/pre2.txt
+++ /dev/null
@@ -1,106 +0,0 @@
-Timestamp: 1399629239033
-Leafhash: 758B8612DFED6A3321215C0586C0AC9F43137CD2BBF043C86301D66DC7D1205A
------BEGIN PRECERTIFICATE-----
-MIIFFzCCBAGgAwIBAgIgd+115NyVfYOnRINB2wJy2eaQRbJ6j8Zau5IdwBNpmzowCwYJKoZIhvcN
-AQELMGYxLDAqBgNVBAMMI1ByZS1jZXJ0aWZpY2F0ZSBTaWduaW5nIENlcnRpZmljYXRlMRAwDgYD
-VQQLDAdDQSBUZWFtMRcwFQYDVQQKDA5UQUlXQU4tQ0EgSU5DLjELMAkGA1UEBhMCVFcwHhcNMTQw
-NTA5MDk1MzU3WhcNMTQwNTE2MTU1OTU5WjB0MR0wGwYDVQQDDBRjdHRlc3QwNS50d2NhLmNvbS50
-dzELMAkGA1UECwwCUkQxFzAVBgNVBAoMDlRBSVdBTi1DQSBJTkMuMQ8wDQYDVQQHDAZUYWlwZWkx
-DzANBgNVBAgMBlRhaXdhbjELMAkGA1UEBhMCVFcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
-AoIBAQDSgb3MYpsqjkNqcOJHIlEmy8ldCzXtmJfoLfvW1g8JyaGgKR6B98ceg1whThF1tPy8aqJv
-fEXGivb+2El1BmxTNvSZ+bOkOT0UsD2hiIgUppD6b/ICWQrIvwrBTNnfJtrwvGD/rygpVTZQoekX
-IVdapI95Cfn+36YXqjX7ixgItEx3t/nzOqBxJNI0p52m9l1sowi2/hGmvc/xqC0Cti4m177c8gP0
-u4oKQRJVF2690F748KfzIMcbS7KbDDDVhtWqwgKaRLvqD+gJAUZ1QYEyzDr5Xhhi1O0FXfhyeeCj
-mRUJBENmhqElt9C1HugaBsno37JP1AQdsuVg776qQQ1PAgMBAAGjggGlMIIBoTArBgNVHSMEJDAi
-gCCVnLtVYCn+QZohG69CSwl1Y2OhEQ7LbPhnh353anz2ezApBgNVHQ4EIgQgt6NL2avrK2PUt8X1
-oG0rd0Wd2ZVDVuJru2T6Z4/eJUEwPwYDVR0fBDgwNjA0oDKgMIYuaHR0cDovL2N0dGVzdC50d2Nh
-LmNvbS50dy9zc2xzZXJ2ZXIvY3R0ZXN0LmNybDAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwID
-qDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwJQYDVR0RBB4wHIIUY3R0ZXN0MDUudHdj
-YS5jb20udHeHBMCoAckwOgYIKwYBBQUHAQEELjAsMCoGCCsGAQUFBzABhh5odHRwOi8vY3R0ZXN0
-LnR3Y2EuY29tLnR3L29jc3AwUQYDVR0gBEowSDBGBgdggR4DAQgFMDswIgYIKwYBBQUHAgEWFmh0
-dHA6Ly93d3cudHdjYS5jb20udHcwFQYIKwYBBQUHAgIwCRoHMC4xLjEuMzATBgorBgEEAdZ5AgQD
-AQH/BAIFADALBgkqhkiG9w0BAQsDggEBAIkN6er89ss6KAZOH/ZpTPbXhO/J8NNq7vJBxhD4z56R
-aRTJpr7Fla9zr8K3aD7bbBUpVeMqER3YA7eeOR8ITBqzMN9SpjdpDlBLcI/6S+7iUVRw4+UvEVqL
-0xlCfdxftGLX+T77y7/qqLxyH+QVuSS4sKzTCfspqAaxteK32A5nWKAiJFUI/ise67o3T9f015hR
-7rHj+U2AomLQwnyiMg4u3D2mYzK9q7VDGJfKIW6wrFYS/lQsFKyb4sUTyGG9VuzgSDIjCXJag7fs
-MZ+/shgsVOTzHUVeHGuKsPcpps0Yvu2W3DybsVoBwtS/vePPnfNfCrDqM9vZCTurvG4KaS4=
------END PRECERTIFICATE-----
-
------BEGIN CERTIFICATE-----
-MIIEUTCCAzugAwIBAgIEATNR3TALBgkqhkiG9w0BAQswVDELMAkGA1UEBhMCVFcxFzAVBgNVBAoT
-DlRBSVdBTi1DQSBJTkMuMRAwDgYDVQQLEwdDQSBUZWFtMRowGAYDVQQDExFSRCBUV0NBIENUVEVT
-VCBDQTAeFw0xNDA1MDkwOTQzMjZaFw0xNTA1MDkxNTU5NTlaMGYxLDAqBgNVBAMMI1ByZS1jZXJ0
-aWZpY2F0ZSBTaWduaW5nIENlcnRpZmljYXRlMRAwDgYDVQQLDAdDQSBUZWFtMRcwFQYDVQQKDA5U
-QUlXQU4tQ0EgSU5DLjELMAkGA1UEBhMCVFcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
-AQCtFIow0xs7VQ42AEck0o+D8pDDOvIclTPJG7j5+wc7lz1wOwbqP8w06Qa/18tg3sdk16dYFg9k
-pIeOU7suaWgeHifBjjj9iXTELH4U0RP3HwxlM23WArt9a5OKM5KJlA2T9obppnfsN9fm6ZGX4TTY
-JqV8x2vgXSkHhVwxl8wnZoywHlHlgThvVVi+/DzZUD8FIXz2/dPeMtSTfHQ6LqIhee9YMIVgqg/f
-tPb5lOhrJEmAl56mJWi1haVYmxZDSa4+1XCJkOxEzQDPpAvIrXVgAQzr6A5jIHZ7VucTEQ5U/9lx
-Gckzv6CFDRxYyjSpBZsxML/d4A1P9nKdWcABqO9PAgMBAAGjggEbMIIBFzArBgNVHSMEJDAigCCE
-xPSrbrwoBcYxPScQhJ7WOGJB5N3Efkav81dvue7NsjApBgNVHQ4EIgQglZy7VWAp/kGaIRuvQksJ
-dWNjoREOy2z4Z4d+d2p89nswPwYDVR0fBDgwNjA0oDKgMIYuaHR0cDovL2N0dGVzdC50d2NhLmNv
-bS50dy9zc2xzZXJ2ZXIvY3R0ZXN0LmNybDASBgNVHRMBAf8ECDAGAQH/AgEAMBUGA1UdJQQOMAwG
-CisGAQQB1nkCBAQwUQYDVR0gBEowSDBGBgdggR4DAQgFMDswIgYIKwYBBQUHAgEWFmh0dHA6Ly93
-d3cudHdjYS5jb20udHcwFQYIKwYBBQUHAgIwCRoHMC4xLjEuMzALBgkqhkiG9w0BAQsDggEBAN8v
-hr/zNUNSSikqAtRVZVgcJTuN3yTlaXX4hMJFAWrbBqJuN++cE6A2BBTkaLpEZajVqPKL5AxL5KWM
-dMFNkpF3i0UKbf4vnpfrQprsamDX5tKqPCAOKa8yL82CBkimOCmLx24WN+VtNitYzh/MqspApNM7
-7wCO8ncvFtS4sC1Gj5M9CjVhxKmMe15O4SZr9aZpGP7raT4CE3X95APKX5yyiAVwPcOPdPkfRRLQ
-gHko60NbxaeayH5sfWa2dNPEjbOkz0SKaXurV9pzrj/2FZNhgsnRsGIJhx2BLm7FoeUC45RarDJD
-YrscJ6DBR83YwJXsaFCyB7l5CP7L13Wr98E=
------END CERTIFICATE-----
-
------BEGIN CERTIFICATE-----
-MIIEvjCCAqagAwIBAgIQQAEzUd0AAAAAAAAAFzPdqzANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG
-EwJUVzEbMBkGA1UEChMSVFdDQSBSRCBEZXBhcnRtZW50MRAwDgYDVQQLEwdDQSBUZWFtMSQwIgYD
-VQQDExtSRCBUV0NBIFJvb3QgQ0EgNDA5NiBTaGEyNTYwHhcNMTQwNTA5MDMyMDUyWhcNMTUwNTA5
-MTU1OTU5WjBUMQswCQYDVQQGEwJUVzEXMBUGA1UEChMOVEFJV0FOLUNBIElOQy4xEDAOBgNVBAsT
-B0NBIFRlYW0xGjAYBgNVBAMTEVJEIFRXQ0EgQ1RURVNUIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEA6xAMprFXHtOkmXIgL63aTx4S20IzdrcdDTMQvwnyYLBhJf8lWz5qeOY37SaC
-4VXILP54qVdML+YBa2BAQfgu6kS+/f73Bp3pSHx8LIHQCt5jdgkNS3OVYK8nQdbWXWeA64bCFdE/
-tlelHSTHtIKXE+v7ug+P5Q/RRBf0Dzi/M1fXTXqXeAga3LaPGPT7o6lZZJh7hp25aJxChIa/1X8x
-99sPx/BqO/WHyYKBCU9Ym05yQFel8mpCgzSbqscKTbKPkvm0ejDANX/WCEziJ3IzR5G9kPoL/zYZ
-ofIqYJMIYRsQRlD/n1ILnMxwdhN3EFlZ0e5xkyIm9TaCqeCZsdFJWQIDAQABo34wfDArBgNVHSME
-JDAigCCwvM16BvA51cl2uO30/ohdOMPVrVBVG5BZ4teNnteYnTApBgNVHQ4EIgQghMT0q268KAXG
-MT0nEISe1jhiQeTdxH5Gr/NXb7nuzbIwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C
-AQAwDQYJKoZIhvcNAQEFBQADggIBABDkaI3GMCKBfJSfnpmxmiU1ht3cfq/9/hpJSzE6k+of5esV
-D3bYW9nnKScCcBy7poeOoc3C7p9fQtsLZbNfhYpG4/Aq0aVYGtZxw/FCWnXi9rUXpSLZh1yW1uV9
-KBj2D8yzGIx99mpHifjjeoCWG0TW/aaHeIolJm2DhkPTLWjd/urN1TP8YqhEiKMHZI3SFWeeH/BV
-WJKE5rX8vtLW1FPnlRPE+Z/FAa52qOyN4ie0A9IhNPs3gtc+bnhdcZaHnxkySqUvWxqQxkzAGaiO
-VnPlnSlnMCn5I2KOT0XVWYOyU9PP1//V/baDftv7VpT5AOtIaz8mQ6Lp4AIcoPFeU8cgJNZhXgmp
-NOv/dW8lWXH6RYxdM7NFmv98Wk3rKLCzOzR6kuXnARKOJghZf4FV+6Fvjgjf/8wLnzhSdCEbyL7A
-znkOSKc9wzUcZCxF8aTWtRT8HYIu8diZo0CzPxN8OyDl5mPsYexhguPHOXyLv/EljZ8yCdy/SsgQ
-JPzuqKu2a3RD4des15EzbnJOxn4DSeqoUfSfaU/KVfmUKpBEJ3ouD2SLAZ7L+4F6NPCte3HEE2kN
-tOmQIwe65htXmLJxDB+dwMjE4dkA2sETaN2dQ9DqpCNkpNxuNdis/uacAAXnDNddPIlR2moCtUx8
-+Y7wlcqBHdmmg5rbFBuBN+esL8J8
------END CERTIFICATE-----
-
------BEGIN CERTIFICATE-----
-MIIFyTCCA7GgAwIBAgIQQAEzK0EAAAAAAAAAFSWxNjANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQG
-EwJUVzEbMBkGA1UEChMSVFdDQSBSRCBEZXBhcnRtZW50MRAwDgYDVQQLEwdDQSBUZWFtMSQwIgYD
-VQQDExtSRCBUV0NBIFJvb3QgQ0EgNDA5NiBTaGEyNTYwHhcNMTMwNjI1MDMwNzIyWhcNMzMwNjI1
-MDMwNzI2WjBiMQswCQYDVQQGEwJUVzEbMBkGA1UEChMSVFdDQSBSRCBEZXBhcnRtZW50MRAwDgYD
-VQQLEwdDQSBUZWFtMSQwIgYDVQQDExtSRCBUV0NBIFJvb3QgQ0EgNDA5NiBTaGEyNTYwggIiMA0G
-CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2Saqg7eNGISFsG+pQfB/e+VTbpg+KmAAydUrJyCPj
-74Gl/MKNeMW6AqUUSiKQq+HTnrHI+I2e85cgAxbSbhXp6utJuOjfsZE5lr7KDkfok9hdMA7YvKuk
-y5dLK9Qcvhj4olt3DU0GKdWgKKtMWg4WOx+Wgu50C/TGyeiMx754O09a0YXlDLji84aQbxUWCP+X
-hq+LXyGqilcTe+wSVjUHWfJJz8ZeVNCz/WXBn2Sljf614T1AkeU9pTnEkJRd/S+eVNVE8gLiAJSF
-/ffHTHGRZoPCTDS26hzSpBAC+va0T4IWvgGJtPNInReXGPeydxHJbsJjwyPQ9n5iclUZmAeKcG7a
-Wow/xrU36euBDIp877djj5lbtb0Rq35slDAGLVy/ouLkcrurPZdJGkhcpACMi4sKK98cx/XnzP9o
-wV+bDYyYlXSl3tv88CidywHI6VPN6Aio4ipsAOmol1AxbkJ+W9INiQzbdmYXD2v3c0Kvcq4/bZMw
-wofoGWGBALF3VYd6aYUnaCHD9gYTPrMHVsMrYDbvlIDkORVL950xvi1SfbRRo36LtYLjupFiJOlP
-xS0DxWN6tVarS+1SyHsdEJYKw+b2ty5Sko5JkCedgSXHPhkL2ap3OfHtegSDpIgWL7ydpaoTyD3y
-Fev6doCPC6cnHitwBCDpoEqNIm+JK2JZYQIDAQABo3sweTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T
-AQH/BAUwAwEB/zArBgNVHSMEJDAigCCwvM16BvA51cl2uO30/ohdOMPVrVBVG5BZ4teNnteYnTAp
-BgNVHQ4EIgQgsLzNegbwOdXJdrjt9P6IXTjD1a1QVRuQWeLXjZ7XmJ0wDQYJKoZIhvcNAQELBQAD
-ggIBAGSVKdVIynZnTpFaK3F2jjaC2oaJ1L8CA6e5OjWi6WUshKG4kJzLASD/U8XQXA8rVSuWShmz
-B7ccm4fy1SmnSvsi4JA5mSDqcIOmwZmIYBAd/+8QK/sijzyO2MNPpqSupuhWxAakHSG8/3Leij2Q
-P2GEXejDq3ewtS/gT1ZVI/ZSlIYxChsKZ3UEkl4XhUhL8fir/5Z+g6WdTFvXUB3wc/JA/MZ+h5Nu
-BsrnrTlxet0vu3UlyOELsF5pMe1WGayR2A56LRL3UKhjFrUJSCTYMBiqAMS3Fsvk+RXttPYtcpiB
-uheX8M/X8g2WTLOklS9/QYy1VmIWZcrfExHrMxQ8FCrxMfQn8fNlkMADmcRbQYeVHHZGx7MQEjBw
-py45jzcPudJTx8Ccz6r0YSxoumC9reS0hASQ/NdXh6vcWfT8qsqYohL/k9J0PbfgJuIExAStIs+Y
-nn4N7HgNftijy+l0sS//rMhVcofUaJzhJcbUe4TX/SL8ZHFkSkhUSPdDd1DR+r1IWKDKd/2FxMn3
-+oKBVsjPdL0HBwwHFQja8TBb5E3vYo4XKKEOGIuFa7NcSq0pF7pK85K0XIypAwgJCXffWP9SynDo
-eK+ZbSOZNOCvH67ZRUQnWo1nZds+6OplhSpWkYDYN834wXEU4zbHRvtymCbIeMZzAXzdsJM2i3zy
-7bTu
------END CERTIFICATE-----
-
diff --git a/tools/testcerts/roots/root1.pem b/tools/testcerts/roots/root1.pem
deleted file mode 100644
index e077900..0000000
--- a/tools/testcerts/roots/root1.pem
+++ /dev/null
@@ -1,23 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE
-BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl
-IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd
-BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx
-OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0
-eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz
-ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3
-DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI
-wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd
-tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8
-i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf
-Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw
-gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF
-lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF
-UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF
-BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
-//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW
-XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2
-lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn
-iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67
-nfhmqA==
------END CERTIFICATE-----
diff --git a/tools/testcerts/roots/root2.pem b/tools/testcerts/roots/root2.pem
deleted file mode 100644
index bdb6474..0000000
--- a/tools/testcerts/roots/root2.pem
+++ /dev/null
@@ -1,21 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
-QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD
-VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw
-NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU
-cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg
-Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821
-+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw
-Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo
-aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy
-2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7
-7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P
-BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL
-VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk
-VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB
-IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl
-j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
-6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355
-e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u
-G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
------END CERTIFICATE-----
diff --git a/tools/testcerts/roots/root3.pem b/tools/testcerts/roots/root3.pem
deleted file mode 100644
index 81c8a7d..0000000
--- a/tools/testcerts/roots/root3.pem
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG
-EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw
-KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw
-MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
-MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu
-Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t
-Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS
-OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3
-MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ
-NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe
-h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB
-Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY
-JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ
-V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp
-myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK
-mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
-vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
------END CERTIFICATE-----
diff --git a/tools/testcerts/roots/root4.pem b/tools/testcerts/roots/root4.pem
deleted file mode 100644
index 3fdb770..0000000
--- a/tools/testcerts/roots/root4.pem
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG
-EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
-HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw
-MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
-dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq
-hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn
-TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5
-BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H
-4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y
-7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB
-o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm
-8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF
-BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr
-EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt
-tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886
-UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
-CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
------END CERTIFICATE-----
diff --git a/tools/testcerts/roots/root5.pem b/tools/testcerts/roots/root5.pem
deleted file mode 100644
index 096fd18..0000000
--- a/tools/testcerts/roots/root5.pem
+++ /dev/null
@@ -1,29 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFyTCCA7GgAwIBAgIQQAEzK0EAAAAAAAAAFSWxNjANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQG
-EwJUVzEbMBkGA1UEChMSVFdDQSBSRCBEZXBhcnRtZW50MRAwDgYDVQQLEwdDQSBUZWFtMSQwIgYD
-VQQDExtSRCBUV0NBIFJvb3QgQ0EgNDA5NiBTaGEyNTYwHhcNMTMwNjI1MDMwNzIyWhcNMzMwNjI1
-MDMwNzI2WjBiMQswCQYDVQQGEwJUVzEbMBkGA1UEChMSVFdDQSBSRCBEZXBhcnRtZW50MRAwDgYD
-VQQLEwdDQSBUZWFtMSQwIgYDVQQDExtSRCBUV0NBIFJvb3QgQ0EgNDA5NiBTaGEyNTYwggIiMA0G
-CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2Saqg7eNGISFsG+pQfB/e+VTbpg+KmAAydUrJyCPj
-74Gl/MKNeMW6AqUUSiKQq+HTnrHI+I2e85cgAxbSbhXp6utJuOjfsZE5lr7KDkfok9hdMA7YvKuk
-y5dLK9Qcvhj4olt3DU0GKdWgKKtMWg4WOx+Wgu50C/TGyeiMx754O09a0YXlDLji84aQbxUWCP+X
-hq+LXyGqilcTe+wSVjUHWfJJz8ZeVNCz/WXBn2Sljf614T1AkeU9pTnEkJRd/S+eVNVE8gLiAJSF
-/ffHTHGRZoPCTDS26hzSpBAC+va0T4IWvgGJtPNInReXGPeydxHJbsJjwyPQ9n5iclUZmAeKcG7a
-Wow/xrU36euBDIp877djj5lbtb0Rq35slDAGLVy/ouLkcrurPZdJGkhcpACMi4sKK98cx/XnzP9o
-wV+bDYyYlXSl3tv88CidywHI6VPN6Aio4ipsAOmol1AxbkJ+W9INiQzbdmYXD2v3c0Kvcq4/bZMw
-wofoGWGBALF3VYd6aYUnaCHD9gYTPrMHVsMrYDbvlIDkORVL950xvi1SfbRRo36LtYLjupFiJOlP
-xS0DxWN6tVarS+1SyHsdEJYKw+b2ty5Sko5JkCedgSXHPhkL2ap3OfHtegSDpIgWL7ydpaoTyD3y
-Fev6doCPC6cnHitwBCDpoEqNIm+JK2JZYQIDAQABo3sweTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T
-AQH/BAUwAwEB/zArBgNVHSMEJDAigCCwvM16BvA51cl2uO30/ohdOMPVrVBVG5BZ4teNnteYnTAp
-BgNVHQ4EIgQgsLzNegbwOdXJdrjt9P6IXTjD1a1QVRuQWeLXjZ7XmJ0wDQYJKoZIhvcNAQELBQAD
-ggIBAGSVKdVIynZnTpFaK3F2jjaC2oaJ1L8CA6e5OjWi6WUshKG4kJzLASD/U8XQXA8rVSuWShmz
-B7ccm4fy1SmnSvsi4JA5mSDqcIOmwZmIYBAd/+8QK/sijzyO2MNPpqSupuhWxAakHSG8/3Leij2Q
-P2GEXejDq3ewtS/gT1ZVI/ZSlIYxChsKZ3UEkl4XhUhL8fir/5Z+g6WdTFvXUB3wc/JA/MZ+h5Nu
-BsrnrTlxet0vu3UlyOELsF5pMe1WGayR2A56LRL3UKhjFrUJSCTYMBiqAMS3Fsvk+RXttPYtcpiB
-uheX8M/X8g2WTLOklS9/QYy1VmIWZcrfExHrMxQ8FCrxMfQn8fNlkMADmcRbQYeVHHZGx7MQEjBw
-py45jzcPudJTx8Ccz6r0YSxoumC9reS0hASQ/NdXh6vcWfT8qsqYohL/k9J0PbfgJuIExAStIs+Y
-nn4N7HgNftijy+l0sS//rMhVcofUaJzhJcbUe4TX/SL8ZHFkSkhUSPdDd1DR+r1IWKDKd/2FxMn3
-+oKBVsjPdL0HBwwHFQja8TBb5E3vYo4XKKEOGIuFa7NcSq0pF7pK85K0XIypAwgJCXffWP9SynDo
-eK+ZbSOZNOCvH67ZRUQnWo1nZds+6OplhSpWkYDYN834wXEU4zbHRvtymCbIeMZzAXzdsJM2i3zy
-7bTu
------END CERTIFICATE-----
diff --git a/tools/to_catlfish.py b/tools/to_catlfish.py
deleted file mode 100755
index 00a359f..0000000
--- a/tools/to_catlfish.py
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2015, NORDUnet A/S.
-# See LICENSE for licensing information.
-
-import argparse
-import subprocess
-import sys
-import select
-
-parser = argparse.ArgumentParser(description='')
-parser.add_argument('toerl')
-parser.add_argument('nodedir')
-parser.add_argument('command')
-args = parser.parse_args()
-
-p = subprocess.Popen(
- [args.toerl, args.nodedir],
- stdin=subprocess.PIPE)
-p.stdin.write(args.command + ".\n")
-p.stdin.flush()
-select.select([], [], [], 0.5)
-p.stdin.close()
-p.wait()
diff --git a/tools/treeinfo.py b/tools/treeinfo.py
deleted file mode 100755
index 036aeb2..0000000
--- a/tools/treeinfo.py
+++ /dev/null
@@ -1,123 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2014, NORDUnet A/S.
-# See LICENSE for licensing information.
-
-import argparse
-import urllib2
-import urllib
-import json
-import base64
-import sys
-import struct
-import hashlib
-import itertools
-from certtools import *
-import zipfile
-import os
-import time
-
-parser = argparse.ArgumentParser(description='')
-parser.add_argument('--store', default=None, metavar="dir", help='Certificates directory')
-
-parser.add_argument('--head', action='store_true', help="Calculate tree head")
-parser.add_argument('--printnode', action='store_true', help="Print tree node")
-
-parser.add_argument('--treesize', type=int, default=None, metavar="treesize", help="Tree size")
-parser.add_argument('--level', type=int, default=None, metavar="level", help="Level")
-parser.add_argument('--index', type=int, default=None, metavar="index", help="Index")
-
-parser.add_argument('--follow', action='store_true', help="Follow upwards")
-
-parser.add_argument('--dot', default=None, metavar="file", help='Output data in dot format')
-
-args = parser.parse_args()
-
-def index_to_root(index, treesize, level=0):
- path = (index, level)
- height = merkle_height(treesize)
- nodes = []
- while node_level(path) < height:
- nodes.append(path)
- path = node_above(path)
- return nodes
-
-def set_tree_node(tree, level, index, value, overwrite=True):
- if not overwrite and index in levels.setdefault(level, {}):
- return
- levels.setdefault(level, {})[index] = value
-
-def draw_path(tree, startlevel, startindex, treesize, colors):
- height = merkle_height(treesize)
- nodes = index_to_root(startindex, treesize, level=startlevel)
-
- for (index, level) in nodes:
- if level == 0:
- set_tree_node(tree, level, index, colors[0])
- else:
- set_tree_node(tree, level, index, colors[1])
- index ^= 1
- levelsize = 2 ** level
- firstleaf = index * levelsize
- if firstleaf < treesize:
- set_tree_node(tree, level, index, "", overwrite=False)
- set_tree_node(tree, height, 0, colors[1])
-
-
-if args.head:
- treehead = get_tree_head(args.store, args.treesize)
- print base64.b16encode(treehead)
-elif args.dot:
- levels = {}
- if args.index >= args.treesize:
- sys.exit(1)
- dotfile = open(args.dot, "w")
- print >>dotfile, 'graph "" {'
- print >>dotfile, 'ordering=out;'
- print >>dotfile, 'node [style=filled];'
-
- height = merkle_height(args.treesize)
-
- draw_path(levels, 0, args.treesize - 1, args.treesize, ["0.600 0.500 0.900", "0.600 0.300 0.900"])
-
- draw_path(levels, args.level, args.index, args.treesize, ["0.300 0.500 0.900", "0.300 0.200 0.900"])
-
- for l in sorted(levels.keys(), reverse=True):
- for i in sorted(levels[l].keys()):
- print >>dotfile, "l%di%d [color=\"%s\" label=\"%s\"];" % (l, i, levels[l][i], path_as_string(i, l, args.treesize))
- if height != l:
- print >>dotfile, "l%di%d -- l%di%d;" % (l + 1, i / 2, l, i)
- if i & 1 == 0:
- print >>dotfile, "ml%di%d [shape=point style=invis];" % (l, i)
- print >>dotfile, "l%di%d -- ml%di%d [weight=100 style=invis];" % (l + 1, i / 2, l, i)
- print >>dotfile, "}"
- dotfile.close()
-elif args.printnode:
- index = args.index
- level = args.level
- if args.index >= args.treesize:
- sys.exit(1)
- height = merkle_height(args.treesize)
- nodes = index_to_root(index, args.treesize, level=level)
-
- for (index, level) in nodes:
- print level, index
- if args.store:
- print base64.b16encode(get_intermediate_hash(args.store, args.treesize, level, index))
-
- if not args.follow:
- sys.exit(0)
-
- index ^= 1
- levelsize = 2 ** level
-
- firstleaf = index * levelsize
- if firstleaf < args.treesize:
- print level, index
- if args.store:
- print base64.b16encode(get_intermediate_hash(args.store, args.treesize, level, index))
-
- print height, 0
- if args.store:
- print base64.b16encode(get_intermediate_hash(args.store, args.treesize, height, 0))
diff --git a/tools/validatestore.py b/tools/validatestore.py
deleted file mode 100755
index 74963e0..0000000
--- a/tools/validatestore.py
+++ /dev/null
@@ -1,96 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (c) 2014, NORDUnet A/S.
-# See LICENSE for licensing information.
-
-import argparse
-import urllib2
-import urllib
-import json
-import base64
-import sys
-import struct
-import hashlib
-import itertools
-from certtools import *
-try:
- from precerttools import *
-except ImportError:
- pass
-import os
-import signal
-import select
-import zipfile
-import traceback
-
-parser = argparse.ArgumentParser(description='')
-parser.add_argument('--store', default=None, metavar="dir", help='Get certificates from directory dir')
-parser.add_argument('--parallel', type=int, default=1, metavar="n", help="Number of parallel workers")
-args = parser.parse_args()
-
-from multiprocessing import Pool
-
-certfilepath = args.store
-
-if certfilepath[-1] == "/":
- certfiles = [certfilepath + filename for filename in sorted(os.listdir(certfilepath)) if os.path.isfile(certfilepath + filename)]
-else:
- certfiles = [certfilepath]
-
-def submitcert((certfile, cert)):
- try:
- certchain = get_certs_from_string(cert)
- if len(certchain) == 0:
- return True
- precerts = get_precerts_from_string(cert)
- hash = get_hash_from_certfile(cert)
- timestamp = get_timestamp_from_certfile(cert)
- assert len(precerts) == 0 or len(precerts) == 1
- precert = precerts[0] if precerts else None
- if precert:
- if ext_key_usage_precert_signing_cert in get_ext_key_usage(certchain[0]):
- issuer_key_hash = get_cert_key_hash(certchain[1])
- issuer = certchain[1]
- else:
- issuer_key_hash = get_cert_key_hash(certchain[0])
- issuer = None
- cleanedcert = cleanprecert(precert, issuer=issuer)
- mtl = pack_mtl_precert(timestamp, cleanedcert, issuer_key_hash)
- leaf_hash = get_leaf_hash(mtl)
- else:
- mtl = pack_mtl(timestamp, certchain[0])
- leaf_hash = get_leaf_hash(mtl)
- if leaf_hash == hash:
- return True
- else:
- print certfile, repr(leaf_hash), repr(hash), precert != None
- return None
- except Exception, e:
- print certfile
- traceback.print_exc()
- raise e
-
-def get_all_certificates(certfiles):
- for certfile in certfiles:
- if certfile.endswith(".zip"):
- zf = zipfile.ZipFile(certfile)
- for name in zf.namelist():
- yield (name, zf.read(name))
- zf.close()
- else:
- yield (certfile, open(certfile).read())
-
-p = Pool(args.parallel, lambda: signal.signal(signal.SIGINT, signal.SIG_IGN))
-
-certs = get_all_certificates(certfiles)
-
-try:
- for result in p.imap_unordered(submitcert, certs):
- if result == None:
- print "error"
- p.terminate()
- p.join()
- sys.exit(1)
-except KeyboardInterrupt:
- p.terminate()
- p.join()
diff --git a/tools/verifysct.py b/tools/verifysct.py
deleted file mode 100755
index 71ea4e9..0000000
--- a/tools/verifysct.py
+++ /dev/null
@@ -1,123 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (c) 2014, NORDUnet A/S.
-# See LICENSE for licensing information.
-
-import argparse
-import urllib2
-import urllib
-import json
-import base64
-import sys
-import struct
-import hashlib
-import itertools
-from certtools import *
-import os
-import signal
-import select
-import zipfile
-
-parser = argparse.ArgumentParser(description='')
-parser.add_argument('baseurl', help="Base URL for CT server")
-parser.add_argument('--sct-file', default=None, metavar="dir", help='SCT:s to verify')
-parser.add_argument('--parallel', type=int, default=16, metavar="n", help="Number of parallel verifications")
-parser.add_argument('--publickey', default=None, metavar="file", help='Public key for the CT log')
-parser.add_argument('--cafile', default=None, metavar="file", help='File containing the CA cert')
-args = parser.parse_args()
-
-create_ssl_context(cafile=args.cafile)
-
-from multiprocessing import Pool
-
-baseurl = args.baseurl
-
-logpublickey = get_public_key_from_file(args.publickey) if args.publickey else None
-
-sth = get_sth(baseurl)
-
-def verifysct(sctentry):
- timing = timing_point()
-
- leafcert = base64.b64decode(sctentry["leafcert"])
- if "issuer_key_hash" in sctentry:
- issuer_key_hash = base64.b64decode(sctentry["issuer_key_hash"])
- else:
- issuer_key_hash = None
- try:
- if issuer_key_hash:
- signed_entry = pack_precert(leafcert, issuer_key_hash)
- else:
- signed_entry = pack_cert(leafcert)
- check_sct_signature(baseurl, signed_entry, sctentry["sct"], precert=issuer_key_hash, publickey=logpublickey)
- timing_point(timing, "checksig")
- except AssertionError, e:
- print "ERROR:", e
- return (None, None)
- except urllib2.HTTPError, e:
- print "ERROR:", e
- return (None, None)
- except ecdsa.keys.BadSignatureError, e:
- print "ERROR: bad signature"
- return (None, None)
-
- if issuer_key_hash:
- merkle_tree_leaf = pack_mtl_precert(sctentry["sct"]["timestamp"], leafcert, issuer_key_hash)
- else:
- merkle_tree_leaf = pack_mtl(sctentry["sct"]["timestamp"], leafcert)
-
- leaf_hash = get_leaf_hash(merkle_tree_leaf)
-
- try:
- proof = get_proof_by_hash(baseurl, leaf_hash, sth["tree_size"])
- except SystemExit:
- return (None, None)
-
- #print proof
-
- leaf_index = proof["leaf_index"]
- inclusion_proof = [base64.b64decode(e) for e in proof["audit_path"]]
-
- calc_root_hash = verify_inclusion_proof(inclusion_proof, leaf_index, sth["tree_size"], leaf_hash)
-
- root_hash = base64.b64decode(sth["sha256_root_hash"])
- if root_hash != calc_root_hash:
- print "sth"
- print base64.b16encode(root_hash)
- print base64.b16encode(calc_root_hash)
- assert root_hash == calc_root_hash
-
- timing_point(timing, "lookup")
- return (True, timing["deltatimes"])
-
-p = Pool(args.parallel, lambda: signal.signal(signal.SIGINT, signal.SIG_IGN))
-
-sctfile = open(args.sct_file)
-scts = (json.loads(row) for row in sctfile)
-
-nverified = 0
-lastprinted = 0
-
-starttime = datetime.datetime.now()
-
-try:
- for result, timing in p.imap_unordered(verifysct, scts):
- if timing == None:
- print "error"
- print "verified", nverified
- p.terminate()
- p.join()
- sys.exit(1)
- if result != None:
- nverified += 1
- deltatime = datetime.datetime.now() - starttime
- deltatime_f = deltatime.seconds + deltatime.microseconds / 1000000.0
- rate = nverified / deltatime_f
- if nverified > lastprinted + 100:
- print nverified, "rate %.1f" % rate
- lastprinted = nverified
- #print timing, "rate %.1f" % rate
- print "verified", nverified
-except KeyboardInterrupt:
- p.terminate()
- p.join()
diff --git a/tools/verifysecondary.py b/tools/verifysecondary.py
deleted file mode 100755
index 9a36b32..0000000
--- a/tools/verifysecondary.py
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2015, NORDUnet A/S.
-# See LICENSE for licensing information.
-
-import argparse
-import base64
-import sys
-import subprocess
-from certtools import build_merkle_tree
-from mergetools import *
-
-parser = argparse.ArgumentParser(description="")
-parser.add_argument('--mergedb', help="Merge database", required=True)
-parser.add_argument('--verifycert', help="Path to verifycert program", required=True)
-parser.add_argument('--knownroots', help="Path to knownroots directory", required=True)
-args = parser.parse_args()
-
-mergedb = args.mergedb
-chainsdir = mergedb + "/chains"
-logorderfile = mergedb + "/logorder"
-
-verifycert = subprocess.Popen([args.verifycert, args.knownroots],
- stdin=subprocess.PIPE, stdout=subprocess.PIPE)
-
-logorder = get_logorder(logorderfile)
-
-for hash in logorder:
- entry = read_chain(chainsdir, hash)
- verify_entry(verifycert, entry, hash)
-
-tree = build_merkle_tree(logorder)
-root_hash = tree[-1][0]
-
-print base64.b16encode(root_hash)
diff --git a/tools/verifysecondary.sh b/tools/verifysecondary.sh
deleted file mode 100755
index 4a90543..0000000
--- a/tools/verifysecondary.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-
-cd $(dirname $0)/../catlfish
-../tools/verifysecondary.py --mergedb="$1" --verifycert=../verifycert.erl --knownroots=../tools/testcerts/roots/