OLD | NEW |
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 Loading... |
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): |
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 |
| 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 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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]) |
OLD | NEW |