From 0a76e4d080a8349456d04434dcb2d4b381eb8ec4 Mon Sep 17 00:00:00 2001 From: Magnus Ahltorp Date: Wed, 18 Mar 2015 14:27:18 +0100 Subject: Added precert handling for SCT calculation --- tools/certtools.py | 20 +++++++++++++++----- tools/submitcert.py | 38 +++++++++++++++++++++++++++++--------- tools/verifysct.py | 17 ++++++++++++++--- 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/tools/certtools.py b/tools/certtools.py index 1436863..cc423af 100644 --- a/tools/certtools.py +++ b/tools/certtools.py @@ -257,7 +257,7 @@ def create_sth_signature(tree_size, timestamp, root_hash, baseurl, key=None): return create_signature(baseurl, tree_head, key=key) -def check_sct_signature(baseurl, leafcert, sct): +def check_sct_signature(baseurl, signed_entry, sct, precert=False): publickey = base64.decodestring(publickeys[baseurl]) calculated_logid = hashlib.sha256(publickey).digest() received_logid = base64.decodestring(sct["id"]) @@ -271,9 +271,12 @@ def check_sct_signature(baseurl, leafcert, sct): version = struct.pack(">b", sct["sct_version"]) signature_type = struct.pack(">b", 0) timestamp = struct.pack(">Q", sct["timestamp"]) - entry_type = struct.pack(">H", 0) + if precert: + entry_type = struct.pack(">H", 1) + else: + entry_type = struct.pack(">H", 0) signed_struct = version + signature_type + timestamp + \ - entry_type + tls_array(leafcert, 3) + \ + entry_type + signed_entry + \ tls_array(base64.decodestring(sct["extensions"]), 2) check_signature(baseurl, signature, signed_struct) @@ -292,15 +295,22 @@ def pack_mtl(timestamp, leafcert): def pack_mtl_precert(timestamp, cleanedcert, issuer_key_hash): entry_type = struct.pack(">H", 1) extensions = "" - assert len(issuer_key_hash) == 32 timestamped_entry = struct.pack(">Q", timestamp) + entry_type + \ - issuer_key_hash + tls_array(cleanedcert, 3) + tls_array(extensions, 2) + pack_precert(cleanedcert, issuer_key_hash) + tls_array(extensions, 2) version = struct.pack(">b", 0) leaf_type = struct.pack(">b", 0) merkle_tree_leaf = version + leaf_type + timestamped_entry return merkle_tree_leaf +def pack_precert(cleanedcert, issuer_key_hash): + assert len(issuer_key_hash) == 32 + + return issuer_key_hash + tls_array(cleanedcert, 3) + +def pack_cert(cert): + return tls_array(cert, 3) + def unpack_mtl(merkle_tree_leaf): version = merkle_tree_leaf[0:1] leaf_type = merkle_tree_leaf[1:2] diff --git a/tools/submitcert.py b/tools/submitcert.py index 1c79544..2e8cc33 100755 --- a/tools/submitcert.py +++ b/tools/submitcert.py @@ -13,6 +13,11 @@ import struct import hashlib import itertools from certtools import * +from certtools import * +try: + from precerttools import * +except ImportError: + pass import os import signal import select @@ -51,8 +56,20 @@ def submitcert((certfile, cert)): 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 @@ -67,7 +84,7 @@ def submitcert((certfile, cert)): try: if args.check_sct: - check_sct_signature(baseurl, certchain[0], result) + check_sct_signature(baseurl, signed_entry, result, precert=precert) timing_point(timing, "checksig") except AssertionError, e: print "ERROR:", certfile, e @@ -81,7 +98,7 @@ def submitcert((certfile, cert)): if lookup_in_log: - merkle_tree_leaf = pack_mtl(result["timestamp"], certchain[0]) + merkle_tree_leaf = pack_mtl(result["timestamp"], leafcert) leaf_hash = get_leaf_hash(merkle_tree_leaf) @@ -119,7 +136,7 @@ def submitcert((certfile, cert)): print "and submitted chain has length", len(submittedcertchain) timing_point(timing, "lookup") - return ((certchain[0], result), timing["deltatimes"]) + return ((leafcert, issuer_key_hash, result), timing["deltatimes"]) def get_ncerts(certfiles): n = 0 @@ -142,9 +159,12 @@ def get_all_certificates(certfiles): else: yield (certfile, open(certfile).read()) -def save_sct(sct, sth): +def save_sct(sct, sth, leafcert, issuer_key_hash): sctlog = open(args.sct_file, "a") - json.dump({"leafcert": base64.b64encode(leafcert), "sct": sct, "sth": sth}, sctlog) + 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() @@ -163,8 +183,8 @@ certs = get_all_certificates(certfiles) (result, timing) = submitcert(certs.next()) if result != None: nsubmitted += 1 - (leafcert, sct) = result - save_sct(sct, sth) + (leafcert, issuer_key_hash, sct) = result + save_sct(sct, sth, leafcert, issuer_key_hash) if args.pre_warm: select.select([], [], [], 3.0) @@ -181,8 +201,8 @@ try: sys.exit(1) if result != None: nsubmitted += 1 - (leafcert, sct) = result - save_sct(sct, sth) + (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 diff --git a/tools/verifysct.py b/tools/verifysct.py index 699a0ad..27ab4c9 100755 --- a/tools/verifysct.py +++ b/tools/verifysct.py @@ -34,8 +34,16 @@ 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: - check_sct_signature(baseurl, leafcert, sctentry["sct"]) + 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) timing_point(timing, "checksig") except AssertionError, e: print "ERROR:", e @@ -47,7 +55,10 @@ def verifysct(sctentry): print "ERROR: bad signature" return (None, None) - merkle_tree_leaf = pack_mtl(sctentry["sct"]["timestamp"], leafcert) + 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) @@ -76,7 +87,7 @@ def verifysct(sctentry): 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] +scts = (json.loads(row) for row in sctfile) nverified = 0 lastprinted = 0 -- cgit v1.1