2013-05-28 12:33:57 -07:00
#!/usr/bin/env python
2012-05-21 04:12:37 -07:00
# 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/.
2008-09-05 06:35:58 -07:00
2013-05-28 12:33:57 -07:00
# 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
2008-09-05 06:35:58 -07:00
import os
2013-05-29 17:17:32 -07:00
import random
2008-09-05 06:35:58 -07:00
import re
2008-10-21 08:50:38 -07:00
import shutil
2013-05-28 12:33:57 -07:00
import subprocess
2008-09-05 06:35:58 -07:00
import sys
2013-05-28 12:33:57 -07:00
import tempfile
2008-09-05 06:35:58 -07:00
2013-05-28 12:33:57 -07:00
from mozbuild . base import MozbuildObject
from mozfile import NamedTemporaryFile
from mozprofile . permissions import ServerLocations
2010-01-15 09:22:54 -08:00
2008-09-05 06:35:58 -07:00
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 ) )
2008-10-21 08:50:38 -07:00
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
2008-09-05 06:35:58 -07:00
def runUtil ( util , args , inputdata = None ) :
2013-05-28 12:33:57 -07:00
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
2008-09-05 06:35:58 -07:00
def createRandomFile ( randomFile ) :
for count in xrange ( 0 , 2048 ) :
2013-05-29 17:17:32 -07:00
randomFile . write ( chr ( random . randint ( 0 , 255 ) ) )
2008-09-05 06:35:58 -07:00
2013-05-28 12:33:57 -07:00
def createCertificateAuthority ( build , srcDir ) :
certutil = build . get_binary_path ( what = " certutil " )
pk12util = build . get_binary_path ( what = " pk12util " )
2008-09-05 06:35:58 -07:00
2013-05-28 12:33:57 -07:00
#TODO: mozfile.TemporaryDirectory
tempDbDir = tempfile . mkdtemp ( )
2013-05-29 17:17:32 -07:00
with NamedTemporaryFile ( ) as pwfile , NamedTemporaryFile ( ) as rndfile :
pgoCAModulePathSrc = os . path . join ( srcDir , " pgoca.p12 " )
pgoCAPathSrc = os . path . join ( srcDir , " pgoca.ca " )
2008-09-05 06:35:58 -07:00
2013-05-29 17:17:32 -07:00
pwfile . write ( " \n " )
# Create temporary certification database for CA generation
status = runUtil ( certutil , [ " -N " , " -d " , tempDbDir , " -f " , pwfile . name ] )
2013-05-28 12:33:57 -07:00
if status :
2008-10-21 08:50:38 -07:00
return status
2013-05-29 17:17:32 -07:00
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 \n 0 \n N \n " )
2013-05-28 12:33:57 -07:00
if status :
2008-10-21 08:50:38 -07:00
return status
2008-09-05 06:35:58 -07:00
2013-05-29 17:17:32 -07:00
status = runUtil ( certutil , [ " -L " , " -d " , tempDbDir , " -n " , " pgo temporary ca " , " -a " , " -o " , pgoCAPathSrc , " -f " , pwfile . name ] )
2013-05-28 12:33:57 -07:00
if status :
2008-09-05 06:35:58 -07:00
return status
2013-05-29 17:17:32 -07:00
status = runUtil ( pk12util , [ " -o " , pgoCAModulePathSrc , " -n " , " pgo temporary ca " , " -d " , tempDbDir , " -w " , pwfile . name , " -k " , pwfile . name ] )
2013-05-28 12:33:57 -07:00
if status :
2013-05-29 17:17:32 -07:00
return status
2013-05-28 12:33:57 -07:00
shutil . rmtree ( tempDbDir )
2013-05-29 17:17:32 -07:00
return 0
2013-05-28 12:33:57 -07:00
def createSSLServerCertificate ( build , srcDir ) :
certutil = build . get_binary_path ( what = " certutil " )
pk12util = build . get_binary_path ( what = " pk12util " )
2013-05-29 17:17:32 -07:00
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 ] )
2013-05-28 12:33:57 -07:00
if status :
2013-05-29 17:17:32 -07:00
return status
status = runUtil ( pk12util , [ " -i " , pgoCAPath , " -w " , pwfile . name , " -d " , srcDir , " -k " , pwfile . name ] )
2013-05-28 12:33:57 -07:00
if status :
2013-05-29 17:17:32 -07:00
return status
# Generate automatic certificate
2013-05-28 12:33:57 -07:00
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 ( )
2013-05-29 17:17:32 -07:00
locationsParam = " "
firstLocation = " "
2013-05-28 12:33:57 -07:00
for loc in iterator :
2013-05-29 17:17:32 -07:00
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
2013-05-28 12:33:57 -07:00
if not firstLocation :
2013-05-29 17:17:32 -07:00
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 ] )
2013-05-28 12:33:57 -07:00
if status :
2013-05-29 17:17:32 -07:00
return status
2008-09-05 06:35:58 -07:00
return 0
if len ( sys . argv ) == 1 :
print " Specify --gen-server or --gen-ca "
sys . exit ( 1 )
2013-05-28 12:33:57 -07:00
build = MozbuildObject . from_environment ( )
certdir = os . path . join ( build . topsrcdir , " build " , " pgo " , " certs " )
2008-09-05 06:35:58 -07:00
if sys . argv [ 1 ] == " --gen-server " :
2013-05-28 12:33:57 -07:00
certificateStatus = createSSLServerCertificate ( build , certdir )
if certificateStatus :
2009-02-10 14:05:27 -08:00
print " TEST-UNEXPECTED-FAIL | SSL Server Certificate generation "
2013-05-29 17:17:32 -07:00
2008-09-05 06:35:58 -07:00
sys . exit ( certificateStatus )
2013-05-29 17:17:32 -07:00
2008-09-05 06:35:58 -07:00
if sys . argv [ 1 ] == " --gen-ca " :
2013-05-28 12:33:57 -07:00
certificateStatus = createCertificateAuthority ( build , certdir )
if certificateStatus :
2009-02-10 14:05:27 -08:00
print " TEST-UNEXPECTED-FAIL | Certificate Authority generation "
2008-09-05 06:35:58 -07:00
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 )