1"""Make the custom certificate and private key files used by test_ssl 2and friends.""" 3 4import os 5import shutil 6import sys 7import tempfile 8from subprocess import * 9 10req_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 89here = os.path.abspath(os.path.dirname(__file__)) 90 91def 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 130TMP_CADIR = 'cadir' 131 132def unmake_ca(): 133 shutil.rmtree(TMP_CADIR) 134 135def 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 161if __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@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