/src/strongswan/src/libstrongswan/plugins/x509/x509_cert.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann |
3 | | * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss |
4 | | * Copyright (C) 2002 Mario Strasser |
5 | | * Copyright (C) 2000-2022 Andreas Steffen |
6 | | * Copyright (C) 2006-2009 Martin Willi |
7 | | * Copyright (C) 2008-2017 Tobias Brunner |
8 | | * |
9 | | * Copyright (C) secunet Security Networks AG |
10 | | * |
11 | | * This program is free software; you can redistribute it and/or modify it |
12 | | * under the terms of the GNU General Public License as published by the |
13 | | * Free Software Foundation; either version 2 of the License, or (at your |
14 | | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. |
15 | | * |
16 | | * This program is distributed in the hope that it will be useful, but |
17 | | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
18 | | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
19 | | * for more details. |
20 | | */ |
21 | | |
22 | | #define _GNU_SOURCE |
23 | | |
24 | | #include <sys/stat.h> |
25 | | #include <time.h> |
26 | | #include <unistd.h> |
27 | | #include <string.h> |
28 | | #include <stdio.h> |
29 | | |
30 | | #include "x509_cert.h" |
31 | | |
32 | | #include <library.h> |
33 | | #include <utils/debug.h> |
34 | | #include <asn1/oid.h> |
35 | | #include <asn1/asn1.h> |
36 | | #include <asn1/asn1_parser.h> |
37 | | #include <crypto/hashers/hasher.h> |
38 | | #include <credentials/keys/private_key.h> |
39 | | #include <collections/linked_list.h> |
40 | | #include <utils/identification.h> |
41 | | #include <selectors/traffic_selector.h> |
42 | | |
43 | | /** |
44 | | * Different kinds of generalNames |
45 | | */ |
46 | | typedef enum { |
47 | | GN_OTHER_NAME = 0, |
48 | | GN_RFC822_NAME = 1, |
49 | | GN_DNS_NAME = 2, |
50 | | GN_X400_ADDRESS = 3, |
51 | | GN_DIRECTORY_NAME = 4, |
52 | | GN_EDI_PARTY_NAME = 5, |
53 | | GN_URI = 6, |
54 | | GN_IP_ADDRESS = 7, |
55 | | GN_REGISTERED_ID = 8, |
56 | | } generalNames_t; |
57 | | |
58 | | |
59 | | typedef struct private_x509_cert_t private_x509_cert_t; |
60 | | |
61 | | /** |
62 | | * Private data of a x509_cert_t object. |
63 | | */ |
64 | | struct private_x509_cert_t { |
65 | | /** |
66 | | * Public interface for this certificate. |
67 | | */ |
68 | | x509_cert_t public; |
69 | | |
70 | | /** |
71 | | * X.509 certificate encoding in ASN.1 DER format |
72 | | */ |
73 | | chunk_t encoding; |
74 | | |
75 | | /** |
76 | | * SHA1 hash of the DER encoding of this X.509 certificate |
77 | | */ |
78 | | chunk_t encoding_hash; |
79 | | |
80 | | /** |
81 | | * X.509 certificate body over which signature is computed |
82 | | */ |
83 | | chunk_t tbsCertificate; |
84 | | |
85 | | /** |
86 | | * Version of the X.509 certificate |
87 | | */ |
88 | | u_int version; |
89 | | |
90 | | /** |
91 | | * Serial number of the X.509 certificate |
92 | | */ |
93 | | chunk_t serialNumber; |
94 | | |
95 | | /** |
96 | | * ID representing the certificate issuer |
97 | | */ |
98 | | identification_t *issuer; |
99 | | |
100 | | /** |
101 | | * Start time of certificate validity |
102 | | */ |
103 | | time_t notBefore; |
104 | | |
105 | | /** |
106 | | * End time of certificate validity |
107 | | */ |
108 | | time_t notAfter; |
109 | | |
110 | | /** |
111 | | * ID representing the certificate subject |
112 | | */ |
113 | | identification_t *subject; |
114 | | |
115 | | /** |
116 | | * List of subjectAltNames as identification_t |
117 | | */ |
118 | | linked_list_t *subjectAltNames; |
119 | | |
120 | | /** |
121 | | * List of crlDistributionPoints as x509_cdp_t* |
122 | | */ |
123 | | linked_list_t *crl_uris; |
124 | | |
125 | | /** |
126 | | * List of ocspAccessLocations as allocated char* |
127 | | */ |
128 | | linked_list_t *ocsp_uris; |
129 | | |
130 | | /** |
131 | | * List of ipAddrBlocks as traffic_selector_t |
132 | | */ |
133 | | linked_list_t *ipAddrBlocks; |
134 | | |
135 | | /** |
136 | | * List of permitted name constraints |
137 | | */ |
138 | | linked_list_t *permitted_names; |
139 | | |
140 | | /** |
141 | | * List of excluded name constraints |
142 | | */ |
143 | | linked_list_t *excluded_names; |
144 | | |
145 | | /** |
146 | | * List of certificatePolicies, as x509_cert_policy_t |
147 | | */ |
148 | | linked_list_t *cert_policies; |
149 | | |
150 | | /** |
151 | | * List of policyMappings, as x509_policy_mapping_t |
152 | | */ |
153 | | linked_list_t *policy_mappings; |
154 | | |
155 | | /** |
156 | | * certificate's embedded public key |
157 | | */ |
158 | | public_key_t *public_key; |
159 | | |
160 | | /** |
161 | | * Subject Key Identifier |
162 | | */ |
163 | | chunk_t subjectKeyIdentifier; |
164 | | |
165 | | /** |
166 | | * Authority Key Identifier |
167 | | */ |
168 | | chunk_t authKeyIdentifier; |
169 | | |
170 | | /** |
171 | | * Authority Key Serial Number |
172 | | */ |
173 | | chunk_t authKeySerialNumber; |
174 | | |
175 | | /** |
176 | | * Optional OID of an [unsupported] critical extension |
177 | | */ |
178 | | chunk_t critical_extension_oid; |
179 | | |
180 | | /** |
181 | | * Path Length Constraint |
182 | | */ |
183 | | u_char pathLenConstraint; |
184 | | |
185 | | /** |
186 | | * requireExplicitPolicy Constraint |
187 | | */ |
188 | | u_char require_explicit; |
189 | | |
190 | | /** |
191 | | * inhibitPolicyMapping Constraint |
192 | | */ |
193 | | u_char inhibit_mapping; |
194 | | |
195 | | /** |
196 | | * inhibitAnyPolicy Constraint |
197 | | */ |
198 | | u_char inhibit_any; |
199 | | |
200 | | /** |
201 | | * x509 constraints and other flags |
202 | | */ |
203 | | x509_flag_t flags; |
204 | | |
205 | | /** |
206 | | * Signature scheme |
207 | | */ |
208 | | signature_params_t *scheme; |
209 | | |
210 | | /** |
211 | | * Signature |
212 | | */ |
213 | | chunk_t signature; |
214 | | |
215 | | /** |
216 | | * Certificate parsed from blob/file? |
217 | | */ |
218 | | bool parsed; |
219 | | |
220 | | /** |
221 | | * reference count |
222 | | */ |
223 | | refcount_t ref; |
224 | | }; |
225 | | |
226 | | /** |
227 | | * Convert a generalName to a string |
228 | | */ |
229 | | static bool gn_to_string(identification_t *id, char **uri) |
230 | 4.17k | { |
231 | 4.17k | int len; |
232 | | |
233 | 4.17k | #ifdef USE_FUZZING |
234 | 4.17k | chunk_t proper; |
235 | 4.17k | chunk_printable(id->get_encoding(id), &proper, '?'); |
236 | 4.17k | len = asprintf(uri, "%.*s", (int)proper.len, proper.ptr); |
237 | 4.17k | chunk_free(&proper); |
238 | | #else |
239 | | len = asprintf(uri, "%Y", id); |
240 | | #endif |
241 | 4.17k | if (!len) |
242 | 2.90k | { |
243 | 2.90k | free(*uri); |
244 | 2.90k | return FALSE; |
245 | 2.90k | } |
246 | 1.26k | return len > 0; |
247 | 4.17k | } |
248 | | |
249 | | /** |
250 | | * Destroy a CertificatePolicy |
251 | | */ |
252 | | static void cert_policy_destroy(x509_cert_policy_t *this) |
253 | 368 | { |
254 | 368 | free(this->oid.ptr); |
255 | 368 | free(this->cps_uri); |
256 | 368 | free(this->unotice_text); |
257 | 368 | free(this); |
258 | 368 | } |
259 | | |
260 | | /** |
261 | | * Free policy mapping |
262 | | */ |
263 | | static void policy_mapping_destroy(x509_policy_mapping_t *mapping) |
264 | 100 | { |
265 | 100 | free(mapping->issuer.ptr); |
266 | 100 | free(mapping->subject.ptr); |
267 | 100 | free(mapping); |
268 | 100 | } |
269 | | |
270 | | /** |
271 | | * Parse a length constraint from an unwrapped integer |
272 | | */ |
273 | | static u_int parse_constraint(chunk_t object) |
274 | 357 | { |
275 | 357 | switch (object.len) |
276 | 357 | { |
277 | 59 | case 0: |
278 | 59 | return 0; |
279 | 283 | case 1: |
280 | 283 | return (object.ptr[0] & 0x80) ? X509_NO_CONSTRAINT : object.ptr[0]; |
281 | 15 | default: |
282 | 15 | return X509_NO_CONSTRAINT; |
283 | 357 | } |
284 | 357 | } |
285 | | |
286 | | /** |
287 | | * ASN.1 definition of a basicConstraints extension |
288 | | */ |
289 | | static const asn1Object_t basicConstraintsObjects[] = { |
290 | | { 0, "basicConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ |
291 | | { 1, "CA", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 1 */ |
292 | | { 1, "pathLenConstraint", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 2 */ |
293 | | { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ |
294 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
295 | | }; |
296 | 15.8k | #define BASIC_CONSTRAINTS_CA 1 |
297 | 608 | #define BASIC_CONSTRAINTS_PATH_LEN 2 |
298 | | |
299 | | /** |
300 | | * Extracts the basicConstraints extension |
301 | | */ |
302 | | static bool parse_basicConstraints(chunk_t blob, int level0, |
303 | | private_x509_cert_t *this) |
304 | 15.8k | { |
305 | 15.8k | asn1_parser_t *parser; |
306 | 15.8k | chunk_t object; |
307 | 15.8k | int objectID; |
308 | 15.8k | bool isCA = FALSE; |
309 | 15.8k | bool success; |
310 | | |
311 | 15.8k | parser = asn1_parser_create(basicConstraintsObjects, blob); |
312 | 15.8k | parser->set_top_level(parser, level0); |
313 | | |
314 | 64.0k | while (parser->iterate(parser, &objectID, &object)) |
315 | 48.1k | { |
316 | 48.1k | switch (objectID) |
317 | 48.1k | { |
318 | 15.8k | case BASIC_CONSTRAINTS_CA: |
319 | 15.8k | isCA = object.len && *object.ptr; |
320 | 15.8k | DBG2(DBG_ASN, " %s", isCA ? "TRUE" : "FALSE"); |
321 | 15.8k | if (isCA) |
322 | 474 | { |
323 | 474 | this->flags |= X509_CA; |
324 | 474 | } |
325 | 15.8k | break; |
326 | 608 | case BASIC_CONSTRAINTS_PATH_LEN: |
327 | 608 | if (isCA) |
328 | 228 | { |
329 | 228 | this->pathLenConstraint = parse_constraint(object); |
330 | 228 | } |
331 | 608 | break; |
332 | 31.7k | default: |
333 | 31.7k | break; |
334 | 48.1k | } |
335 | 48.1k | } |
336 | 15.8k | success = parser->success(parser); |
337 | 15.8k | parser->destroy(parser); |
338 | | |
339 | 15.8k | return success; |
340 | 15.8k | } |
341 | | |
342 | | /** |
343 | | * ASN.1 definition of otherName |
344 | | */ |
345 | | static const asn1Object_t otherNameObjects[] = { |
346 | | {0, "type-id", ASN1_OID, ASN1_BODY }, /* 0 */ |
347 | | {0, "value", ASN1_CONTEXT_C_0, ASN1_BODY }, /* 1 */ |
348 | | {0, "exit", ASN1_EOC, ASN1_EXIT } |
349 | | }; |
350 | 109 | #define ON_OBJ_ID_TYPE 0 |
351 | 100 | #define ON_OBJ_VALUE 1 |
352 | | |
353 | | /** |
354 | | * Extracts an otherName |
355 | | */ |
356 | | static bool parse_otherName(chunk_t *blob, int level0, id_type_t *type) |
357 | 119 | { |
358 | 119 | asn1_parser_t *parser; |
359 | 119 | chunk_t object; |
360 | 119 | int objectID; |
361 | 119 | int oid = OID_UNKNOWN; |
362 | 119 | bool success = FALSE; |
363 | | |
364 | 119 | parser = asn1_parser_create(otherNameObjects, *blob); |
365 | 119 | parser->set_top_level(parser, level0); |
366 | | |
367 | 325 | while (parser->iterate(parser, &objectID, &object)) |
368 | 209 | { |
369 | 209 | switch (objectID) |
370 | 209 | { |
371 | 109 | case ON_OBJ_ID_TYPE: |
372 | 109 | oid = asn1_known_oid(object); |
373 | 109 | break; |
374 | 100 | case ON_OBJ_VALUE: |
375 | 100 | switch (oid) |
376 | 100 | { |
377 | 57 | case OID_XMPP_ADDR: |
378 | 57 | if (asn1_parse_simple_object(&object, ASN1_UTF8STRING, |
379 | 57 | parser->get_level(parser)+1, "xmppAddr")) |
380 | 55 | { /* we handle xmppAddr as RFC822 addr */ |
381 | 55 | *blob = object; |
382 | 55 | *type = ID_RFC822_ADDR; |
383 | 55 | } |
384 | 2 | else |
385 | 2 | { |
386 | 2 | goto end; |
387 | 2 | } |
388 | 55 | break; |
389 | 55 | case OID_USER_PRINCIPAL_NAME: |
390 | 25 | if (asn1_parse_simple_object(&object, ASN1_UTF8STRING, |
391 | 25 | parser->get_level(parser)+1, "msUPN")) |
392 | 24 | { /* we handle UPNs as RFC822 addr */ |
393 | 24 | *blob = object; |
394 | 24 | *type = ID_RFC822_ADDR; |
395 | 24 | } |
396 | 1 | else |
397 | 1 | { |
398 | 1 | goto end; |
399 | 1 | } |
400 | 24 | break; |
401 | 100 | } |
402 | 97 | break; |
403 | 97 | default: |
404 | 0 | break; |
405 | 209 | } |
406 | 209 | } |
407 | 116 | success = parser->success(parser); |
408 | | |
409 | 119 | end: |
410 | 119 | parser->destroy(parser); |
411 | 119 | return success; |
412 | 116 | } |
413 | | |
414 | | /** |
415 | | * ASN.1 definition of generalName |
416 | | */ |
417 | | static const asn1Object_t generalNameObjects[] = { |
418 | | { 0, "otherName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 0 */ |
419 | | { 0, "end choice", ASN1_EOC, ASN1_END }, /* 1 */ |
420 | | { 0, "rfc822Name", ASN1_CONTEXT_S_1, ASN1_OPT|ASN1_BODY }, /* 2 */ |
421 | | { 0, "end choice", ASN1_EOC, ASN1_END }, /* 3 */ |
422 | | { 0, "dnsName", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 4 */ |
423 | | { 0, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ |
424 | | { 0, "x400Address", ASN1_CONTEXT_S_3, ASN1_OPT|ASN1_BODY }, /* 6 */ |
425 | | { 0, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ |
426 | | { 0, "directoryName", ASN1_CONTEXT_C_4, ASN1_OPT|ASN1_BODY }, /* 8 */ |
427 | | { 0, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ |
428 | | { 0, "ediPartyName", ASN1_CONTEXT_C_5, ASN1_OPT|ASN1_BODY }, /* 10 */ |
429 | | { 0, "end choice", ASN1_EOC, ASN1_END }, /* 11 */ |
430 | | { 0, "URI", ASN1_CONTEXT_S_6, ASN1_OPT|ASN1_BODY }, /* 12 */ |
431 | | { 0, "end choice", ASN1_EOC, ASN1_END }, /* 13 */ |
432 | | { 0, "ipAddress", ASN1_CONTEXT_S_7, ASN1_OPT|ASN1_BODY }, /* 14 */ |
433 | | { 0, "end choice", ASN1_EOC, ASN1_END }, /* 15 */ |
434 | | { 0, "registeredID", ASN1_CONTEXT_S_8, ASN1_OPT|ASN1_BODY }, /* 16 */ |
435 | | { 0, "end choice", ASN1_EOC, ASN1_END }, /* 17 */ |
436 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
437 | | }; |
438 | 119 | #define GN_OBJ_OTHER_NAME 0 |
439 | 778 | #define GN_OBJ_RFC822_NAME 2 |
440 | 9.02k | #define GN_OBJ_DNS_NAME 4 |
441 | 0 | #define GN_OBJ_X400_ADDRESS 6 |
442 | 16.1k | #define GN_OBJ_DIRECTORY_NAME 8 |
443 | 2 | #define GN_OBJ_EDI_PARTY_NAME 10 |
444 | 602 | #define GN_OBJ_URI 12 |
445 | 319 | #define GN_OBJ_IP_ADDRESS 14 |
446 | 3 | #define GN_OBJ_REGISTERED_ID 16 |
447 | | |
448 | | /** |
449 | | * Extracts a generalName |
450 | | */ |
451 | | static identification_t *parse_generalName(chunk_t blob, int level0) |
452 | 27.0k | { |
453 | 27.0k | asn1_parser_t *parser; |
454 | 27.0k | chunk_t object; |
455 | 27.0k | int objectID ; |
456 | | |
457 | 27.0k | identification_t *gn = NULL; |
458 | | |
459 | 27.0k | parser = asn1_parser_create(generalNameObjects, blob); |
460 | 27.0k | parser->set_top_level(parser, level0); |
461 | | |
462 | 116k | while (parser->iterate(parser, &objectID, &object)) |
463 | 116k | { |
464 | 116k | id_type_t id_type = ID_ANY; |
465 | | |
466 | 116k | switch (objectID) |
467 | 116k | { |
468 | 778 | case GN_OBJ_RFC822_NAME: |
469 | 778 | id_type = ID_RFC822_ADDR; |
470 | 778 | break; |
471 | 9.02k | case GN_OBJ_DNS_NAME: |
472 | 9.02k | id_type = ID_FQDN; |
473 | 9.02k | break; |
474 | 602 | case GN_OBJ_URI: |
475 | 602 | id_type = ID_DER_ASN1_GN_URI; |
476 | 602 | break; |
477 | 16.1k | case GN_OBJ_DIRECTORY_NAME: |
478 | 16.1k | id_type = ID_DER_ASN1_DN; |
479 | 16.1k | break; |
480 | 319 | case GN_OBJ_IP_ADDRESS: |
481 | 319 | switch (object.len) |
482 | 319 | { |
483 | 225 | case 4: |
484 | 225 | id_type = ID_IPV4_ADDR; |
485 | 225 | break; |
486 | 2 | case 8: |
487 | 2 | id_type = ID_IPV4_ADDR_SUBNET; |
488 | 2 | break; |
489 | 63 | case 16: |
490 | 63 | id_type = ID_IPV6_ADDR; |
491 | 63 | break; |
492 | 0 | case 32: |
493 | 0 | id_type = ID_IPV6_ADDR_SUBNET; |
494 | 0 | break; |
495 | 29 | default: |
496 | 29 | break; |
497 | 319 | } |
498 | 319 | break; |
499 | 319 | case GN_OBJ_OTHER_NAME: |
500 | 119 | if (!parse_otherName(&object, parser->get_level(parser)+1, |
501 | 119 | &id_type)) |
502 | 22 | { |
503 | 22 | goto end; |
504 | 22 | } |
505 | 97 | break; |
506 | 97 | case GN_OBJ_X400_ADDRESS: |
507 | 2 | case GN_OBJ_EDI_PARTY_NAME: |
508 | 3 | case GN_OBJ_REGISTERED_ID: |
509 | 89.8k | default: |
510 | 89.8k | break; |
511 | 116k | } |
512 | 116k | if (id_type != ID_ANY) |
513 | 26.8k | { |
514 | 26.8k | gn = identification_create_from_encoding(id_type, object); |
515 | 26.8k | DBG2(DBG_ASN, " '%Y'", gn); |
516 | 26.8k | goto end; |
517 | 26.8k | } |
518 | 116k | } |
519 | | |
520 | 27.0k | end: |
521 | 27.0k | parser->destroy(parser); |
522 | 27.0k | return gn; |
523 | 27.0k | } |
524 | | |
525 | | /** |
526 | | * ASN.1 definition of generalNames |
527 | | */ |
528 | | static const asn1Object_t generalNamesObjects[] = { |
529 | | { 0, "generalNames", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ |
530 | | { 1, "generalName", ASN1_EOC, ASN1_RAW }, /* 1 */ |
531 | | { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ |
532 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
533 | | }; |
534 | 44.1k | #define GENERAL_NAMES_GN 1 |
535 | | |
536 | | /** |
537 | | * Extracts one or several GNs and puts them into a chained list |
538 | | */ |
539 | | bool x509_parse_generalNames(chunk_t blob, int level0, bool implicit, |
540 | | linked_list_t *list) |
541 | 8.84k | { |
542 | 8.84k | asn1_parser_t *parser; |
543 | 8.84k | chunk_t object; |
544 | 8.84k | identification_t *gn; |
545 | 8.84k | int objectID; |
546 | 8.84k | bool success = FALSE; |
547 | | |
548 | 8.84k | parser = asn1_parser_create(generalNamesObjects, blob); |
549 | 8.84k | parser->set_top_level(parser, level0); |
550 | 8.84k | parser->set_flags(parser, implicit, FALSE); |
551 | | |
552 | 52.8k | while (parser->iterate(parser, &objectID, &object)) |
553 | 44.1k | { |
554 | 44.1k | if (objectID == GENERAL_NAMES_GN) |
555 | 26.7k | { |
556 | 26.7k | gn = parse_generalName(object, parser->get_level(parser)+1); |
557 | 26.7k | if (!gn) |
558 | 114 | { |
559 | 114 | goto end; |
560 | 114 | } |
561 | 26.6k | list->insert_last(list, (void *)gn); |
562 | 26.6k | } |
563 | 44.1k | } |
564 | 8.73k | success = parser->success(parser); |
565 | | |
566 | 8.84k | end: |
567 | 8.84k | parser->destroy(parser); |
568 | | |
569 | 8.84k | return success; |
570 | 8.73k | } |
571 | | |
572 | | /** |
573 | | * ASN.1 definition of a authorityKeyIdentifier extension |
574 | | */ |
575 | | static const asn1Object_t authKeyIdentifierObjects[] = { |
576 | | { 0, "authorityKeyIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ |
577 | | { 1, "keyIdentifier", ASN1_CONTEXT_S_0, ASN1_OPT|ASN1_BODY }, /* 1 */ |
578 | | { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ |
579 | | { 1, "authorityCertIssuer", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_OBJ }, /* 3 */ |
580 | | { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */ |
581 | | { 1, "authorityCertSerialNumber", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 5 */ |
582 | | { 1, "end opt", ASN1_EOC, ASN1_END }, /* 6 */ |
583 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
584 | | }; |
585 | 24.8k | #define AUTH_KEY_ID_KEY_ID 1 |
586 | 5 | #define AUTH_KEY_ID_CERT_ISSUER 3 |
587 | 89 | #define AUTH_KEY_ID_CERT_SERIAL 5 |
588 | | |
589 | | /** |
590 | | * Extracts an authoritykeyIdentifier |
591 | | */ |
592 | | chunk_t x509_parse_authorityKeyIdentifier(chunk_t blob, int level0, |
593 | | chunk_t *authKeySerialNumber) |
594 | 26.0k | { |
595 | 26.0k | asn1_parser_t *parser; |
596 | 26.0k | chunk_t object; |
597 | 26.0k | int objectID; |
598 | 26.0k | chunk_t authKeyIdentifier = chunk_empty; |
599 | | |
600 | 26.0k | *authKeySerialNumber = chunk_empty; |
601 | | |
602 | 26.0k | parser = asn1_parser_create(authKeyIdentifierObjects, blob); |
603 | 26.0k | parser->set_top_level(parser, level0); |
604 | | |
605 | 151k | while (parser->iterate(parser, &objectID, &object)) |
606 | 125k | { |
607 | 125k | switch (objectID) |
608 | 125k | { |
609 | 24.8k | case AUTH_KEY_ID_KEY_ID: |
610 | 24.8k | authKeyIdentifier = chunk_clone(object); |
611 | 24.8k | break; |
612 | 5 | case AUTH_KEY_ID_CERT_ISSUER: |
613 | | /* TODO: x509_parse_generalNames(object, level+1, TRUE); */ |
614 | 5 | break; |
615 | 89 | case AUTH_KEY_ID_CERT_SERIAL: |
616 | 89 | *authKeySerialNumber = object; |
617 | 89 | break; |
618 | 100k | default: |
619 | 100k | break; |
620 | 125k | } |
621 | 125k | } |
622 | 26.0k | parser->destroy(parser); |
623 | | |
624 | 26.0k | return authKeyIdentifier; |
625 | 26.0k | } |
626 | | |
627 | | /** |
628 | | * ASN.1 definition of a authorityInfoAccess extension |
629 | | */ |
630 | | static const asn1Object_t authInfoAccessObjects[] = { |
631 | | { 0, "authorityInfoAccess", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ |
632 | | { 1, "accessDescription", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ |
633 | | { 2, "accessMethod", ASN1_OID, ASN1_BODY }, /* 2 */ |
634 | | { 2, "accessLocation", ASN1_EOC, ASN1_RAW }, /* 3 */ |
635 | | { 0, "end loop", ASN1_EOC, ASN1_END }, /* 4 */ |
636 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
637 | | }; |
638 | 250 | #define AUTH_INFO_ACCESS_METHOD 2 |
639 | 248 | #define AUTH_INFO_ACCESS_LOCATION 3 |
640 | | |
641 | | /** |
642 | | * Extracts an authorityInfoAcess location |
643 | | */ |
644 | | static bool parse_authorityInfoAccess(chunk_t blob, int level0, |
645 | | private_x509_cert_t *this) |
646 | 126 | { |
647 | 126 | asn1_parser_t *parser; |
648 | 126 | chunk_t object; |
649 | 126 | int objectID; |
650 | 126 | int accessMethod = OID_UNKNOWN; |
651 | 126 | bool success = FALSE; |
652 | | |
653 | 126 | parser = asn1_parser_create(authInfoAccessObjects, blob); |
654 | 126 | parser->set_top_level(parser, level0); |
655 | | |
656 | 1.10k | while (parser->iterate(parser, &objectID, &object)) |
657 | 976 | { |
658 | 976 | switch (objectID) |
659 | 976 | { |
660 | 250 | case AUTH_INFO_ACCESS_METHOD: |
661 | 250 | accessMethod = asn1_known_oid(object); |
662 | 250 | break; |
663 | 248 | case AUTH_INFO_ACCESS_LOCATION: |
664 | 248 | { |
665 | 248 | switch (accessMethod) |
666 | 248 | { |
667 | 60 | case OID_OCSP: |
668 | 126 | case OID_CA_ISSUERS: |
669 | 126 | { |
670 | 126 | identification_t *id; |
671 | 126 | char *uri; |
672 | | |
673 | 126 | id = parse_generalName(object, |
674 | 126 | parser->get_level(parser)+1); |
675 | 126 | if (id == NULL) |
676 | 1 | { |
677 | | /* parsing went wrong - abort */ |
678 | 1 | goto end; |
679 | 1 | } |
680 | 125 | DBG2(DBG_ASN, " '%Y'", id); |
681 | 125 | if (accessMethod == OID_OCSP && |
682 | 125 | gn_to_string(id, &uri)) |
683 | 47 | { |
684 | 47 | this->ocsp_uris->insert_last(this->ocsp_uris, uri); |
685 | 47 | } |
686 | 125 | id->destroy(id); |
687 | 125 | } |
688 | 0 | break; |
689 | 122 | default: |
690 | | /* unknown accessMethod, ignoring */ |
691 | 122 | break; |
692 | 248 | } |
693 | 247 | break; |
694 | 248 | } |
695 | 478 | default: |
696 | 478 | break; |
697 | 976 | } |
698 | 976 | } |
699 | 125 | success = parser->success(parser); |
700 | | |
701 | 126 | end: |
702 | 126 | parser->destroy(parser); |
703 | | |
704 | 126 | return success; |
705 | 125 | } |
706 | | |
707 | | /** |
708 | | * Extract KeyUsage flags |
709 | | */ |
710 | | static void parse_keyUsage(chunk_t blob, private_x509_cert_t *this) |
711 | 1.77k | { |
712 | 1.77k | enum { |
713 | 1.77k | KU_DIGITAL_SIGNATURE = 0, |
714 | 1.77k | KU_NON_REPUDIATION = 1, |
715 | 1.77k | KU_KEY_ENCIPHERMENT = 2, |
716 | 1.77k | KU_DATA_ENCIPHERMENT = 3, |
717 | 1.77k | KU_KEY_AGREEMENT = 4, |
718 | 1.77k | KU_KEY_CERT_SIGN = 5, |
719 | 1.77k | KU_CRL_SIGN = 6, |
720 | 1.77k | KU_ENCIPHER_ONLY = 7, |
721 | 1.77k | KU_DECIPHER_ONLY = 8, |
722 | 1.77k | }; |
723 | | |
724 | 1.77k | if (asn1_unwrap(&blob, &blob) == ASN1_BIT_STRING && blob.len) |
725 | 670 | { |
726 | 670 | int bit, byte, unused = blob.ptr[0]; |
727 | | |
728 | 670 | blob = chunk_skip(blob, 1); |
729 | 2.45k | for (byte = 0; byte < blob.len; byte++) |
730 | 1.78k | { |
731 | 14.2k | for (bit = 0; bit < 8; bit++) |
732 | 13.0k | { |
733 | 13.0k | if (byte == blob.len - 1 && bit > (7 - unused)) |
734 | 591 | { |
735 | 591 | break; |
736 | 591 | } |
737 | 12.4k | if (blob.ptr[byte] & 1 << (7 - bit)) |
738 | 5.82k | { |
739 | 5.82k | switch (byte * 8 + bit) |
740 | 5.82k | { |
741 | 334 | case KU_CRL_SIGN: |
742 | 334 | this->flags |= X509_CRL_SIGN; |
743 | 334 | break; |
744 | 311 | case KU_DIGITAL_SIGNATURE: |
745 | 476 | case KU_NON_REPUDIATION: |
746 | 476 | this->flags |= X509_IKE_COMPLIANT; |
747 | 476 | break; |
748 | 315 | case KU_KEY_CERT_SIGN: |
749 | | /* we use the caBasicConstraint, MUST be set */ |
750 | 564 | case KU_KEY_ENCIPHERMENT: |
751 | 728 | case KU_DATA_ENCIPHERMENT: |
752 | 900 | case KU_KEY_AGREEMENT: |
753 | 951 | case KU_ENCIPHER_ONLY: |
754 | 983 | case KU_DECIPHER_ONLY: |
755 | 983 | break; |
756 | 5.82k | } |
757 | 5.82k | } |
758 | 12.4k | } |
759 | 1.78k | } |
760 | 670 | } |
761 | 1.77k | } |
762 | | |
763 | | /** |
764 | | * ASN.1 definition of a extendedKeyUsage extension |
765 | | */ |
766 | | static const asn1Object_t extendedKeyUsageObjects[] = { |
767 | | { 0, "extendedKeyUsage", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ |
768 | | { 1, "keyPurposeID", ASN1_OID, ASN1_BODY }, /* 1 */ |
769 | | { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ |
770 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
771 | | }; |
772 | 1.78k | #define EXT_KEY_USAGE_PURPOSE_ID 1 |
773 | | |
774 | | /** |
775 | | * Extracts extendedKeyUsage OIDs (shared with x509_pkcs10.c) |
776 | | */ |
777 | | bool x509_parse_eku_extension(chunk_t blob, int level0, x509_flag_t *flags) |
778 | 252 | { |
779 | 252 | asn1_parser_t *parser; |
780 | 252 | chunk_t object; |
781 | 252 | int objectID; |
782 | 252 | bool success; |
783 | | |
784 | 252 | parser = asn1_parser_create(extendedKeyUsageObjects, blob); |
785 | 252 | parser->set_top_level(parser, level0); |
786 | | |
787 | 2.04k | while (parser->iterate(parser, &objectID, &object)) |
788 | 1.78k | { |
789 | 1.78k | if (objectID == EXT_KEY_USAGE_PURPOSE_ID) |
790 | 1.35k | { |
791 | 1.35k | switch (asn1_known_oid(object)) |
792 | 1.35k | { |
793 | 55 | case OID_SERVER_AUTH: |
794 | 55 | *flags |= X509_SERVER_AUTH; |
795 | 55 | break; |
796 | 43 | case OID_CLIENT_AUTH: |
797 | 43 | *flags |= X509_CLIENT_AUTH; |
798 | 43 | break; |
799 | 15 | case OID_IKE_INTERMEDIATE: |
800 | 15 | *flags |= X509_IKE_INTERMEDIATE; |
801 | 15 | break; |
802 | 22 | case OID_OCSP_SIGNING: |
803 | 22 | *flags |= X509_OCSP_SIGNER; |
804 | 22 | break; |
805 | 13 | case OID_MS_SMARTCARD_LOGON: |
806 | 13 | *flags |= X509_MS_SMARTCARD_LOGON; |
807 | 13 | break; |
808 | 1.21k | default: |
809 | 1.21k | break; |
810 | 1.35k | } |
811 | 1.35k | } |
812 | 1.78k | } |
813 | 252 | success = parser->success(parser); |
814 | 252 | parser->destroy(parser); |
815 | | |
816 | 252 | return success; |
817 | 252 | } |
818 | | |
819 | | /** |
820 | | * ASN.1 definition of crlDistributionPoints |
821 | | */ |
822 | | static const asn1Object_t crlDistributionPointsObjects[] = { |
823 | | { 0, "crlDistributionPoints", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ |
824 | | { 1, "DistributionPoint", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ |
825 | | { 2, "distributionPoint", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_CHOICE }, /* 2 */ |
826 | | { 3, "fullName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_OBJ }, /* 3 */ |
827 | | { 3, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 4 */ |
828 | | { 3, "nameRelToCRLIssuer",ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 5 */ |
829 | | { 3, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 6 */ |
830 | | { 2, "end opt/choices", ASN1_EOC, ASN1_END|ASN1_CHOICE }, /* 7 */ |
831 | | { 2, "reasons", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 8 */ |
832 | | { 2, "end opt", ASN1_EOC, ASN1_END }, /* 9 */ |
833 | | { 2, "crlIssuer", ASN1_CONTEXT_C_2, ASN1_OPT|ASN1_OBJ }, /* 10 */ |
834 | | { 2, "end opt", ASN1_EOC, ASN1_END }, /* 11 */ |
835 | | { 0, "end loop", ASN1_EOC, ASN1_END }, /* 12 */ |
836 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
837 | | }; |
838 | 724 | #define CRL_DIST_POINTS 1 |
839 | 348 | #define CRL_DIST_POINTS_FULLNAME 3 |
840 | 219 | #define CRL_DIST_POINTS_ISSUER 10 |
841 | | |
842 | | /** |
843 | | * Add entry to the list of each pairing of URI and Issuer |
844 | | */ |
845 | | static void add_cdps(linked_list_t *list, linked_list_t *uris, |
846 | | linked_list_t *issuers) |
847 | 1.20k | { |
848 | 1.20k | identification_t *issuer, *id; |
849 | 1.20k | enumerator_t *enumerator; |
850 | 1.20k | x509_cdp_t *cdp; |
851 | 1.20k | char *uri; |
852 | | |
853 | 5.31k | while (uris->remove_last(uris, (void**)&id) == SUCCESS) |
854 | 4.11k | { |
855 | 4.11k | if (gn_to_string(id, &uri)) |
856 | 1.21k | { |
857 | 1.21k | if (issuers->get_count(issuers)) |
858 | 299 | { |
859 | 299 | enumerator = issuers->create_enumerator(issuers); |
860 | 7.36k | while (enumerator->enumerate(enumerator, &issuer)) |
861 | 7.06k | { |
862 | 7.06k | INIT(cdp, |
863 | 7.06k | .uri = strdup(uri), |
864 | 7.06k | .issuer = issuer->clone(issuer), |
865 | 7.06k | ); |
866 | 7.06k | list->insert_last(list, cdp); |
867 | 7.06k | } |
868 | 299 | enumerator->destroy(enumerator); |
869 | 299 | free(uri); |
870 | 299 | } |
871 | 917 | else |
872 | 917 | { |
873 | 917 | INIT(cdp, |
874 | 917 | .uri = uri, |
875 | 917 | ); |
876 | 917 | list->insert_last(list, cdp); |
877 | 917 | } |
878 | 1.21k | } |
879 | 4.11k | id->destroy(id); |
880 | 4.11k | } |
881 | 4.00k | while (issuers->remove_last(issuers, (void**)&id) == SUCCESS) |
882 | 2.80k | { |
883 | 2.80k | id->destroy(id); |
884 | 2.80k | } |
885 | 1.20k | } |
886 | | |
887 | | /** |
888 | | * Extracts one or several crlDistributionPoints into a list |
889 | | */ |
890 | | bool x509_parse_crlDistributionPoints(chunk_t blob, int level0, |
891 | | linked_list_t *list) |
892 | 550 | { |
893 | 550 | linked_list_t *uris, *issuers; |
894 | 550 | asn1_parser_t *parser; |
895 | 550 | chunk_t object; |
896 | 550 | int objectID; |
897 | 550 | bool success = FALSE; |
898 | | |
899 | 550 | uris = linked_list_create(); |
900 | 550 | issuers = linked_list_create(); |
901 | 550 | parser = asn1_parser_create(crlDistributionPointsObjects, blob); |
902 | 550 | parser->set_top_level(parser, level0); |
903 | | |
904 | 5.36k | while (parser->iterate(parser, &objectID, &object)) |
905 | 4.88k | { |
906 | 4.88k | switch (objectID) |
907 | 4.88k | { |
908 | 724 | case CRL_DIST_POINTS: |
909 | 724 | add_cdps(list, uris, issuers); |
910 | 724 | break; |
911 | 348 | case CRL_DIST_POINTS_FULLNAME: |
912 | 348 | if (!x509_parse_generalNames(object, |
913 | 348 | parser->get_level(parser) + 1, TRUE, uris)) |
914 | 18 | { |
915 | 18 | goto end; |
916 | 18 | } |
917 | 330 | break; |
918 | 330 | case CRL_DIST_POINTS_ISSUER: |
919 | 219 | if (!x509_parse_generalNames(object, |
920 | 219 | parser->get_level(parser) + 1, TRUE, issuers)) |
921 | 53 | { |
922 | 53 | goto end; |
923 | 53 | } |
924 | 166 | break; |
925 | 3.59k | default: |
926 | 3.59k | break; |
927 | 4.88k | } |
928 | 4.88k | } |
929 | 479 | success = parser->success(parser); |
930 | 479 | add_cdps(list, uris, issuers); |
931 | | |
932 | 550 | end: |
933 | 550 | parser->destroy(parser); |
934 | 550 | uris->destroy_offset(uris, offsetof(identification_t, destroy)); |
935 | 550 | issuers->destroy_offset(issuers, offsetof(identification_t, destroy)); |
936 | | |
937 | 550 | return success; |
938 | 479 | } |
939 | | |
940 | | /** |
941 | | * ASN.1 definition of nameConstraints |
942 | | */ |
943 | | static const asn1Object_t nameConstraintsObjects[] = { |
944 | | { 0, "nameConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ |
945 | | { 1, "permittedSubtrees", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_LOOP }, /* 1 */ |
946 | | { 2, "generalSubtree", ASN1_SEQUENCE, ASN1_BODY }, /* 2 */ |
947 | | { 1, "end loop", ASN1_EOC, ASN1_END }, /* 3 */ |
948 | | { 1, "excludedSubtrees", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_LOOP }, /* 4 */ |
949 | | { 2, "generalSubtree", ASN1_SEQUENCE, ASN1_BODY }, /* 5 */ |
950 | | { 1, "end loop", ASN1_EOC, ASN1_END }, /* 6 */ |
951 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
952 | | }; |
953 | 66 | #define NAME_CONSTRAINT_PERMITTED 2 |
954 | 67 | #define NAME_CONSTRAINT_EXCLUDED 5 |
955 | | |
956 | | /** |
957 | | * Parse permitted/excluded nameConstraints |
958 | | */ |
959 | | static bool parse_nameConstraints(chunk_t blob, int level0, |
960 | | private_x509_cert_t *this) |
961 | 140 | { |
962 | 140 | asn1_parser_t *parser; |
963 | 140 | identification_t *id; |
964 | 140 | chunk_t object; |
965 | 140 | int objectID; |
966 | 140 | bool success = FALSE; |
967 | | |
968 | 140 | parser = asn1_parser_create(nameConstraintsObjects, blob); |
969 | 140 | parser->set_top_level(parser, level0); |
970 | | |
971 | 672 | while (parser->iterate(parser, &objectID, &object)) |
972 | 546 | { |
973 | 546 | switch (objectID) |
974 | 546 | { |
975 | 66 | case NAME_CONSTRAINT_PERMITTED: |
976 | 66 | id = parse_generalName(object, parser->get_level(parser) + 1); |
977 | 66 | if (!id) |
978 | 4 | { |
979 | 4 | goto end; |
980 | 4 | } |
981 | 62 | this->permitted_names->insert_last(this->permitted_names, id); |
982 | 62 | break; |
983 | 67 | case NAME_CONSTRAINT_EXCLUDED: |
984 | 67 | id = parse_generalName(object, parser->get_level(parser) + 1); |
985 | 67 | if (!id) |
986 | 10 | { |
987 | 10 | goto end; |
988 | 10 | } |
989 | 57 | this->excluded_names->insert_last(this->excluded_names, id); |
990 | 57 | break; |
991 | 413 | default: |
992 | 413 | break; |
993 | 546 | } |
994 | 546 | } |
995 | 126 | success = parser->success(parser); |
996 | | |
997 | 140 | end: |
998 | 140 | parser->destroy(parser); |
999 | | |
1000 | 140 | return success; |
1001 | 126 | } |
1002 | | |
1003 | | /** |
1004 | | * ASN.1 definition of a certificatePolicies extension |
1005 | | */ |
1006 | | static const asn1Object_t certificatePoliciesObject[] = { |
1007 | | { 0, "certificatePolicies", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ |
1008 | | { 1, "policyInformation", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ |
1009 | | { 2, "policyId", ASN1_OID, ASN1_BODY }, /* 2 */ |
1010 | | { 2, "qualifiers", ASN1_SEQUENCE, ASN1_OPT|ASN1_LOOP }, /* 3 */ |
1011 | | { 3, "qualifierInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 4 */ |
1012 | | { 4, "qualifierId", ASN1_OID, ASN1_BODY }, /* 5 */ |
1013 | | { 4, "qualifier", ASN1_EOC, ASN1_CHOICE }, /* 6 */ |
1014 | | { 5, "cPSuri", ASN1_IA5STRING, ASN1_OPT|ASN1_BODY }, /* 7 */ |
1015 | | { 5, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 8 */ |
1016 | | { 5, "userNotice", ASN1_SEQUENCE, ASN1_OPT|ASN1_BODY }, /* 9 */ |
1017 | | { 6, "explicitText", ASN1_EOC, ASN1_RAW }, /* 10 */ |
1018 | | { 5, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 11 */ |
1019 | | { 4, "end choices", ASN1_EOC, ASN1_END|ASN1_CHOICE }, /* 12 */ |
1020 | | { 2, "end opt/loop", ASN1_EOC, ASN1_END }, /* 13 */ |
1021 | | { 0, "end loop", ASN1_EOC, ASN1_END }, /* 14 */ |
1022 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
1023 | | }; |
1024 | 368 | #define CERT_POLICY_ID 2 |
1025 | 171 | #define CERT_POLICY_QUALIFIER_ID 5 |
1026 | 161 | #define CERT_POLICY_CPS_URI 7 |
1027 | 10 | #define CERT_POLICY_EXPLICIT_TEXT 10 |
1028 | | |
1029 | | /** |
1030 | | * Parse certificatePolicies |
1031 | | */ |
1032 | | static bool parse_certificatePolicies(chunk_t blob, int level0, |
1033 | | private_x509_cert_t *this) |
1034 | 200 | { |
1035 | 200 | x509_cert_policy_t *policy = NULL; |
1036 | 200 | asn1_parser_t *parser; |
1037 | 200 | chunk_t object; |
1038 | 200 | int objectID, qualifier = OID_UNKNOWN; |
1039 | 200 | bool success; |
1040 | | |
1041 | 200 | parser = asn1_parser_create(certificatePoliciesObject, blob); |
1042 | 200 | parser->set_top_level(parser, level0); |
1043 | | |
1044 | 2.78k | while (parser->iterate(parser, &objectID, &object)) |
1045 | 2.58k | { |
1046 | 2.58k | switch (objectID) |
1047 | 2.58k | { |
1048 | 368 | case CERT_POLICY_ID: |
1049 | 368 | INIT(policy, |
1050 | 368 | .oid = chunk_clone(object), |
1051 | 368 | ); |
1052 | 368 | this->cert_policies->insert_last(this->cert_policies, policy); |
1053 | 368 | break; |
1054 | 171 | case CERT_POLICY_QUALIFIER_ID: |
1055 | 171 | qualifier = asn1_known_oid(object); |
1056 | 171 | break; |
1057 | 161 | case CERT_POLICY_CPS_URI: |
1058 | 161 | if (policy && !policy->cps_uri && object.len && |
1059 | 161 | qualifier == OID_POLICY_QUALIFIER_CPS && |
1060 | 161 | chunk_printable(object, NULL, 0)) |
1061 | 28 | { |
1062 | 28 | policy->cps_uri = strndup(object.ptr, object.len); |
1063 | 28 | } |
1064 | 161 | break; |
1065 | 10 | case CERT_POLICY_EXPLICIT_TEXT: |
1066 | | /* TODO */ |
1067 | 10 | break; |
1068 | 1.87k | default: |
1069 | 1.87k | break; |
1070 | 2.58k | } |
1071 | 2.58k | } |
1072 | 200 | success = parser->success(parser); |
1073 | 200 | parser->destroy(parser); |
1074 | | |
1075 | 200 | return success; |
1076 | 200 | } |
1077 | | |
1078 | | /** |
1079 | | * ASN.1 definition of a policyMappings extension |
1080 | | */ |
1081 | | static const asn1Object_t policyMappingsObjects[] = { |
1082 | | { 0, "policyMappings", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ |
1083 | | { 1, "policyMapping", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ |
1084 | | { 2, "issuerPolicy", ASN1_OID, ASN1_BODY }, /* 2 */ |
1085 | | { 2, "subjectPolicy", ASN1_OID, ASN1_BODY }, /* 3 */ |
1086 | | { 0, "end loop", ASN1_EOC, ASN1_END }, /* 4 */ |
1087 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
1088 | | }; |
1089 | 100 | #define POLICY_MAPPING 1 |
1090 | 94 | #define POLICY_MAPPING_ISSUER 2 |
1091 | 90 | #define POLICY_MAPPING_SUBJECT 3 |
1092 | | |
1093 | | /** |
1094 | | * Parse policyMappings |
1095 | | */ |
1096 | | static bool parse_policyMappings(chunk_t blob, int level0, |
1097 | | private_x509_cert_t *this) |
1098 | 97 | { |
1099 | 97 | x509_policy_mapping_t *map = NULL; |
1100 | 97 | asn1_parser_t *parser; |
1101 | 97 | chunk_t object; |
1102 | 97 | int objectID; |
1103 | 97 | bool success; |
1104 | | |
1105 | 97 | parser = asn1_parser_create(policyMappingsObjects, blob); |
1106 | 97 | parser->set_top_level(parser, level0); |
1107 | | |
1108 | 511 | while (parser->iterate(parser, &objectID, &object)) |
1109 | 414 | { |
1110 | 414 | switch (objectID) |
1111 | 414 | { |
1112 | 100 | case POLICY_MAPPING: |
1113 | 100 | INIT(map); |
1114 | 100 | this->policy_mappings->insert_last(this->policy_mappings, map); |
1115 | 100 | break; |
1116 | 94 | case POLICY_MAPPING_ISSUER: |
1117 | 94 | if (map && !map->issuer.len) |
1118 | 94 | { |
1119 | 94 | map->issuer = chunk_clone(object); |
1120 | 94 | } |
1121 | 94 | break; |
1122 | 90 | case POLICY_MAPPING_SUBJECT: |
1123 | 90 | if (map && !map->subject.len) |
1124 | 90 | { |
1125 | 90 | map->subject = chunk_clone(object); |
1126 | 90 | } |
1127 | 90 | break; |
1128 | 130 | default: |
1129 | 130 | break; |
1130 | 414 | } |
1131 | 414 | } |
1132 | 97 | success = parser->success(parser); |
1133 | 97 | parser->destroy(parser); |
1134 | | |
1135 | 97 | return success; |
1136 | 97 | } |
1137 | | |
1138 | | /** |
1139 | | * ASN.1 definition of a policyConstraints extension |
1140 | | */ |
1141 | | static const asn1Object_t policyConstraintsObjects[] = { |
1142 | | { 0, "policyConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ |
1143 | | { 1, "requireExplicitPolicy", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_NONE }, /* 1 */ |
1144 | | { 2, "SkipCerts", ASN1_INTEGER, ASN1_BODY }, /* 2 */ |
1145 | | { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ |
1146 | | { 1, "inhibitPolicyMapping", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_NONE }, /* 4 */ |
1147 | | { 2, "SkipCerts", ASN1_INTEGER, ASN1_BODY }, /* 5 */ |
1148 | | { 1, "end opt", ASN1_EOC, ASN1_END }, /* 6 */ |
1149 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
1150 | | }; |
1151 | 53 | #define POLICY_CONSTRAINT_EXPLICIT 2 |
1152 | 55 | #define POLICY_CONSTRAINT_INHIBIT 5 |
1153 | | |
1154 | | /** |
1155 | | * Parse policyConstraints |
1156 | | */ |
1157 | | static bool parse_policyConstraints(chunk_t blob, int level0, |
1158 | | private_x509_cert_t *this) |
1159 | 215 | { |
1160 | 215 | asn1_parser_t *parser; |
1161 | 215 | chunk_t object; |
1162 | 215 | int objectID; |
1163 | 215 | bool success; |
1164 | | |
1165 | 215 | parser = asn1_parser_create(policyConstraintsObjects, blob); |
1166 | 215 | parser->set_top_level(parser, level0); |
1167 | | |
1168 | 1.05k | while (parser->iterate(parser, &objectID, &object)) |
1169 | 838 | { |
1170 | 838 | switch (objectID) |
1171 | 838 | { |
1172 | 53 | case POLICY_CONSTRAINT_EXPLICIT: |
1173 | 53 | this->require_explicit = parse_constraint(object); |
1174 | 53 | break; |
1175 | 55 | case POLICY_CONSTRAINT_INHIBIT: |
1176 | 55 | this->inhibit_mapping = parse_constraint(object); |
1177 | 55 | break; |
1178 | 730 | default: |
1179 | 730 | break; |
1180 | 838 | } |
1181 | 838 | } |
1182 | 215 | success = parser->success(parser); |
1183 | 215 | parser->destroy(parser); |
1184 | | |
1185 | 215 | return success; |
1186 | 215 | } |
1187 | | |
1188 | | /** |
1189 | | * ASN.1 definition of ipAddrBlocks according to RFC 3779 |
1190 | | */ |
1191 | | static const asn1Object_t ipAddrBlocksObjects[] = { |
1192 | | { 0, "ipAddrBlocks", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ |
1193 | | { 1, "ipAddressFamily", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ |
1194 | | { 2, "addressFamily", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ |
1195 | | { 2, "ipAddressChoice", ASN1_EOC, ASN1_CHOICE }, /* 3 */ |
1196 | | { 3, "inherit", ASN1_NULL, ASN1_OPT }, /* 4 */ |
1197 | | { 3, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 5 */ |
1198 | | { 3, "addressesOrRanges", ASN1_SEQUENCE, ASN1_OPT|ASN1_LOOP }, /* 6 */ |
1199 | | { 4, "addressOrRange", ASN1_EOC, ASN1_CHOICE }, /* 7 */ |
1200 | | { 5, "addressPrefix", ASN1_BIT_STRING, ASN1_OPT|ASN1_BODY }, /* 8 */ |
1201 | | { 5, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 9 */ |
1202 | | { 5, "addressRange", ASN1_SEQUENCE, ASN1_OPT }, /* 10 */ |
1203 | | { 6, "min", ASN1_BIT_STRING, ASN1_BODY }, /* 11 */ |
1204 | | { 6, "max", ASN1_BIT_STRING, ASN1_BODY }, /* 12 */ |
1205 | | { 5, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 13 */ |
1206 | | { 4, "end choices", ASN1_EOC, ASN1_END|ASN1_CHOICE }, /* 14 */ |
1207 | | { 3, "end loop/choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 15 */ |
1208 | | { 2, "end choices", ASN1_EOC, ASN1_END|ASN1_CHOICE }, /* 16 */ |
1209 | | { 0, "end loop", ASN1_EOC, ASN1_END }, /* 17 */ |
1210 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
1211 | | }; |
1212 | 218 | #define IP_ADDR_BLOCKS_FAMILY 2 |
1213 | 51 | #define IP_ADDR_BLOCKS_INHERIT 4 |
1214 | 130 | #define IP_ADDR_BLOCKS_PREFIX 8 |
1215 | 120 | #define IP_ADDR_BLOCKS_MIN 11 |
1216 | 105 | #define IP_ADDR_BLOCKS_MAX 12 |
1217 | | |
1218 | | static bool check_address_object(ts_type_t ts_type, chunk_t object) |
1219 | 355 | { |
1220 | 355 | switch (ts_type) |
1221 | 355 | { |
1222 | 116 | case TS_IPV4_ADDR_RANGE: |
1223 | 116 | if (object.len > 5) |
1224 | 4 | { |
1225 | 4 | DBG1(DBG_ASN, "IPv4 address object is larger than 5 octets"); |
1226 | 4 | return FALSE; |
1227 | 4 | } |
1228 | 112 | break; |
1229 | 234 | case TS_IPV6_ADDR_RANGE: |
1230 | 234 | if (object.len > 17) |
1231 | 3 | { |
1232 | 3 | DBG1(DBG_ASN, "IPv6 address object is larger than 17 octets"); |
1233 | 3 | return FALSE; |
1234 | 3 | } |
1235 | 231 | break; |
1236 | 231 | default: |
1237 | 5 | DBG1(DBG_ASN, "unknown address family"); |
1238 | 5 | return FALSE; |
1239 | 355 | } |
1240 | 343 | if (object.len == 0) |
1241 | 4 | { |
1242 | 4 | DBG1(DBG_ASN, "An ASN.1 bit string must contain at least the " |
1243 | 4 | "initial octet"); |
1244 | 4 | return FALSE; |
1245 | 4 | } |
1246 | 339 | if (object.len == 1 && object.ptr[0] != 0) |
1247 | 12 | { |
1248 | 12 | DBG1(DBG_ASN, "An empty ASN.1 bit string must contain a zero " |
1249 | 12 | "initial octet"); |
1250 | 12 | return FALSE; |
1251 | 12 | } |
1252 | 327 | if (object.ptr[0] > 7) |
1253 | 12 | { |
1254 | 12 | DBG1(DBG_ASN, "number of unused bits is too large"); |
1255 | 12 | return FALSE; |
1256 | 12 | } |
1257 | 315 | return TRUE; |
1258 | 327 | } |
1259 | | |
1260 | | static bool parse_ipAddrBlocks(chunk_t blob, int level0, |
1261 | | private_x509_cert_t *this) |
1262 | 108 | { |
1263 | 108 | asn1_parser_t *parser; |
1264 | 108 | chunk_t object, min_object; |
1265 | 108 | ts_type_t ts_type = 0; |
1266 | 108 | traffic_selector_t *ts; |
1267 | 108 | int objectID; |
1268 | 108 | bool success = FALSE; |
1269 | | |
1270 | 108 | parser = asn1_parser_create(ipAddrBlocksObjects, blob); |
1271 | 108 | parser->set_top_level(parser, level0); |
1272 | | |
1273 | 2.81k | while (parser->iterate(parser, &objectID, &object)) |
1274 | 2.74k | { |
1275 | 2.74k | switch (objectID) |
1276 | 2.74k | { |
1277 | 218 | case IP_ADDR_BLOCKS_FAMILY: |
1278 | 218 | ts_type = 0; |
1279 | 218 | if (object.len == 2 && object.ptr[0] == 0) |
1280 | 171 | { |
1281 | 171 | if (object.ptr[1] == 1) |
1282 | 48 | { |
1283 | 48 | ts_type = TS_IPV4_ADDR_RANGE; |
1284 | 48 | } |
1285 | 123 | else if (object.ptr[1] == 2) |
1286 | 102 | { |
1287 | 102 | ts_type = TS_IPV6_ADDR_RANGE; |
1288 | 102 | } |
1289 | 21 | else |
1290 | 21 | { |
1291 | 21 | break; |
1292 | 21 | } |
1293 | 150 | DBG2(DBG_ASN, " %N", ts_type_name, ts_type); |
1294 | 150 | } |
1295 | 197 | break; |
1296 | 197 | case IP_ADDR_BLOCKS_INHERIT: |
1297 | 51 | DBG1(DBG_ASN, "inherit choice is not supported"); |
1298 | 51 | break; |
1299 | 130 | case IP_ADDR_BLOCKS_PREFIX: |
1300 | 130 | if (!check_address_object(ts_type, object)) |
1301 | 16 | { |
1302 | 16 | goto end; |
1303 | 16 | } |
1304 | 114 | ts = traffic_selector_create_from_rfc3779_format(ts_type, |
1305 | 114 | object, object); |
1306 | 114 | DBG2(DBG_ASN, " %R", ts); |
1307 | 114 | this->ipAddrBlocks->insert_last(this->ipAddrBlocks, ts); |
1308 | 114 | break; |
1309 | 120 | case IP_ADDR_BLOCKS_MIN: |
1310 | 120 | if (!check_address_object(ts_type, object)) |
1311 | 14 | { |
1312 | 14 | goto end; |
1313 | 14 | } |
1314 | 106 | min_object = object; |
1315 | 106 | break; |
1316 | 105 | case IP_ADDR_BLOCKS_MAX: |
1317 | 105 | if (!check_address_object(ts_type, object)) |
1318 | 10 | { |
1319 | 10 | goto end; |
1320 | 10 | } |
1321 | 95 | ts = traffic_selector_create_from_rfc3779_format(ts_type, |
1322 | 95 | min_object, object); |
1323 | 95 | DBG2(DBG_ASN, " %R", ts); |
1324 | 95 | this->ipAddrBlocks->insert_last(this->ipAddrBlocks, ts); |
1325 | 95 | break; |
1326 | 2.11k | default: |
1327 | 2.11k | break; |
1328 | 2.74k | } |
1329 | 2.74k | } |
1330 | 68 | success = parser->success(parser); |
1331 | 68 | this->flags |= X509_IP_ADDR_BLOCKS; |
1332 | | |
1333 | 108 | end: |
1334 | 108 | parser->destroy(parser); |
1335 | | |
1336 | 108 | return success; |
1337 | 68 | } |
1338 | | |
1339 | | /** |
1340 | | * ASN.1 definition of an X.509v3 x509_cert |
1341 | | */ |
1342 | | static const asn1Object_t certObjects[] = { |
1343 | | { 0, "x509", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ |
1344 | | { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ |
1345 | | { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */ |
1346 | | { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ |
1347 | | { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */ |
1348 | | { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */ |
1349 | | { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */ |
1350 | | { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */ |
1351 | | { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */ |
1352 | | { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */ |
1353 | | { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ |
1354 | | { 2, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_RAW }, /* 11 */ |
1355 | | { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */ |
1356 | | { 2, "end opt", ASN1_EOC, ASN1_END }, /* 13 */ |
1357 | | { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 14 */ |
1358 | | { 2, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ |
1359 | | { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 16 */ |
1360 | | { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 17 */ |
1361 | | { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 18 */ |
1362 | | { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 19 */ |
1363 | | { 5, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 20 */ |
1364 | | { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 21 */ |
1365 | | { 3, "end loop", ASN1_EOC, ASN1_END }, /* 22 */ |
1366 | | { 2, "end opt", ASN1_EOC, ASN1_END }, /* 23 */ |
1367 | | { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 24 */ |
1368 | | { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 25 */ |
1369 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
1370 | | }; |
1371 | 44.9k | #define X509_OBJ_TBS_CERTIFICATE 1 |
1372 | 44.9k | #define X509_OBJ_VERSION 3 |
1373 | 44.8k | #define X509_OBJ_SERIAL_NUMBER 4 |
1374 | 44.8k | #define X509_OBJ_SIG_ALG 5 |
1375 | 43.5k | #define X509_OBJ_ISSUER 6 |
1376 | 43.5k | #define X509_OBJ_NOT_BEFORE 8 |
1377 | 43.5k | #define X509_OBJ_NOT_AFTER 9 |
1378 | 43.4k | #define X509_OBJ_SUBJECT 10 |
1379 | 43.4k | #define X509_OBJ_SUBJECT_PUBLIC_KEY_INFO 11 |
1380 | 27.0k | #define X509_OBJ_OPTIONAL_EXTENSIONS 16 |
1381 | 57.3k | #define X509_OBJ_EXTN_ID 19 |
1382 | 57.3k | #define X509_OBJ_CRITICAL 20 |
1383 | 57.2k | #define X509_OBJ_EXTN_VALUE 21 |
1384 | 41.9k | #define X509_OBJ_ALGORITHM 24 |
1385 | 41.6k | #define X509_OBJ_SIGNATURE 25 |
1386 | | |
1387 | | /** |
1388 | | * Parses an X.509v3 certificate |
1389 | | */ |
1390 | | static bool parse_certificate(private_x509_cert_t *this) |
1391 | 58.6k | { |
1392 | 58.6k | asn1_parser_t *parser; |
1393 | 58.6k | chunk_t object; |
1394 | 58.6k | int objectID; |
1395 | 58.6k | int extn_oid = OID_UNKNOWN; |
1396 | 58.6k | signature_params_t sig_alg = {}; |
1397 | 58.6k | bool critical = FALSE, key_usage_parsed = FALSE; |
1398 | 58.6k | bool success = FALSE; |
1399 | | |
1400 | 58.6k | parser = asn1_parser_create(certObjects, this->encoding); |
1401 | | |
1402 | 1.10M | while (parser->iterate(parser, &objectID, &object)) |
1403 | 1.05M | { |
1404 | 1.05M | u_int level = parser->get_level(parser)+1; |
1405 | | |
1406 | 1.05M | switch (objectID) |
1407 | 1.05M | { |
1408 | 44.9k | case X509_OBJ_TBS_CERTIFICATE: |
1409 | 44.9k | this->tbsCertificate = object; |
1410 | 44.9k | break; |
1411 | 44.9k | case X509_OBJ_VERSION: |
1412 | 44.9k | this->version = (object.len) ? (1+(u_int)*object.ptr) : 1; |
1413 | 44.9k | if (this->version < 1 || this->version > 3) |
1414 | 18 | { |
1415 | 18 | DBG1(DBG_ASN, "X.509v%d not supported", this->version); |
1416 | 18 | goto end; |
1417 | 18 | } |
1418 | 44.9k | else |
1419 | 44.9k | { |
1420 | 44.9k | DBG2(DBG_ASN, " X.509v%d", this->version); |
1421 | 44.9k | } |
1422 | 44.9k | break; |
1423 | 44.9k | case X509_OBJ_SERIAL_NUMBER: |
1424 | 44.8k | this->serialNumber = object; |
1425 | 44.8k | break; |
1426 | 44.8k | case X509_OBJ_SIG_ALG: |
1427 | 44.8k | if (!signature_params_parse(object, level, &sig_alg)) |
1428 | 1.16k | { |
1429 | 1.16k | DBG1(DBG_ASN, " unable to parse signature algorithm"); |
1430 | 1.16k | goto end; |
1431 | 1.16k | } |
1432 | 43.6k | break; |
1433 | 43.6k | case X509_OBJ_ISSUER: |
1434 | 43.5k | this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object); |
1435 | 43.5k | DBG2(DBG_ASN, " '%Y'", this->issuer); |
1436 | 43.5k | break; |
1437 | 43.5k | case X509_OBJ_NOT_BEFORE: |
1438 | 43.5k | this->notBefore = asn1_parse_time(object, level); |
1439 | 43.5k | break; |
1440 | 43.5k | case X509_OBJ_NOT_AFTER: |
1441 | 43.5k | this->notAfter = asn1_parse_time(object, level); |
1442 | 43.5k | break; |
1443 | 43.4k | case X509_OBJ_SUBJECT: |
1444 | 43.4k | this->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object); |
1445 | 43.4k | DBG2(DBG_ASN, " '%Y'", this->subject); |
1446 | 43.4k | break; |
1447 | 43.4k | case X509_OBJ_SUBJECT_PUBLIC_KEY_INFO: |
1448 | 43.4k | DBG2(DBG_ASN, "-- > --"); |
1449 | 43.4k | this->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, |
1450 | 43.4k | KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END); |
1451 | 43.4k | DBG2(DBG_ASN, "-- < --"); |
1452 | 43.4k | if (this->public_key == NULL) |
1453 | 308 | { |
1454 | 308 | goto end; |
1455 | 308 | } |
1456 | 43.1k | break; |
1457 | 43.1k | case X509_OBJ_OPTIONAL_EXTENSIONS: |
1458 | 27.0k | if (this->version != 3) |
1459 | 4 | { |
1460 | 4 | DBG1(DBG_ASN, "Only X.509v3 certificates have extensions"); |
1461 | 4 | goto end; |
1462 | 4 | } |
1463 | 27.0k | break; |
1464 | 57.3k | case X509_OBJ_EXTN_ID: |
1465 | 57.3k | extn_oid = asn1_known_oid(object); |
1466 | 57.3k | break; |
1467 | 57.3k | case X509_OBJ_CRITICAL: |
1468 | 57.3k | critical = object.len && *object.ptr; |
1469 | 57.3k | DBG2(DBG_ASN, " %s", critical ? "TRUE" : "FALSE"); |
1470 | 57.3k | break; |
1471 | 57.2k | case X509_OBJ_EXTN_VALUE: |
1472 | 57.2k | { |
1473 | 57.2k | switch (extn_oid) |
1474 | 57.2k | { |
1475 | 463 | case OID_SUBJECT_KEY_ID: |
1476 | 463 | if (!asn1_parse_simple_object(&object, ASN1_OCTET_STRING, |
1477 | 463 | level, "keyIdentifier")) |
1478 | 27 | { |
1479 | 27 | goto end; |
1480 | 27 | } |
1481 | 436 | this->subjectKeyIdentifier = object; |
1482 | 436 | break; |
1483 | 8.27k | case OID_SUBJECT_ALT_NAME: |
1484 | 8.27k | if (!x509_parse_generalNames(object, level, FALSE, |
1485 | 8.27k | this->subjectAltNames)) |
1486 | 120 | { |
1487 | 120 | goto end; |
1488 | 120 | } |
1489 | 8.15k | break; |
1490 | 15.8k | case OID_BASIC_CONSTRAINTS: |
1491 | 15.8k | if (!parse_basicConstraints(object, level, this)) |
1492 | 12 | { |
1493 | 12 | goto end; |
1494 | 12 | } |
1495 | 15.8k | break; |
1496 | 15.8k | case OID_CRL_DISTRIBUTION_POINTS: |
1497 | 371 | if (!x509_parse_crlDistributionPoints(object, level, |
1498 | 371 | this->crl_uris)) |
1499 | 65 | { |
1500 | 65 | goto end; |
1501 | 65 | } |
1502 | 306 | break; |
1503 | 25.4k | case OID_AUTHORITY_KEY_ID: |
1504 | 25.4k | chunk_free(&this->authKeyIdentifier); |
1505 | 25.4k | this->authKeyIdentifier = x509_parse_authorityKeyIdentifier( |
1506 | 25.4k | object, level, &this->authKeySerialNumber); |
1507 | 25.4k | break; |
1508 | 126 | case OID_AUTHORITY_INFO_ACCESS: |
1509 | 126 | if (!parse_authorityInfoAccess(object, level, this)) |
1510 | 15 | { |
1511 | 15 | goto end; |
1512 | 15 | } |
1513 | 111 | break; |
1514 | 1.77k | case OID_KEY_USAGE: |
1515 | 1.77k | parse_keyUsage(object, this); |
1516 | 1.77k | key_usage_parsed = TRUE; |
1517 | 1.77k | break; |
1518 | 252 | case OID_EXTENDED_KEY_USAGE: |
1519 | 252 | if (!x509_parse_eku_extension(object, level, &this->flags)) |
1520 | 49 | { |
1521 | 49 | goto end; |
1522 | 49 | } |
1523 | 203 | break; |
1524 | 203 | case OID_IP_ADDR_BLOCKS: |
1525 | 108 | if (!parse_ipAddrBlocks(object, level, this)) |
1526 | 69 | { |
1527 | 69 | goto end; |
1528 | 69 | } |
1529 | 39 | break; |
1530 | 140 | case OID_NAME_CONSTRAINTS: |
1531 | 140 | if (!parse_nameConstraints(object, level, this)) |
1532 | 31 | { |
1533 | 31 | goto end; |
1534 | 31 | } |
1535 | 109 | break; |
1536 | 200 | case OID_CERTIFICATE_POLICIES: |
1537 | 200 | if (!parse_certificatePolicies(object, level, this)) |
1538 | 31 | { |
1539 | 31 | goto end; |
1540 | 31 | } |
1541 | 169 | break; |
1542 | 169 | case OID_POLICY_MAPPINGS: |
1543 | 97 | if (!parse_policyMappings(object, level, this)) |
1544 | 20 | { |
1545 | 20 | goto end; |
1546 | 20 | } |
1547 | 77 | break; |
1548 | 215 | case OID_POLICY_CONSTRAINTS: |
1549 | 215 | if (!parse_policyConstraints(object, level, this)) |
1550 | 14 | { |
1551 | 14 | goto end; |
1552 | 14 | } |
1553 | 201 | break; |
1554 | 201 | case OID_INHIBIT_ANY_POLICY: |
1555 | 31 | if (!asn1_parse_simple_object(&object, ASN1_INTEGER, |
1556 | 31 | level, "inhibitAnyPolicy")) |
1557 | 10 | { |
1558 | 10 | goto end; |
1559 | 10 | } |
1560 | 21 | this->inhibit_any = parse_constraint(object); |
1561 | 21 | break; |
1562 | 15 | case OID_NS_REVOCATION_URL: |
1563 | 27 | case OID_NS_CA_REVOCATION_URL: |
1564 | 56 | case OID_NS_CA_POLICY_URL: |
1565 | 87 | case OID_NS_COMMENT: |
1566 | 87 | if (!asn1_parse_simple_object(&object, ASN1_IA5STRING, |
1567 | 87 | level, oid_names[extn_oid].name)) |
1568 | 9 | { |
1569 | 9 | goto end; |
1570 | 9 | } |
1571 | 78 | break; |
1572 | 3.75k | default: |
1573 | 3.75k | if (critical && lib->settings->get_bool(lib->settings, |
1574 | 24 | "%s.x509.enforce_critical", TRUE, lib->ns)) |
1575 | 24 | { |
1576 | 24 | DBG1(DBG_ASN, "critical '%s' extension not supported", |
1577 | 24 | (extn_oid == OID_UNKNOWN) ? "unknown" : |
1578 | 24 | (char*)oid_names[extn_oid].name); |
1579 | 24 | goto end; |
1580 | 24 | } |
1581 | 3.73k | break; |
1582 | 57.2k | } |
1583 | 56.7k | break; |
1584 | 57.2k | } |
1585 | 56.7k | case X509_OBJ_ALGORITHM: |
1586 | 41.9k | INIT(this->scheme); |
1587 | 41.9k | if (!signature_params_parse(object, level, this->scheme)) |
1588 | 201 | { |
1589 | 201 | DBG1(DBG_ASN, " unable to parse signature algorithm"); |
1590 | 201 | goto end; |
1591 | 201 | } |
1592 | 41.7k | if (!signature_params_equal(this->scheme, &sig_alg)) |
1593 | 120 | { |
1594 | 120 | DBG1(DBG_ASN, " signature algorithms do not agree"); |
1595 | 120 | goto end; |
1596 | 120 | } |
1597 | 41.6k | break; |
1598 | 41.6k | case X509_OBJ_SIGNATURE: |
1599 | 41.6k | this->signature = chunk_skip(object, 1); |
1600 | 41.6k | break; |
1601 | 372k | default: |
1602 | 372k | break; |
1603 | 1.05M | } |
1604 | 1.05M | } |
1605 | 56.3k | success = parser->success(parser); |
1606 | | |
1607 | 58.6k | end: |
1608 | 58.6k | parser->destroy(parser); |
1609 | 58.6k | signature_params_clear(&sig_alg); |
1610 | 58.6k | if (success) |
1611 | 41.6k | { |
1612 | 41.6k | hasher_t *hasher; |
1613 | | |
1614 | 41.6k | if (!key_usage_parsed) |
1615 | 41.0k | { |
1616 | | /* we are compliant with RFC 4945 without keyUsage extension */ |
1617 | 41.0k | this->flags |= X509_IKE_COMPLIANT; |
1618 | | /* allow CA certificates without keyUsage extension to sign CRLs */ |
1619 | 41.0k | if (this->flags & X509_CA) |
1620 | 48 | { |
1621 | 48 | this->flags |= X509_CRL_SIGN; |
1622 | 48 | } |
1623 | 41.0k | } |
1624 | | |
1625 | | /* check if the certificate is self-signed */ |
1626 | 41.6k | if (this->public.interface.interface.issued_by( |
1627 | 41.6k | &this->public.interface.interface, |
1628 | 41.6k | &this->public.interface.interface, |
1629 | 41.6k | NULL)) |
1630 | 3 | { |
1631 | 3 | this->flags |= X509_SELF_SIGNED; |
1632 | 3 | } |
1633 | | /* create certificate hash */ |
1634 | 41.6k | hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); |
1635 | 41.6k | if (!hasher || |
1636 | 41.6k | !hasher->allocate_hash(hasher, this->encoding, &this->encoding_hash)) |
1637 | 0 | { |
1638 | 0 | DESTROY_IF(hasher); |
1639 | 0 | DBG1(DBG_ASN, " unable to create hash of certificate, SHA1 not supported"); |
1640 | 0 | return FALSE; |
1641 | 0 | } |
1642 | 41.6k | hasher->destroy(hasher); |
1643 | 41.6k | } |
1644 | 58.6k | return success; |
1645 | 58.6k | } |
1646 | | |
1647 | | METHOD(certificate_t, get_type, certificate_type_t, |
1648 | | private_x509_cert_t *this) |
1649 | 0 | { |
1650 | 0 | return CERT_X509; |
1651 | 0 | } |
1652 | | |
1653 | | METHOD(certificate_t, get_subject, identification_t*, |
1654 | | private_x509_cert_t *this) |
1655 | 17.0k | { |
1656 | 17.0k | return this->subject; |
1657 | 17.0k | } |
1658 | | |
1659 | | METHOD(certificate_t, get_issuer, identification_t*, |
1660 | | private_x509_cert_t *this) |
1661 | 0 | { |
1662 | 0 | return this->issuer; |
1663 | 0 | } |
1664 | | |
1665 | | METHOD(certificate_t, has_subject, id_match_t, |
1666 | | private_x509_cert_t *this, identification_t *subject) |
1667 | 0 | { |
1668 | 0 | identification_t *current; |
1669 | 0 | enumerator_t *enumerator; |
1670 | 0 | id_match_t match, best; |
1671 | 0 | chunk_t encoding; |
1672 | |
|
1673 | 0 | if (subject->get_type(subject) == ID_KEY_ID) |
1674 | 0 | { |
1675 | 0 | encoding = subject->get_encoding(subject); |
1676 | |
|
1677 | 0 | if (this->encoding_hash.len && |
1678 | 0 | chunk_equals(this->encoding_hash, encoding)) |
1679 | 0 | { |
1680 | 0 | return ID_MATCH_PERFECT; |
1681 | 0 | } |
1682 | 0 | if (this->subjectKeyIdentifier.len && |
1683 | 0 | chunk_equals(this->subjectKeyIdentifier, encoding)) |
1684 | 0 | { |
1685 | 0 | return ID_MATCH_PERFECT; |
1686 | 0 | } |
1687 | 0 | if (this->public_key && |
1688 | 0 | this->public_key->has_fingerprint(this->public_key, encoding)) |
1689 | 0 | { |
1690 | 0 | return ID_MATCH_PERFECT; |
1691 | 0 | } |
1692 | 0 | if (chunk_equals(this->serialNumber, encoding)) |
1693 | 0 | { |
1694 | 0 | return ID_MATCH_PERFECT; |
1695 | 0 | } |
1696 | 0 | } |
1697 | 0 | best = this->subject->matches(this->subject, subject); |
1698 | 0 | enumerator = this->subjectAltNames->create_enumerator(this->subjectAltNames); |
1699 | 0 | while (enumerator->enumerate(enumerator, ¤t)) |
1700 | 0 | { |
1701 | 0 | match = current->matches(current, subject); |
1702 | 0 | if (match > best) |
1703 | 0 | { |
1704 | 0 | best = match; |
1705 | 0 | } |
1706 | 0 | } |
1707 | 0 | enumerator->destroy(enumerator); |
1708 | 0 | return best; |
1709 | 0 | } |
1710 | | |
1711 | | METHOD(certificate_t, has_issuer, id_match_t, |
1712 | | private_x509_cert_t *this, identification_t *issuer) |
1713 | 0 | { |
1714 | | /* issuerAltNames currently not supported */ |
1715 | 0 | return this->issuer->matches(this->issuer, issuer); |
1716 | 0 | } |
1717 | | |
1718 | | METHOD(certificate_t, issued_by, bool, |
1719 | | private_x509_cert_t *this, certificate_t *issuer, |
1720 | | signature_params_t **scheme) |
1721 | 41.6k | { |
1722 | 41.6k | public_key_t *key; |
1723 | 41.6k | bool valid; |
1724 | 41.6k | x509_t *x509 = (x509_t*)issuer; |
1725 | 41.6k | chunk_t keyid = chunk_empty; |
1726 | | |
1727 | 41.6k | if (&this->public.interface.interface == issuer) |
1728 | 41.6k | { |
1729 | 41.6k | if (this->flags & X509_SELF_SIGNED) |
1730 | 0 | { |
1731 | 0 | if (scheme) |
1732 | 0 | { |
1733 | 0 | *scheme = signature_params_clone(this->scheme); |
1734 | 0 | } |
1735 | 0 | return TRUE; |
1736 | 0 | } |
1737 | 41.6k | } |
1738 | 0 | else |
1739 | 0 | { |
1740 | 0 | if (issuer->get_type(issuer) != CERT_X509) |
1741 | 0 | { |
1742 | 0 | return FALSE; |
1743 | 0 | } |
1744 | 0 | if (!(x509->get_flags(x509) & X509_CA)) |
1745 | 0 | { |
1746 | 0 | return FALSE; |
1747 | 0 | } |
1748 | 0 | } |
1749 | | |
1750 | | /* compare keyIdentifiers if available, otherwise use DNs */ |
1751 | 41.6k | if (this->authKeyIdentifier.ptr) |
1752 | 24.6k | { |
1753 | 24.6k | keyid = x509->get_subjectKeyIdentifier(x509); |
1754 | 24.6k | if (keyid.len && !chunk_equals(keyid, this->authKeyIdentifier)) |
1755 | 15.4k | { |
1756 | 15.4k | return FALSE; |
1757 | 15.4k | } |
1758 | 24.6k | } |
1759 | 26.1k | if (!keyid.len) |
1760 | 17.0k | { |
1761 | 17.0k | if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer))) |
1762 | 12.0k | { |
1763 | 12.0k | return FALSE; |
1764 | 12.0k | } |
1765 | 17.0k | } |
1766 | | |
1767 | | /* get the public key of the issuer */ |
1768 | 14.1k | key = issuer->get_public_key(issuer); |
1769 | 14.1k | if (!key) |
1770 | 0 | { |
1771 | 0 | return FALSE; |
1772 | 0 | } |
1773 | 14.1k | valid = key->verify(key, this->scheme->scheme, this->scheme->params, |
1774 | 14.1k | this->tbsCertificate, this->signature); |
1775 | 14.1k | key->destroy(key); |
1776 | 14.1k | if (valid && scheme) |
1777 | 0 | { |
1778 | 0 | *scheme = signature_params_clone(this->scheme); |
1779 | 0 | } |
1780 | 14.1k | return valid; |
1781 | 14.1k | } |
1782 | | |
1783 | | METHOD(certificate_t, get_public_key, public_key_t*, |
1784 | | private_x509_cert_t *this) |
1785 | 14.1k | { |
1786 | 14.1k | this->public_key->get_ref(this->public_key); |
1787 | 14.1k | return this->public_key; |
1788 | 14.1k | } |
1789 | | |
1790 | | METHOD(certificate_t, get_ref, certificate_t*, |
1791 | | private_x509_cert_t *this) |
1792 | 0 | { |
1793 | 0 | ref_get(&this->ref); |
1794 | 0 | return &this->public.interface.interface; |
1795 | 0 | } |
1796 | | |
1797 | | METHOD(certificate_t, get_validity, bool, |
1798 | | private_x509_cert_t *this, time_t *when, time_t *not_before, |
1799 | | time_t *not_after) |
1800 | 0 | { |
1801 | 0 | time_t t = when ? *when : time(NULL); |
1802 | |
|
1803 | 0 | if (not_before) |
1804 | 0 | { |
1805 | 0 | *not_before = this->notBefore; |
1806 | 0 | } |
1807 | 0 | if (not_after) |
1808 | 0 | { |
1809 | 0 | *not_after = this->notAfter; |
1810 | 0 | } |
1811 | 0 | return (t >= this->notBefore && t <= this->notAfter); |
1812 | 0 | } |
1813 | | |
1814 | | METHOD(certificate_t, get_encoding, bool, |
1815 | | private_x509_cert_t *this, cred_encoding_type_t type, chunk_t *encoding) |
1816 | 0 | { |
1817 | 0 | if (type == CERT_ASN1_DER) |
1818 | 0 | { |
1819 | 0 | *encoding = chunk_clone(this->encoding); |
1820 | 0 | return TRUE; |
1821 | 0 | } |
1822 | 0 | return lib->encoding->encode(lib->encoding, type, NULL, encoding, |
1823 | 0 | CRED_PART_X509_ASN1_DER, this->encoding, CRED_PART_END); |
1824 | 0 | } |
1825 | | |
1826 | | METHOD(certificate_t, equals, bool, |
1827 | | private_x509_cert_t *this, certificate_t *other) |
1828 | 0 | { |
1829 | 0 | chunk_t encoding; |
1830 | 0 | bool equal; |
1831 | |
|
1832 | 0 | if (this == (private_x509_cert_t*)other) |
1833 | 0 | { |
1834 | 0 | return TRUE; |
1835 | 0 | } |
1836 | 0 | if (other->get_type(other) != CERT_X509) |
1837 | 0 | { |
1838 | 0 | return FALSE; |
1839 | 0 | } |
1840 | 0 | if (other->equals == (void*)equals) |
1841 | 0 | { /* skip allocation if we have the same implementation */ |
1842 | 0 | return chunk_equals(this->encoding, ((private_x509_cert_t*)other)->encoding); |
1843 | 0 | } |
1844 | 0 | if (!other->get_encoding(other, CERT_ASN1_DER, &encoding)) |
1845 | 0 | { |
1846 | 0 | return FALSE; |
1847 | 0 | } |
1848 | 0 | equal = chunk_equals(this->encoding, encoding); |
1849 | 0 | free(encoding.ptr); |
1850 | 0 | return equal; |
1851 | 0 | } |
1852 | | |
1853 | | METHOD(x509_t, get_flags, x509_flag_t, |
1854 | | private_x509_cert_t *this) |
1855 | 0 | { |
1856 | 0 | return this->flags; |
1857 | 0 | } |
1858 | | |
1859 | | METHOD(x509_t, get_serial, chunk_t, |
1860 | | private_x509_cert_t *this) |
1861 | 0 | { |
1862 | 0 | return chunk_skip_zero(this->serialNumber); |
1863 | 0 | } |
1864 | | |
1865 | | METHOD(x509_t, get_subjectKeyIdentifier, chunk_t, |
1866 | | private_x509_cert_t *this) |
1867 | 24.6k | { |
1868 | 24.6k | if (this->subjectKeyIdentifier.ptr) |
1869 | 41 | { |
1870 | 41 | return this->subjectKeyIdentifier; |
1871 | 41 | } |
1872 | 24.5k | else |
1873 | 24.5k | { |
1874 | 24.5k | chunk_t fingerprint; |
1875 | | |
1876 | 24.5k | if (this->public_key->get_fingerprint(this->public_key, |
1877 | 24.5k | KEYID_PUBKEY_SHA1, &fingerprint)) |
1878 | 24.5k | { |
1879 | 24.5k | return fingerprint; |
1880 | 24.5k | } |
1881 | 0 | else |
1882 | 0 | { |
1883 | 0 | return chunk_empty; |
1884 | 0 | } |
1885 | 24.5k | } |
1886 | 24.6k | } |
1887 | | |
1888 | | METHOD(x509_t, get_authKeyIdentifier, chunk_t, |
1889 | | private_x509_cert_t *this) |
1890 | 0 | { |
1891 | 0 | return this->authKeyIdentifier; |
1892 | 0 | } |
1893 | | |
1894 | | METHOD(x509_t, get_constraint, u_int, |
1895 | | private_x509_cert_t *this, x509_constraint_t type) |
1896 | 0 | { |
1897 | 0 | switch (type) |
1898 | 0 | { |
1899 | 0 | case X509_PATH_LEN: |
1900 | 0 | return this->pathLenConstraint; |
1901 | 0 | case X509_REQUIRE_EXPLICIT_POLICY: |
1902 | 0 | return this->require_explicit; |
1903 | 0 | case X509_INHIBIT_POLICY_MAPPING: |
1904 | 0 | return this->inhibit_mapping; |
1905 | 0 | case X509_INHIBIT_ANY_POLICY: |
1906 | 0 | return this->inhibit_any; |
1907 | 0 | default: |
1908 | 0 | return X509_NO_CONSTRAINT; |
1909 | 0 | } |
1910 | 0 | } |
1911 | | |
1912 | | METHOD(x509_t, create_subjectAltName_enumerator, enumerator_t*, |
1913 | | private_x509_cert_t *this) |
1914 | 0 | { |
1915 | 0 | return this->subjectAltNames->create_enumerator(this->subjectAltNames); |
1916 | 0 | } |
1917 | | |
1918 | | METHOD(x509_t, create_ocsp_uri_enumerator, enumerator_t*, |
1919 | | private_x509_cert_t *this) |
1920 | 0 | { |
1921 | 0 | return this->ocsp_uris->create_enumerator(this->ocsp_uris); |
1922 | 0 | } |
1923 | | |
1924 | | METHOD(x509_t, create_crl_uri_enumerator, enumerator_t*, |
1925 | | private_x509_cert_t *this) |
1926 | 0 | { |
1927 | 0 | return this->crl_uris->create_enumerator(this->crl_uris); |
1928 | 0 | } |
1929 | | |
1930 | | METHOD(x509_t, create_ipAddrBlock_enumerator, enumerator_t*, |
1931 | | private_x509_cert_t *this) |
1932 | 0 | { |
1933 | 0 | return this->ipAddrBlocks->create_enumerator(this->ipAddrBlocks); |
1934 | 0 | } |
1935 | | |
1936 | | METHOD(x509_t, create_name_constraint_enumerator, enumerator_t*, |
1937 | | private_x509_cert_t *this, bool perm) |
1938 | 0 | { |
1939 | 0 | if (perm) |
1940 | 0 | { |
1941 | 0 | return this->permitted_names->create_enumerator(this->permitted_names); |
1942 | 0 | } |
1943 | 0 | return this->excluded_names->create_enumerator(this->excluded_names); |
1944 | 0 | } |
1945 | | |
1946 | | METHOD(x509_t, create_cert_policy_enumerator, enumerator_t*, |
1947 | | private_x509_cert_t *this) |
1948 | 0 | { |
1949 | 0 | return this->cert_policies->create_enumerator(this->cert_policies); |
1950 | 0 | } |
1951 | | |
1952 | | METHOD(x509_t, create_policy_mapping_enumerator, enumerator_t*, |
1953 | | private_x509_cert_t *this) |
1954 | 0 | { |
1955 | 0 | return this->policy_mappings->create_enumerator(this->policy_mappings); |
1956 | 0 | } |
1957 | | |
1958 | | METHOD(certificate_t, destroy, void, |
1959 | | private_x509_cert_t *this) |
1960 | 165k | { |
1961 | 165k | if (ref_put(&this->ref)) |
1962 | 165k | { |
1963 | 165k | this->subjectAltNames->destroy_offset(this->subjectAltNames, |
1964 | 165k | offsetof(identification_t, destroy)); |
1965 | 165k | this->crl_uris->destroy_function(this->crl_uris, |
1966 | 165k | (void*)x509_cdp_destroy); |
1967 | 165k | this->ocsp_uris->destroy_function(this->ocsp_uris, free); |
1968 | 165k | this->ipAddrBlocks->destroy_offset(this->ipAddrBlocks, |
1969 | 165k | offsetof(traffic_selector_t, destroy)); |
1970 | 165k | this->permitted_names->destroy_offset(this->permitted_names, |
1971 | 165k | offsetof(identification_t, destroy)); |
1972 | 165k | this->excluded_names->destroy_offset(this->excluded_names, |
1973 | 165k | offsetof(identification_t, destroy)); |
1974 | 165k | this->cert_policies->destroy_function(this->cert_policies, |
1975 | 165k | (void*)cert_policy_destroy); |
1976 | 165k | this->policy_mappings->destroy_function(this->policy_mappings, |
1977 | 165k | (void*)policy_mapping_destroy); |
1978 | 165k | signature_params_destroy(this->scheme); |
1979 | 165k | DESTROY_IF(this->issuer); |
1980 | 165k | DESTROY_IF(this->subject); |
1981 | 165k | DESTROY_IF(this->public_key); |
1982 | 165k | chunk_free(&this->authKeyIdentifier); |
1983 | 165k | chunk_free(&this->encoding); |
1984 | 165k | chunk_free(&this->encoding_hash); |
1985 | 165k | chunk_free(&this->critical_extension_oid); |
1986 | 165k | if (!this->parsed) |
1987 | 106k | { /* only parsed certificates point these fields to "encoded" */ |
1988 | 106k | chunk_free(&this->signature); |
1989 | 106k | chunk_free(&this->serialNumber); |
1990 | 106k | chunk_free(&this->tbsCertificate); |
1991 | 106k | } |
1992 | 165k | free(this); |
1993 | 165k | } |
1994 | 165k | } |
1995 | | |
1996 | | /** |
1997 | | * create an empty but initialized X.509 certificate |
1998 | | */ |
1999 | | static private_x509_cert_t* create_empty(void) |
2000 | 165k | { |
2001 | 165k | private_x509_cert_t *this; |
2002 | | |
2003 | 165k | INIT(this, |
2004 | 165k | .public = { |
2005 | 165k | .interface = { |
2006 | 165k | .interface = { |
2007 | 165k | .get_type = _get_type, |
2008 | 165k | .get_subject = _get_subject, |
2009 | 165k | .get_issuer = _get_issuer, |
2010 | 165k | .has_subject = _has_subject, |
2011 | 165k | .has_issuer = _has_issuer, |
2012 | 165k | .issued_by = _issued_by, |
2013 | 165k | .get_public_key = _get_public_key, |
2014 | 165k | .get_validity = _get_validity, |
2015 | 165k | .get_encoding = _get_encoding, |
2016 | 165k | .equals = _equals, |
2017 | 165k | .get_ref = _get_ref, |
2018 | 165k | .destroy = _destroy, |
2019 | 165k | }, |
2020 | 165k | .get_flags = _get_flags, |
2021 | 165k | .get_serial = _get_serial, |
2022 | 165k | .get_subjectKeyIdentifier = _get_subjectKeyIdentifier, |
2023 | 165k | .get_authKeyIdentifier = _get_authKeyIdentifier, |
2024 | 165k | .get_constraint = _get_constraint, |
2025 | 165k | .create_subjectAltName_enumerator = _create_subjectAltName_enumerator, |
2026 | 165k | .create_crl_uri_enumerator = _create_crl_uri_enumerator, |
2027 | 165k | .create_ocsp_uri_enumerator = _create_ocsp_uri_enumerator, |
2028 | 165k | .create_ipAddrBlock_enumerator = _create_ipAddrBlock_enumerator, |
2029 | 165k | .create_name_constraint_enumerator = _create_name_constraint_enumerator, |
2030 | 165k | .create_cert_policy_enumerator = _create_cert_policy_enumerator, |
2031 | 165k | .create_policy_mapping_enumerator = _create_policy_mapping_enumerator, |
2032 | 165k | }, |
2033 | 165k | }, |
2034 | 165k | .version = 1, |
2035 | 165k | .subjectAltNames = linked_list_create(), |
2036 | 165k | .crl_uris = linked_list_create(), |
2037 | 165k | .ocsp_uris = linked_list_create(), |
2038 | 165k | .ipAddrBlocks = linked_list_create(), |
2039 | 165k | .permitted_names = linked_list_create(), |
2040 | 165k | .excluded_names = linked_list_create(), |
2041 | 165k | .cert_policies = linked_list_create(), |
2042 | 165k | .policy_mappings = linked_list_create(), |
2043 | 165k | .pathLenConstraint = X509_NO_CONSTRAINT, |
2044 | 165k | .require_explicit = X509_NO_CONSTRAINT, |
2045 | 165k | .inhibit_mapping = X509_NO_CONSTRAINT, |
2046 | 165k | .inhibit_any = X509_NO_CONSTRAINT, |
2047 | 165k | .ref = 1, |
2048 | 165k | ); |
2049 | 165k | return this; |
2050 | 165k | } |
2051 | | |
2052 | | /** |
2053 | | * Build a generalName from an id |
2054 | | */ |
2055 | | static chunk_t build_generalName(identification_t *id) |
2056 | 0 | { |
2057 | 0 | int context; |
2058 | |
|
2059 | 0 | switch (id->get_type(id)) |
2060 | 0 | { |
2061 | 0 | case ID_DER_ASN1_GN: |
2062 | 0 | return chunk_clone(id->get_encoding(id)); |
2063 | 0 | case ID_RFC822_ADDR: |
2064 | 0 | context = ASN1_CONTEXT_S_1; |
2065 | 0 | break; |
2066 | 0 | case ID_FQDN: |
2067 | 0 | context = ASN1_CONTEXT_S_2; |
2068 | 0 | break; |
2069 | 0 | case ID_DER_ASN1_DN: |
2070 | 0 | context = ASN1_CONTEXT_C_4; |
2071 | 0 | break; |
2072 | 0 | case ID_DER_ASN1_GN_URI: |
2073 | 0 | context = ASN1_CONTEXT_S_6; |
2074 | 0 | break; |
2075 | 0 | case ID_IPV4_ADDR: |
2076 | 0 | case ID_IPV6_ADDR: |
2077 | 0 | case ID_IPV4_ADDR_SUBNET: |
2078 | 0 | case ID_IPV6_ADDR_SUBNET: |
2079 | 0 | context = ASN1_CONTEXT_S_7; |
2080 | 0 | break; |
2081 | 0 | default: |
2082 | 0 | DBG1(DBG_ASN, "encoding %N as generalName not supported", |
2083 | 0 | id_type_names, id->get_type(id)); |
2084 | 0 | return chunk_empty; |
2085 | 0 | } |
2086 | 0 | return asn1_wrap(context, "c", id->get_encoding(id)); |
2087 | 0 | } |
2088 | | |
2089 | | /** |
2090 | | * Encode a linked list of subjectAltNames |
2091 | | */ |
2092 | | chunk_t x509_build_subjectAltNames(linked_list_t *list) |
2093 | 0 | { |
2094 | 0 | chunk_t subjectAltNames = chunk_empty, name; |
2095 | 0 | enumerator_t *enumerator; |
2096 | 0 | identification_t *id; |
2097 | |
|
2098 | 0 | if (list->get_count(list) == 0) |
2099 | 0 | { |
2100 | 0 | return chunk_empty; |
2101 | 0 | } |
2102 | | |
2103 | 0 | enumerator = list->create_enumerator(list); |
2104 | 0 | while (enumerator->enumerate(enumerator, &id)) |
2105 | 0 | { |
2106 | 0 | name = build_generalName(id); |
2107 | 0 | subjectAltNames = chunk_cat("mm", subjectAltNames, name); |
2108 | 0 | } |
2109 | 0 | enumerator->destroy(enumerator); |
2110 | |
|
2111 | 0 | return asn1_wrap(ASN1_SEQUENCE, "mm", |
2112 | 0 | asn1_build_known_oid(OID_SUBJECT_ALT_NAME), |
2113 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
2114 | 0 | asn1_wrap(ASN1_SEQUENCE, "m", subjectAltNames) |
2115 | 0 | ) |
2116 | 0 | ); |
2117 | 0 | } |
2118 | | |
2119 | | /** |
2120 | | * Encode CRL distribution points extension from a x509_cdp_t list |
2121 | | */ |
2122 | | chunk_t x509_build_crlDistributionPoints(linked_list_t *list, int extn) |
2123 | 0 | { |
2124 | 0 | chunk_t crlDistributionPoints = chunk_empty; |
2125 | 0 | enumerator_t *enumerator; |
2126 | 0 | x509_cdp_t *cdp; |
2127 | |
|
2128 | 0 | if (list->get_count(list) == 0) |
2129 | 0 | { |
2130 | 0 | return chunk_empty; |
2131 | 0 | } |
2132 | | |
2133 | 0 | enumerator = list->create_enumerator(list); |
2134 | 0 | while (enumerator->enumerate(enumerator, &cdp)) |
2135 | 0 | { |
2136 | 0 | chunk_t distributionPoint, crlIssuer = chunk_empty; |
2137 | |
|
2138 | 0 | if (cdp->issuer) |
2139 | 0 | { |
2140 | 0 | crlIssuer = asn1_wrap(ASN1_CONTEXT_C_2, "m", |
2141 | 0 | build_generalName(cdp->issuer)); |
2142 | 0 | } |
2143 | 0 | distributionPoint = asn1_wrap(ASN1_SEQUENCE, "mm", |
2144 | 0 | asn1_wrap(ASN1_CONTEXT_C_0, "m", |
2145 | 0 | asn1_wrap(ASN1_CONTEXT_C_0, "m", |
2146 | 0 | asn1_wrap(ASN1_CONTEXT_S_6, "c", |
2147 | 0 | chunk_create(cdp->uri, strlen(cdp->uri))))), |
2148 | 0 | crlIssuer); |
2149 | 0 | crlDistributionPoints = chunk_cat("mm", crlDistributionPoints, |
2150 | 0 | distributionPoint); |
2151 | 0 | } |
2152 | 0 | enumerator->destroy(enumerator); |
2153 | |
|
2154 | 0 | return asn1_wrap(ASN1_SEQUENCE, "mm", |
2155 | 0 | asn1_build_known_oid(extn), |
2156 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
2157 | 0 | asn1_wrap(ASN1_SEQUENCE, "m", crlDistributionPoints))); |
2158 | 0 | } |
2159 | | |
2160 | | static chunk_t generate_ts(traffic_selector_t *ts) |
2161 | 0 | { |
2162 | 0 | chunk_t from, to; |
2163 | 0 | uint8_t minbits = 0, maxbits = 0, unused; |
2164 | 0 | host_t *net; |
2165 | 0 | int bit, byte; |
2166 | |
|
2167 | 0 | if (ts->to_subnet(ts, &net, &minbits)) |
2168 | 0 | { |
2169 | 0 | unused = round_up(minbits, BITS_PER_BYTE) - minbits; |
2170 | 0 | from = asn1_wrap(ASN1_BIT_STRING, "m", |
2171 | 0 | chunk_cat("cc", chunk_from_thing(unused), |
2172 | 0 | chunk_create(net->get_address(net).ptr, |
2173 | 0 | (minbits + unused) / BITS_PER_BYTE))); |
2174 | 0 | net->destroy(net); |
2175 | 0 | return from; |
2176 | 0 | } |
2177 | 0 | net->destroy(net); |
2178 | |
|
2179 | 0 | from = ts->get_from_address(ts); |
2180 | 0 | for (byte = from.len - 1; byte >= 0; byte--) |
2181 | 0 | { |
2182 | 0 | if (from.ptr[byte] != 0) |
2183 | 0 | { |
2184 | 0 | minbits = byte * BITS_PER_BYTE + BITS_PER_BYTE; |
2185 | 0 | for (bit = 0; bit < BITS_PER_BYTE; bit++) |
2186 | 0 | { |
2187 | 0 | if (from.ptr[byte] & 1 << bit) |
2188 | 0 | { |
2189 | 0 | break; |
2190 | 0 | } |
2191 | 0 | minbits--; |
2192 | 0 | } |
2193 | 0 | break; |
2194 | 0 | } |
2195 | 0 | } |
2196 | 0 | to = ts->get_to_address(ts); |
2197 | 0 | for (byte = to.len - 1; byte >= 0; byte--) |
2198 | 0 | { |
2199 | 0 | if (to.ptr[byte] != 0xFF) |
2200 | 0 | { |
2201 | 0 | maxbits = byte * BITS_PER_BYTE + BITS_PER_BYTE; |
2202 | 0 | for (bit = 0; bit < BITS_PER_BYTE; bit++) |
2203 | 0 | { |
2204 | 0 | if ((to.ptr[byte] & 1 << bit) == 0) |
2205 | 0 | { |
2206 | 0 | break; |
2207 | 0 | } |
2208 | 0 | maxbits--; |
2209 | 0 | } |
2210 | 0 | break; |
2211 | 0 | } |
2212 | 0 | } |
2213 | 0 | unused = round_up(minbits, BITS_PER_BYTE) - minbits; |
2214 | 0 | from = asn1_wrap(ASN1_BIT_STRING, "m", |
2215 | 0 | chunk_cat("cc", chunk_from_thing(unused), |
2216 | 0 | chunk_create(from.ptr, |
2217 | 0 | (minbits + unused) / BITS_PER_BYTE))); |
2218 | 0 | unused = round_up(maxbits, BITS_PER_BYTE) - maxbits; |
2219 | 0 | to = asn1_wrap(ASN1_BIT_STRING, "m", |
2220 | 0 | chunk_cat("cc", chunk_from_thing(unused), |
2221 | 0 | chunk_create(to.ptr, |
2222 | 0 | (maxbits + unused) / BITS_PER_BYTE))); |
2223 | 0 | return asn1_wrap(ASN1_SEQUENCE, "mm", from, to); |
2224 | 0 | } |
2225 | | |
2226 | | /** |
2227 | | * Generate an extendedKeyUsage X.509v3 extension (shared with x509_pkcs10.c) |
2228 | | */ |
2229 | | chunk_t x509_generate_eku_extension(x509_flag_t flags) |
2230 | 0 | { |
2231 | 0 | chunk_t extendedKeyUsage = chunk_empty, ocspSigning = chunk_empty; |
2232 | 0 | chunk_t serverAuth = chunk_empty, clientAuth = chunk_empty; |
2233 | 0 | chunk_t ikeIntermediate = chunk_empty, msSmartcardLogon = chunk_empty; |
2234 | |
|
2235 | 0 | if (flags & X509_SERVER_AUTH) |
2236 | 0 | { |
2237 | 0 | serverAuth = asn1_build_known_oid(OID_SERVER_AUTH); |
2238 | 0 | } |
2239 | 0 | if (flags & X509_CLIENT_AUTH) |
2240 | 0 | { |
2241 | 0 | clientAuth = asn1_build_known_oid(OID_CLIENT_AUTH); |
2242 | 0 | } |
2243 | 0 | if (flags & X509_IKE_INTERMEDIATE) |
2244 | 0 | { |
2245 | 0 | ikeIntermediate = asn1_build_known_oid(OID_IKE_INTERMEDIATE); |
2246 | 0 | } |
2247 | 0 | if (flags & X509_OCSP_SIGNER) |
2248 | 0 | { |
2249 | 0 | ocspSigning = asn1_build_known_oid(OID_OCSP_SIGNING); |
2250 | 0 | } |
2251 | 0 | if (flags & X509_MS_SMARTCARD_LOGON) |
2252 | 0 | { |
2253 | 0 | msSmartcardLogon = asn1_build_known_oid(OID_MS_SMARTCARD_LOGON); |
2254 | 0 | } |
2255 | |
|
2256 | 0 | if (serverAuth.ptr || clientAuth.ptr || ikeIntermediate.ptr || |
2257 | 0 | ocspSigning.ptr || msSmartcardLogon.ptr) |
2258 | 0 | { |
2259 | 0 | extendedKeyUsage = asn1_wrap(ASN1_SEQUENCE, "mm", |
2260 | 0 | asn1_build_known_oid(OID_EXTENDED_KEY_USAGE), |
2261 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
2262 | 0 | asn1_wrap(ASN1_SEQUENCE, "mmmmm", |
2263 | 0 | serverAuth, clientAuth, ikeIntermediate, |
2264 | 0 | ocspSigning, msSmartcardLogon))); |
2265 | 0 | } |
2266 | |
|
2267 | 0 | return extendedKeyUsage; |
2268 | 0 | } |
2269 | | |
2270 | | /** |
2271 | | * Generate and sign a new certificate |
2272 | | */ |
2273 | | static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert, |
2274 | | private_key_t *sign_key, int digest_alg) |
2275 | 0 | { |
2276 | 0 | const chunk_t keyUsageCrlSign = chunk_from_chars(0x01, 0x02); |
2277 | 0 | const chunk_t keyUsageCertSignCrlSign = chunk_from_chars(0x01, 0x06); |
2278 | 0 | chunk_t extensions = chunk_empty, certPolicies = chunk_empty; |
2279 | 0 | chunk_t basicConstraints = chunk_empty, nameConstraints = chunk_empty; |
2280 | 0 | chunk_t keyUsage = chunk_empty, keyUsageBits = chunk_empty; |
2281 | 0 | chunk_t subjectAltNames = chunk_empty, policyMappings = chunk_empty; |
2282 | 0 | chunk_t subjectKeyIdentifier = chunk_empty, authKeyIdentifier = chunk_empty; |
2283 | 0 | chunk_t crlDistributionPoints = chunk_empty, authorityInfoAccess = chunk_empty; |
2284 | 0 | chunk_t policyConstraints = chunk_empty, inhibitAnyPolicy = chunk_empty; |
2285 | 0 | chunk_t ipAddrBlocks = chunk_empty, sig_scheme = chunk_empty; |
2286 | 0 | chunk_t criticalExtension = chunk_empty, extendedKeyUsage = chunk_empty; |
2287 | 0 | identification_t *issuer, *subject; |
2288 | 0 | chunk_t key_info; |
2289 | 0 | hasher_t *hasher; |
2290 | 0 | enumerator_t *enumerator; |
2291 | 0 | char *uri; |
2292 | |
|
2293 | 0 | subject = cert->subject; |
2294 | 0 | if (sign_cert) |
2295 | 0 | { |
2296 | 0 | issuer = sign_cert->get_subject(sign_cert); |
2297 | 0 | if (!cert->public_key) |
2298 | 0 | { |
2299 | 0 | return FALSE; |
2300 | 0 | } |
2301 | 0 | } |
2302 | 0 | else |
2303 | 0 | { /* self signed */ |
2304 | 0 | issuer = subject; |
2305 | 0 | if (!cert->public_key) |
2306 | 0 | { |
2307 | 0 | cert->public_key = sign_key->get_public_key(sign_key); |
2308 | 0 | } |
2309 | 0 | cert->flags |= X509_SELF_SIGNED; |
2310 | 0 | } |
2311 | 0 | cert->issuer = issuer->clone(issuer); |
2312 | 0 | if (!cert->notBefore) |
2313 | 0 | { |
2314 | 0 | cert->notBefore = time(NULL); |
2315 | 0 | } |
2316 | 0 | if (!cert->notAfter) |
2317 | 0 | { /* defaults to 1 year from now */ |
2318 | 0 | cert->notAfter = cert->notBefore + 60 * 60 * 24 * 365; |
2319 | 0 | } |
2320 | | |
2321 | | /* select signature scheme, if not already specified */ |
2322 | 0 | if (!cert->scheme) |
2323 | 0 | { |
2324 | 0 | INIT(cert->scheme, |
2325 | 0 | .scheme = signature_scheme_from_oid( |
2326 | 0 | hasher_signature_algorithm_to_oid(digest_alg, |
2327 | 0 | sign_key->get_type(sign_key))), |
2328 | 0 | ); |
2329 | 0 | } |
2330 | 0 | if (cert->scheme->scheme == SIGN_UNKNOWN) |
2331 | 0 | { |
2332 | 0 | return FALSE; |
2333 | 0 | } |
2334 | 0 | if (!signature_params_build(cert->scheme, &sig_scheme)) |
2335 | 0 | { |
2336 | 0 | return FALSE; |
2337 | 0 | } |
2338 | | |
2339 | 0 | if (!cert->public_key->get_encoding(cert->public_key, |
2340 | 0 | PUBKEY_SPKI_ASN1_DER, &key_info)) |
2341 | 0 | { |
2342 | 0 | chunk_free(&sig_scheme); |
2343 | 0 | return FALSE; |
2344 | 0 | } |
2345 | | |
2346 | | /* encode subjectAltNames */ |
2347 | 0 | subjectAltNames = x509_build_subjectAltNames(cert->subjectAltNames); |
2348 | |
|
2349 | 0 | crlDistributionPoints = x509_build_crlDistributionPoints(cert->crl_uris, |
2350 | 0 | OID_CRL_DISTRIBUTION_POINTS); |
2351 | | |
2352 | | /* encode OCSP URIs in authorityInfoAccess extension */ |
2353 | 0 | enumerator = cert->ocsp_uris->create_enumerator(cert->ocsp_uris); |
2354 | 0 | while (enumerator->enumerate(enumerator, &uri)) |
2355 | 0 | { |
2356 | 0 | chunk_t accessDescription; |
2357 | |
|
2358 | 0 | accessDescription = asn1_wrap(ASN1_SEQUENCE, "mm", |
2359 | 0 | asn1_build_known_oid(OID_OCSP), |
2360 | 0 | asn1_wrap(ASN1_CONTEXT_S_6, "c", |
2361 | 0 | chunk_create(uri, strlen(uri)))); |
2362 | 0 | authorityInfoAccess = chunk_cat("mm", authorityInfoAccess, |
2363 | 0 | accessDescription); |
2364 | 0 | } |
2365 | 0 | enumerator->destroy(enumerator); |
2366 | 0 | if (authorityInfoAccess.ptr) |
2367 | 0 | { |
2368 | 0 | authorityInfoAccess = asn1_wrap(ASN1_SEQUENCE, "mm", |
2369 | 0 | asn1_build_known_oid(OID_AUTHORITY_INFO_ACCESS), |
2370 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
2371 | 0 | asn1_wrap(ASN1_SEQUENCE, "m", authorityInfoAccess))); |
2372 | 0 | } |
2373 | | |
2374 | | /* build CA basicConstraint and keyUsage flags for CA certificates */ |
2375 | 0 | if (cert->flags & X509_CA) |
2376 | 0 | { |
2377 | 0 | chunk_t pathLenConstraint = chunk_empty; |
2378 | |
|
2379 | 0 | if (cert->pathLenConstraint != X509_NO_CONSTRAINT) |
2380 | 0 | { |
2381 | 0 | pathLenConstraint = asn1_integer("c", |
2382 | 0 | chunk_from_thing(cert->pathLenConstraint)); |
2383 | 0 | } |
2384 | 0 | basicConstraints = asn1_wrap(ASN1_SEQUENCE, "mmm", |
2385 | 0 | asn1_build_known_oid(OID_BASIC_CONSTRAINTS), |
2386 | 0 | asn1_wrap(ASN1_BOOLEAN, "c", |
2387 | 0 | chunk_from_chars(0xFF)), |
2388 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
2389 | 0 | asn1_wrap(ASN1_SEQUENCE, "mm", |
2390 | 0 | asn1_wrap(ASN1_BOOLEAN, "c", |
2391 | 0 | chunk_from_chars(0xFF)), |
2392 | 0 | pathLenConstraint))); |
2393 | | /* set CertificateSign and implicitly CRLsign */ |
2394 | 0 | keyUsageBits = keyUsageCertSignCrlSign; |
2395 | 0 | } |
2396 | 0 | else if (cert->flags & X509_CRL_SIGN) |
2397 | 0 | { |
2398 | 0 | keyUsageBits = keyUsageCrlSign; |
2399 | 0 | } |
2400 | 0 | if (keyUsageBits.len) |
2401 | 0 | { |
2402 | 0 | keyUsage = asn1_wrap(ASN1_SEQUENCE, "mmm", |
2403 | 0 | asn1_build_known_oid(OID_KEY_USAGE), |
2404 | 0 | asn1_wrap(ASN1_BOOLEAN, "c", chunk_from_chars(0xFF)), |
2405 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
2406 | 0 | asn1_wrap(ASN1_BIT_STRING, "c", keyUsageBits))); |
2407 | 0 | } |
2408 | | |
2409 | | /* add extendedKeyUsage flags */ |
2410 | 0 | extendedKeyUsage = x509_generate_eku_extension(cert->flags); |
2411 | | |
2412 | | /* add subjectKeyIdentifier to CA and OCSP signer certificates */ |
2413 | 0 | if (cert->flags & (X509_CA | X509_OCSP_SIGNER | X509_CRL_SIGN)) |
2414 | 0 | { |
2415 | 0 | chunk_t keyid; |
2416 | |
|
2417 | 0 | if (cert->public_key->get_fingerprint(cert->public_key, |
2418 | 0 | KEYID_PUBKEY_SHA1, &keyid)) |
2419 | 0 | { |
2420 | 0 | subjectKeyIdentifier = asn1_wrap(ASN1_SEQUENCE, "mm", |
2421 | 0 | asn1_build_known_oid(OID_SUBJECT_KEY_ID), |
2422 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
2423 | 0 | asn1_wrap(ASN1_OCTET_STRING, "c", keyid))); |
2424 | 0 | } |
2425 | 0 | } |
2426 | | |
2427 | | /* add the keyid authKeyIdentifier for non self-signed certificates */ |
2428 | 0 | if (sign_cert) |
2429 | 0 | { |
2430 | 0 | x509_t *sign_x509 = (x509_t*)sign_cert; |
2431 | 0 | chunk_t keyid = chunk_empty; |
2432 | |
|
2433 | 0 | if (sign_cert->get_type(sign_cert) == CERT_X509) |
2434 | 0 | { |
2435 | 0 | keyid = sign_x509->get_subjectKeyIdentifier(sign_x509); |
2436 | 0 | } |
2437 | 0 | if (keyid.len || |
2438 | 0 | sign_key->get_fingerprint(sign_key, KEYID_PUBKEY_SHA1, &keyid)) |
2439 | 0 | { |
2440 | 0 | authKeyIdentifier = asn1_wrap(ASN1_SEQUENCE, "mm", |
2441 | 0 | asn1_build_known_oid(OID_AUTHORITY_KEY_ID), |
2442 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
2443 | 0 | asn1_wrap(ASN1_SEQUENCE, "m", |
2444 | 0 | asn1_wrap(ASN1_CONTEXT_S_0, "c", keyid)))); |
2445 | 0 | } |
2446 | 0 | } |
2447 | |
|
2448 | 0 | if (cert->ipAddrBlocks->get_count(cert->ipAddrBlocks)) |
2449 | 0 | { |
2450 | 0 | chunk_t v4blocks = chunk_empty, v6blocks = chunk_empty, block; |
2451 | 0 | traffic_selector_t *ts; |
2452 | |
|
2453 | 0 | enumerator = cert->ipAddrBlocks->create_enumerator(cert->ipAddrBlocks); |
2454 | 0 | while (enumerator->enumerate(enumerator, &ts)) |
2455 | 0 | { |
2456 | 0 | switch (ts->get_type(ts)) |
2457 | 0 | { |
2458 | 0 | case TS_IPV4_ADDR_RANGE: |
2459 | 0 | block = generate_ts(ts); |
2460 | 0 | v4blocks = chunk_cat("mm", v4blocks, block); |
2461 | 0 | break; |
2462 | 0 | case TS_IPV6_ADDR_RANGE: |
2463 | 0 | block = generate_ts(ts); |
2464 | 0 | v6blocks = chunk_cat("mm", v6blocks, block); |
2465 | 0 | break; |
2466 | 0 | default: |
2467 | 0 | break; |
2468 | 0 | } |
2469 | 0 | } |
2470 | 0 | enumerator->destroy(enumerator); |
2471 | |
|
2472 | 0 | if (v4blocks.ptr) |
2473 | 0 | { |
2474 | 0 | v4blocks = asn1_wrap(ASN1_SEQUENCE, "mm", |
2475 | 0 | asn1_wrap(ASN1_OCTET_STRING, "c", |
2476 | 0 | chunk_from_chars(0x00,0x01)), |
2477 | 0 | asn1_wrap(ASN1_SEQUENCE, "m", v4blocks)); |
2478 | 0 | } |
2479 | 0 | if (v6blocks.ptr) |
2480 | 0 | { |
2481 | 0 | v6blocks = asn1_wrap(ASN1_SEQUENCE, "mm", |
2482 | 0 | asn1_wrap(ASN1_OCTET_STRING, "c", |
2483 | 0 | chunk_from_chars(0x00,0x02)), |
2484 | 0 | asn1_wrap(ASN1_SEQUENCE, "m", v6blocks)); |
2485 | 0 | } |
2486 | 0 | ipAddrBlocks = asn1_wrap(ASN1_SEQUENCE, "mm", |
2487 | 0 | asn1_build_known_oid(OID_IP_ADDR_BLOCKS), |
2488 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
2489 | 0 | asn1_wrap(ASN1_SEQUENCE, "mm", |
2490 | 0 | v4blocks, v6blocks))); |
2491 | 0 | cert->flags |= X509_IP_ADDR_BLOCKS; |
2492 | 0 | } |
2493 | | |
2494 | 0 | if (cert->permitted_names->get_count(cert->permitted_names) || |
2495 | 0 | cert->excluded_names->get_count(cert->excluded_names)) |
2496 | 0 | { |
2497 | 0 | chunk_t permitted = chunk_empty, excluded = chunk_empty, subtree; |
2498 | 0 | identification_t *id; |
2499 | |
|
2500 | 0 | enumerator = create_name_constraint_enumerator(cert, TRUE); |
2501 | 0 | while (enumerator->enumerate(enumerator, &id)) |
2502 | 0 | { |
2503 | 0 | subtree = asn1_wrap(ASN1_SEQUENCE, "m", build_generalName(id)); |
2504 | 0 | permitted = chunk_cat("mm", permitted, subtree); |
2505 | 0 | } |
2506 | 0 | enumerator->destroy(enumerator); |
2507 | 0 | if (permitted.ptr) |
2508 | 0 | { |
2509 | 0 | permitted = asn1_wrap(ASN1_CONTEXT_C_0, "m", permitted); |
2510 | 0 | } |
2511 | |
|
2512 | 0 | enumerator = create_name_constraint_enumerator(cert, FALSE); |
2513 | 0 | while (enumerator->enumerate(enumerator, &id)) |
2514 | 0 | { |
2515 | 0 | subtree = asn1_wrap(ASN1_SEQUENCE, "m", build_generalName(id)); |
2516 | 0 | excluded = chunk_cat("mm", excluded, subtree); |
2517 | 0 | } |
2518 | 0 | enumerator->destroy(enumerator); |
2519 | 0 | if (excluded.ptr) |
2520 | 0 | { |
2521 | 0 | excluded = asn1_wrap(ASN1_CONTEXT_C_1, "m", excluded); |
2522 | 0 | } |
2523 | |
|
2524 | 0 | nameConstraints = asn1_wrap(ASN1_SEQUENCE, "mm", |
2525 | 0 | asn1_build_known_oid(OID_NAME_CONSTRAINTS), |
2526 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
2527 | 0 | asn1_wrap(ASN1_SEQUENCE, "mm", |
2528 | 0 | permitted, excluded))); |
2529 | 0 | } |
2530 | |
|
2531 | 0 | if (cert->cert_policies->get_count(cert->cert_policies)) |
2532 | 0 | { |
2533 | 0 | x509_cert_policy_t *policy; |
2534 | |
|
2535 | 0 | enumerator = create_cert_policy_enumerator(cert); |
2536 | 0 | while (enumerator->enumerate(enumerator, &policy)) |
2537 | 0 | { |
2538 | 0 | chunk_t chunk = chunk_empty, cps = chunk_empty, notice = chunk_empty; |
2539 | |
|
2540 | 0 | if (policy->cps_uri) |
2541 | 0 | { |
2542 | 0 | cps = asn1_wrap(ASN1_SEQUENCE, "mm", |
2543 | 0 | asn1_build_known_oid(OID_POLICY_QUALIFIER_CPS), |
2544 | 0 | asn1_wrap(ASN1_IA5STRING, "c", |
2545 | 0 | chunk_create(policy->cps_uri, |
2546 | 0 | strlen(policy->cps_uri)))); |
2547 | 0 | } |
2548 | 0 | if (policy->unotice_text) |
2549 | 0 | { |
2550 | 0 | notice = asn1_wrap(ASN1_SEQUENCE, "mm", |
2551 | 0 | asn1_build_known_oid(OID_POLICY_QUALIFIER_UNOTICE), |
2552 | 0 | asn1_wrap(ASN1_SEQUENCE, "m", |
2553 | 0 | asn1_wrap(ASN1_VISIBLESTRING, "c", |
2554 | 0 | chunk_create(policy->unotice_text, |
2555 | 0 | strlen(policy->unotice_text))))); |
2556 | 0 | } |
2557 | 0 | if (cps.len || notice.len) |
2558 | 0 | { |
2559 | 0 | chunk = asn1_wrap(ASN1_SEQUENCE, "mm", cps, notice); |
2560 | 0 | } |
2561 | 0 | chunk = asn1_wrap(ASN1_SEQUENCE, "mm", |
2562 | 0 | asn1_wrap(ASN1_OID, "c", policy->oid), chunk); |
2563 | 0 | certPolicies = chunk_cat("mm", certPolicies, chunk); |
2564 | 0 | } |
2565 | 0 | enumerator->destroy(enumerator); |
2566 | |
|
2567 | 0 | certPolicies = asn1_wrap(ASN1_SEQUENCE, "mm", |
2568 | 0 | asn1_build_known_oid(OID_CERTIFICATE_POLICIES), |
2569 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
2570 | 0 | asn1_wrap(ASN1_SEQUENCE, "m", certPolicies))); |
2571 | 0 | } |
2572 | |
|
2573 | 0 | if (cert->policy_mappings->get_count(cert->policy_mappings)) |
2574 | 0 | { |
2575 | 0 | x509_policy_mapping_t *mapping; |
2576 | |
|
2577 | 0 | enumerator = create_policy_mapping_enumerator(cert); |
2578 | 0 | while (enumerator->enumerate(enumerator, &mapping)) |
2579 | 0 | { |
2580 | 0 | chunk_t chunk; |
2581 | |
|
2582 | 0 | chunk = asn1_wrap(ASN1_SEQUENCE, "mm", |
2583 | 0 | asn1_wrap(ASN1_OID, "c", mapping->issuer), |
2584 | 0 | asn1_wrap(ASN1_OID, "c", mapping->subject)); |
2585 | 0 | policyMappings = chunk_cat("mm", policyMappings, chunk); |
2586 | 0 | } |
2587 | 0 | enumerator->destroy(enumerator); |
2588 | |
|
2589 | 0 | policyMappings = asn1_wrap(ASN1_SEQUENCE, "mm", |
2590 | 0 | asn1_build_known_oid(OID_POLICY_MAPPINGS), |
2591 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
2592 | 0 | asn1_wrap(ASN1_SEQUENCE, "m", policyMappings))); |
2593 | 0 | } |
2594 | |
|
2595 | 0 | if (cert->inhibit_mapping != X509_NO_CONSTRAINT || |
2596 | 0 | cert->require_explicit != X509_NO_CONSTRAINT) |
2597 | 0 | { |
2598 | 0 | chunk_t inhibit = chunk_empty, explicit = chunk_empty; |
2599 | |
|
2600 | 0 | if (cert->require_explicit != X509_NO_CONSTRAINT) |
2601 | 0 | { |
2602 | 0 | explicit = asn1_wrap(ASN1_CONTEXT_C_0, "m", |
2603 | 0 | asn1_integer("c", |
2604 | 0 | chunk_from_thing(cert->require_explicit))); |
2605 | 0 | } |
2606 | 0 | if (cert->inhibit_mapping != X509_NO_CONSTRAINT) |
2607 | 0 | { |
2608 | 0 | inhibit = asn1_wrap(ASN1_CONTEXT_C_1, "m", |
2609 | 0 | asn1_integer("c", |
2610 | 0 | chunk_from_thing(cert->inhibit_mapping))); |
2611 | 0 | } |
2612 | 0 | policyConstraints = asn1_wrap(ASN1_SEQUENCE, "mmm", |
2613 | 0 | asn1_build_known_oid(OID_POLICY_CONSTRAINTS), |
2614 | 0 | asn1_wrap(ASN1_BOOLEAN, "c", chunk_from_chars(0xFF)), |
2615 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
2616 | 0 | asn1_wrap(ASN1_SEQUENCE, "mm", |
2617 | 0 | explicit, inhibit))); |
2618 | 0 | } |
2619 | |
|
2620 | 0 | if (cert->inhibit_any != X509_NO_CONSTRAINT) |
2621 | 0 | { |
2622 | 0 | inhibitAnyPolicy = asn1_wrap(ASN1_SEQUENCE, "mmm", |
2623 | 0 | asn1_build_known_oid(OID_INHIBIT_ANY_POLICY), |
2624 | 0 | asn1_wrap(ASN1_BOOLEAN, "c", chunk_from_chars(0xFF)), |
2625 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
2626 | 0 | asn1_integer("c", |
2627 | 0 | chunk_from_thing(cert->inhibit_any)))); |
2628 | 0 | } |
2629 | |
|
2630 | 0 | if (cert->critical_extension_oid.len > 0) |
2631 | 0 | { |
2632 | 0 | criticalExtension = asn1_wrap(ASN1_SEQUENCE, "mmm", |
2633 | 0 | asn1_simple_object(ASN1_OID, cert->critical_extension_oid), |
2634 | 0 | asn1_simple_object(ASN1_BOOLEAN, chunk_from_chars(0xFF)), |
2635 | 0 | asn1_simple_object(ASN1_OCTET_STRING, chunk_empty)); |
2636 | 0 | } |
2637 | |
|
2638 | 0 | if (basicConstraints.ptr || keyUsage.ptr || subjectKeyIdentifier.ptr || |
2639 | 0 | authKeyIdentifier.ptr || subjectAltNames.ptr || extendedKeyUsage.ptr || |
2640 | 0 | crlDistributionPoints.ptr || authorityInfoAccess.ptr || |
2641 | 0 | nameConstraints.ptr || certPolicies.ptr || policyMappings.ptr || |
2642 | 0 | policyConstraints.ptr || inhibitAnyPolicy.ptr || ipAddrBlocks.ptr || |
2643 | 0 | criticalExtension.ptr) |
2644 | 0 | { |
2645 | 0 | extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m", |
2646 | 0 | asn1_wrap(ASN1_SEQUENCE, "mmmmmmmmmmmmmmm", |
2647 | 0 | basicConstraints, keyUsage, subjectKeyIdentifier, |
2648 | 0 | authKeyIdentifier, subjectAltNames, |
2649 | 0 | extendedKeyUsage, crlDistributionPoints, |
2650 | 0 | authorityInfoAccess, nameConstraints, certPolicies, |
2651 | 0 | policyMappings, policyConstraints, inhibitAnyPolicy, |
2652 | 0 | ipAddrBlocks, criticalExtension)); |
2653 | 0 | } |
2654 | |
|
2655 | 0 | cert->tbsCertificate = asn1_wrap(ASN1_SEQUENCE, "mmccmcmm", |
2656 | 0 | asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2), |
2657 | 0 | asn1_integer("c", cert->serialNumber), |
2658 | 0 | sig_scheme, |
2659 | 0 | issuer->get_encoding(issuer), |
2660 | 0 | asn1_wrap(ASN1_SEQUENCE, "mm", |
2661 | 0 | asn1_from_time(&cert->notBefore, ASN1_UTCTIME), |
2662 | 0 | asn1_from_time(&cert->notAfter, ASN1_UTCTIME)), |
2663 | 0 | subject->get_encoding(subject), |
2664 | 0 | key_info, extensions); |
2665 | |
|
2666 | 0 | if (!sign_key->sign(sign_key, cert->scheme->scheme, cert->scheme->params, |
2667 | 0 | cert->tbsCertificate, &cert->signature)) |
2668 | 0 | { |
2669 | 0 | chunk_free(&sig_scheme); |
2670 | 0 | return FALSE; |
2671 | 0 | } |
2672 | 0 | cert->encoding = asn1_wrap(ASN1_SEQUENCE, "cmm", cert->tbsCertificate, |
2673 | 0 | sig_scheme, |
2674 | 0 | asn1_bitstring("c", cert->signature)); |
2675 | |
|
2676 | 0 | hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); |
2677 | 0 | if (!hasher || |
2678 | 0 | !hasher->allocate_hash(hasher, cert->encoding, &cert->encoding_hash)) |
2679 | 0 | { |
2680 | 0 | DESTROY_IF(hasher); |
2681 | 0 | return FALSE; |
2682 | 0 | } |
2683 | 0 | hasher->destroy(hasher); |
2684 | 0 | return TRUE; |
2685 | 0 | } |
2686 | | |
2687 | | /** |
2688 | | * See header. |
2689 | | */ |
2690 | | x509_cert_t *x509_cert_load(certificate_type_t type, va_list args) |
2691 | 106k | { |
2692 | 106k | x509_flag_t flags = 0; |
2693 | 106k | chunk_t blob = chunk_empty; |
2694 | | |
2695 | 106k | while (TRUE) |
2696 | 165k | { |
2697 | 165k | switch (va_arg(args, builder_part_t)) |
2698 | 165k | { |
2699 | 58.6k | case BUILD_BLOB_ASN1_DER: |
2700 | 58.6k | blob = va_arg(args, chunk_t); |
2701 | 58.6k | continue; |
2702 | 0 | case BUILD_X509_FLAG: |
2703 | 0 | flags |= va_arg(args, x509_flag_t); |
2704 | 0 | continue; |
2705 | 58.6k | case BUILD_END: |
2706 | 58.6k | break; |
2707 | 48.1k | default: |
2708 | 48.1k | return NULL; |
2709 | 165k | } |
2710 | 58.6k | break; |
2711 | 165k | } |
2712 | | |
2713 | 58.6k | if (blob.ptr) |
2714 | 58.6k | { |
2715 | 58.6k | private_x509_cert_t *cert = create_empty(); |
2716 | | |
2717 | 58.6k | cert->encoding = chunk_clone(blob); |
2718 | 58.6k | cert->parsed = TRUE; |
2719 | 58.6k | if (parse_certificate(cert)) |
2720 | 41.6k | { |
2721 | 41.6k | cert->flags |= flags; |
2722 | 41.6k | return &cert->public; |
2723 | 41.6k | } |
2724 | 17.0k | destroy(cert); |
2725 | 17.0k | } |
2726 | 17.0k | return NULL; |
2727 | 58.6k | } |
2728 | | |
2729 | | /** |
2730 | | * See header. |
2731 | | */ |
2732 | | x509_cert_t *x509_cert_gen(certificate_type_t type, va_list args) |
2733 | 106k | { |
2734 | 106k | private_x509_cert_t *cert; |
2735 | 106k | certificate_t *sign_cert = NULL; |
2736 | 106k | private_key_t *sign_key = NULL; |
2737 | 106k | hash_algorithm_t digest_alg = HASH_SHA256; |
2738 | 106k | u_int constraint; |
2739 | | |
2740 | 106k | cert = create_empty(); |
2741 | 106k | while (TRUE) |
2742 | 106k | { |
2743 | 106k | switch (va_arg(args, builder_part_t)) |
2744 | 106k | { |
2745 | 0 | case BUILD_X509_FLAG: |
2746 | 0 | cert->flags |= va_arg(args, x509_flag_t); |
2747 | 0 | continue; |
2748 | 0 | case BUILD_SIGNING_KEY: |
2749 | 0 | sign_key = va_arg(args, private_key_t*); |
2750 | 0 | continue; |
2751 | 0 | case BUILD_SIGNING_CERT: |
2752 | 0 | sign_cert = va_arg(args, certificate_t*); |
2753 | 0 | continue; |
2754 | 0 | case BUILD_PUBLIC_KEY: |
2755 | 0 | cert->public_key = va_arg(args, public_key_t*); |
2756 | 0 | cert->public_key->get_ref(cert->public_key); |
2757 | 0 | continue; |
2758 | 0 | case BUILD_SUBJECT: |
2759 | 0 | cert->subject = va_arg(args, identification_t*); |
2760 | 0 | cert->subject = cert->subject->clone(cert->subject); |
2761 | 0 | continue; |
2762 | 0 | case BUILD_SUBJECT_ALTNAMES: |
2763 | 0 | { |
2764 | 0 | enumerator_t *enumerator; |
2765 | 0 | identification_t *id; |
2766 | 0 | linked_list_t *list; |
2767 | |
|
2768 | 0 | list = va_arg(args, linked_list_t*); |
2769 | 0 | enumerator = list->create_enumerator(list); |
2770 | 0 | while (enumerator->enumerate(enumerator, &id)) |
2771 | 0 | { |
2772 | 0 | cert->subjectAltNames->insert_last(cert->subjectAltNames, |
2773 | 0 | id->clone(id)); |
2774 | 0 | } |
2775 | 0 | enumerator->destroy(enumerator); |
2776 | 0 | continue; |
2777 | 0 | } |
2778 | 0 | case BUILD_CRL_DISTRIBUTION_POINTS: |
2779 | 0 | { |
2780 | 0 | enumerator_t *enumerator; |
2781 | 0 | linked_list_t *list; |
2782 | 0 | x509_cdp_t *in, *cdp; |
2783 | |
|
2784 | 0 | list = va_arg(args, linked_list_t*); |
2785 | 0 | enumerator = list->create_enumerator(list); |
2786 | 0 | while (enumerator->enumerate(enumerator, &in)) |
2787 | 0 | { |
2788 | 0 | INIT(cdp, |
2789 | 0 | .uri = strdup(in->uri), |
2790 | 0 | .issuer = in->issuer ? in->issuer->clone(in->issuer) : NULL, |
2791 | 0 | ); |
2792 | 0 | cert->crl_uris->insert_last(cert->crl_uris, cdp); |
2793 | 0 | } |
2794 | 0 | enumerator->destroy(enumerator); |
2795 | 0 | continue; |
2796 | 0 | } |
2797 | 0 | case BUILD_OCSP_ACCESS_LOCATIONS: |
2798 | 0 | { |
2799 | 0 | enumerator_t *enumerator; |
2800 | 0 | linked_list_t *list; |
2801 | 0 | char *uri; |
2802 | |
|
2803 | 0 | list = va_arg(args, linked_list_t*); |
2804 | 0 | enumerator = list->create_enumerator(list); |
2805 | 0 | while (enumerator->enumerate(enumerator, &uri)) |
2806 | 0 | { |
2807 | 0 | cert->ocsp_uris->insert_last(cert->ocsp_uris, strdup(uri)); |
2808 | 0 | } |
2809 | 0 | enumerator->destroy(enumerator); |
2810 | 0 | continue; |
2811 | 0 | } |
2812 | 0 | case BUILD_PATHLEN: |
2813 | 0 | constraint = va_arg(args, u_int); |
2814 | 0 | cert->pathLenConstraint = (constraint < 128) ? |
2815 | 0 | constraint : X509_NO_CONSTRAINT; |
2816 | 0 | continue; |
2817 | 0 | case BUILD_ADDRBLOCKS: |
2818 | 0 | { |
2819 | 0 | enumerator_t *enumerator; |
2820 | 0 | traffic_selector_t *ts; |
2821 | 0 | linked_list_t *list; |
2822 | |
|
2823 | 0 | list = va_arg(args, linked_list_t*); |
2824 | 0 | enumerator = list->create_enumerator(list); |
2825 | 0 | while (enumerator->enumerate(enumerator, &ts)) |
2826 | 0 | { |
2827 | 0 | cert->ipAddrBlocks->insert_last(cert->ipAddrBlocks, |
2828 | 0 | ts->clone(ts)); |
2829 | 0 | } |
2830 | 0 | enumerator->destroy(enumerator); |
2831 | 0 | continue; |
2832 | 0 | } |
2833 | 0 | case BUILD_PERMITTED_NAME_CONSTRAINTS: |
2834 | 0 | { |
2835 | 0 | enumerator_t *enumerator; |
2836 | 0 | linked_list_t *list; |
2837 | 0 | identification_t *constraint; |
2838 | |
|
2839 | 0 | list = va_arg(args, linked_list_t*); |
2840 | 0 | enumerator = list->create_enumerator(list); |
2841 | 0 | while (enumerator->enumerate(enumerator, &constraint)) |
2842 | 0 | { |
2843 | 0 | cert->permitted_names->insert_last(cert->permitted_names, |
2844 | 0 | constraint->clone(constraint)); |
2845 | 0 | } |
2846 | 0 | enumerator->destroy(enumerator); |
2847 | 0 | continue; |
2848 | 0 | } |
2849 | 0 | case BUILD_EXCLUDED_NAME_CONSTRAINTS: |
2850 | 0 | { |
2851 | 0 | enumerator_t *enumerator; |
2852 | 0 | linked_list_t *list; |
2853 | 0 | identification_t *constraint; |
2854 | |
|
2855 | 0 | list = va_arg(args, linked_list_t*); |
2856 | 0 | enumerator = list->create_enumerator(list); |
2857 | 0 | while (enumerator->enumerate(enumerator, &constraint)) |
2858 | 0 | { |
2859 | 0 | cert->excluded_names->insert_last(cert->excluded_names, |
2860 | 0 | constraint->clone(constraint)); |
2861 | 0 | } |
2862 | 0 | enumerator->destroy(enumerator); |
2863 | 0 | continue; |
2864 | 0 | } |
2865 | 0 | case BUILD_CERTIFICATE_POLICIES: |
2866 | 0 | { |
2867 | 0 | enumerator_t *enumerator; |
2868 | 0 | linked_list_t *list; |
2869 | 0 | x509_cert_policy_t *policy, *in; |
2870 | |
|
2871 | 0 | list = va_arg(args, linked_list_t*); |
2872 | 0 | enumerator = list->create_enumerator(list); |
2873 | 0 | while (enumerator->enumerate(enumerator, &in)) |
2874 | 0 | { |
2875 | 0 | INIT(policy, |
2876 | 0 | .oid = chunk_clone(in->oid), |
2877 | 0 | .cps_uri = strdupnull(in->cps_uri), |
2878 | 0 | .unotice_text = strdupnull(in->unotice_text), |
2879 | 0 | ); |
2880 | 0 | cert->cert_policies->insert_last(cert->cert_policies, policy); |
2881 | 0 | } |
2882 | 0 | enumerator->destroy(enumerator); |
2883 | 0 | continue; |
2884 | 0 | } |
2885 | 0 | case BUILD_POLICY_MAPPINGS: |
2886 | 0 | { |
2887 | 0 | enumerator_t *enumerator; |
2888 | 0 | linked_list_t *list; |
2889 | 0 | x509_policy_mapping_t* mapping, *in; |
2890 | |
|
2891 | 0 | list = va_arg(args, linked_list_t*); |
2892 | 0 | enumerator = list->create_enumerator(list); |
2893 | 0 | while (enumerator->enumerate(enumerator, &in)) |
2894 | 0 | { |
2895 | 0 | INIT(mapping, |
2896 | 0 | .issuer = chunk_clone(in->issuer), |
2897 | 0 | .subject = chunk_clone(in->subject), |
2898 | 0 | ); |
2899 | 0 | cert->policy_mappings->insert_last(cert->policy_mappings, |
2900 | 0 | mapping); |
2901 | 0 | } |
2902 | 0 | enumerator->destroy(enumerator); |
2903 | 0 | continue; |
2904 | 0 | } |
2905 | 0 | case BUILD_POLICY_REQUIRE_EXPLICIT: |
2906 | 0 | constraint = va_arg(args, u_int); |
2907 | 0 | cert->require_explicit = (constraint < 128) ? |
2908 | 0 | constraint : X509_NO_CONSTRAINT; |
2909 | 0 | continue; |
2910 | 0 | case BUILD_POLICY_INHIBIT_MAPPING: |
2911 | 0 | constraint = va_arg(args, u_int); |
2912 | 0 | cert->inhibit_mapping = (constraint < 128) ? |
2913 | 0 | constraint : X509_NO_CONSTRAINT; |
2914 | 0 | continue; |
2915 | 0 | case BUILD_POLICY_INHIBIT_ANY: |
2916 | 0 | constraint = va_arg(args, u_int); |
2917 | 0 | cert->inhibit_any = (constraint < 128) ? |
2918 | 0 | constraint : X509_NO_CONSTRAINT; |
2919 | 0 | continue; |
2920 | 0 | case BUILD_NOT_BEFORE_TIME: |
2921 | 0 | cert->notBefore = va_arg(args, time_t); |
2922 | 0 | continue; |
2923 | 0 | case BUILD_NOT_AFTER_TIME: |
2924 | 0 | cert->notAfter = va_arg(args, time_t); |
2925 | 0 | continue; |
2926 | 0 | case BUILD_SERIAL: |
2927 | 0 | cert->serialNumber = chunk_clone(va_arg(args, chunk_t)); |
2928 | 0 | continue; |
2929 | 0 | case BUILD_SIGNATURE_SCHEME: |
2930 | 0 | cert->scheme = va_arg(args, signature_params_t*); |
2931 | 0 | cert->scheme = signature_params_clone(cert->scheme); |
2932 | 0 | continue; |
2933 | 0 | case BUILD_DIGEST_ALG: |
2934 | 0 | digest_alg = va_arg(args, int); |
2935 | 0 | continue; |
2936 | 0 | case BUILD_CRITICAL_EXTENSION: |
2937 | 0 | cert->critical_extension_oid = chunk_clone(va_arg(args, chunk_t)); |
2938 | 0 | continue; |
2939 | 0 | case BUILD_END: |
2940 | 0 | break; |
2941 | 106k | default: |
2942 | 106k | destroy(cert); |
2943 | 106k | return NULL; |
2944 | 106k | } |
2945 | 0 | break; |
2946 | 106k | } |
2947 | | |
2948 | 0 | if (sign_key && generate(cert, sign_cert, sign_key, digest_alg)) |
2949 | 0 | { |
2950 | 0 | return &cert->public; |
2951 | 0 | } |
2952 | 0 | destroy(cert); |
2953 | 0 | return NULL; |
2954 | 0 | } |