/src/p11-kit/trust/parser.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2012 Red Hat Inc. |
3 | | * |
4 | | * Redistribution and use in source and binary forms, with or without |
5 | | * modification, are permitted provided that the following conditions |
6 | | * are met: |
7 | | * |
8 | | * * Redistributions of source code must retain the above |
9 | | * copyright notice, this list of conditions and the |
10 | | * following disclaimer. |
11 | | * * Redistributions in binary form must reproduce the |
12 | | * above copyright notice, this list of conditions and |
13 | | * the following disclaimer in the documentation and/or |
14 | | * other materials provided with the distribution. |
15 | | * * The names of contributors to this software may not be |
16 | | * used to endorse or promote products derived from this |
17 | | * software without specific prior written permission. |
18 | | * |
19 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
20 | | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
21 | | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
22 | | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
23 | | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
24 | | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
25 | | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
26 | | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
27 | | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
28 | | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF |
29 | | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
30 | | * DAMAGE. |
31 | | * |
32 | | * Author: Stef Walter <stefw@redhat.com> |
33 | | */ |
34 | | |
35 | | #include "config.h" |
36 | | |
37 | | #include "array.h" |
38 | | #include "asn1.h" |
39 | | #include "attrs.h" |
40 | 2.37k | #define P11_DEBUG_FLAG P11_DEBUG_TRUST |
41 | | #include "debug.h" |
42 | | #include "dict.h" |
43 | | #include "digest.h" |
44 | | #include "message.h" |
45 | | #include "module.h" |
46 | | #include "oid.h" |
47 | | #include "parser.h" |
48 | | #include "path.h" |
49 | | #include "pem.h" |
50 | | #include "pkcs11x.h" |
51 | | #include "persist.h" |
52 | | #include "types.h" |
53 | | #include "x509.h" |
54 | | |
55 | | #include <libtasn1.h> |
56 | | |
57 | | #include <sys/types.h> |
58 | | #include <sys/stat.h> |
59 | | |
60 | | #include <assert.h> |
61 | | #include <errno.h> |
62 | | #include <fcntl.h> |
63 | | #include <stdarg.h> |
64 | | #include <stdlib.h> |
65 | | #include <string.h> |
66 | | #include <unistd.h> |
67 | | |
68 | | #ifdef ENABLE_NLS |
69 | | #include <libintl.h> |
70 | 2.32k | #define _(x) dgettext(PACKAGE_NAME, x) |
71 | | #else |
72 | | #define _(x) (x) |
73 | | #endif |
74 | | |
75 | | struct _p11_parser { |
76 | | p11_asn1_cache *asn1_cache; |
77 | | p11_dict *asn1_defs; |
78 | | bool asn1_owned; |
79 | | p11_persist *persist; |
80 | | char *basename; |
81 | | p11_array *parsed; |
82 | | p11_array *formats; |
83 | | int flags; |
84 | | }; |
85 | | |
86 | | #define ID_LENGTH P11_DIGEST_SHA1_LEN |
87 | | |
88 | | typedef int (* parser_func) (p11_parser *parser, |
89 | | const unsigned char *data, |
90 | | size_t length); |
91 | | |
92 | | static CK_ATTRIBUTE * |
93 | | populate_trust (p11_parser *parser, |
94 | | CK_ATTRIBUTE *attrs) |
95 | 3.81k | { |
96 | 3.81k | CK_BBOOL trustedv; |
97 | 3.81k | CK_BBOOL distrustv; |
98 | | |
99 | 3.81k | CK_ATTRIBUTE trusted = { CKA_TRUSTED, &trustedv, sizeof (trustedv) }; |
100 | 3.81k | CK_ATTRIBUTE distrust = { CKA_X_DISTRUSTED, &distrustv, sizeof (distrustv) }; |
101 | | |
102 | | /* |
103 | | * If we're are parsing an anchor location, then warn about any ditsrusted |
104 | | * certificates there, but don't go ahead and automatically make them |
105 | | * trusted anchors. |
106 | | */ |
107 | 3.81k | if (parser->flags & P11_PARSE_FLAG_ANCHOR) { |
108 | 0 | if (p11_attrs_find_bool (attrs, CKA_X_DISTRUSTED, &distrustv) && distrustv) { |
109 | 0 | p11_message (_("certificate with distrust in location for anchors: %s"), parser->basename); |
110 | 0 | return attrs; |
111 | |
|
112 | 0 | } |
113 | | |
114 | 0 | trustedv = CK_TRUE; |
115 | 0 | distrustv = CK_FALSE; |
116 | | |
117 | | /* |
118 | | * If we're parsing a blocklist location, then force all certificates to |
119 | | * be distrusted, regardless of whether they contain anchor information. |
120 | | */ |
121 | 3.81k | } else if (parser->flags & P11_PARSE_FLAG_BLOCKLIST) { |
122 | 0 | if (p11_attrs_find_bool (attrs, CKA_TRUSTED, &trustedv) && trustedv) |
123 | 0 | p11_message (_("overriding trust for anchor in blocklist: %s"), parser->basename); |
124 | |
|
125 | 0 | trustedv = CK_FALSE; |
126 | 0 | distrustv = CK_TRUE; |
127 | | |
128 | | /* |
129 | | * If the location doesn't have a flag, then fill in trust attributes |
130 | | * if they are missing: neither an anchor or blocklist. |
131 | | */ |
132 | 3.81k | } else { |
133 | 3.81k | trustedv = CK_FALSE; |
134 | 3.81k | distrustv = CK_FALSE; |
135 | | |
136 | 3.81k | if (p11_attrs_find_valid (attrs, CKA_TRUSTED)) |
137 | 2.45k | trusted.type = CKA_INVALID; |
138 | 3.81k | if (p11_attrs_find_valid (attrs, CKA_X_DISTRUSTED)) |
139 | 2.23k | distrust.type = CKA_INVALID; |
140 | 3.81k | } |
141 | | |
142 | 3.81k | return p11_attrs_build (attrs, &trusted, &distrust, NULL); |
143 | 3.81k | } |
144 | | |
145 | | static bool |
146 | | sink_object (p11_parser *parser, |
147 | | CK_ATTRIBUTE *attrs) |
148 | 149k | { |
149 | 149k | CK_OBJECT_CLASS klass; |
150 | | |
151 | 149k | if (p11_attrs_find_ulong (attrs, CKA_CLASS, &klass) && |
152 | 8.29k | klass == CKO_CERTIFICATE) { |
153 | 3.81k | attrs = populate_trust (parser, attrs); |
154 | 3.81k | return_val_if_fail (attrs != NULL, false); |
155 | 3.81k | } |
156 | | |
157 | 149k | if (!p11_array_push (parser->parsed, attrs)) { |
158 | 0 | p11_attrs_free (attrs); |
159 | 0 | return_val_if_reached (false); |
160 | 0 | } |
161 | | |
162 | 149k | return true; |
163 | 149k | } |
164 | | |
165 | | static CK_ATTRIBUTE * |
166 | | certificate_attrs (p11_parser *parser, |
167 | | const unsigned char *der, |
168 | | size_t der_len) |
169 | 3.24k | { |
170 | 3.24k | CK_OBJECT_CLASS klassv = CKO_CERTIFICATE; |
171 | 3.24k | CK_CERTIFICATE_TYPE x509 = CKC_X_509; |
172 | 3.24k | CK_BBOOL modifiablev = CK_FALSE; |
173 | | |
174 | 3.24k | CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &modifiablev, sizeof (modifiablev) }; |
175 | 3.24k | CK_ATTRIBUTE klass = { CKA_CLASS, &klassv, sizeof (klassv) }; |
176 | 3.24k | CK_ATTRIBUTE certificate_type = { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }; |
177 | 3.24k | CK_ATTRIBUTE value = { CKA_VALUE, (void *)der, der_len }; |
178 | | |
179 | 3.24k | return p11_attrs_build (NULL, &klass, &modifiable, &certificate_type, &value, NULL); |
180 | 3.24k | } |
181 | | |
182 | | int |
183 | | p11_parser_format_x509 (p11_parser *parser, |
184 | | const unsigned char *data, |
185 | | size_t length) |
186 | 3.79k | { |
187 | 3.79k | char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; |
188 | 3.79k | CK_ATTRIBUTE *attrs = NULL; |
189 | 3.79k | CK_ATTRIBUTE *value = NULL; |
190 | 3.79k | asn1_node cert = NULL; |
191 | | |
192 | 3.79k | cert = p11_asn1_decode (parser->asn1_defs, "PKIX1.Certificate", data, length, message); |
193 | 3.79k | if (cert == NULL) |
194 | 3.59k | return P11_PARSE_UNRECOGNIZED; |
195 | | |
196 | 200 | attrs = certificate_attrs (parser, data, length); |
197 | 200 | if (attrs == NULL) { |
198 | 0 | asn1_delete_structure (&cert); |
199 | 0 | return_val_if_reached (P11_PARSE_FAILURE); |
200 | 0 | } |
201 | | |
202 | 200 | value = p11_attrs_find_valid (attrs, CKA_VALUE); |
203 | 200 | if (value == NULL) { |
204 | 0 | asn1_delete_structure (&cert); |
205 | 0 | p11_attrs_free (attrs); |
206 | 0 | return_val_if_reached (P11_PARSE_FAILURE); |
207 | 0 | } |
208 | 200 | p11_asn1_cache_take (parser->asn1_cache, cert, "PKIX1.Certificate", |
209 | 200 | value->pValue, value->ulValueLen); |
210 | | |
211 | 200 | if (!sink_object (parser, attrs)) { |
212 | 0 | asn1_delete_structure (&cert); |
213 | 0 | return_val_if_reached (P11_PARSE_FAILURE); |
214 | 0 | } |
215 | 200 | return P11_PARSE_SUCCESS; |
216 | 200 | } |
217 | | |
218 | | static CK_ATTRIBUTE * |
219 | | extension_attrs (p11_parser *parser, |
220 | | const CK_ATTRIBUTE *public_key_info, |
221 | | const char *oid_str, |
222 | | const unsigned char *oid_der, |
223 | | bool critical, |
224 | | const unsigned char *value, |
225 | | int length) |
226 | 4.07k | { |
227 | 4.07k | CK_OBJECT_CLASS klassv = CKO_X_CERTIFICATE_EXTENSION; |
228 | 4.07k | CK_BBOOL modifiablev = CK_FALSE; |
229 | | |
230 | 4.07k | CK_ATTRIBUTE klass = { CKA_CLASS, &klassv, sizeof (klassv) }; |
231 | 4.07k | CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &modifiablev, sizeof (modifiablev) }; |
232 | 4.07k | CK_ATTRIBUTE oid = { CKA_OBJECT_ID, (void *)oid_der, p11_oid_length (oid_der) }; |
233 | | |
234 | 4.07k | CK_ATTRIBUTE *attrs = NULL; |
235 | 4.07k | asn1_node dest = NULL; |
236 | 4.07k | unsigned char *der = NULL; |
237 | 4.07k | size_t len; |
238 | 4.07k | int ret; |
239 | | |
240 | 4.07k | attrs = p11_attrs_build (NULL, public_key_info, &klass, &modifiable, &oid, NULL); |
241 | 4.07k | return_val_if_fail (attrs != NULL, NULL); |
242 | | |
243 | 4.07k | dest = p11_asn1_create (parser->asn1_defs, "PKIX1.Extension"); |
244 | 4.07k | if (dest == NULL) { |
245 | 0 | warn_if_reached (); |
246 | 0 | goto fail; |
247 | 0 | } |
248 | | |
249 | 4.07k | ret = asn1_write_value (dest, "extnID", oid_str, 1); |
250 | 4.07k | if (ret != ASN1_SUCCESS) { |
251 | 0 | warn_if_reached (); |
252 | 0 | goto fail; |
253 | 0 | } |
254 | | |
255 | 4.07k | if (critical) { |
256 | 2.42k | ret = asn1_write_value (dest, "critical", "TRUE", 1); |
257 | 2.42k | if (ret != ASN1_SUCCESS) { |
258 | 0 | warn_if_reached (); |
259 | 0 | goto fail; |
260 | 0 | } |
261 | 2.42k | } |
262 | | |
263 | 4.07k | ret = asn1_write_value (dest, "extnValue", value, length); |
264 | 4.07k | if (ret != ASN1_SUCCESS) { |
265 | 0 | warn_if_reached (); |
266 | 0 | goto fail; |
267 | 0 | } |
268 | | |
269 | 4.07k | der = p11_asn1_encode (dest, &len); |
270 | 4.07k | if (der == NULL) { |
271 | 0 | warn_if_reached (); |
272 | 0 | goto fail; |
273 | 0 | } |
274 | | |
275 | 4.07k | attrs = p11_attrs_take (attrs, CKA_VALUE, der, len); |
276 | 4.07k | if (attrs == NULL) { |
277 | 0 | warn_if_reached (); |
278 | 0 | free (der); |
279 | 0 | goto fail; |
280 | 0 | } |
281 | | |
282 | | /* An opmitization so that the builder can get at this without parsing */ |
283 | 4.07k | p11_asn1_cache_take (parser->asn1_cache, dest, "PKIX1.Extension", der, len); |
284 | 4.07k | return attrs; |
285 | | |
286 | 0 | fail: |
287 | 0 | asn1_delete_structure (&dest); |
288 | 0 | p11_attrs_free (attrs); |
289 | 0 | return NULL; |
290 | 4.07k | } |
291 | | |
292 | | static CK_ATTRIBUTE * |
293 | | attached_attrs (p11_parser *parser, |
294 | | const CK_ATTRIBUTE *public_key_info, |
295 | | const char *oid_str, |
296 | | const unsigned char *oid_der, |
297 | | bool critical, |
298 | | asn1_node ext) |
299 | 3.69k | { |
300 | 3.69k | CK_ATTRIBUTE *attrs; |
301 | 3.69k | unsigned char *der; |
302 | 3.69k | size_t len; |
303 | | |
304 | 3.69k | der = p11_asn1_encode (ext, &len); |
305 | 3.69k | return_val_if_fail (der != NULL, NULL); |
306 | | |
307 | 3.69k | attrs = extension_attrs (parser, public_key_info, oid_str, oid_der, |
308 | 3.69k | critical, der, len); |
309 | 3.69k | free (der); |
310 | 3.69k | return_val_if_fail (attrs != NULL, NULL); |
311 | | |
312 | 3.69k | return attrs; |
313 | 3.69k | } |
314 | | |
315 | | static p11_dict * |
316 | | load_seq_of_oid_str (asn1_node node, |
317 | | const char *seqof) |
318 | 4.29k | { |
319 | 4.29k | p11_dict *oids; |
320 | 4.29k | char field[128]; |
321 | 4.29k | char *oid; |
322 | 4.29k | size_t len; |
323 | 4.29k | int i; |
324 | | |
325 | 4.29k | oids = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, NULL); |
326 | 4.29k | return_val_if_fail (oids != NULL, NULL); |
327 | | |
328 | 9.46k | for (i = 1; ; i++) { |
329 | 9.46k | if (snprintf (field, sizeof (field), "%s.?%u", seqof, i) < 0) { |
330 | 0 | p11_dict_free (oids); |
331 | 0 | return_val_if_reached (NULL); |
332 | 0 | } |
333 | | |
334 | 9.46k | oid = p11_asn1_read (node, field, &len); |
335 | 9.46k | if (oid == NULL) |
336 | 4.29k | break; |
337 | | |
338 | 5.16k | if (!p11_dict_set (oids, oid, oid)) { |
339 | 0 | free (oid); |
340 | 0 | p11_dict_free (oids); |
341 | 0 | return_val_if_reached (NULL); |
342 | 0 | } |
343 | 5.16k | } |
344 | | |
345 | 4.29k | return oids; |
346 | 4.29k | } |
347 | | |
348 | | static CK_ATTRIBUTE * |
349 | | attached_eku_attrs (p11_parser *parser, |
350 | | const CK_ATTRIBUTE *public_key_info, |
351 | | const char *oid_str, |
352 | | const unsigned char *oid_der, |
353 | | bool critical, |
354 | | p11_dict *oid_strs) |
355 | 4.09k | { |
356 | 4.09k | CK_ATTRIBUTE *attrs; |
357 | 4.09k | p11_dictiter iter; |
358 | 4.09k | asn1_node dest; |
359 | 4.09k | int count = 0; |
360 | 4.09k | void *value; |
361 | 4.09k | int ret; |
362 | | |
363 | 4.09k | dest = p11_asn1_create (parser->asn1_defs, "PKIX1.ExtKeyUsageSyntax"); |
364 | 4.09k | return_val_if_fail (dest != NULL, NULL); |
365 | | |
366 | 4.09k | p11_dict_iterate (oid_strs, &iter); |
367 | 7.97k | while (p11_dict_next (&iter, NULL, &value)) { |
368 | 4.28k | ret = asn1_write_value (dest, "", "NEW", 1); |
369 | 4.28k | if (ret != ASN1_SUCCESS) { |
370 | 0 | asn1_delete_structure (&dest); |
371 | 0 | return_val_if_reached (NULL); |
372 | 0 | } |
373 | | |
374 | 4.28k | ret = asn1_write_value (dest, "?LAST", value, -1); |
375 | 4.28k | if (ret != ASN1_SUCCESS) { |
376 | 397 | asn1_delete_structure (&dest); |
377 | 397 | return_val_if_reached (NULL); |
378 | 397 | } |
379 | | |
380 | 3.88k | count++; |
381 | 3.88k | } |
382 | | |
383 | | /* |
384 | | * If no oids have been written, then we have to put in a reserved |
385 | | * value, due to the way that ExtendedKeyUsage is defined in RFC 5280. |
386 | | * There must be at least one purpose. This is important since *not* |
387 | | * having an ExtendedKeyUsage is very different than having one without |
388 | | * certain usages. |
389 | | * |
390 | | * We account for this in p11_parse_extended_key_usage(). However for |
391 | | * most callers this should not matter, as they only check whether a |
392 | | * given purpose is present, and don't make assumptions about ones |
393 | | * that they don't know about. |
394 | | */ |
395 | | |
396 | 3.69k | if (count == 0) { |
397 | 1.97k | ret = asn1_write_value (dest, "", "NEW", 1); |
398 | 1.97k | if (ret != ASN1_SUCCESS) { |
399 | 0 | asn1_delete_structure (&dest); |
400 | 0 | return_val_if_reached (NULL); |
401 | 0 | } |
402 | | |
403 | 1.97k | ret = asn1_write_value (dest, "?LAST", P11_OID_RESERVED_PURPOSE_STR, -1); |
404 | 1.97k | if (ret != ASN1_SUCCESS) { |
405 | 0 | asn1_delete_structure (&dest); |
406 | 0 | return_val_if_reached (NULL); |
407 | 0 | } |
408 | 1.97k | } |
409 | | |
410 | | |
411 | 3.69k | attrs = attached_attrs (parser, public_key_info, oid_str, oid_der, critical, dest); |
412 | 3.69k | asn1_delete_structure (&dest); |
413 | | |
414 | 3.69k | return attrs; |
415 | 3.69k | } |
416 | | |
417 | | /* Call to this function always invalidates pointer to `cert` |
418 | | */ |
419 | | static CK_ATTRIBUTE * |
420 | | build_openssl_extensions (p11_parser *parser, |
421 | | CK_ATTRIBUTE *cert, |
422 | | const CK_ATTRIBUTE *public_key_info, |
423 | | asn1_node aux, |
424 | | const unsigned char *aux_der, |
425 | | size_t aux_len) |
426 | 2.62k | { |
427 | 2.62k | CK_BBOOL trusted = CK_FALSE; |
428 | 2.62k | CK_BBOOL distrust = CK_FALSE; |
429 | | |
430 | 2.62k | CK_ATTRIBUTE trust_attrs[] = { |
431 | 2.62k | { CKA_TRUSTED, &trusted, sizeof (trusted) }, |
432 | 2.62k | { CKA_X_DISTRUSTED, &distrust, sizeof (distrust) }, |
433 | 2.62k | { CKA_INVALID }, |
434 | 2.62k | }; |
435 | | |
436 | 2.62k | CK_ATTRIBUTE *attrs; |
437 | 2.62k | p11_dict *trust = NULL; |
438 | 2.62k | p11_dict *reject = NULL; |
439 | 2.62k | p11_dictiter iter; |
440 | 2.62k | void *key; |
441 | 2.62k | int start; |
442 | 2.62k | int end; |
443 | 2.62k | int ret; |
444 | 2.62k | int num; |
445 | | |
446 | | /* |
447 | | * This will load an empty list if there is no OPTIONAL trust field. |
448 | | * OpenSSL assumes that for a TRUSTED CERTIFICATE a missing trust field |
449 | | * is identical to untrusted for all purposes. |
450 | | * |
451 | | * This is different from ExtendedKeyUsage, where a missing certificate |
452 | | * extension means that it is trusted for all purposes. |
453 | | */ |
454 | 2.62k | trust = load_seq_of_oid_str (aux, "trust"); |
455 | | |
456 | 2.62k | ret = asn1_number_of_elements (aux, "reject", &num); |
457 | 2.62k | if (ret != ASN1_SUCCESS && ret != ASN1_ELEMENT_NOT_FOUND) { |
458 | 0 | warn_if_reached (); |
459 | 0 | goto fail; |
460 | 0 | } |
461 | 2.62k | if (ret == ASN1_SUCCESS) |
462 | 1.67k | reject = load_seq_of_oid_str (aux, "reject"); |
463 | | |
464 | | /* Remove all rejected oids from the trust set */ |
465 | 2.62k | if (trust && reject) { |
466 | 1.67k | p11_dict_iterate (reject, &iter); |
467 | 5.27k | while (p11_dict_next (&iter, &key, NULL)) |
468 | 3.60k | p11_dict_remove (trust, key); |
469 | 1.67k | } |
470 | | |
471 | | /* |
472 | | * The trust field (or lack of it) becomes a standard ExtKeyUsageSyntax. |
473 | | * |
474 | | * critical: require that this is enforced |
475 | | */ |
476 | | |
477 | 2.62k | if (trust) { |
478 | 2.62k | attrs = attached_eku_attrs (parser, public_key_info, |
479 | 2.62k | P11_OID_EXTENDED_KEY_USAGE_STR, |
480 | 2.62k | P11_OID_EXTENDED_KEY_USAGE, |
481 | 2.62k | true, trust); |
482 | 2.62k | if (attrs == NULL) { |
483 | 202 | warn_if_reached (); |
484 | 202 | goto fail; |
485 | 202 | } |
486 | 2.42k | if (!sink_object (parser, attrs)) { |
487 | 0 | warn_if_reached (); |
488 | 0 | goto fail; |
489 | 0 | } |
490 | 2.42k | } |
491 | | |
492 | | /* |
493 | | * For the reject field we use a custom defined extension. We track this |
494 | | * for completeness, although the above ExtendedKeyUsage extension handles |
495 | | * this data fine. See oid.h for more details. It uses ExtKeyUsageSyntax structure. |
496 | | * |
497 | | * non-critical: non-standard, and also covered by trusts |
498 | | */ |
499 | | |
500 | 2.42k | if (reject && p11_dict_size (reject) > 0) { |
501 | 1.46k | attrs = attached_eku_attrs (parser, public_key_info, |
502 | 1.46k | P11_OID_OPENSSL_REJECT_STR, |
503 | 1.46k | P11_OID_OPENSSL_REJECT, |
504 | 1.46k | false, reject); |
505 | 1.46k | if (attrs == NULL) { |
506 | 195 | warn_if_reached (); |
507 | 195 | goto fail; |
508 | 195 | } |
509 | 1.27k | if (!sink_object (parser, attrs)) { |
510 | 0 | warn_if_reached (); |
511 | 0 | goto fail; |
512 | 0 | } |
513 | 1.27k | } |
514 | | |
515 | | /* |
516 | | * OpenSSL model blocklists as anchors with all purposes being removed/rejected, |
517 | | * we account for that here. If there is an ExtendedKeyUsage without any |
518 | | * useful purposes, then treat like a blocklist. |
519 | | */ |
520 | 2.23k | if (trust && p11_dict_size (trust) == 0) { |
521 | 1.77k | trusted = CK_FALSE; |
522 | 1.77k | distrust = CK_TRUE; |
523 | | |
524 | | /* |
525 | | * Otherwise a 'TRUSTED CERTIFICATE' in an input directory is enough to |
526 | | * mark this as a trusted certificate. |
527 | | */ |
528 | 1.77k | } else if (trust && p11_dict_size (trust) > 0) { |
529 | 455 | trusted = CK_TRUE; |
530 | 455 | distrust = CK_FALSE; |
531 | 455 | } |
532 | | |
533 | | /* |
534 | | * OpenSSL model blocklists as anchors with all purposes being removed/rejected, |
535 | | * we account for that here. If there is an ExtendedKeyUsage without any |
536 | | * useful purposes, then treat like a blocklist. |
537 | | */ |
538 | | |
539 | 2.23k | cert = p11_attrs_merge (cert, p11_attrs_dup (trust_attrs), true); |
540 | 2.23k | if (cert == NULL) { |
541 | 0 | warn_if_reached (); |
542 | 0 | goto fail; |
543 | 0 | } |
544 | | |
545 | 2.23k | p11_dict_free (trust); |
546 | 2.23k | p11_dict_free (reject); |
547 | 2.23k | trust = NULL; |
548 | 2.23k | reject = NULL; |
549 | | |
550 | | /* |
551 | | * For the keyid field we use the SubjectKeyIdentifier extension. It |
552 | | * is already in the correct form, an OCTET STRING. |
553 | | * |
554 | | * non-critical: as recommended in RFC 5280 |
555 | | */ |
556 | | |
557 | 2.23k | ret = asn1_der_decoding_startEnd (aux, aux_der, aux_len, "keyid", &start, &end); |
558 | 2.23k | if (ret != ASN1_SUCCESS && ret != ASN1_ELEMENT_NOT_FOUND) { |
559 | 0 | warn_if_reached (); |
560 | 0 | goto fail; |
561 | 0 | } |
562 | | |
563 | 2.23k | if (ret == ASN1_SUCCESS) { |
564 | 377 | attrs = extension_attrs (parser, public_key_info, |
565 | 377 | P11_OID_SUBJECT_KEY_IDENTIFIER_STR, |
566 | 377 | P11_OID_SUBJECT_KEY_IDENTIFIER, |
567 | 377 | false, aux_der + start, (end - start) + 1); |
568 | 377 | if (attrs == NULL || !sink_object (parser, attrs)) { |
569 | 0 | warn_if_reached (); |
570 | 0 | goto fail; |
571 | 0 | } |
572 | 377 | } |
573 | | |
574 | 2.23k | return cert; |
575 | | |
576 | 397 | fail: |
577 | 397 | p11_dict_free (trust); |
578 | 397 | p11_dict_free (reject); |
579 | 397 | p11_attrs_free (cert); |
580 | 397 | return NULL; |
581 | 2.23k | } |
582 | | |
583 | | static int |
584 | | parse_openssl_trusted_certificate (p11_parser *parser, |
585 | | const unsigned char *data, |
586 | | size_t length) |
587 | 4.35k | { |
588 | 4.35k | char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; |
589 | 4.35k | CK_ATTRIBUTE public_key_info = { CKA_PUBLIC_KEY_INFO }; |
590 | 4.35k | CK_ATTRIBUTE *value = NULL; |
591 | 4.35k | CK_ATTRIBUTE *attrs = NULL; |
592 | 4.35k | char *label = NULL; |
593 | 4.35k | asn1_node cert = NULL; |
594 | 4.35k | asn1_node aux = NULL; |
595 | 4.35k | ssize_t cert_len; |
596 | 4.35k | size_t len; |
597 | 4.35k | int start; |
598 | 4.35k | int end; |
599 | 4.35k | bool ok; |
600 | 4.35k | int ret = P11_PARSE_FAILURE; |
601 | | |
602 | | /* |
603 | | * This OpenSSL format is weird. It's just two DER structures |
604 | | * placed end to end without any wrapping SEQ. So calculate the |
605 | | * length of the first DER TLV we see and try to parse that as |
606 | | * the X.509 certificate. |
607 | | */ |
608 | | |
609 | 4.35k | cert_len = p11_asn1_tlv_length (data, length); |
610 | 4.35k | if (cert_len <= 0) |
611 | 689 | return P11_PARSE_UNRECOGNIZED; |
612 | | |
613 | 3.67k | cert = p11_asn1_decode (parser->asn1_defs, "PKIX1.Certificate", data, cert_len, message); |
614 | 3.67k | if (cert == NULL) |
615 | 230 | return P11_PARSE_UNRECOGNIZED; |
616 | | |
617 | | /* OpenSSL sometimes outputs TRUSTED CERTIFICATE format without the CertAux supplement */ |
618 | 3.44k | if (cert_len < length) { |
619 | 3.02k | aux = p11_asn1_decode (parser->asn1_defs, "OPENSSL.CertAux", data + cert_len, |
620 | 3.02k | length - cert_len, message); |
621 | 3.02k | if (aux == NULL) { |
622 | 392 | ret = P11_PARSE_UNRECOGNIZED; |
623 | 392 | goto cleanup; |
624 | 392 | } |
625 | 3.02k | } |
626 | | |
627 | 3.04k | attrs = certificate_attrs (parser, data, cert_len); |
628 | 3.04k | if (attrs == NULL) { |
629 | 0 | warn_if_reached(); |
630 | 0 | goto cleanup; |
631 | 0 | } |
632 | | |
633 | | /* Cache the parsed certificate ASN.1 for later use by the builder */ |
634 | 3.04k | value = p11_attrs_find_valid (attrs, CKA_VALUE); |
635 | 3.04k | if (value == NULL) { |
636 | 0 | warn_if_reached(); |
637 | 0 | goto cleanup; |
638 | 0 | } |
639 | | |
640 | | /* Pull out the subject public key info */ |
641 | 3.04k | if (asn1_der_decoding_startEnd (cert, data, cert_len, |
642 | 3.04k | "tbsCertificate.subjectPublicKeyInfo", |
643 | 3.04k | &start, &end) != ASN1_SUCCESS) { |
644 | 198 | warn_if_reached(); |
645 | 198 | goto cleanup; |
646 | 198 | } |
647 | | |
648 | 2.85k | public_key_info.pValue = (char *)data + start; |
649 | 2.85k | public_key_info.ulValueLen = (end - start) + 1; |
650 | | |
651 | 2.85k | p11_asn1_cache_take (parser->asn1_cache, cert, "PKIX1.Certificate", |
652 | 2.85k | value->pValue, value->ulValueLen); |
653 | | /* cache owns cert */ |
654 | 2.85k | cert = NULL; |
655 | | |
656 | | /* Pull the label out of the CertAux */ |
657 | 2.85k | if (aux) { |
658 | 2.62k | len = 0; |
659 | 2.62k | label = p11_asn1_read (aux, "alias", &len); |
660 | 2.62k | if (label != NULL) { |
661 | 1.16k | attrs = p11_attrs_take (attrs, CKA_LABEL, label, strlen (label)); |
662 | 1.16k | if (attrs == NULL) { |
663 | 0 | warn_if_reached(); |
664 | 0 | goto cleanup; |
665 | 0 | } |
666 | | /* attrs owns label */ |
667 | 1.16k | label = NULL; |
668 | 1.16k | } |
669 | | |
670 | 2.62k | attrs = build_openssl_extensions (parser, attrs, &public_key_info, aux, |
671 | 2.62k | data + cert_len, length - cert_len); |
672 | 2.62k | if (attrs == NULL) { |
673 | 397 | warn_if_reached(); |
674 | 397 | goto cleanup; |
675 | 397 | } |
676 | 2.62k | } |
677 | | |
678 | 2.45k | ok = sink_object (parser, attrs); |
679 | | /* attrs freed or owned by parser */ |
680 | 2.45k | attrs = NULL; |
681 | 2.45k | if (!ok) { |
682 | 0 | warn_if_reached(); |
683 | 0 | goto cleanup; |
684 | 0 | } |
685 | 2.45k | ret = P11_PARSE_SUCCESS; |
686 | | |
687 | 3.44k | cleanup: |
688 | 3.44k | asn1_delete_structure (&cert); |
689 | 3.44k | asn1_delete_structure (&aux); |
690 | 3.44k | p11_attrs_free (attrs); |
691 | 3.44k | free (label); |
692 | 3.44k | return ret; |
693 | 2.45k | } |
694 | | |
695 | | static void |
696 | | on_pem_block (const char *type, |
697 | | const unsigned char *contents, |
698 | | size_t length, |
699 | | void *user_data) |
700 | 6.15k | { |
701 | 6.15k | p11_parser *parser = user_data; |
702 | 6.15k | int ret; |
703 | | |
704 | 6.15k | if (strcmp (type, "CERTIFICATE") == 0) { |
705 | 607 | ret = p11_parser_format_x509 (parser, contents, length); |
706 | | |
707 | 5.54k | } else if (strcmp (type, "TRUSTED CERTIFICATE") == 0) { |
708 | 4.35k | ret = parse_openssl_trusted_certificate (parser, contents, length); |
709 | | |
710 | 4.35k | } else { |
711 | 1.18k | p11_debug ("Saw unsupported or unrecognized PEM block of type %s", type); |
712 | 1.18k | ret = P11_PARSE_SUCCESS; |
713 | 1.18k | } |
714 | | |
715 | 6.15k | if (ret != P11_PARSE_SUCCESS) |
716 | 2.32k | p11_message (_("Couldn't parse PEM block of type %s"), type); |
717 | 6.15k | } |
718 | | |
719 | | int |
720 | | p11_parser_format_pem (p11_parser *parser, |
721 | | const unsigned char *data, |
722 | | size_t length) |
723 | 3.17k | { |
724 | 3.17k | int num; |
725 | | |
726 | 3.17k | num = p11_pem_parse ((const char *)data, length, on_pem_block, parser); |
727 | | |
728 | 3.17k | if (num == 0) |
729 | 2.68k | return P11_PARSE_UNRECOGNIZED; |
730 | | |
731 | 498 | return P11_PARSE_SUCCESS; |
732 | 3.17k | } |
733 | | |
734 | | int |
735 | | p11_parser_format_persist (p11_parser *parser, |
736 | | const unsigned char *data, |
737 | | size_t length) |
738 | 2.68k | { |
739 | 2.68k | CK_BBOOL modifiablev = CK_TRUE; |
740 | 2.68k | CK_ATTRIBUTE *attrs; |
741 | 2.68k | p11_array *objects; |
742 | 2.68k | bool ret; |
743 | 2.68k | int i; |
744 | | |
745 | 2.68k | CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &modifiablev, sizeof (modifiablev) }; |
746 | | |
747 | 2.68k | if (!p11_persist_magic (data, length)) |
748 | 534 | return P11_PARSE_UNRECOGNIZED; |
749 | | |
750 | 2.14k | if (!parser->persist) { |
751 | 2.14k | parser->persist = p11_persist_new (); |
752 | 2.14k | return_val_if_fail (parser->persist != NULL, P11_PARSE_UNRECOGNIZED); |
753 | 2.14k | } |
754 | | |
755 | 2.14k | objects = p11_array_new (p11_attrs_free); |
756 | 2.14k | return_val_if_fail (objects != NULL, P11_PARSE_FAILURE); |
757 | | |
758 | 2.14k | ret = p11_persist_read (parser->persist, parser->basename, data, length, objects); |
759 | 2.14k | if (ret) { |
760 | 1.28k | if (!p11_persist_is_generated (data, length)) |
761 | 1.28k | modifiablev = CK_FALSE; |
762 | 143k | for (i = 0; i < objects->num; i++) { |
763 | 142k | attrs = p11_attrs_build (objects->elem[i], &modifiable, NULL); |
764 | | |
765 | | /* Prevent double-free */ |
766 | 142k | objects->elem[i] = NULL; |
767 | | |
768 | 142k | if (attrs == NULL || !sink_object (parser, attrs)) { |
769 | 0 | p11_array_free (objects); |
770 | 0 | return_val_if_reached (P11_PARSE_FAILURE); |
771 | 0 | } |
772 | 142k | } |
773 | 1.28k | } |
774 | | |
775 | 2.14k | p11_array_free (objects); |
776 | 2.14k | return ret ? P11_PARSE_SUCCESS : P11_PARSE_UNRECOGNIZED; |
777 | 2.14k | } |
778 | | |
779 | | p11_parser * |
780 | | p11_parser_new (p11_asn1_cache *asn1_cache) |
781 | 3.18k | { |
782 | 3.18k | p11_parser parser = { 0, }, *result; |
783 | | |
784 | 3.18k | if (asn1_cache == NULL) { |
785 | 3.18k | parser.asn1_owned = true; |
786 | 3.18k | parser.asn1_defs = p11_asn1_defs_load (); |
787 | 3.18k | } else { |
788 | 0 | parser.asn1_defs = p11_asn1_cache_defs (asn1_cache); |
789 | 0 | parser.asn1_cache = asn1_cache; |
790 | 0 | parser.asn1_owned = false; |
791 | 0 | } |
792 | | |
793 | 3.18k | parser.parsed = p11_array_new (p11_attrs_free); |
794 | 3.18k | if (parser.parsed == NULL) { |
795 | 0 | if (parser.asn1_owned) |
796 | 0 | p11_dict_free (parser.asn1_defs); |
797 | 0 | return_val_if_reached (NULL); |
798 | 0 | } |
799 | | |
800 | 3.18k | result = memdup (&parser, sizeof (parser)); |
801 | 3.18k | if (result == NULL) { |
802 | 0 | p11_array_free (parser.parsed); |
803 | 0 | if (parser.asn1_owned) |
804 | 0 | p11_dict_free (parser.asn1_defs); |
805 | 0 | return_val_if_reached (NULL); |
806 | 0 | } |
807 | 3.18k | return result; |
808 | 3.18k | } |
809 | | |
810 | | void |
811 | | p11_parser_free (p11_parser *parser) |
812 | 3.18k | { |
813 | 3.18k | return_if_fail (parser != NULL); |
814 | 3.18k | p11_persist_free (parser->persist); |
815 | 3.18k | p11_array_free (parser->parsed); |
816 | 3.18k | p11_array_free (parser->formats); |
817 | 3.18k | if (parser->asn1_owned) |
818 | 3.18k | p11_dict_free (parser->asn1_defs); |
819 | 3.18k | free (parser); |
820 | 3.18k | } |
821 | | |
822 | | p11_array * |
823 | | p11_parser_parsed (p11_parser *parser) |
824 | 0 | { |
825 | 0 | return_val_if_fail (parser != NULL, NULL); |
826 | 0 | return parser->parsed; |
827 | 0 | } |
828 | | |
829 | | void |
830 | | p11_parser_formats (p11_parser *parser, |
831 | | ...) |
832 | 3.18k | { |
833 | 3.18k | p11_array *formats; |
834 | 3.18k | parser_func func; |
835 | 3.18k | va_list va; |
836 | | |
837 | 3.18k | formats = p11_array_new (NULL); |
838 | 3.18k | return_if_fail (formats != NULL); |
839 | | |
840 | 3.18k | va_start (va, parser); |
841 | 12.7k | for (;;) { |
842 | 12.7k | func = va_arg (va, parser_func); |
843 | 12.7k | if (func == NULL) |
844 | 3.18k | break; |
845 | 9.55k | if (!p11_array_push (formats, func)) { |
846 | 0 | p11_array_free (formats); |
847 | 0 | va_end (va); |
848 | 0 | return_if_reached (); |
849 | 0 | } |
850 | 9.55k | } |
851 | 3.18k | va_end (va); |
852 | | |
853 | 3.18k | p11_array_free (parser->formats); |
854 | 3.18k | parser->formats = formats; |
855 | 3.18k | } |
856 | | |
857 | | int |
858 | | p11_parse_memory (p11_parser *parser, |
859 | | const char *filename, |
860 | | int flags, |
861 | | const unsigned char *data, |
862 | | size_t length) |
863 | 3.18k | { |
864 | 3.18k | int ret = P11_PARSE_UNRECOGNIZED; |
865 | 3.18k | char *base; |
866 | 3.18k | int i; |
867 | | |
868 | 3.18k | return_val_if_fail (parser != NULL, P11_PARSE_FAILURE); |
869 | 3.18k | return_val_if_fail (filename != NULL, P11_PARSE_FAILURE); |
870 | 3.18k | return_val_if_fail (parser->formats != NULL, P11_PARSE_FAILURE); |
871 | | |
872 | 3.18k | p11_array_clear (parser->parsed); |
873 | 3.18k | base = p11_path_base (filename); |
874 | 3.18k | parser->basename = base; |
875 | 3.18k | parser->flags = flags; |
876 | | |
877 | 12.2k | for (i = 0; ret == P11_PARSE_UNRECOGNIZED && i < parser->formats->num; i++) |
878 | 9.04k | ret = ((parser_func)parser->formats->elem[i]) (parser, data, length); |
879 | | |
880 | 3.18k | p11_asn1_cache_flush (parser->asn1_cache); |
881 | | |
882 | 3.18k | free (base); |
883 | 3.18k | parser->basename = NULL; |
884 | 3.18k | parser->flags = 0; |
885 | | |
886 | 3.18k | return ret; |
887 | 3.18k | } |
888 | | |
889 | | int |
890 | | p11_parse_file (p11_parser *parser, |
891 | | const char *filename, |
892 | | struct stat *sb, |
893 | | int flags) |
894 | 0 | { |
895 | 0 | p11_mmap *map; |
896 | 0 | void *data; |
897 | 0 | size_t size; |
898 | 0 | int ret; |
899 | |
|
900 | 0 | return_val_if_fail (parser != NULL, P11_PARSE_FAILURE); |
901 | 0 | return_val_if_fail (filename != NULL, P11_PARSE_FAILURE); |
902 | | |
903 | 0 | map = p11_mmap_open (filename, sb, &data, &size); |
904 | 0 | if (map == NULL) { |
905 | 0 | p11_message_err (errno, _("couldn't open and map file: %s"), filename); |
906 | 0 | return P11_PARSE_FAILURE; |
907 | 0 | } |
908 | | |
909 | 0 | ret = p11_parse_memory (parser, filename, flags, data, size); |
910 | |
|
911 | 0 | p11_mmap_close (map); |
912 | 0 | return ret; |
913 | 0 | } |