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