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