genpgocert.py 6.3 KB

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