diff options
Diffstat (limited to 'build/pgo/genpgocert.py')
-rw-r--r-- | build/pgo/genpgocert.py | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/build/pgo/genpgocert.py b/build/pgo/genpgocert.py new file mode 100644 index 0000000000..c58bcd40d6 --- /dev/null +++ b/build/pgo/genpgocert.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# This script exists to generate the Certificate Authority and server +# certificates used for SSL testing in Mochitest. The already generated +# certs are located at $topsrcdir/build/pgo/certs/ . + +import mozinfo +import os +import random +import re +import shutil +import subprocess +import sys +import tempfile + +from mozbuild.base import MozbuildObject +from mozfile import NamedTemporaryFile +from mozprofile.permissions import ServerLocations + +dbFiles = [ + re.compile("^cert[0-9]+\.db$"), + re.compile("^key[0-9]+\.db$"), + re.compile("^secmod\.db$") +] + +def unlinkDbFiles(path): + for root, dirs, files in os.walk(path): + for name in files: + for dbFile in dbFiles: + if dbFile.match(name) and os.path.exists(os.path.join(root, name)): + os.unlink(os.path.join(root, name)) + +def dbFilesExist(path): + for root, dirs, files in os.walk(path): + for name in files: + for dbFile in dbFiles: + if dbFile.match(name) and os.path.exists(os.path.join(root, name)): + return True + return False + + +def runUtil(util, args, inputdata = None): + env = os.environ.copy() + if mozinfo.os == "linux": + pathvar = "LD_LIBRARY_PATH" + app_path = os.path.dirname(util) + if pathvar in env: + env[pathvar] = "%s%s%s" % (app_path, os.pathsep, env[pathvar]) + else: + env[pathvar] = app_path + proc = subprocess.Popen([util] + args, env=env, + stdin=subprocess.PIPE if inputdata else None) + proc.communicate(inputdata) + return proc.returncode + + +def createRandomFile(randomFile): + for count in xrange(0, 2048): + randomFile.write(chr(random.randint(0, 255))) + + +def createCertificateAuthority(build, srcDir): + certutil = build.get_binary_path(what="certutil") + pk12util = build.get_binary_path(what="pk12util") + + #TODO: mozfile.TemporaryDirectory + tempDbDir = tempfile.mkdtemp() + with NamedTemporaryFile() as pwfile, NamedTemporaryFile() as rndfile: + pgoCAModulePathSrc = os.path.join(srcDir, "pgoca.p12") + pgoCAPathSrc = os.path.join(srcDir, "pgoca.ca") + + pwfile.write("\n") + + # Create temporary certification database for CA generation + status = runUtil(certutil, ["-N", "-d", tempDbDir, "-f", pwfile.name]) + if status: + return status + + createRandomFile(rndfile) + 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") + if status: + return status + + status = runUtil(certutil, ["-L", "-d", tempDbDir, "-n", "pgo temporary ca", "-a", "-o", pgoCAPathSrc, "-f", pwfile.name]) + if status: + return status + + status = runUtil(pk12util, ["-o", pgoCAModulePathSrc, "-n", "pgo temporary ca", "-d", tempDbDir, "-w", pwfile.name, "-k", pwfile.name]) + if status: + return status + + shutil.rmtree(tempDbDir) + return 0 + + +def createSSLServerCertificate(build, srcDir): + certutil = build.get_binary_path(what="certutil") + pk12util = build.get_binary_path(what="pk12util") + + with NamedTemporaryFile() as pwfile, NamedTemporaryFile() as rndfile: + pgoCAPath = os.path.join(srcDir, "pgoca.p12") + + pwfile.write("\n") + + if not dbFilesExist(srcDir): + # Make sure all DB files from src are really deleted + unlinkDbFiles(srcDir) + + # Create certification database for ssltunnel + status = runUtil(certutil, ["-N", "-d", srcDir, "-f", pwfile.name]) + if status: + return status + + status = runUtil(pk12util, ["-i", pgoCAPath, "-w", pwfile.name, "-d", srcDir, "-k", pwfile.name]) + if status: + return status + + # Generate automatic certificate + locations = ServerLocations(os.path.join(build.topsrcdir, + "build", "pgo", + "server-locations.txt")) + iterator = iter(locations) + + # Skips the first entry, I don't know why: bug 879740 + iterator.next() + + locationsParam = "" + firstLocation = "" + for loc in iterator: + if loc.scheme == "https" and "nocert" not in loc.options: + customCertOption = False + customCertRE = re.compile("^cert=(?:\w+)") + for option in loc.options: + match = customCertRE.match(option) + if match: + customCertOption = True + break + + if not customCertOption: + if len(locationsParam) > 0: + locationsParam += "," + locationsParam += loc.host + + if firstLocation == "": + firstLocation = loc.host + + if not firstLocation: + print "Nothing to generate, no automatic secure hosts specified" + else: + createRandomFile(rndfile) + + runUtil(certutil, ["-D", "-n", "pgo server certificate", "-d", srcDir, "-z", rndfile.name, "-f", pwfile.name]) + # Ignore the result, the certificate may not be present when new database is being built + + 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]) + if status: + return status + + return 0 + +if len(sys.argv) == 1: + print "Specify --gen-server or --gen-ca" + sys.exit(1) + +build = MozbuildObject.from_environment() +certdir = os.path.join(build.topsrcdir, "build", "pgo", "certs") +if sys.argv[1] == "--gen-server": + certificateStatus = createSSLServerCertificate(build, certdir) + if certificateStatus: + print "TEST-UNEXPECTED-FAIL | SSL Server Certificate generation" + + sys.exit(certificateStatus) + +if sys.argv[1] == "--gen-ca": + certificateStatus = createCertificateAuthority(build, certdir) + if certificateStatus: + print "TEST-UNEXPECTED-FAIL | Certificate Authority generation" + else: + print "\n\n" + print "===================================================" + print " IMPORTANT:" + print " To use this new certificate authority in tests" + print " run 'make' at testing/mochitest" + print "===================================================" + + sys.exit(certificateStatus) + +print "Invalid option specified" +sys.exit(1) |