blob: 41b5f46c882ca3efe3ea76991eac0a49a15398e7 [file] [log] [blame]
Antoine Pitrou81564092010-10-08 23:06:24 +00001"""Make the custom certificate and private key files used by test_ssl
2and friends."""
3
4import os
Christian Heimesbd5c7d22018-01-20 15:16:30 +01005import pprint
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01006import shutil
Antoine Pitrou81564092010-10-08 23:06:24 +00007import tempfile
8from subprocess import *
9
10req_template = """
Christian Heimesbd5c7d22018-01-20 15:16:30 +010011 [ default ]
12 base_url = http://testca.pythontest.net/testca
13
Antoine Pitrou81564092010-10-08 23:06:24 +000014 [req]
15 distinguished_name = req_distinguished_name
Antoine Pitrou81564092010-10-08 23:06:24 +000016 prompt = no
17
18 [req_distinguished_name]
19 C = XY
20 L = Castle Anthrax
21 O = Python Software Foundation
22 CN = {hostname}
23
Christian Heimesbd5c7d22018-01-20 15:16:30 +010024 [req_x509_extensions_simple]
Christian Heimes1c03abd2016-09-06 23:25:35 +020025 subjectAltName = @san
26
Christian Heimesbd5c7d22018-01-20 15:16:30 +010027 [req_x509_extensions_full]
28 subjectAltName = @san
29 keyUsage = critical,keyEncipherment,digitalSignature
30 extendedKeyUsage = serverAuth,clientAuth
31 basicConstraints = critical,CA:false
32 subjectKeyIdentifier = hash
33 authorityKeyIdentifier = keyid:always,issuer:always
34 authorityInfoAccess = @issuer_ocsp_info
35 crlDistributionPoints = @crl_info
36
37 [ issuer_ocsp_info ]
38 caIssuers;URI.0 = $base_url/pycacert.cer
39 OCSP;URI.0 = $base_url/ocsp/
40
41 [ crl_info ]
42 URI.0 = $base_url/revocation.crl
43
Christian Heimes1c03abd2016-09-06 23:25:35 +020044 [san]
45 DNS.1 = {hostname}
46 {extra_san}
47
48 [dir_sect]
49 C = XY
50 L = Castle Anthrax
51 O = Python Software Foundation
52 CN = dirname example
53
54 [princ_name]
55 realm = EXP:0, GeneralString:KERBEROS.REALM
56 principal_name = EXP:1, SEQUENCE:principal_seq
57
58 [principal_seq]
59 name_type = EXP:0, INTEGER:1
60 name_string = EXP:1, SEQUENCE:principals
61
62 [principals]
63 princ1 = GeneralString:username
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +010064
65 [ ca ]
66 default_ca = CA_default
67
68 [ CA_default ]
69 dir = cadir
70 database = $dir/index.txt
Christian Heimes22587792013-11-21 23:56:13 +010071 crlnumber = $dir/crl.txt
Christian Heimese6dac002018-08-30 07:25:49 +020072 default_md = sha256
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +010073 default_days = 3600
Christian Heimes22587792013-11-21 23:56:13 +010074 default_crl_days = 3600
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +010075 certificate = pycacert.pem
76 private_key = pycakey.pem
77 serial = $dir/serial
78 RANDFILE = $dir/.rand
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +010079 policy = policy_match
80
81 [ policy_match ]
82 countryName = match
83 stateOrProvinceName = optional
84 organizationName = match
85 organizationalUnitName = optional
86 commonName = supplied
87 emailAddress = optional
88
89 [ policy_anything ]
90 countryName = optional
91 stateOrProvinceName = optional
92 localityName = optional
93 organizationName = optional
94 organizationalUnitName = optional
95 commonName = supplied
96 emailAddress = optional
97
98
99 [ v3_ca ]
100
101 subjectKeyIdentifier=hash
102 authorityKeyIdentifier=keyid:always,issuer
103 basicConstraints = CA:true
104
Antoine Pitrou81564092010-10-08 23:06:24 +0000105 """
106
107here = os.path.abspath(os.path.dirname(__file__))
108
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100109
110def make_cert_key(hostname, sign=False, extra_san='',
Christian Heimese6dac002018-08-30 07:25:49 +0200111 ext='req_x509_extensions_full', key='rsa:3072'):
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100112 print("creating cert for " + hostname)
Antoine Pitrou81564092010-10-08 23:06:24 +0000113 tempnames = []
114 for i in range(3):
115 with tempfile.NamedTemporaryFile(delete=False) as f:
116 tempnames.append(f.name)
117 req_file, cert_file, key_file = tempnames
118 try:
Christian Heimes1c03abd2016-09-06 23:25:35 +0200119 req = req_template.format(hostname=hostname, extra_san=extra_san)
Antoine Pitrou81564092010-10-08 23:06:24 +0000120 with open(req_file, 'w') as f:
Christian Heimes1c03abd2016-09-06 23:25:35 +0200121 f.write(req)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100122 args = ['req', '-new', '-days', '3650', '-nodes',
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100123 '-newkey', key, '-keyout', key_file,
124 '-extensions', ext,
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100125 '-config', req_file]
126 if sign:
127 with tempfile.NamedTemporaryFile(delete=False) as f:
128 tempnames.append(f.name)
129 reqfile = f.name
130 args += ['-out', reqfile ]
131
132 else:
133 args += ['-x509', '-out', cert_file ]
Antoine Pitrou81564092010-10-08 23:06:24 +0000134 check_call(['openssl'] + args)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100135
136 if sign:
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100137 args = [
138 'ca',
139 '-config', req_file,
140 '-extensions', ext,
141 '-out', cert_file,
142 '-outdir', 'cadir',
143 '-policy', 'policy_anything',
144 '-batch', '-infiles', reqfile
145 ]
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100146 check_call(['openssl'] + args)
147
148
Antoine Pitrou81564092010-10-08 23:06:24 +0000149 with open(cert_file, 'r') as f:
150 cert = f.read()
151 with open(key_file, 'r') as f:
152 key = f.read()
153 return cert, key
154 finally:
155 for name in tempnames:
156 os.remove(name)
157
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100158TMP_CADIR = 'cadir'
159
160def unmake_ca():
161 shutil.rmtree(TMP_CADIR)
162
163def make_ca():
164 os.mkdir(TMP_CADIR)
165 with open(os.path.join('cadir','index.txt'),'a+') as f:
166 pass # empty file
Christian Heimes22587792013-11-21 23:56:13 +0100167 with open(os.path.join('cadir','crl.txt'),'a+') as f:
Antoine Pitroud2e9fdf2014-07-26 11:15:52 -0400168 f.write("00")
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100169 with open(os.path.join('cadir','index.txt.attr'),'w+') as f:
170 f.write('unique_subject = no')
171
172 with tempfile.NamedTemporaryFile("w") as t:
Christian Heimes1c03abd2016-09-06 23:25:35 +0200173 t.write(req_template.format(hostname='our-ca-server', extra_san=''))
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100174 t.flush()
175 with tempfile.NamedTemporaryFile() as f:
176 args = ['req', '-new', '-days', '3650', '-extensions', 'v3_ca', '-nodes',
Christian Heimese6dac002018-08-30 07:25:49 +0200177 '-newkey', 'rsa:3072', '-keyout', 'pycakey.pem',
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100178 '-out', f.name,
179 '-subj', '/C=XY/L=Castle Anthrax/O=Python Software Foundation CA/CN=our-ca-server']
180 check_call(['openssl'] + args)
181 args = ['ca', '-config', t.name, '-create_serial',
182 '-out', 'pycacert.pem', '-batch', '-outdir', TMP_CADIR,
183 '-keyfile', 'pycakey.pem', '-days', '3650',
184 '-selfsign', '-extensions', 'v3_ca', '-infiles', f.name ]
185 check_call(['openssl'] + args)
Christian Heimes22587792013-11-21 23:56:13 +0100186 args = ['ca', '-config', t.name, '-gencrl', '-out', 'revocation.crl']
187 check_call(['openssl'] + args)
Antoine Pitrou81564092010-10-08 23:06:24 +0000188
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100189 # capath hashes depend on subject!
190 check_call([
191 'openssl', 'x509', '-in', 'pycacert.pem', '-out', 'capath/ceff1710.0'
192 ])
193 shutil.copy('capath/ceff1710.0', 'capath/b1930218.0')
194
195
196def print_cert(path):
197 import _ssl
198 pprint.pprint(_ssl._test_decode_cert(path))
199
200
Antoine Pitrou81564092010-10-08 23:06:24 +0000201if __name__ == '__main__':
202 os.chdir(here)
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100203 cert, key = make_cert_key('localhost', ext='req_x509_extensions_simple')
Antoine Pitrou81564092010-10-08 23:06:24 +0000204 with open('ssl_cert.pem', 'w') as f:
205 f.write(cert)
206 with open('ssl_key.pem', 'w') as f:
207 f.write(key)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100208 print("password protecting ssl_key.pem in ssl_key.passwd.pem")
Miss Islington (bot)4267e8f2019-09-25 09:13:54 -0700209 check_call(['openssl','pkey','-in','ssl_key.pem','-out','ssl_key.passwd.pem','-aes256','-passout','pass:somepass'])
210 check_call(['openssl','pkey','-in','ssl_key.pem','-out','keycert.passwd.pem','-aes256','-passout','pass:somepass'])
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100211
Antoine Pitrou81564092010-10-08 23:06:24 +0000212 with open('keycert.pem', 'w') as f:
213 f.write(key)
214 f.write(cert)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100215
216 with open('keycert.passwd.pem', 'a+') as f:
217 f.write(cert)
218
Antoine Pitrou803e6d62010-10-13 10:36:15 +0000219 # For certificate matching tests
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100220 make_ca()
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100221 cert, key = make_cert_key('fakehostname', ext='req_x509_extensions_simple')
Antoine Pitrou803e6d62010-10-13 10:36:15 +0000222 with open('keycert2.pem', 'w') as f:
223 f.write(key)
224 f.write(cert)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100225
226 cert, key = make_cert_key('localhost', True)
227 with open('keycert3.pem', 'w') as f:
228 f.write(key)
229 f.write(cert)
230
231 cert, key = make_cert_key('fakehostname', True)
232 with open('keycert4.pem', 'w') as f:
233 f.write(key)
234 f.write(cert)
235
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100236 cert, key = make_cert_key(
237 'localhost-ecc', True, key='param:secp384r1.pem'
238 )
239 with open('keycertecc.pem', 'w') as f:
240 f.write(key)
241 f.write(cert)
242
Christian Heimes1c03abd2016-09-06 23:25:35 +0200243 extra_san = [
244 'otherName.1 = 1.2.3.4;UTF8:some other identifier',
245 'otherName.2 = 1.3.6.1.5.2.2;SEQUENCE:princ_name',
246 'email.1 = user@example.org',
247 'DNS.2 = www.example.org',
248 # GEN_X400
249 'dirName.1 = dir_sect',
250 # GEN_EDIPARTY
251 'URI.1 = https://www.python.org/',
252 'IP.1 = 127.0.0.1',
253 'IP.2 = ::1',
254 'RID.1 = 1.2.3.4.5',
255 ]
256
257 cert, key = make_cert_key('allsans', extra_san='\n'.join(extra_san))
258 with open('allsans.pem', 'w') as f:
259 f.write(key)
260 f.write(cert)
261
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100262 extra_san = [
263 # könig (king)
264 'DNS.2 = xn--knig-5qa.idn.pythontest.net',
265 # königsgäßchen (king's alleyway)
266 'DNS.3 = xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
267 'DNS.4 = xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
268 # βόλοσ (marble)
269 'DNS.5 = xn--nxasmq6b.idna2003.pythontest.net',
270 'DNS.6 = xn--nxasmm1c.idna2008.pythontest.net',
271 ]
272
273 # IDN SANS, signed
274 cert, key = make_cert_key('idnsans', True, extra_san='\n'.join(extra_san))
275 with open('idnsans.pem', 'w') as f:
276 f.write(key)
277 f.write(cert)
278
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100279 unmake_ca()
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100280 print("update Lib/test/test_ssl.py and Lib/test/test_asyncio/util.py")
281 print_cert('keycert.pem')
282 print_cert('keycert3.pem')