Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(500)

Side by Side Diff: net/data/verify_certificate_chain_unittest/common.py

Issue 2036033002: Add CertIssuerSourceAia: authorityInfoAccess fetching for CertPathBuilder. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@cert-parsing-path-building
Patch Set: derp Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright (c) 2015 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2015 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Set of helpers to generate signed X.509v3 certificates. 6 """Set of helpers to generate signed X.509v3 certificates.
7 7
8 This works by shelling out calls to the 'openssl req' and 'openssl ca' 8 This works by shelling out calls to the 'openssl req' and 'openssl ca'
9 commands, and passing the appropriate command line flags and configuration file 9 commands, and passing the appropriate command line flags and configuration file
10 (.cnf). 10 (.cnf).
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 if path_id == 0: 65 if path_id == 0:
66 return name 66 return name
67 67
68 # Otherwise append the count to make it unique. 68 # Otherwise append the count to make it unique.
69 return '%s_%d' % (name, path_id) 69 return '%s_%d' % (name, path_id)
70 70
71 71
72 class Certificate(object): 72 class Certificate(object):
73 """Helper for building an X.509 certificate.""" 73 """Helper for building an X.509 certificate."""
74 74
75 def __init__(self, name, cert_type, issuer): 75 def __init__(self, name, cert_type, issuer, key_from=None):
eroman 2016/06/14 00:22:22 Rather than making this an optional parameter to i
mattm 2016/06/14 21:37:30 done.
76 # The name will be used for the subject's CN, and also as a component of 76 # The name will be used for the subject's CN, and also as a component of
77 # the temporary filenames to help with debugging. 77 # the temporary filenames to help with debugging.
78 self.name = name 78 self.name = name
79 self.path_id = GetUniquePathId(name) 79 self.path_id = GetUniquePathId(name)
80 80
81 # If specified, use they key from the given Certificate object instead of
eroman 2016/06/14 00:22:22 they --> the
mattm 2016/06/14 21:37:30 Done.
82 # generating a new one.
83 self.key_from = key_from
84
81 # The issuer is also a Certificate object. Passing |None| means it is a 85 # The issuer is also a Certificate object. Passing |None| means it is a
82 # self-signed certificate. 86 # self-signed certificate.
83 self.issuer = issuer 87 self.issuer = issuer
84 if issuer is None: 88 if issuer is None:
85 self.issuer = self 89 self.issuer = self
86 90
87 # The config contains all the OpenSSL options that will be passed via a 91 # The config contains all the OpenSSL options that will be passed via a
88 # .cnf file. Set up defaults. 92 # .cnf file. Set up defaults.
89 self.config = openssl_conf.Config() 93 self.config = openssl_conf.Config()
90 self.init_config() 94 self.init_config()
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 # Initialize any files that will be needed if this certificate is used to 130 # Initialize any files that will be needed if this certificate is used to
127 # sign other certificates. Starts off serial numbers at 1, and will 131 # sign other certificates. Starts off serial numbers at 1, and will
128 # increment them for each signed certificate. 132 # increment them for each signed certificate.
129 write_string_to_file('01\n', self.get_serial_path()) 133 write_string_to_file('01\n', self.get_serial_path())
130 write_string_to_file('', self.get_database_path()) 134 write_string_to_file('', self.get_database_path())
131 135
132 136
133 def generate_rsa_key(self, size_bits): 137 def generate_rsa_key(self, size_bits):
134 """Generates an RSA private key for the certificate.""" 138 """Generates an RSA private key for the certificate."""
135 subprocess.check_call( 139 subprocess.check_call(
136 ['openssl', 'genrsa', '-out', self.get_key_path(), str(size_bits)]) 140 ['openssl', 'genrsa', '-out', self.get_key_path(), str(size_bits)])
eroman 2016/06/14 00:22:22 Can you add some safety-measures to prevent over-w
mattm 2016/06/14 21:37:30 Done.
137 141
138 142
139 def generate_ec_key(self, named_curve): 143 def generate_ec_key(self, named_curve):
140 """Generates an EC private key for the certificate. |named_curve| can be 144 """Generates an EC private key for the certificate. |named_curve| can be
141 something like secp384r1""" 145 something like secp384r1"""
142 subprocess.check_call( 146 subprocess.check_call(
143 ['openssl', 'ecparam', '-out', self.get_key_path(), 147 ['openssl', 'ecparam', '-out', self.get_key_path(),
eroman 2016/06/14 00:22:22 same here.
mattm 2016/06/14 21:37:30 Done.
144 '-name', named_curve, '-genkey']) 148 '-name', named_curve, '-genkey'])
145 149
146 150
147 def set_validity_range(self, start_date, end_date): 151 def set_validity_range(self, start_date, end_date):
148 """Sets the Validity notBefore and notAfter properties for the 152 """Sets the Validity notBefore and notAfter properties for the
149 certificate""" 153 certificate"""
150 self.validity_flags = ['-startdate', start_date, '-enddate', end_date] 154 self.validity_flags = ['-startdate', start_date, '-enddate', end_date]
151 155
152 156
153 def set_signature_hash(self, md): 157 def set_signature_hash(self, md):
154 """Sets the hash function that will be used when signing this certificate. 158 """Sets the hash function that will be used when signing this certificate.
155 Can be sha1, sha256, sha512, md5, etc.""" 159 Can be sha1, sha256, sha512, md5, etc."""
156 self.md_flags = ['-md', md] 160 self.md_flags = ['-md', md]
157 161
158 162
159 def get_extensions(self): 163 def get_extensions(self):
160 return self.config.get_section('req_ext') 164 return self.config.get_section('req_ext')
161 165
162 166
163 def get_path(self, suffix): 167 def get_path(self, suffix):
164 """Forms a path to an output file for this certificate, containing the 168 """Forms a path to an output file for this certificate, containing the
165 indicated suffix. The certificate's name will be used as its basis.""" 169 indicated suffix. The certificate's name will be used as its basis."""
166 return os.path.join(g_out_dir, '%s%s' % (self.path_id, suffix)) 170 return os.path.join(g_out_dir, '%s%s' % (self.path_id, suffix))
167 171
168 172
169 def get_key_path(self): 173 def get_key_path(self):
174 if self.key_from is not None:
175 return self.key_from.get_key_path()
170 return self.get_path('.key') 176 return self.get_path('.key')
171 177
172 178
173 def get_cert_path(self): 179 def get_cert_path(self):
174 return self.get_path('.pem') 180 return self.get_path('.pem')
175 181
176 182
177 def get_serial_path(self): 183 def get_serial_path(self):
178 return self.get_path('.serial') 184 return self.get_path('.serial')
179 185
(...skipping 29 matching lines...) Expand all
209 215
210 self.finalized = True 216 self.finalized = True
211 217
212 # Ensure that the issuer has been "finalized", since its outputs need to be 218 # Ensure that the issuer has been "finalized", since its outputs need to be
213 # accessible. Note that self.issuer could be the same as self. 219 # accessible. Note that self.issuer could be the same as self.
214 self.issuer.finalize() 220 self.issuer.finalize()
215 221
216 # Ensure the certificate has a key. Callers have the option to generate a 222 # Ensure the certificate has a key. Callers have the option to generate a
217 # different type of key, but if that was not done default to a new 2048-bit 223 # different type of key, but if that was not done default to a new 2048-bit
218 # RSA key. 224 # RSA key.
219 if not os.path.isfile(self.get_key_path()): 225 if not os.path.isfile(self.get_key_path()):
eroman 2016/06/14 00:22:22 Can you similarly add a safety measure here? (Or
mattm 2016/06/14 21:37:30 calls generate_rsa_key which has the assert in it,
220 self.generate_rsa_key(2048) 226 self.generate_rsa_key(2048)
221 227
222 # Serialize the config to a file. 228 # Serialize the config to a file.
223 self.config.write_to_file(self.get_config_path()) 229 self.config.write_to_file(self.get_config_path())
224 230
225 # Create a CSR. 231 # Create a CSR.
226 subprocess.check_call( 232 subprocess.check_call(
227 ['openssl', 'req', '-new', 233 ['openssl', 'req', '-new',
228 '-key', self.get_key_path(), 234 '-key', self.get_key_path(),
229 '-out', self.get_csr_path(), 235 '-out', self.get_csr_path(),
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 section = self.config.get_section('crl_ext') 350 section = self.config.get_section('crl_ext')
345 section.set_property('authorityKeyIdentifier', 'keyid:always') 351 section.set_property('authorityKeyIdentifier', 'keyid:always')
346 section.set_property('authorityInfoAccess', '@issuer_info') 352 section.set_property('authorityInfoAccess', '@issuer_info')
347 353
348 354
349 def data_to_pem(block_header, block_data): 355 def data_to_pem(block_header, block_data):
350 return '-----BEGIN %s-----\n%s\n-----END %s-----\n' % (block_header, 356 return '-----BEGIN %s-----\n%s\n-----END %s-----\n' % (block_header,
351 base64.b64encode(block_data), block_header) 357 base64.b64encode(block_data), block_header)
352 358
353 359
354 def write_test_file(description, chain, trusted_certs, utc_time, verify_result): 360 def write_test_file(description, chain, trusted_certs, utc_time, verify_result,
361 out_pem=None):
355 """Writes a test file that contains all the inputs necessary to run a 362 """Writes a test file that contains all the inputs necessary to run a
356 verification on a certificate chain""" 363 verification on a certificate chain"""
357 364
358 # Prepend the script name that generated the file to the description. 365 # Prepend the script name that generated the file to the description.
359 test_data = '[Created by: %s]\n\n%s\n' % (sys.argv[0], description) 366 test_data = '[Created by: %s]\n\n%s\n' % (sys.argv[0], description)
360 367
361 # Write the certificate chain to the output file. 368 # Write the certificate chain to the output file.
362 for cert in chain: 369 for cert in chain:
363 test_data += '\n' + cert.get_cert_pem() 370 test_data += '\n' + cert.get_cert_pem()
364 371
365 # Write the trust store. 372 # Write the trust store.
366 for cert in trusted_certs: 373 for cert in trusted_certs:
367 cert_data = cert.get_cert_pem() 374 cert_data = cert.get_cert_pem()
368 # Use a different block type in the .pem file. 375 # Use a different block type in the .pem file.
369 cert_data = cert_data.replace('CERTIFICATE', 'TRUSTED_CERTIFICATE') 376 cert_data = cert_data.replace('CERTIFICATE', 'TRUSTED_CERTIFICATE')
370 test_data += '\n' + cert_data 377 test_data += '\n' + cert_data
371 378
372 test_data += '\n' + data_to_pem('TIME', utc_time) 379 test_data += '\n' + data_to_pem('TIME', utc_time)
373 380
374 verify_result_string = 'SUCCESS' if verify_result else 'FAIL' 381 verify_result_string = 'SUCCESS' if verify_result else 'FAIL'
375 test_data += '\n' + data_to_pem('VERIFY_RESULT', verify_result_string) 382 test_data += '\n' + data_to_pem('VERIFY_RESULT', verify_result_string)
376 383
377 write_string_to_file(test_data, g_out_pem) 384 write_string_to_file(test_data, out_pem if out_pem else g_out_pem)
378 385
379 386
380 def write_string_to_file(data, path): 387 def write_string_to_file(data, path):
381 with open(path, 'w') as f: 388 with open(path, 'w') as f:
382 f.write(data) 389 f.write(data)
383 390
384 391
385 def init(invoking_script_path): 392 def init(invoking_script_path):
386 """Creates an output directory to contain all the temporary files that may be 393 """Creates an output directory to contain all the temporary files that may be
387 created, as well as determining the path for the final output. These paths 394 created, as well as determining the path for the final output. These paths
(...skipping 18 matching lines...) Expand all
406 shutil.rmtree(g_out_dir, True) 413 shutil.rmtree(g_out_dir, True)
407 os.makedirs(g_out_dir) 414 os.makedirs(g_out_dir)
408 415
409 g_out_pem = os.path.join('%s.pem' % (out_name)) 416 g_out_pem = os.path.join('%s.pem' % (out_name))
410 417
411 418
412 def create_self_signed_root_certificate(name): 419 def create_self_signed_root_certificate(name):
413 return Certificate(name, TYPE_CA, None) 420 return Certificate(name, TYPE_CA, None)
414 421
415 422
416 def create_intermediary_certificate(name, issuer): 423 def create_intermediary_certificate(name, issuer, **kw_args):
417 return Certificate(name, TYPE_CA, issuer) 424 return Certificate(name, TYPE_CA, issuer, **kw_args)
418 425
419 426
420 def create_end_entity_certificate(name, issuer): 427 def create_end_entity_certificate(name, issuer, **kw_args):
421 return Certificate(name, TYPE_END_ENTITY, issuer) 428 return Certificate(name, TYPE_END_ENTITY, issuer, **kw_args)
422 429
423 init(sys.argv[0]) 430 init(sys.argv[0])
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698