From 6402eeefc18c47b7dceea5e0dda0b8aeec6719bd Mon Sep 17 00:00:00 2001
From: Magnus Ahltorp <map@kth.se>
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