(root)/
Python-3.12.0/
Lib/
test/
make_ssl_certs.py
       1  """Make the custom certificate and private key files used by test_ssl
       2  and friends."""
       3  
       4  import os
       5  import pprint
       6  import shutil
       7  import tempfile
       8  from subprocess import *
       9  
      10  startdate = "20180829142316Z"
      11  enddate = "20371028142316Z"
      12  
      13  req_template = """
      14      [ default ]
      15      base_url               = http://testca.pythontest.net/testca
      16  
      17      [req]
      18      distinguished_name     = req_distinguished_name
      19      prompt                 = no
      20  
      21      [req_distinguished_name]
      22      C                      = XY
      23      L                      = Castle Anthrax
      24      O                      = Python Software Foundation
      25      CN                     = {hostname}
      26  
      27      [req_x509_extensions_nosan]
      28  
      29      [req_x509_extensions_simple]
      30      subjectAltName         = @san
      31  
      32      [req_x509_extensions_full]
      33      subjectAltName         = @san
      34      keyUsage               = critical,keyEncipherment,digitalSignature
      35      extendedKeyUsage       = serverAuth,clientAuth
      36      basicConstraints       = critical,CA:false
      37      subjectKeyIdentifier   = hash
      38      authorityKeyIdentifier = keyid:always,issuer:always
      39      authorityInfoAccess    = @issuer_ocsp_info
      40      crlDistributionPoints  = @crl_info
      41  
      42      [ issuer_ocsp_info ]
      43      caIssuers;URI.0        = $base_url/pycacert.cer
      44      OCSP;URI.0             = $base_url/ocsp/
      45  
      46      [ crl_info ]
      47      URI.0                  = $base_url/revocation.crl
      48  
      49      [san]
      50      DNS.1 = {hostname}
      51      {extra_san}
      52  
      53      [dir_sect]
      54      C                      = XY
      55      L                      = Castle Anthrax
      56      O                      = Python Software Foundation
      57      CN                     = dirname example
      58  
      59      [princ_name]
      60      realm = EXP:0, GeneralString:KERBEROS.REALM
      61      principal_name = EXP:1, SEQUENCE:principal_seq
      62  
      63      [principal_seq]
      64      name_type = EXP:0, INTEGER:1
      65      name_string = EXP:1, SEQUENCE:principals
      66  
      67      [principals]
      68      princ1 = GeneralString:username
      69  
      70      [ ca ]
      71      default_ca      = CA_default
      72  
      73      [ CA_default ]
      74      dir = cadir
      75      database  = $dir/index.txt
      76      crlnumber = $dir/crl.txt
      77      default_md = sha256
      78      startdate = {startdate}
      79      default_startdate = {startdate}
      80      enddate = {enddate}
      81      default_enddate = {enddate}
      82      default_days = 7000
      83      default_crl_days = 7000
      84      certificate = pycacert.pem
      85      private_key = pycakey.pem
      86      serial    = $dir/serial
      87      RANDFILE  = $dir/.rand
      88      policy          = policy_match
      89  
      90      [ policy_match ]
      91      countryName             = match
      92      stateOrProvinceName     = optional
      93      organizationName        = match
      94      organizationalUnitName  = optional
      95      commonName              = supplied
      96      emailAddress            = optional
      97  
      98      [ policy_anything ]
      99      countryName   = optional
     100      stateOrProvinceName = optional
     101      localityName    = optional
     102      organizationName  = optional
     103      organizationalUnitName  = optional
     104      commonName    = supplied
     105      emailAddress    = optional
     106  
     107  
     108      [ v3_ca ]
     109  
     110      subjectKeyIdentifier=hash
     111      authorityKeyIdentifier=keyid:always,issuer
     112      basicConstraints = CA:true
     113  
     114      """
     115  
     116  here = os.path.abspath(os.path.dirname(__file__))
     117  
     118  
     119  def make_cert_key(hostname, sign=False, extra_san='',
     120                    ext='req_x509_extensions_full', key='rsa:3072'):
     121      print("creating cert for " + hostname)
     122      tempnames = []
     123      for i in range(3):
     124          with tempfile.NamedTemporaryFile(delete=False) as f:
     125              tempnames.append(f.name)
     126      req_file, cert_file, key_file = tempnames
     127      try:
     128          req = req_template.format(
     129              hostname=hostname,
     130              extra_san=extra_san,
     131              startdate=startdate,
     132              enddate=enddate
     133          )
     134          with open(req_file, 'w') as f:
     135              f.write(req)
     136          args = ['req', '-new', '-nodes', '-days', '7000',
     137                  '-newkey', key, '-keyout', key_file,
     138                  '-extensions', ext,
     139                  '-config', req_file]
     140          if sign:
     141              with tempfile.NamedTemporaryFile(delete=False) as f:
     142                  tempnames.append(f.name)
     143                  reqfile = f.name
     144              args += ['-out', reqfile ]
     145  
     146          else:
     147              args += ['-x509', '-out', cert_file ]
     148          check_call(['openssl'] + args)
     149  
     150          if sign:
     151              args = [
     152                  'ca',
     153                  '-config', req_file,
     154                  '-extensions', ext,
     155                  '-out', cert_file,
     156                  '-outdir', 'cadir',
     157                  '-policy', 'policy_anything',
     158                  '-batch', '-infiles', reqfile
     159              ]
     160              check_call(['openssl'] + args)
     161  
     162  
     163          with open(cert_file, 'r') as f:
     164              cert = f.read()
     165          with open(key_file, 'r') as f:
     166              key = f.read()
     167          return cert, key
     168      finally:
     169          for name in tempnames:
     170              os.remove(name)
     171  
     172  TMP_CADIR = 'cadir'
     173  
     174  def unmake_ca():
     175      shutil.rmtree(TMP_CADIR)
     176  
     177  def make_ca():
     178      os.mkdir(TMP_CADIR)
     179      with open(os.path.join('cadir','index.txt'),'a+') as f:
     180          pass # empty file
     181      with open(os.path.join('cadir','crl.txt'),'a+') as f:
     182          f.write("00")
     183      with open(os.path.join('cadir','index.txt.attr'),'w+') as f:
     184          f.write('unique_subject = no')
     185      # random start value for serial numbers
     186      with open(os.path.join('cadir','serial'), 'w') as f:
     187          f.write('CB2D80995A69525B\n')
     188  
     189      with tempfile.NamedTemporaryFile("w") as t:
     190          req = req_template.format(
     191              hostname='our-ca-server',
     192              extra_san='',
     193              startdate=startdate,
     194              enddate=enddate
     195          )
     196          t.write(req)
     197          t.flush()
     198          with tempfile.NamedTemporaryFile() as f:
     199              args = ['req', '-config', t.name, '-new',
     200                      '-nodes',
     201                      '-newkey', 'rsa:3072',
     202                      '-keyout', 'pycakey.pem',
     203                      '-out', f.name,
     204                      '-subj', '/C=XY/L=Castle Anthrax/O=Python Software Foundation CA/CN=our-ca-server']
     205              check_call(['openssl'] + args)
     206              args = ['ca', '-config', t.name,
     207                      '-out', 'pycacert.pem', '-batch', '-outdir', TMP_CADIR,
     208                      '-keyfile', 'pycakey.pem',
     209                      '-selfsign', '-extensions', 'v3_ca', '-infiles', f.name ]
     210              check_call(['openssl'] + args)
     211              args = ['ca', '-config', t.name, '-gencrl', '-out', 'revocation.crl']
     212              check_call(['openssl'] + args)
     213  
     214      # capath hashes depend on subject!
     215      check_call([
     216          'openssl', 'x509', '-in', 'pycacert.pem', '-out', 'capath/ceff1710.0'
     217      ])
     218      shutil.copy('capath/ceff1710.0', 'capath/b1930218.0')
     219  
     220  
     221  def print_cert(path):
     222      import _ssl
     223      pprint.pprint(_ssl._test_decode_cert(path))
     224  
     225  
     226  if __name__ == '__main__':
     227      os.chdir(here)
     228      cert, key = make_cert_key('localhost', ext='req_x509_extensions_simple')
     229      with open('ssl_cert.pem', 'w') as f:
     230          f.write(cert)
     231      with open('ssl_key.pem', 'w') as f:
     232          f.write(key)
     233      print("password protecting ssl_key.pem in ssl_key.passwd.pem")
     234      check_call(['openssl','pkey','-in','ssl_key.pem','-out','ssl_key.passwd.pem','-aes256','-passout','pass:somepass'])
     235      check_call(['openssl','pkey','-in','ssl_key.pem','-out','keycert.passwd.pem','-aes256','-passout','pass:somepass'])
     236  
     237      with open('keycert.pem', 'w') as f:
     238          f.write(key)
     239          f.write(cert)
     240  
     241      with open('keycert.passwd.pem', 'a+') as f:
     242          f.write(cert)
     243  
     244      # For certificate matching tests
     245      make_ca()
     246      cert, key = make_cert_key('fakehostname', ext='req_x509_extensions_simple')
     247      with open('keycert2.pem', 'w') as f:
     248          f.write(key)
     249          f.write(cert)
     250  
     251      cert, key = make_cert_key('localhost', sign=True)
     252      with open('keycert3.pem', 'w') as f:
     253          f.write(key)
     254          f.write(cert)
     255  
     256      cert, key = make_cert_key('fakehostname', sign=True)
     257      with open('keycert4.pem', 'w') as f:
     258          f.write(key)
     259          f.write(cert)
     260  
     261      cert, key = make_cert_key(
     262          'localhost-ecc', sign=True, key='param:secp384r1.pem'
     263      )
     264      with open('keycertecc.pem', 'w') as f:
     265          f.write(key)
     266          f.write(cert)
     267  
     268      extra_san = [
     269          'otherName.1 = 1.2.3.4;UTF8:some other identifier',
     270          'otherName.2 = 1.3.6.1.5.2.2;SEQUENCE:princ_name',
     271          'email.1 = user@example.org',
     272          'DNS.2 = www.example.org',
     273          # GEN_X400
     274          'dirName.1 = dir_sect',
     275          # GEN_EDIPARTY
     276          'URI.1 = https://www.python.org/',
     277          'IP.1 = 127.0.0.1',
     278          'IP.2 = ::1',
     279          'RID.1 = 1.2.3.4.5',
     280      ]
     281  
     282      cert, key = make_cert_key('allsans', sign=True, extra_san='\n'.join(extra_san))
     283      with open('allsans.pem', 'w') as f:
     284          f.write(key)
     285          f.write(cert)
     286  
     287      extra_san = [
     288          # könig (king)
     289          'DNS.2 = xn--knig-5qa.idn.pythontest.net',
     290          # königsgäßchen (king's alleyway)
     291          'DNS.3 = xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
     292          'DNS.4 = xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
     293          # βόλοσ (marble)
     294          'DNS.5 = xn--nxasmq6b.idna2003.pythontest.net',
     295          'DNS.6 = xn--nxasmm1c.idna2008.pythontest.net',
     296      ]
     297  
     298      # IDN SANS, signed
     299      cert, key = make_cert_key('idnsans', sign=True, extra_san='\n'.join(extra_san))
     300      with open('idnsans.pem', 'w') as f:
     301          f.write(key)
     302          f.write(cert)
     303  
     304      cert, key = make_cert_key('nosan', sign=True, ext='req_x509_extensions_nosan')
     305      with open('nosan.pem', 'w') as f:
     306          f.write(key)
     307          f.write(cert)
     308  
     309      unmake_ca()
     310      print("update Lib/test/test_ssl.py and Lib/test/test_asyncio/utils.py")
     311      print_cert('keycert.pem')
     312      print_cert('keycert3.pem')