1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/build/pgo/genpgocert.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,192 @@ 1.4 +#!/usr/bin/env python 1.5 +# This Source Code Form is subject to the terms of the Mozilla Public 1.6 +# License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 +# file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.8 + 1.9 +# This script exists to generate the Certificate Authority and server 1.10 +# certificates used for SSL testing in Mochitest. The already generated 1.11 +# certs are located at $topsrcdir/build/pgo/certs/ . 1.12 + 1.13 +import mozinfo 1.14 +import os 1.15 +import random 1.16 +import re 1.17 +import shutil 1.18 +import subprocess 1.19 +import sys 1.20 +import tempfile 1.21 + 1.22 +from mozbuild.base import MozbuildObject 1.23 +from mozfile import NamedTemporaryFile 1.24 +from mozprofile.permissions import ServerLocations 1.25 + 1.26 +dbFiles = [ 1.27 + re.compile("^cert[0-9]+\.db$"), 1.28 + re.compile("^key[0-9]+\.db$"), 1.29 + re.compile("^secmod\.db$") 1.30 +] 1.31 + 1.32 +def unlinkDbFiles(path): 1.33 + for root, dirs, files in os.walk(path): 1.34 + for name in files: 1.35 + for dbFile in dbFiles: 1.36 + if dbFile.match(name) and os.path.exists(os.path.join(root, name)): 1.37 + os.unlink(os.path.join(root, name)) 1.38 + 1.39 +def dbFilesExist(path): 1.40 + for root, dirs, files in os.walk(path): 1.41 + for name in files: 1.42 + for dbFile in dbFiles: 1.43 + if dbFile.match(name) and os.path.exists(os.path.join(root, name)): 1.44 + return True 1.45 + return False 1.46 + 1.47 + 1.48 +def runUtil(util, args, inputdata = None): 1.49 + env = os.environ.copy() 1.50 + if mozinfo.os == "linux": 1.51 + pathvar = "LD_LIBRARY_PATH" 1.52 + app_path = os.path.dirname(util) 1.53 + if pathvar in env: 1.54 + env[pathvar] = "%s%s%s" % (app_path, os.pathsep, env[pathvar]) 1.55 + else: 1.56 + env[pathvar] = app_path 1.57 + proc = subprocess.Popen([util] + args, env=env, 1.58 + stdin=subprocess.PIPE if inputdata else None) 1.59 + proc.communicate(inputdata) 1.60 + return proc.returncode 1.61 + 1.62 + 1.63 +def createRandomFile(randomFile): 1.64 + for count in xrange(0, 2048): 1.65 + randomFile.write(chr(random.randint(0, 255))) 1.66 + 1.67 + 1.68 +def createCertificateAuthority(build, srcDir): 1.69 + certutil = build.get_binary_path(what="certutil") 1.70 + pk12util = build.get_binary_path(what="pk12util") 1.71 + 1.72 + #TODO: mozfile.TemporaryDirectory 1.73 + tempDbDir = tempfile.mkdtemp() 1.74 + with NamedTemporaryFile() as pwfile, NamedTemporaryFile() as rndfile: 1.75 + pgoCAModulePathSrc = os.path.join(srcDir, "pgoca.p12") 1.76 + pgoCAPathSrc = os.path.join(srcDir, "pgoca.ca") 1.77 + 1.78 + pwfile.write("\n") 1.79 + 1.80 + # Create temporary certification database for CA generation 1.81 + status = runUtil(certutil, ["-N", "-d", tempDbDir, "-f", pwfile.name]) 1.82 + if status: 1.83 + return status 1.84 + 1.85 + createRandomFile(rndfile) 1.86 + status = runUtil(certutil, ["-S", "-d", tempDbDir, "-s", "CN=Temporary Certificate Authority, O=Mozilla Testing, OU=Profile Guided Optimization", "-t", "C,,", "-x", "-m", "1", "-v", "120", "-n", "pgo temporary ca", "-2", "-f", pwfile.name, "-z", rndfile.name], "Y\n0\nN\n") 1.87 + if status: 1.88 + return status 1.89 + 1.90 + status = runUtil(certutil, ["-L", "-d", tempDbDir, "-n", "pgo temporary ca", "-a", "-o", pgoCAPathSrc, "-f", pwfile.name]) 1.91 + if status: 1.92 + return status 1.93 + 1.94 + status = runUtil(pk12util, ["-o", pgoCAModulePathSrc, "-n", "pgo temporary ca", "-d", tempDbDir, "-w", pwfile.name, "-k", pwfile.name]) 1.95 + if status: 1.96 + return status 1.97 + 1.98 + shutil.rmtree(tempDbDir) 1.99 + return 0 1.100 + 1.101 + 1.102 +def createSSLServerCertificate(build, srcDir): 1.103 + certutil = build.get_binary_path(what="certutil") 1.104 + pk12util = build.get_binary_path(what="pk12util") 1.105 + 1.106 + with NamedTemporaryFile() as pwfile, NamedTemporaryFile() as rndfile: 1.107 + pgoCAPath = os.path.join(srcDir, "pgoca.p12") 1.108 + 1.109 + pwfile.write("\n") 1.110 + 1.111 + if not dbFilesExist(srcDir): 1.112 + # Make sure all DB files from src are really deleted 1.113 + unlinkDbFiles(srcDir) 1.114 + 1.115 + # Create certification database for ssltunnel 1.116 + status = runUtil(certutil, ["-N", "-d", srcDir, "-f", pwfile.name]) 1.117 + if status: 1.118 + return status 1.119 + 1.120 + status = runUtil(pk12util, ["-i", pgoCAPath, "-w", pwfile.name, "-d", srcDir, "-k", pwfile.name]) 1.121 + if status: 1.122 + return status 1.123 + 1.124 + # Generate automatic certificate 1.125 + locations = ServerLocations(os.path.join(build.topsrcdir, 1.126 + "build", "pgo", 1.127 + "server-locations.txt")) 1.128 + iterator = iter(locations) 1.129 + 1.130 + # Skips the first entry, I don't know why: bug 879740 1.131 + iterator.next() 1.132 + 1.133 + locationsParam = "" 1.134 + firstLocation = "" 1.135 + for loc in iterator: 1.136 + if loc.scheme == "https" and "nocert" not in loc.options: 1.137 + customCertOption = False 1.138 + customCertRE = re.compile("^cert=(?:\w+)") 1.139 + for option in loc.options: 1.140 + match = customCertRE.match(option) 1.141 + if match: 1.142 + customCertOption = True 1.143 + break 1.144 + 1.145 + if not customCertOption: 1.146 + if len(locationsParam) > 0: 1.147 + locationsParam += "," 1.148 + locationsParam += loc.host 1.149 + 1.150 + if firstLocation == "": 1.151 + firstLocation = loc.host 1.152 + 1.153 + if not firstLocation: 1.154 + print "Nothing to generate, no automatic secure hosts specified" 1.155 + else: 1.156 + createRandomFile(rndfile) 1.157 + 1.158 + runUtil(certutil, ["-D", "-n", "pgo server certificate", "-d", srcDir, "-z", rndfile.name, "-f", pwfile.name]) 1.159 + # Ignore the result, the certificate may not be present when new database is being built 1.160 + 1.161 + status = runUtil(certutil, ["-S", "-s", "CN=%s" % firstLocation, "-t", "Pu,,", "-c", "pgo temporary ca", "-m", "2", "-8", locationsParam, "-v", "120", "-n", "pgo server certificate", "-d", srcDir, "-z", rndfile.name, "-f", pwfile.name]) 1.162 + if status: 1.163 + return status 1.164 + 1.165 + return 0 1.166 + 1.167 +if len(sys.argv) == 1: 1.168 + print "Specify --gen-server or --gen-ca" 1.169 + sys.exit(1) 1.170 + 1.171 +build = MozbuildObject.from_environment() 1.172 +certdir = os.path.join(build.topsrcdir, "build", "pgo", "certs") 1.173 +if sys.argv[1] == "--gen-server": 1.174 + certificateStatus = createSSLServerCertificate(build, certdir) 1.175 + if certificateStatus: 1.176 + print "TEST-UNEXPECTED-FAIL | SSL Server Certificate generation" 1.177 + 1.178 + sys.exit(certificateStatus) 1.179 + 1.180 +if sys.argv[1] == "--gen-ca": 1.181 + certificateStatus = createCertificateAuthority(build, certdir) 1.182 + if certificateStatus: 1.183 + print "TEST-UNEXPECTED-FAIL | Certificate Authority generation" 1.184 + else: 1.185 + print "\n\n" 1.186 + print "===================================================" 1.187 + print " IMPORTANT:" 1.188 + print " To use this new certificate authority in tests" 1.189 + print " run 'make' at testing/mochitest" 1.190 + print "===================================================" 1.191 + 1.192 + sys.exit(certificateStatus) 1.193 + 1.194 +print "Invalid option specified" 1.195 +sys.exit(1)