build/pgo/genpgocert.py

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 #!/usr/bin/env python
michael@0 2 # This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 5
michael@0 6 # This script exists to generate the Certificate Authority and server
michael@0 7 # certificates used for SSL testing in Mochitest. The already generated
michael@0 8 # certs are located at $topsrcdir/build/pgo/certs/ .
michael@0 9
michael@0 10 import mozinfo
michael@0 11 import os
michael@0 12 import random
michael@0 13 import re
michael@0 14 import shutil
michael@0 15 import subprocess
michael@0 16 import sys
michael@0 17 import tempfile
michael@0 18
michael@0 19 from mozbuild.base import MozbuildObject
michael@0 20 from mozfile import NamedTemporaryFile
michael@0 21 from mozprofile.permissions import ServerLocations
michael@0 22
michael@0 23 dbFiles = [
michael@0 24 re.compile("^cert[0-9]+\.db$"),
michael@0 25 re.compile("^key[0-9]+\.db$"),
michael@0 26 re.compile("^secmod\.db$")
michael@0 27 ]
michael@0 28
michael@0 29 def unlinkDbFiles(path):
michael@0 30 for root, dirs, files in os.walk(path):
michael@0 31 for name in files:
michael@0 32 for dbFile in dbFiles:
michael@0 33 if dbFile.match(name) and os.path.exists(os.path.join(root, name)):
michael@0 34 os.unlink(os.path.join(root, name))
michael@0 35
michael@0 36 def dbFilesExist(path):
michael@0 37 for root, dirs, files in os.walk(path):
michael@0 38 for name in files:
michael@0 39 for dbFile in dbFiles:
michael@0 40 if dbFile.match(name) and os.path.exists(os.path.join(root, name)):
michael@0 41 return True
michael@0 42 return False
michael@0 43
michael@0 44
michael@0 45 def runUtil(util, args, inputdata = None):
michael@0 46 env = os.environ.copy()
michael@0 47 if mozinfo.os == "linux":
michael@0 48 pathvar = "LD_LIBRARY_PATH"
michael@0 49 app_path = os.path.dirname(util)
michael@0 50 if pathvar in env:
michael@0 51 env[pathvar] = "%s%s%s" % (app_path, os.pathsep, env[pathvar])
michael@0 52 else:
michael@0 53 env[pathvar] = app_path
michael@0 54 proc = subprocess.Popen([util] + args, env=env,
michael@0 55 stdin=subprocess.PIPE if inputdata else None)
michael@0 56 proc.communicate(inputdata)
michael@0 57 return proc.returncode
michael@0 58
michael@0 59
michael@0 60 def createRandomFile(randomFile):
michael@0 61 for count in xrange(0, 2048):
michael@0 62 randomFile.write(chr(random.randint(0, 255)))
michael@0 63
michael@0 64
michael@0 65 def createCertificateAuthority(build, srcDir):
michael@0 66 certutil = build.get_binary_path(what="certutil")
michael@0 67 pk12util = build.get_binary_path(what="pk12util")
michael@0 68
michael@0 69 #TODO: mozfile.TemporaryDirectory
michael@0 70 tempDbDir = tempfile.mkdtemp()
michael@0 71 with NamedTemporaryFile() as pwfile, NamedTemporaryFile() as rndfile:
michael@0 72 pgoCAModulePathSrc = os.path.join(srcDir, "pgoca.p12")
michael@0 73 pgoCAPathSrc = os.path.join(srcDir, "pgoca.ca")
michael@0 74
michael@0 75 pwfile.write("\n")
michael@0 76
michael@0 77 # Create temporary certification database for CA generation
michael@0 78 status = runUtil(certutil, ["-N", "-d", tempDbDir, "-f", pwfile.name])
michael@0 79 if status:
michael@0 80 return status
michael@0 81
michael@0 82 createRandomFile(rndfile)
michael@0 83 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")
michael@0 84 if status:
michael@0 85 return status
michael@0 86
michael@0 87 status = runUtil(certutil, ["-L", "-d", tempDbDir, "-n", "pgo temporary ca", "-a", "-o", pgoCAPathSrc, "-f", pwfile.name])
michael@0 88 if status:
michael@0 89 return status
michael@0 90
michael@0 91 status = runUtil(pk12util, ["-o", pgoCAModulePathSrc, "-n", "pgo temporary ca", "-d", tempDbDir, "-w", pwfile.name, "-k", pwfile.name])
michael@0 92 if status:
michael@0 93 return status
michael@0 94
michael@0 95 shutil.rmtree(tempDbDir)
michael@0 96 return 0
michael@0 97
michael@0 98
michael@0 99 def createSSLServerCertificate(build, srcDir):
michael@0 100 certutil = build.get_binary_path(what="certutil")
michael@0 101 pk12util = build.get_binary_path(what="pk12util")
michael@0 102
michael@0 103 with NamedTemporaryFile() as pwfile, NamedTemporaryFile() as rndfile:
michael@0 104 pgoCAPath = os.path.join(srcDir, "pgoca.p12")
michael@0 105
michael@0 106 pwfile.write("\n")
michael@0 107
michael@0 108 if not dbFilesExist(srcDir):
michael@0 109 # Make sure all DB files from src are really deleted
michael@0 110 unlinkDbFiles(srcDir)
michael@0 111
michael@0 112 # Create certification database for ssltunnel
michael@0 113 status = runUtil(certutil, ["-N", "-d", srcDir, "-f", pwfile.name])
michael@0 114 if status:
michael@0 115 return status
michael@0 116
michael@0 117 status = runUtil(pk12util, ["-i", pgoCAPath, "-w", pwfile.name, "-d", srcDir, "-k", pwfile.name])
michael@0 118 if status:
michael@0 119 return status
michael@0 120
michael@0 121 # Generate automatic certificate
michael@0 122 locations = ServerLocations(os.path.join(build.topsrcdir,
michael@0 123 "build", "pgo",
michael@0 124 "server-locations.txt"))
michael@0 125 iterator = iter(locations)
michael@0 126
michael@0 127 # Skips the first entry, I don't know why: bug 879740
michael@0 128 iterator.next()
michael@0 129
michael@0 130 locationsParam = ""
michael@0 131 firstLocation = ""
michael@0 132 for loc in iterator:
michael@0 133 if loc.scheme == "https" and "nocert" not in loc.options:
michael@0 134 customCertOption = False
michael@0 135 customCertRE = re.compile("^cert=(?:\w+)")
michael@0 136 for option in loc.options:
michael@0 137 match = customCertRE.match(option)
michael@0 138 if match:
michael@0 139 customCertOption = True
michael@0 140 break
michael@0 141
michael@0 142 if not customCertOption:
michael@0 143 if len(locationsParam) > 0:
michael@0 144 locationsParam += ","
michael@0 145 locationsParam += loc.host
michael@0 146
michael@0 147 if firstLocation == "":
michael@0 148 firstLocation = loc.host
michael@0 149
michael@0 150 if not firstLocation:
michael@0 151 print "Nothing to generate, no automatic secure hosts specified"
michael@0 152 else:
michael@0 153 createRandomFile(rndfile)
michael@0 154
michael@0 155 runUtil(certutil, ["-D", "-n", "pgo server certificate", "-d", srcDir, "-z", rndfile.name, "-f", pwfile.name])
michael@0 156 # Ignore the result, the certificate may not be present when new database is being built
michael@0 157
michael@0 158 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])
michael@0 159 if status:
michael@0 160 return status
michael@0 161
michael@0 162 return 0
michael@0 163
michael@0 164 if len(sys.argv) == 1:
michael@0 165 print "Specify --gen-server or --gen-ca"
michael@0 166 sys.exit(1)
michael@0 167
michael@0 168 build = MozbuildObject.from_environment()
michael@0 169 certdir = os.path.join(build.topsrcdir, "build", "pgo", "certs")
michael@0 170 if sys.argv[1] == "--gen-server":
michael@0 171 certificateStatus = createSSLServerCertificate(build, certdir)
michael@0 172 if certificateStatus:
michael@0 173 print "TEST-UNEXPECTED-FAIL | SSL Server Certificate generation"
michael@0 174
michael@0 175 sys.exit(certificateStatus)
michael@0 176
michael@0 177 if sys.argv[1] == "--gen-ca":
michael@0 178 certificateStatus = createCertificateAuthority(build, certdir)
michael@0 179 if certificateStatus:
michael@0 180 print "TEST-UNEXPECTED-FAIL | Certificate Authority generation"
michael@0 181 else:
michael@0 182 print "\n\n"
michael@0 183 print "==================================================="
michael@0 184 print " IMPORTANT:"
michael@0 185 print " To use this new certificate authority in tests"
michael@0 186 print " run 'make' at testing/mochitest"
michael@0 187 print "==================================================="
michael@0 188
michael@0 189 sys.exit(certificateStatus)
michael@0 190
michael@0 191 print "Invalid option specified"
michael@0 192 sys.exit(1)

mercurial