2 # This Source Code Form is subject to the terms of the Mozilla Public
3 # License, v. 2.0. If a copy of the MPL was not distributed with this
4 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 # This script exists to generate the Certificate Authority and server
7 # certificates used for SSL testing in Mochitest. The already generated
8 # certs are located at $topsrcdir/build/pgo/certs/ .
19 from mozbuild
.base
import MozbuildObject
20 from mozfile
import NamedTemporaryFile
21 from mozprofile
.permissions
import ServerLocations
24 re
.compile("^cert[0-9]+\.db$"),
25 re
.compile("^key[0-9]+\.db$"),
26 re
.compile("^secmod\.db$")
29 def unlinkDbFiles(path
):
30 for root
, dirs
, files
in os
.walk(path
):
32 for dbFile
in dbFiles
:
33 if dbFile
.match(name
) and os
.path
.exists(os
.path
.join(root
, name
)):
34 os
.unlink(os
.path
.join(root
, name
))
36 def dbFilesExist(path
):
37 for root
, dirs
, files
in os
.walk(path
):
39 for dbFile
in dbFiles
:
40 if dbFile
.match(name
) and os
.path
.exists(os
.path
.join(root
, name
)):
45 def runUtil(util
, args
, inputdata
= None):
46 env
= os
.environ
.copy()
47 if mozinfo
.os
== "linux":
48 pathvar
= "LD_LIBRARY_PATH"
49 app_path
= os
.path
.dirname(util
)
51 env
[pathvar
] = "%s%s%s" % (app_path
, os
.pathsep
, env
[pathvar
])
53 env
[pathvar
] = app_path
54 proc
= subprocess
.Popen([util
] + args
, env
=env
,
55 stdin
=subprocess
.PIPE
if inputdata
else None)
56 proc
.communicate(inputdata
)
57 return proc
.returncode
60 def createRandomFile(randomFile
):
61 for count
in xrange(0, 2048):
62 randomFile
.write(chr(random
.randint(0, 255)))
65 def createCertificateAuthority(build
, srcDir
):
66 certutil
= build
.get_binary_path(what
="certutil")
67 pk12util
= build
.get_binary_path(what
="pk12util")
69 #TODO: mozfile.TemporaryDirectory
70 tempDbDir
= tempfile
.mkdtemp()
71 with
NamedTemporaryFile() as pwfile
, NamedTemporaryFile() as rndfile
:
72 pgoCAModulePathSrc
= os
.path
.join(srcDir
, "pgoca.p12")
73 pgoCAPathSrc
= os
.path
.join(srcDir
, "pgoca.ca")
77 # Create temporary certification database for CA generation
78 status
= runUtil(certutil
, ["-N", "-d", tempDbDir
, "-f", pwfile
.name
])
82 createRandomFile(rndfile
)
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")
87 status
= runUtil(certutil
, ["-L", "-d", tempDbDir
, "-n", "pgo temporary ca", "-a", "-o", pgoCAPathSrc
, "-f", pwfile
.name
])
91 status
= runUtil(pk12util
, ["-o", pgoCAModulePathSrc
, "-n", "pgo temporary ca", "-d", tempDbDir
, "-w", pwfile
.name
, "-k", pwfile
.name
])
95 shutil
.rmtree(tempDbDir
)
99 def createSSLServerCertificate(build
, srcDir
):
100 certutil
= build
.get_binary_path(what
="certutil")
101 pk12util
= build
.get_binary_path(what
="pk12util")
103 with
NamedTemporaryFile() as pwfile
, NamedTemporaryFile() as rndfile
:
104 pgoCAPath
= os
.path
.join(srcDir
, "pgoca.p12")
108 if not dbFilesExist(srcDir
):
109 # Make sure all DB files from src are really deleted
110 unlinkDbFiles(srcDir
)
112 # Create certification database for ssltunnel
113 status
= runUtil(certutil
, ["-N", "-d", srcDir
, "-f", pwfile
.name
])
117 status
= runUtil(pk12util
, ["-i", pgoCAPath
, "-w", pwfile
.name
, "-d", srcDir
, "-k", pwfile
.name
])
121 # Generate automatic certificate
122 locations
= ServerLocations(os
.path
.join(build
.topsrcdir
,
124 "server-locations.txt"))
125 iterator
= iter(locations
)
127 # Skips the first entry, I don't know why: bug 879740
133 if loc
.scheme
== "https" and "nocert" not in loc
.options
:
134 customCertOption
= False
135 customCertRE
= re
.compile("^cert=(?:\w+)")
136 for option
in loc
.options
:
137 match
= customCertRE
.match(option
)
139 customCertOption
= True
142 if not customCertOption
:
143 if len(locationsParam
) > 0:
144 locationsParam
+= ","
145 locationsParam
+= loc
.host
147 if firstLocation
== "":
148 firstLocation
= loc
.host
150 if not firstLocation
:
151 print "Nothing to generate, no automatic secure hosts specified"
153 createRandomFile(rndfile
)
155 runUtil(certutil
, ["-D", "-n", "pgo server certificate", "-d", srcDir
, "-z", rndfile
.name
, "-f", pwfile
.name
])
156 # Ignore the result, the certificate may not be present when new database is being built
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
])
164 if len(sys
.argv
) == 1:
165 print "Specify --gen-server or --gen-ca"
168 build
= MozbuildObject
.from_environment()
169 certdir
= os
.path
.join(build
.topsrcdir
, "build", "pgo", "certs")
170 if sys
.argv
[1] == "--gen-server":
171 certificateStatus
= createSSLServerCertificate(build
, certdir
)
172 if certificateStatus
:
173 print "TEST-UNEXPECTED-FAIL | SSL Server Certificate generation"
175 sys
.exit(certificateStatus
)
177 if sys
.argv
[1] == "--gen-ca":
178 certificateStatus
= createCertificateAuthority(build
, certdir
)
179 if certificateStatus
:
180 print "TEST-UNEXPECTED-FAIL | Certificate Authority generation"
183 print "==================================================="
185 print " To use this new certificate authority in tests"
186 print " run 'make' at testing/mochitest"
187 print "==================================================="
189 sys
.exit(certificateStatus
)
191 print "Invalid option specified"