Home | History | Annotate | Download | only in test
      1 """Make the custom certificate and private key files used by test_ssl
      2 and friends."""
      3 
      4 import os
      5 import shutil
      6 import sys
      7 import tempfile
      8 from subprocess import *
      9 
     10 req_template = """
     11     [req]
     12     distinguished_name     = req_distinguished_name
     13     x509_extensions        = req_x509_extensions
     14     prompt                 = no
     15 
     16     [req_distinguished_name]
     17     C                      = XY
     18     L                      = Castle Anthrax
     19     O                      = Python Software Foundation
     20     CN                     = {hostname}
     21 
     22     [req_x509_extensions]
     23     subjectAltName         = @san
     24 
     25     [san]
     26     DNS.1 = {hostname}
     27     {extra_san}
     28 
     29     [dir_sect]
     30     C                      = XY
     31     L                      = Castle Anthrax
     32     O                      = Python Software Foundation
     33     CN                     = dirname example
     34 
     35     [princ_name]
     36     realm = EXP:0, GeneralString:KERBEROS.REALM
     37     principal_name = EXP:1, SEQUENCE:principal_seq
     38 
     39     [principal_seq]
     40     name_type = EXP:0, INTEGER:1
     41     name_string = EXP:1, SEQUENCE:principals
     42 
     43     [principals]
     44     princ1 = GeneralString:username
     45 
     46     [ ca ]
     47     default_ca      = CA_default
     48 
     49     [ CA_default ]
     50     dir = cadir
     51     database  = $dir/index.txt
     52     crlnumber = $dir/crl.txt
     53     default_md = sha1
     54     default_days = 3600
     55     default_crl_days = 3600
     56     certificate = pycacert.pem
     57     private_key = pycakey.pem
     58     serial    = $dir/serial
     59     RANDFILE  = $dir/.rand
     60 
     61     policy          = policy_match
     62 
     63     [ policy_match ]
     64     countryName             = match
     65     stateOrProvinceName     = optional
     66     organizationName        = match
     67     organizationalUnitName  = optional
     68     commonName              = supplied
     69     emailAddress            = optional
     70 
     71     [ policy_anything ]
     72     countryName   = optional
     73     stateOrProvinceName = optional
     74     localityName    = optional
     75     organizationName  = optional
     76     organizationalUnitName  = optional
     77     commonName    = supplied
     78     emailAddress    = optional
     79 
     80 
     81     [ v3_ca ]
     82 
     83     subjectKeyIdentifier=hash
     84     authorityKeyIdentifier=keyid:always,issuer
     85     basicConstraints = CA:true
     86 
     87     """
     88 
     89 here = os.path.abspath(os.path.dirname(__file__))
     90 
     91 def make_cert_key(hostname, sign=False, extra_san=''):
     92     print("creating cert for " + hostname)
     93     tempnames = []
     94     for i in range(3):
     95         with tempfile.NamedTemporaryFile(delete=False) as f:
     96             tempnames.append(f.name)
     97     req_file, cert_file, key_file = tempnames
     98     try:
     99         req = req_template.format(hostname=hostname, extra_san=extra_san)
    100         with open(req_file, 'w') as f:
    101             f.write(req)
    102         args = ['req', '-new', '-days', '3650', '-nodes',
    103                 '-newkey', 'rsa:1024', '-keyout', key_file,
    104                 '-config', req_file]
    105         if sign:
    106             with tempfile.NamedTemporaryFile(delete=False) as f:
    107                 tempnames.append(f.name)
    108                 reqfile = f.name
    109             args += ['-out', reqfile ]
    110 
    111         else:
    112             args += ['-x509', '-out', cert_file ]
    113         check_call(['openssl'] + args)
    114 
    115         if sign:
    116             args = ['ca', '-config', req_file, '-out', cert_file, '-outdir', 'cadir',
    117                     '-policy', 'policy_anything', '-batch', '-infiles', reqfile ]
    118             check_call(['openssl'] + args)
    119 
    120 
    121         with open(cert_file, 'r') as f:
    122             cert = f.read()
    123         with open(key_file, 'r') as f:
    124             key = f.read()
    125         return cert, key
    126     finally:
    127         for name in tempnames:
    128             os.remove(name)
    129 
    130 TMP_CADIR = 'cadir'
    131 
    132 def unmake_ca():
    133     shutil.rmtree(TMP_CADIR)
    134 
    135 def make_ca():
    136     os.mkdir(TMP_CADIR)
    137     with open(os.path.join('cadir','index.txt'),'a+') as f:
    138         pass # empty file
    139     with open(os.path.join('cadir','crl.txt'),'a+') as f:
    140         f.write("00")
    141     with open(os.path.join('cadir','index.txt.attr'),'w+') as f:
    142         f.write('unique_subject = no')
    143 
    144     with tempfile.NamedTemporaryFile("w") as t:
    145         t.write(req_template.format(hostname='our-ca-server', extra_san=''))
    146         t.flush()
    147         with tempfile.NamedTemporaryFile() as f:
    148             args = ['req', '-new', '-days', '3650', '-extensions', 'v3_ca', '-nodes',
    149                     '-newkey', 'rsa:2048', '-keyout', 'pycakey.pem',
    150                     '-out', f.name,
    151                     '-subj', '/C=XY/L=Castle Anthrax/O=Python Software Foundation CA/CN=our-ca-server']
    152             check_call(['openssl'] + args)
    153             args = ['ca', '-config', t.name, '-create_serial',
    154                     '-out', 'pycacert.pem', '-batch', '-outdir', TMP_CADIR,
    155                     '-keyfile', 'pycakey.pem', '-days', '3650',
    156                     '-selfsign', '-extensions', 'v3_ca', '-infiles', f.name ]
    157             check_call(['openssl'] + args)
    158             args = ['ca', '-config', t.name, '-gencrl', '-out', 'revocation.crl']
    159             check_call(['openssl'] + args)
    160 
    161 if __name__ == '__main__':
    162     os.chdir(here)
    163     cert, key = make_cert_key('localhost')
    164     with open('ssl_cert.pem', 'w') as f:
    165         f.write(cert)
    166     with open('ssl_key.pem', 'w') as f:
    167         f.write(key)
    168     print("password protecting ssl_key.pem in ssl_key.passwd.pem")
    169     check_call(['openssl','rsa','-in','ssl_key.pem','-out','ssl_key.passwd.pem','-des3','-passout','pass:somepass'])
    170     check_call(['openssl','rsa','-in','ssl_key.pem','-out','keycert.passwd.pem','-des3','-passout','pass:somepass'])
    171 
    172     with open('keycert.pem', 'w') as f:
    173         f.write(key)
    174         f.write(cert)
    175 
    176     with open('keycert.passwd.pem', 'a+') as f:
    177         f.write(cert)
    178 
    179     # For certificate matching tests
    180     make_ca()
    181     cert, key = make_cert_key('fakehostname')
    182     with open('keycert2.pem', 'w') as f:
    183         f.write(key)
    184         f.write(cert)
    185 
    186     cert, key = make_cert_key('localhost', True)
    187     with open('keycert3.pem', 'w') as f:
    188         f.write(key)
    189         f.write(cert)
    190 
    191     cert, key = make_cert_key('fakehostname', True)
    192     with open('keycert4.pem', 'w') as f:
    193         f.write(key)
    194         f.write(cert)
    195 
    196     extra_san = [
    197         'otherName.1 = 1.2.3.4;UTF8:some other identifier',
    198         'otherName.2 = 1.3.6.1.5.2.2;SEQUENCE:princ_name',
    199         'email.1 = user (at] example.org',
    200         'DNS.2 = www.example.org',
    201         # GEN_X400
    202         'dirName.1 = dir_sect',
    203         # GEN_EDIPARTY
    204         'URI.1 = https://www.python.org/',
    205         'IP.1 = 127.0.0.1',
    206         'IP.2 = ::1',
    207         'RID.1 = 1.2.3.4.5',
    208     ]
    209 
    210     cert, key = make_cert_key('allsans', extra_san='\n'.join(extra_san))
    211     with open('allsans.pem', 'w') as f:
    212         f.write(key)
    213         f.write(cert)
    214 
    215     unmake_ca()
    216     print("\n\nPlease change the values in test_ssl.py, test_parse_cert function related to notAfter,notBefore and serialNumber")
    217     check_call(['openssl','x509','-in','keycert.pem','-dates','-serial','-noout'])
    218