OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 # Copyright 2015 The Chromium Authors. All rights reserved. | |
3 # Use of this source code is governed by a BSD-style license that can be | |
4 # found in the LICENSE file. | |
5 | |
6 import base64 | |
7 import copy | |
8 import os | |
9 import subprocess | |
10 import tempfile | |
11 | |
12 | |
13 class RDN: | |
14 def __init__(self): | |
15 self.attrs = [] | |
16 | |
17 def add_attr(self, attr_type, attr_value_type, attr_value, | |
18 attr_modifier=None): | |
19 self.attrs.append((attr_type, attr_value_type, attr_value, attr_modifier)) | |
20 return self | |
21 | |
22 def __str__(self): | |
23 s = '' | |
24 for n, attr in enumerate(self.attrs): | |
25 s += 'attrTypeAndValue%i=SEQUENCE:attrTypeAndValueSequence%i_%i\n' % ( | |
26 n, id(self), n) | |
27 | |
28 s += '\n' | |
29 for n, attr in enumerate(self.attrs): | |
30 attr_type, attr_value_type, attr_value, attr_modifier = attr | |
31 s += '[attrTypeAndValueSequence%i_%i]\n' % (id(self), n) | |
32 # Note the quotes around the string value here, which is necessary for | |
33 # trailing whitespace to be included by openssl. | |
34 s += 'type=OID:%s\n' % attr_type | |
35 s += 'value=' | |
36 if attr_modifier: | |
37 s += attr_modifier + ',' | |
38 s += '%s:"%s"\n' % (attr_value_type, attr_value) | |
39 | |
40 return s | |
41 | |
42 | |
43 class NameGenerator: | |
44 def __init__(self): | |
45 self.rdns = [] | |
46 | |
47 def add_rdn(self): | |
48 rdn = RDN() | |
49 self.rdns.append(rdn) | |
50 return rdn | |
51 | |
52 def __str__(self): | |
53 s = 'asn1 = SEQUENCE:rdnSequence\n\n[rdnSequence]\n' | |
54 for n, rdn in enumerate(self.rdns): | |
55 s += 'rdn%i = SET:rdnSet%i\n' % (n, n) | |
56 | |
57 s += '\n' | |
58 | |
59 for n, rdn in enumerate(self.rdns): | |
60 s += '[rdnSet%i]\n%s\n' % (n, rdn) | |
61 | |
62 return s | |
63 | |
64 | |
65 def generate(s, fn): | |
66 out_fn = os.path.join('..', 'names', fn + '.pem') | |
67 conf_tempfile = tempfile.NamedTemporaryFile() | |
68 conf_tempfile.write(str(s)) | |
69 conf_tempfile.flush() | |
70 der_tmpfile = tempfile.NamedTemporaryFile() | |
71 description_tmpfile = tempfile.NamedTemporaryFile() | |
72 subprocess.check_call(['openssl', 'asn1parse', '-genconf', conf_tempfile.name, | |
73 '-i', '-out', der_tmpfile.name], | |
74 stdout=description_tmpfile) | |
75 conf_tempfile.close() | |
76 | |
77 output_file = open(out_fn, 'w') | |
78 description_tmpfile.seek(0) | |
79 output_file.write(description_tmpfile.read()) | |
80 output_file.write('-----BEGIN NAME-----\n') | |
81 output_file.write(base64.encodestring(der_tmpfile.read())) | |
82 output_file.write('-----END NAME-----\n') | |
83 output_file.close() | |
84 | |
85 | |
86 def unmangled(s): | |
87 return s | |
88 | |
89 | |
90 def extra_whitespace(s): | |
91 return ' ' + s.replace(' ', ' ') + ' ' | |
92 | |
93 | |
94 def case_swap(s): | |
95 return s.swapcase() | |
96 | |
97 | |
98 def main(): | |
99 for valuetype in ('PRINTABLESTRING', 'T61STRING', 'UTF8', 'BMPSTRING', | |
100 'UNIVERSALSTRING'): | |
101 for string_mangler in (unmangled, extra_whitespace, case_swap): | |
102 n=NameGenerator() | |
103 n.add_rdn().add_attr('countryName', 'PRINTABLESTRING', 'US') | |
104 n.add_rdn().add_attr('stateOrProvinceName', | |
105 valuetype, | |
106 string_mangler('New York')) | |
107 n.add_rdn().add_attr('localityName', | |
108 valuetype, | |
109 string_mangler("ABCDEFGHIJKLMNOPQRSTUVWXYZ " | |
110 "abcdefghijklmnopqrstuvwxyz " | |
111 "0123456789 '()+,-./:=?")) | |
112 | |
113 n_extra_attr = copy.deepcopy(n) | |
114 n_extra_attr.rdns[-1].add_attr('organizationName', | |
115 valuetype, | |
116 string_mangler('Name of company')) | |
117 | |
118 n_dupe_attr = copy.deepcopy(n) | |
119 n_dupe_attr.rdns[-1].add_attr(*n_dupe_attr.rdns[-1].attrs[-1]) | |
120 | |
121 n_extra_rdn = copy.deepcopy(n) | |
122 n_extra_rdn.add_rdn().add_attr('organizationName', | |
123 valuetype, | |
124 string_mangler('Name of company')) | |
125 | |
126 filename_base = 'ascii-' + valuetype + '-' + string_mangler.__name__ | |
127 | |
128 generate(n, filename_base) | |
129 generate(n_extra_attr, filename_base + '-extra_attr') | |
130 generate(n_dupe_attr, filename_base + '-dupe_attr') | |
131 generate(n_extra_rdn, filename_base + '-extra_rdn') | |
132 | |
133 for valuetype in ('UTF8', 'BMPSTRING', 'UNIVERSALSTRING'): | |
134 n=NameGenerator() | |
135 n.add_rdn().add_attr('countryName', 'PRINTABLESTRING', 'JP') | |
136 n.add_rdn().add_attr('localityName', | |
137 valuetype, | |
138 "\xe6\x9d\xb1\xe4\xba\xac", | |
139 "FORMAT:UTF8") | |
140 | |
141 filename_base = 'unicode_bmp-' + valuetype + '-' + 'unmangled' | |
142 generate(n, filename_base) | |
143 | |
144 for valuetype in ('UTF8', 'UNIVERSALSTRING'): | |
145 n=NameGenerator() | |
146 n.add_rdn().add_attr('countryName', 'PRINTABLESTRING', 'JP') | |
147 n.add_rdn().add_attr('localityName', | |
148 valuetype, | |
149 "\xf0\x9d\x90\x80\xf0\x9d\x90\x99", | |
150 "FORMAT:UTF8") | |
151 | |
152 filename_base = 'unicode_supplementary-' + valuetype + '-' + 'unmangled' | |
153 generate(n, filename_base) | |
154 | |
155 generate("""asn1 = SEQUENCE:rdnSequence | |
156 [rdnSequence] | |
157 rdn0 = SET:rdnSet0 | |
158 [rdnSet0] | |
159 attrTypeAndValue0=SEQUENCE:attrTypeAndValueSequence0_0 | |
160 [attrTypeAndValueSequence0_0] | |
161 type=OID:countryName | |
162 value=PRINTABLESTRING:"US" | |
163 extra=PRINTABLESTRING:"hello world" | |
164 """, "invalid-AttributeTypeAndValue-extradata") | |
165 | |
166 generate("""asn1 = SEQUENCE:rdnSequence | |
167 [rdnSequence] | |
168 rdn0 = SET:rdnSet0 | |
169 [rdnSet0] | |
170 attrTypeAndValue0=SEQUENCE:attrTypeAndValueSequence0_0 | |
171 [attrTypeAndValueSequence0_0] | |
172 type=OID:countryName | |
173 """, "invalid-AttributeTypeAndValue-onlyOneElement") | |
174 | |
175 generate("""asn1 = SEQUENCE:rdnSequence | |
176 [rdnSequence] | |
177 rdn0 = SET:rdnSet0 | |
178 [rdnSet0] | |
179 attrTypeAndValue0=SEQUENCE:attrTypeAndValueSequence0_0 | |
180 [attrTypeAndValueSequence0_0] | |
181 """, "invalid-AttributeTypeAndValue-empty") | |
182 | |
183 generate("""asn1 = SEQUENCE:rdnSequence | |
184 [rdnSequence] | |
185 rdn0 = SET:rdnSet0 | |
186 [rdnSet0] | |
187 attrTypeAndValue0=SEQUENCE:attrTypeAndValueSequence0_0 | |
188 [attrTypeAndValueSequence0_0] | |
189 type=PRINTABLESTRING:"hello world" | |
190 value=PRINTABLESTRING:"US" | |
191 """, "invalid-AttributeTypeAndValue-badAttributeType") | |
192 | |
193 generate("""asn1 = SEQUENCE:rdnSequence | |
194 [rdnSequence] | |
195 rdn0 = SET:rdnSet0 | |
196 [rdnSet0] | |
197 attrTypeAndValue0=SET:attrTypeAndValueSequence0_0 | |
198 [attrTypeAndValueSequence0_0] | |
199 type=OID:countryName | |
200 value=PRINTABLESTRING:"US" | |
201 """, "invalid-AttributeTypeAndValue-setNotSequence") | |
202 | |
203 generate("""asn1 = SEQUENCE:rdnSequence | |
204 [rdnSequence] | |
205 rdn0 = SEQUENCE:rdnSet0 | |
206 [rdnSet0] | |
207 attrTypeAndValue0=SEQUENCE:attrTypeAndValueSequence0_0 | |
208 [attrTypeAndValueSequence0_0] | |
209 type=OID:countryName | |
210 value=PRINTABLESTRING:"US" | |
211 """, "invalid-RDN-sequenceInsteadOfSet") | |
212 | |
213 generate("""asn1 = SEQUENCE:rdnSequence | |
214 [rdnSequence] | |
215 rdn0 = SET:rdnSet0 | |
216 [rdnSet0] | |
217 """, "invalid-RDN-empty") | |
218 | |
219 generate("""asn1 = SET:rdnSequence | |
220 [rdnSequence] | |
221 rdn0 = SET:rdnSet0 | |
222 [rdnSet0] | |
223 attrTypeAndValue0=SEQUENCE:attrTypeAndValueSequence0_0 | |
224 [attrTypeAndValueSequence0_0] | |
225 type=OID:countryName | |
226 value=PRINTABLESTRING:"US" | |
227 """, "invalid-Name-setInsteadOfSequence") | |
228 | |
229 generate("""asn1 = SEQUENCE:rdnSequence | |
230 [rdnSequence] | |
231 """, "valid-Name-empty") | |
232 | |
233 # Certs with a RDN that is sorted differently due to length of the values, but | |
234 # which should compare equal when normalized. | |
235 generate("""asn1 = SEQUENCE:rdnSequence | |
236 [rdnSequence] | |
237 rdn0 = SET:rdnSet0 | |
238 [rdnSet0] | |
239 attrTypeAndValue0=SEQUENCE:attrTypeAndValueSequence0_0 | |
240 attrTypeAndValue1=SEQUENCE:attrTypeAndValueSequence0_1 | |
241 [attrTypeAndValueSequence0_0] | |
242 type=OID:stateOrProvinceName | |
243 value=PRINTABLESTRING:" state" | |
244 [attrTypeAndValueSequence0_1] | |
245 type=OID:localityName | |
246 value=PRINTABLESTRING:"locality" | |
247 """, "ascii-PRINTABLESTRING-rdn_sorting_1") | |
248 | |
249 generate("""asn1 = SEQUENCE:rdnSequence | |
250 [rdnSequence] | |
251 rdn0 = SET:rdnSet0 | |
252 [rdnSet0] | |
253 attrTypeAndValue0=SEQUENCE:attrTypeAndValueSequence0_0 | |
254 attrTypeAndValue1=SEQUENCE:attrTypeAndValueSequence0_1 | |
255 [attrTypeAndValueSequence0_0] | |
256 type=OID:stateOrProvinceName | |
257 value=PRINTABLESTRING:"state" | |
258 [attrTypeAndValueSequence0_1] | |
259 type=OID:localityName | |
260 value=PRINTABLESTRING:" locality" | |
261 """, "ascii-PRINTABLESTRING-rdn_sorting_2") | |
262 | |
263 # Certs with a RDN that is sorted differently due to length of the values, and | |
264 # also contains multiple values with the same type. | |
265 generate("""asn1 = SEQUENCE:rdnSequence | |
266 [rdnSequence] | |
267 rdn0 = SET:rdnSet0 | |
268 [rdnSet0] | |
269 attrTypeAndValue0=SEQUENCE:attrTypeAndValueSequence0_0 | |
270 attrTypeAndValue1=SEQUENCE:attrTypeAndValueSequence0_1 | |
271 attrTypeAndValue2=SEQUENCE:attrTypeAndValueSequence0_2 | |
272 attrTypeAndValue3=SEQUENCE:attrTypeAndValueSequence0_3 | |
273 attrTypeAndValue4=SEQUENCE:attrTypeAndValueSequence0_4 | |
274 [attrTypeAndValueSequence0_0] | |
275 type=OID:domainComponent | |
276 value=IA5STRING:" cOm" | |
277 [attrTypeAndValueSequence0_1] | |
278 type=OID:domainComponent | |
279 value=IA5STRING:"eXaMple" | |
280 [attrTypeAndValueSequence0_2] | |
281 type=OID:domainComponent | |
282 value=IA5STRING:"wWw" | |
283 [attrTypeAndValueSequence0_3] | |
284 type=OID:localityName | |
285 value=PRINTABLESTRING:"NEw" | |
286 [attrTypeAndValueSequence0_4] | |
287 type=OID:localityName | |
288 value=PRINTABLESTRING:" yORk " | |
289 """, "ascii-mixed-rdn_dupetype_sorting_1") | |
290 | |
291 generate("""asn1 = SEQUENCE:rdnSequence | |
292 [rdnSequence] | |
293 rdn0 = SET:rdnSet0 | |
294 [rdnSet0] | |
295 attrTypeAndValue0=SEQUENCE:attrTypeAndValueSequence0_0 | |
296 attrTypeAndValue1=SEQUENCE:attrTypeAndValueSequence0_1 | |
297 attrTypeAndValue2=SEQUENCE:attrTypeAndValueSequence0_2 | |
298 attrTypeAndValue3=SEQUENCE:attrTypeAndValueSequence0_3 | |
299 attrTypeAndValue4=SEQUENCE:attrTypeAndValueSequence0_4 | |
300 [attrTypeAndValueSequence0_0] | |
301 type=OID:domainComponent | |
302 value=IA5STRING:"cOM" | |
303 [attrTypeAndValueSequence0_1] | |
304 type=OID:domainComponent | |
305 value=IA5STRING:"eXampLE" | |
306 [attrTypeAndValueSequence0_2] | |
307 type=OID:domainComponent | |
308 value=IA5STRING:" Www " | |
309 [attrTypeAndValueSequence0_3] | |
310 type=OID:localityName | |
311 value=PRINTABLESTRING:" nEw " | |
312 [attrTypeAndValueSequence0_4] | |
313 type=OID:localityName | |
314 value=PRINTABLESTRING:"yoRK" | |
315 """, "ascii-mixed-rdn_dupetype_sorting_2") | |
316 | |
317 # Minimal valid config. Copy and modify this one when generating new invalid | |
318 # configs. | |
319 generate("""asn1 = SEQUENCE:rdnSequence | |
320 [rdnSequence] | |
321 rdn0 = SET:rdnSet0 | |
322 [rdnSet0] | |
323 attrTypeAndValue0=SEQUENCE:attrTypeAndValueSequence0_0 | |
324 [attrTypeAndValueSequence0_0] | |
325 type=OID:countryName | |
326 value=PRINTABLESTRING:"US" | |
327 """, "valid-minimal") | |
328 | |
329 if __name__ == '__main__': | |
330 main() | |
OLD | NEW |