blob: e4a86d39081417484ecbad239d2ad797c38b1ecb [file] [log] [blame]
Guo-wei Shiehee408212015-12-09 11:25:38 -08001# -*- coding:utf-8 -*-
2# Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3#
4# Use of this source code is governed by a BSD-style license
5# that can be found in the LICENSE file in the root of the source
6# tree. An additional intellectual property rights grant can be found
7# in the file PATENTS. All contributing project authors may
8# be found in the AUTHORS file in the root of the source tree.
9
10
11"""This is a tool to transform a crt file into a C/C++ header.
12
13Usage:
14generate_sslroots.py cert_file.crt [--verbose | -v] [--full_cert | -f]
15
16Arguments:
17 -v Print output while running.
18 -f Add public key and certificate name. Default is to skip and reduce
19 generated file size.
20"""
21
22import commands
23from optparse import OptionParser
24import os
25import re
26import string
27
Mirko Bonadei86bd33a2020-04-24 21:53:49 +020028_GENERATED_FILE = 'ssl_roots.h'
Guo-wei Shiehee408212015-12-09 11:25:38 -080029_PREFIX = '__generated__'
30_EXTENSION = '.crt'
31_SUBJECT_NAME_ARRAY = 'subject_name'
32_SUBJECT_NAME_VARIABLE = 'SubjectName'
33_PUBLIC_KEY_ARRAY = 'public_key'
34_PUBLIC_KEY_VARIABLE = 'PublicKey'
35_CERTIFICATE_ARRAY = 'certificate'
36_CERTIFICATE_VARIABLE = 'Certificate'
37_CERTIFICATE_SIZE_VARIABLE = 'CertificateSize'
38_INT_TYPE = 'size_t'
Taylor Brandstetterbee59832020-10-28 14:06:21 -070039_CHAR_TYPE = 'unsigned char* const'
Guo-wei Shiehee408212015-12-09 11:25:38 -080040_VERBOSE = 'verbose'
41
42
43def main():
44 """The main entrypoint."""
45 parser = OptionParser('usage %prog FILE')
46 parser.add_option('-v', '--verbose', dest='verbose', action='store_true')
47 parser.add_option('-f', '--full_cert', dest='full_cert', action='store_true')
48 options, args = parser.parse_args()
49 if len(args) < 1:
50 parser.error('No crt file specified.')
51 return
52 root_dir = _SplitCrt(args[0], options)
53 _GenCFiles(root_dir, options)
54 _Cleanup(root_dir)
55
56
57def _SplitCrt(source_file, options):
58 sub_file_blocks = []
59 label_name = ''
60 root_dir = os.path.dirname(os.path.abspath(source_file)) + '/'
61 _PrintOutput(root_dir, options)
62 f = open(source_file)
63 for line in f:
64 if line.startswith('# Label: '):
65 sub_file_blocks.append(line)
66 label = re.search(r'\".*\"', line)
67 temp_label = label.group(0)
68 end = len(temp_label)-1
69 label_name = _SafeName(temp_label[1:end])
70 elif line.startswith('-----END CERTIFICATE-----'):
71 sub_file_blocks.append(line)
72 new_file_name = root_dir + _PREFIX + label_name + _EXTENSION
73 _PrintOutput('Generating: ' + new_file_name, options)
74 new_file = open(new_file_name, 'w')
75 for out_line in sub_file_blocks:
76 new_file.write(out_line)
77 new_file.close()
78 sub_file_blocks = []
79 else:
80 sub_file_blocks.append(line)
81 f.close()
82 return root_dir
83
84
85def _GenCFiles(root_dir, options):
86 output_header_file = open(root_dir + _GENERATED_FILE, 'w')
87 output_header_file.write(_CreateOutputHeader())
88 if options.full_cert:
89 subject_name_list = _CreateArraySectionHeader(_SUBJECT_NAME_VARIABLE,
90 _CHAR_TYPE, options)
91 public_key_list = _CreateArraySectionHeader(_PUBLIC_KEY_VARIABLE,
92 _CHAR_TYPE, options)
93 certificate_list = _CreateArraySectionHeader(_CERTIFICATE_VARIABLE,
94 _CHAR_TYPE, options)
95 certificate_size_list = _CreateArraySectionHeader(_CERTIFICATE_SIZE_VARIABLE,
96 _INT_TYPE, options)
97
98 for _, _, files in os.walk(root_dir):
99 for current_file in files:
100 if current_file.startswith(_PREFIX):
101 prefix_length = len(_PREFIX)
102 length = len(current_file) - len(_EXTENSION)
103 label = current_file[prefix_length:length]
104 filtered_output, cert_size = _CreateCertSection(root_dir, current_file,
105 label, options)
106 output_header_file.write(filtered_output + '\n\n\n')
107 if options.full_cert:
108 subject_name_list += _AddLabelToArray(label, _SUBJECT_NAME_ARRAY)
109 public_key_list += _AddLabelToArray(label, _PUBLIC_KEY_ARRAY)
110 certificate_list += _AddLabelToArray(label, _CERTIFICATE_ARRAY)
111 certificate_size_list += (' %s,\n') %(cert_size)
112
113 if options.full_cert:
114 subject_name_list += _CreateArraySectionFooter()
115 output_header_file.write(subject_name_list)
116 public_key_list += _CreateArraySectionFooter()
117 output_header_file.write(public_key_list)
118 certificate_list += _CreateArraySectionFooter()
119 output_header_file.write(certificate_list)
120 certificate_size_list += _CreateArraySectionFooter()
121 output_header_file.write(certificate_size_list)
Taylor Brandstetterbee59832020-10-28 14:06:21 -0700122 output_header_file.write(_CreateOutputFooter())
Guo-wei Shiehee408212015-12-09 11:25:38 -0800123 output_header_file.close()
124
125
126def _Cleanup(root_dir):
127 for f in os.listdir(root_dir):
128 if f.startswith(_PREFIX):
129 os.remove(root_dir + f)
130
131
132def _CreateCertSection(root_dir, source_file, label, options):
133 command = 'openssl x509 -in %s%s -noout -C' %(root_dir, source_file)
134 _PrintOutput(command, options)
135 output = commands.getstatusoutput(command)[1]
136 renamed_output = output.replace('unsigned char XXX_',
137 'const unsigned char ' + label + '_')
138 filtered_output = ''
139 cert_block = '^const unsigned char.*?};$'
140 prog = re.compile(cert_block, re.IGNORECASE | re.MULTILINE | re.DOTALL)
141 if not options.full_cert:
142 filtered_output = prog.sub('', renamed_output, count=2)
143 else:
144 filtered_output = renamed_output
145
146 cert_size_block = r'\d\d\d+'
147 prog2 = re.compile(cert_size_block, re.MULTILINE | re.VERBOSE)
148 result = prog2.findall(renamed_output)
149 cert_size = result[len(result) - 1]
150
151 return filtered_output, cert_size
152
153
154def _CreateOutputHeader():
Taylor Brandstetterbee59832020-10-28 14:06:21 -0700155 output = ('/*\n'
156 ' * Copyright 2004 The WebRTC Project Authors. All rights '
157 'reserved.\n'
158 ' *\n'
159 ' * Use of this source code is governed by a BSD-style license\n'
160 ' * that can be found in the LICENSE file in the root of the '
161 'source\n'
162 ' * tree. An additional intellectual property rights grant can be '
163 'found\n'
164 ' * in the file PATENTS. All contributing project authors may\n'
165 ' * be found in the AUTHORS file in the root of the source tree.\n'
166 ' */\n\n'
167 '#ifndef RTC_BASE_SSL_ROOTS_H_\n'
168 '#define RTC_BASE_SSL_ROOTS_H_\n\n'
169 '// This file is the root certificates in C form that are needed to'
Guo-wei Shiehee408212015-12-09 11:25:38 -0800170 ' connect to\n// Google.\n\n'
171 '// It was generated with the following command line:\n'
Taylor Brandstetterbee59832020-10-28 14:06:21 -0700172 '// > python tools_webrtc/sslroots/generate_sslroots.py'
173 '\n// https://pki.goog/roots.pem\n\n'
174 '// clang-format off\n'
175 '// Don\'t bother formatting generated code,\n'
176 '// also it would breaks subject/issuer lines.\n\n')
Guo-wei Shiehee408212015-12-09 11:25:38 -0800177 return output
178
Taylor Brandstetterbee59832020-10-28 14:06:21 -0700179def _CreateOutputFooter():
180 output = ('// clang-format on\n\n'
181 '#endif // RTC_BASE_SSL_ROOTS_H_\n')
182 return output
Guo-wei Shiehee408212015-12-09 11:25:38 -0800183
184def _CreateArraySectionHeader(type_name, type_type, options):
185 output = ('const %s kSSLCert%sList[] = {\n') %(type_type, type_name)
186 _PrintOutput(output, options)
187 return output
188
189
190def _AddLabelToArray(label, type_name):
191 return ' %s_%s,\n' %(label, type_name)
192
193
194def _CreateArraySectionFooter():
195 return '};\n\n'
196
197
198def _SafeName(original_file_name):
199 bad_chars = ' -./\\()áéíőú'
200 replacement_chars = ''
201 for _ in bad_chars:
202 replacement_chars += '_'
203 translation_table = string.maketrans(bad_chars, replacement_chars)
204 return original_file_name.translate(translation_table)
205
206
207def _PrintOutput(output, options):
208 if options.verbose:
209 print output
210
211if __name__ == '__main__':
212 main()