From 6402eeefc18c47b7dceea5e0dda0b8aeec6719bd Mon Sep 17 00:00:00 2001 From: Magnus Ahltorp Date: Fri, 10 Apr 2015 15:42:03 +0200 Subject: Verify SSL certificates and hostnames in python code Closes CATLFISH-34 --- Makefile | 22 +++++++++++----------- tools/certtools.py | 23 ++++++++++++++++------- tools/fetchallcerts.py | 3 +++ tools/merge.py | 4 +++- tools/submitcert.py | 3 +++ tools/testcase1.py | 3 +++ tools/verifysct.py | 3 +++ 7 files changed, 42 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index 909aa52..51500aa 100644 --- a/Makefile +++ b/Makefile @@ -59,7 +59,7 @@ tests-start: allstarted=1 ; \ notstarted= ; \ for testurl in $(TESTURLS); do \ - if curl -s -k -4 https://$$testurl > /dev/null ; then : ; else allstarted=0 ; notstarted="$$testurl $$notstarted" ; fi ; \ + if curl -s --cacert $(INSTDIR)/tests/httpsca/demoCA/cacert.pem -4 https://$$testurl > /dev/null ; then : ; else allstarted=0 ; notstarted="$$testurl $$notstarted" ; fi ; \ : ; \ done ; \ if [ $$allstarted -eq 1 ]; then break ; \ @@ -67,20 +67,20 @@ tests-start: done tests-run: - @(cd $(INSTDIR) && python ../tools/testcase1.py https://localhost:8080/ tests/keys/logkey.pem) || (echo "Tests failed" ; false) - @(cd $(INSTDIR) && python ../tools/fetchallcerts.py $(BASEURL) --publickey=tests/keys/logkey.pem) || (echo "Verification failed" ; false) + @(cd $(INSTDIR) && python ../tools/testcase1.py https://localhost:8080/ tests/keys/logkey.pem tests/httpsca/demoCA/cacert.pem) || (echo "Tests failed" ; false) + @(cd $(INSTDIR) && python ../tools/fetchallcerts.py $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Verification failed" ; false) @(cd $(INSTDIR) && rm -f submittedcerts) - @(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert1.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem) || (echo "Submission failed" ; false) - @(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert2.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem) || (echo "Submission failed" ; false) - @(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert3.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem) || (echo "Submission failed" ; false) - @(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert4.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem) || (echo "Submission failed" ; false) - @(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert5.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem) || (echo "Submission failed" ; false) - @(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/pre1.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem) || (echo "Submission failed" ; false) - @(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/pre2.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem) || (echo "Submission failed" ; false) + @(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert1.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false) + @(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert2.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false) + @(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert3.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false) + @(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert4.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false) + @(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert5.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false) + @(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/pre1.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false) + @(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/pre2.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false) @(cd $(INSTDIR) && python ../tools/merge.py --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-merge.cfg) || (echo "Merge failed" ; false) tests-run2: - @(cd $(INSTDIR) ; python ../tools/verifysct.py --sct-file=submittedcerts --parallel 1 $(BASEURL) --publickey=tests/keys/logkey.pem) || echo "Verification of SCT:s failed" + @(cd $(INSTDIR) ; python ../tools/verifysct.py --sct-file=submittedcerts --parallel 1 $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || echo "Verification of SCT:s failed" tests-stop: @for node in $(NODES); do \ diff --git a/tools/certtools.py b/tools/certtools.py index 498a2e0..405aabd 100644 --- a/tools/certtools.py +++ b/tools/certtools.py @@ -88,12 +88,24 @@ def get_root_cert(issuer): return root_cert -def urlopen(url, data=None): +class sslparameters: + sslcontext = None + +def create_ssl_context(cafile=None): try: - opener = urllib2.build_opener(urllib2.HTTPSHandler(context=ssl.SSLContext(ssl.PROTOCOL_TLSv1))) + sslparameters.sslcontext = ssl.create_default_context(cafile=cafile) except AttributeError: + sslparameters.sslcontext = None + +def get_opener(): + try: + opener = urllib2.build_opener(urllib2.HTTPSHandler(context=sslparameters.sslcontext)) + except TypeError: opener = urllib2.build_opener(urllib2.HTTPSHandler()) - return opener.open(url, data) + return opener + +def urlopen(url, data=None): + return get_opener().open(url, data) def get_sth(baseurl): result = urlopen(baseurl + "ct/v1/get-sth").read() @@ -238,10 +250,7 @@ def check_auth_header(authheader, expected_key, publickeydir, data, path): return True def http_request(url, data=None, key=None, verifynode=None, publickeydir="."): - try: - opener = urllib2.build_opener(urllib2.HTTPSHandler(context=ssl.SSLContext(ssl.PROTOCOL_TLSv1))) - except AttributeError: - opener = urllib2.build_opener(urllib2.HTTPSHandler()) + opener = get_opener() (keyname, keyfile) = key privatekey = get_eckey_from_file(keyfile) diff --git a/tools/fetchallcerts.py b/tools/fetchallcerts.py index 395fe69..943759e 100755 --- a/tools/fetchallcerts.py +++ b/tools/fetchallcerts.py @@ -23,8 +23,11 @@ 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('--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): diff --git a/tools/merge.py b/tools/merge.py index ce3bf0b..c9d73fb 100755 --- a/tools/merge.py +++ b/tools/merge.py @@ -20,7 +20,8 @@ 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 + get_public_key_from_file, get_leaf_hash, decode_certificate_chain, \ + create_ssl_context parser = argparse.ArgumentParser(description="") parser.add_argument('--config', help="System configuration", required=True) @@ -39,6 +40,7 @@ paths = localconfig["paths"] mergedb = paths["mergedb"] signingnodes = config["signingnodes"] +create_ssl_context(cafile=paths["https_cacertfile"]) chainsdir = mergedb + "/chains" logorderfile = mergedb + "/logorder" diff --git a/tools/submitcert.py b/tools/submitcert.py index ba4b337..663dd50 100755 --- a/tools/submitcert.py +++ b/tools/submitcert.py @@ -31,8 +31,11 @@ parser.add_argument('--parallel', type=int, default=16, metavar="n", help="Numbe 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 diff --git a/tools/testcase1.py b/tools/testcase1.py index 1d46230..c1100ea 100755 --- a/tools/testcase1.py +++ b/tools/testcase1.py @@ -16,6 +16,7 @@ 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", @@ -27,6 +28,8 @@ 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 = "" diff --git a/tools/verifysct.py b/tools/verifysct.py index 4b8e38a..71ea4e9 100755 --- a/tools/verifysct.py +++ b/tools/verifysct.py @@ -23,8 +23,11 @@ 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 -- cgit v1.1