/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 | 4.96k | #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.29k | #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 | 4.00k | { |
96 | 4.00k | CK_BBOOL trustedv; |
97 | 4.00k | CK_BBOOL distrustv; |
98 | | |
99 | 4.00k | CK_ATTRIBUTE trusted = { CKA_TRUSTED, &trustedv, sizeof (trustedv) }; |
100 | 4.00k | 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 | 4.00k | 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 | 4.00k | } 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 | 4.00k | } else { |
133 | 4.00k | trustedv = CK_FALSE; |
134 | 4.00k | distrustv = CK_FALSE; |
135 | | |
136 | 4.00k | if (p11_attrs_find_valid (attrs, CKA_TRUSTED)) |
137 | 1.82k | trusted.type = CKA_INVALID; |
138 | 4.00k | if (p11_attrs_find_valid (attrs, CKA_X_DISTRUSTED)) |
139 | 1.75k | distrust.type = CKA_INVALID; |
140 | 4.00k | } |
141 | | |
142 | 4.00k | return p11_attrs_build (attrs, &trusted, &distrust, NULL); |
143 | 4.00k | } |
144 | | |
145 | | static void |
146 | | sink_object (p11_parser *parser, |
147 | | CK_ATTRIBUTE *attrs) |
148 | 83.2k | { |
149 | 83.2k | CK_OBJECT_CLASS klass; |
150 | | |
151 | 83.2k | if (p11_attrs_find_ulong (attrs, CKA_CLASS, &klass) && |
152 | 7.79k | klass == CKO_CERTIFICATE) { |
153 | 4.00k | attrs = populate_trust (parser, attrs); |
154 | 4.00k | return_if_fail (attrs != NULL); |
155 | 4.00k | } |
156 | | |
157 | 83.2k | if (!p11_array_push (parser->parsed, attrs)) |
158 | 0 | return_if_reached (); |
159 | 83.2k | } |
160 | | |
161 | | static CK_ATTRIBUTE * |
162 | | certificate_attrs (p11_parser *parser, |
163 | | const unsigned char *der, |
164 | | size_t der_len) |
165 | 2.62k | { |
166 | 2.62k | CK_OBJECT_CLASS klassv = CKO_CERTIFICATE; |
167 | 2.62k | CK_CERTIFICATE_TYPE x509 = CKC_X_509; |
168 | 2.62k | CK_BBOOL modifiablev = CK_FALSE; |
169 | | |
170 | 2.62k | CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &modifiablev, sizeof (modifiablev) }; |
171 | 2.62k | CK_ATTRIBUTE klass = { CKA_CLASS, &klassv, sizeof (klassv) }; |
172 | 2.62k | CK_ATTRIBUTE certificate_type = { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }; |
173 | 2.62k | CK_ATTRIBUTE value = { CKA_VALUE, (void *)der, der_len }; |
174 | | |
175 | 2.62k | return p11_attrs_build (NULL, &klass, &modifiable, &certificate_type, &value, NULL); |
176 | 2.62k | } |
177 | | |
178 | | int |
179 | | p11_parser_format_x509 (p11_parser *parser, |
180 | | const unsigned char *data, |
181 | | size_t length) |
182 | 2.26k | { |
183 | 2.26k | char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; |
184 | 2.26k | CK_ATTRIBUTE *attrs; |
185 | 2.26k | CK_ATTRIBUTE *value; |
186 | 2.26k | asn1_node cert; |
187 | | |
188 | 2.26k | cert = p11_asn1_decode (parser->asn1_defs, "PKIX1.Certificate", data, length, message); |
189 | 2.26k | if (cert == NULL) |
190 | 2.25k | return P11_PARSE_UNRECOGNIZED; |
191 | | |
192 | 9 | attrs = certificate_attrs (parser, data, length); |
193 | 9 | return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE); |
194 | | |
195 | 9 | value = p11_attrs_find_valid (attrs, CKA_VALUE); |
196 | 9 | return_val_if_fail (value != NULL, P11_PARSE_FAILURE); |
197 | 9 | p11_asn1_cache_take (parser->asn1_cache, cert, "PKIX1.Certificate", |
198 | 9 | value->pValue, value->ulValueLen); |
199 | | |
200 | 9 | sink_object (parser, attrs); |
201 | 9 | return P11_PARSE_SUCCESS; |
202 | 9 | } |
203 | | |
204 | | static CK_ATTRIBUTE * |
205 | | extension_attrs (p11_parser *parser, |
206 | | CK_ATTRIBUTE *public_key_info, |
207 | | const char *oid_str, |
208 | | const unsigned char *oid_der, |
209 | | bool critical, |
210 | | const unsigned char *value, |
211 | | int length) |
212 | 3.12k | { |
213 | 3.12k | CK_OBJECT_CLASS klassv = CKO_X_CERTIFICATE_EXTENSION; |
214 | 3.12k | CK_BBOOL modifiablev = CK_FALSE; |
215 | | |
216 | 3.12k | CK_ATTRIBUTE klass = { CKA_CLASS, &klassv, sizeof (klassv) }; |
217 | 3.12k | CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &modifiablev, sizeof (modifiablev) }; |
218 | 3.12k | CK_ATTRIBUTE oid = { CKA_OBJECT_ID, (void *)oid_der, p11_oid_length (oid_der) }; |
219 | | |
220 | 3.12k | CK_ATTRIBUTE *attrs; |
221 | 3.12k | asn1_node dest; |
222 | 3.12k | unsigned char *der; |
223 | 3.12k | size_t len; |
224 | 3.12k | int ret; |
225 | | |
226 | 3.12k | attrs = p11_attrs_build (NULL, public_key_info, &klass, &modifiable, &oid, NULL); |
227 | 3.12k | return_val_if_fail (attrs != NULL, NULL); |
228 | | |
229 | 3.12k | dest = p11_asn1_create (parser->asn1_defs, "PKIX1.Extension"); |
230 | 3.12k | return_val_if_fail (dest != NULL, NULL); |
231 | | |
232 | 3.12k | ret = asn1_write_value (dest, "extnID", oid_str, 1); |
233 | 3.12k | return_val_if_fail (ret == ASN1_SUCCESS, NULL); |
234 | | |
235 | 3.12k | if (critical) |
236 | 1.75k | ret = asn1_write_value (dest, "critical", "TRUE", 1); |
237 | 3.12k | return_val_if_fail (ret == ASN1_SUCCESS, NULL); |
238 | | |
239 | 3.12k | ret = asn1_write_value (dest, "extnValue", value, length); |
240 | 3.12k | return_val_if_fail (ret == ASN1_SUCCESS, NULL); |
241 | | |
242 | 3.12k | der = p11_asn1_encode (dest, &len); |
243 | 3.12k | return_val_if_fail (der != NULL, NULL); |
244 | | |
245 | 3.12k | attrs = p11_attrs_take (attrs, CKA_VALUE, der, len); |
246 | 3.12k | return_val_if_fail (attrs != NULL, NULL); |
247 | | |
248 | | /* An opmitization so that the builder can get at this without parsing */ |
249 | 3.12k | p11_asn1_cache_take (parser->asn1_cache, dest, "PKIX1.Extension", der, len); |
250 | 3.12k | return attrs; |
251 | 3.12k | } |
252 | | |
253 | | static CK_ATTRIBUTE * |
254 | | attached_attrs (p11_parser *parser, |
255 | | CK_ATTRIBUTE *public_key_info, |
256 | | const char *oid_str, |
257 | | const unsigned char *oid_der, |
258 | | bool critical, |
259 | | asn1_node ext) |
260 | 2.25k | { |
261 | 2.25k | CK_ATTRIBUTE *attrs; |
262 | 2.25k | unsigned char *der; |
263 | 2.25k | size_t len; |
264 | | |
265 | 2.25k | der = p11_asn1_encode (ext, &len); |
266 | 2.25k | return_val_if_fail (der != NULL, NULL); |
267 | | |
268 | 2.25k | attrs = extension_attrs (parser, public_key_info, oid_str, oid_der, |
269 | 2.25k | critical, der, len); |
270 | 2.25k | return_val_if_fail (attrs != NULL, NULL); |
271 | | |
272 | 2.25k | free (der); |
273 | 2.25k | return attrs; |
274 | 2.25k | } |
275 | | |
276 | | static p11_dict * |
277 | | load_seq_of_oid_str (asn1_node node, |
278 | | const char *seqof) |
279 | 2.34k | { |
280 | 2.34k | p11_dict *oids; |
281 | 2.34k | char field[128]; |
282 | 2.34k | char *oid; |
283 | 2.34k | size_t len; |
284 | 2.34k | int i; |
285 | | |
286 | 2.34k | oids = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, NULL); |
287 | | |
288 | 5.50k | for (i = 1; ; i++) { |
289 | 5.50k | if (snprintf (field, sizeof (field), "%s.?%u", seqof, i) < 0) |
290 | 0 | return_val_if_reached (NULL); |
291 | | |
292 | 5.50k | oid = p11_asn1_read (node, field, &len); |
293 | 5.50k | if (oid == NULL) |
294 | 2.34k | break; |
295 | | |
296 | 3.16k | if (!p11_dict_set (oids, oid, oid)) |
297 | 0 | return_val_if_reached (NULL); |
298 | 3.16k | } |
299 | | |
300 | 2.34k | return oids; |
301 | 2.34k | } |
302 | | |
303 | | static CK_ATTRIBUTE * |
304 | | attached_eku_attrs (p11_parser *parser, |
305 | | CK_ATTRIBUTE *public_key_info, |
306 | | const char *oid_str, |
307 | | const unsigned char *oid_der, |
308 | | bool critical, |
309 | | p11_dict *oid_strs) |
310 | 2.25k | { |
311 | 2.25k | CK_ATTRIBUTE *attrs; |
312 | 2.25k | p11_dictiter iter; |
313 | 2.25k | asn1_node dest; |
314 | 2.25k | int count = 0; |
315 | 2.25k | void *value; |
316 | 2.25k | int ret; |
317 | | |
318 | 2.25k | dest = p11_asn1_create (parser->asn1_defs, "PKIX1.ExtKeyUsageSyntax"); |
319 | 2.25k | return_val_if_fail (dest != NULL, NULL); |
320 | | |
321 | 2.25k | p11_dict_iterate (oid_strs, &iter); |
322 | 5.41k | while (p11_dict_next (&iter, NULL, &value)) { |
323 | 3.15k | ret = asn1_write_value (dest, "", "NEW", 1); |
324 | 3.15k | return_val_if_fail (ret == ASN1_SUCCESS, NULL); |
325 | | |
326 | 3.15k | ret = asn1_write_value (dest, "?LAST", value, -1); |
327 | 3.15k | return_val_if_fail (ret == ASN1_SUCCESS, NULL); |
328 | | |
329 | 3.15k | count++; |
330 | 3.15k | } |
331 | | |
332 | | /* |
333 | | * If no oids have been written, then we have to put in a reserved |
334 | | * value, due to the way that ExtendedKeyUsage is defined in RFC 5280. |
335 | | * There must be at least one purpose. This is important since *not* |
336 | | * having an ExtendedKeyUsage is very different than having one without |
337 | | * certain usages. |
338 | | * |
339 | | * We account for this in p11_parse_extended_key_usage(). However for |
340 | | * most callers this should not matter, as they only check whether a |
341 | | * given purpose is present, and don't make assumptions about ones |
342 | | * that they don't know about. |
343 | | */ |
344 | | |
345 | 2.25k | if (count == 0) { |
346 | 1.61k | ret = asn1_write_value (dest, "", "NEW", 1); |
347 | 1.61k | return_val_if_fail (ret == ASN1_SUCCESS, NULL); |
348 | | |
349 | 1.61k | ret = asn1_write_value (dest, "?LAST", P11_OID_RESERVED_PURPOSE_STR, -1); |
350 | 1.61k | return_val_if_fail (ret == ASN1_SUCCESS, NULL); |
351 | 1.61k | } |
352 | | |
353 | | |
354 | 2.25k | attrs = attached_attrs (parser, public_key_info, oid_str, oid_der, critical, dest); |
355 | 2.25k | asn1_delete_structure (&dest); |
356 | | |
357 | 2.25k | return attrs; |
358 | 2.25k | } |
359 | | |
360 | | static CK_ATTRIBUTE * |
361 | | build_openssl_extensions (p11_parser *parser, |
362 | | CK_ATTRIBUTE *cert, |
363 | | CK_ATTRIBUTE *public_key_info, |
364 | | asn1_node aux, |
365 | | const unsigned char *aux_der, |
366 | | size_t aux_len) |
367 | 1.75k | { |
368 | 1.75k | CK_BBOOL trusted = CK_FALSE; |
369 | 1.75k | CK_BBOOL distrust = CK_FALSE; |
370 | | |
371 | 1.75k | CK_ATTRIBUTE trust_attrs[] = { |
372 | 1.75k | { CKA_TRUSTED, &trusted, sizeof (trusted) }, |
373 | 1.75k | { CKA_X_DISTRUSTED, &distrust, sizeof (distrust) }, |
374 | 1.75k | { CKA_INVALID }, |
375 | 1.75k | }; |
376 | | |
377 | 1.75k | CK_ATTRIBUTE *attrs; |
378 | 1.75k | p11_dict *trust = NULL; |
379 | 1.75k | p11_dict *reject = NULL; |
380 | 1.75k | p11_dictiter iter; |
381 | 1.75k | void *key; |
382 | 1.75k | int start; |
383 | 1.75k | int end; |
384 | 1.75k | int ret; |
385 | 1.75k | int num; |
386 | | |
387 | | /* |
388 | | * This will load an empty list if there is no OPTIONAL trust field. |
389 | | * OpenSSL assumes that for a TRUSTED CERTIFICATE a missing trust field |
390 | | * is identical to untrusted for all purposes. |
391 | | * |
392 | | * This is different from ExtendedKeyUsage, where a missing certificate |
393 | | * extension means that it is trusted for all purposes. |
394 | | */ |
395 | 1.75k | trust = load_seq_of_oid_str (aux, "trust"); |
396 | | |
397 | 1.75k | ret = asn1_number_of_elements (aux, "reject", &num); |
398 | 1.75k | return_val_if_fail (ret == ASN1_SUCCESS || ret == ASN1_ELEMENT_NOT_FOUND, NULL); |
399 | 1.75k | if (ret == ASN1_SUCCESS) |
400 | 589 | reject = load_seq_of_oid_str (aux, "reject"); |
401 | | |
402 | | /* Remove all rejected oids from the trust set */ |
403 | 1.75k | if (trust && reject) { |
404 | 589 | p11_dict_iterate (reject, &iter); |
405 | 3.57k | while (p11_dict_next (&iter, &key, NULL)) |
406 | 2.99k | p11_dict_remove (trust, key); |
407 | 589 | } |
408 | | |
409 | | /* |
410 | | * The trust field (or lack of it) becomes a standard ExtKeyUsageSyntax. |
411 | | * |
412 | | * critical: require that this is enforced |
413 | | */ |
414 | | |
415 | 1.75k | if (trust) { |
416 | 1.75k | attrs = attached_eku_attrs (parser, public_key_info, |
417 | 1.75k | P11_OID_EXTENDED_KEY_USAGE_STR, |
418 | 1.75k | P11_OID_EXTENDED_KEY_USAGE, |
419 | 1.75k | true, trust); |
420 | 1.75k | return_val_if_fail (attrs != NULL, NULL); |
421 | 1.75k | sink_object (parser, attrs); |
422 | 1.75k | } |
423 | | |
424 | | /* |
425 | | * For the reject field we use a custom defined extension. We track this |
426 | | * for completeness, although the above ExtendedKeyUsage extension handles |
427 | | * this data fine. See oid.h for more details. It uses ExtKeyUsageSyntax structure. |
428 | | * |
429 | | * non-critical: non-standard, and also covered by trusts |
430 | | */ |
431 | | |
432 | 1.75k | if (reject && p11_dict_size (reject) > 0) { |
433 | 502 | attrs = attached_eku_attrs (parser, public_key_info, |
434 | 502 | P11_OID_OPENSSL_REJECT_STR, |
435 | 502 | P11_OID_OPENSSL_REJECT, |
436 | 502 | false, reject); |
437 | 502 | return_val_if_fail (attrs != NULL, NULL); |
438 | 502 | sink_object (parser, attrs); |
439 | 502 | } |
440 | | |
441 | | /* |
442 | | * OpenSSL model blocklists as anchors with all purposes being removed/rejected, |
443 | | * we account for that here. If there is an ExtendedKeyUsage without any |
444 | | * useful purposes, then treat like a blocklist. |
445 | | */ |
446 | 1.75k | if (trust && p11_dict_size (trust) == 0) { |
447 | 1.61k | trusted = CK_FALSE; |
448 | 1.61k | distrust = CK_TRUE; |
449 | | |
450 | | /* |
451 | | * Otherwise a 'TRUSTED CERTIFICATE' in an input directory is enough to |
452 | | * mark this as a trusted certificate. |
453 | | */ |
454 | 1.61k | } else if (trust && p11_dict_size (trust) > 0) { |
455 | 145 | trusted = CK_TRUE; |
456 | 145 | distrust = CK_FALSE; |
457 | 145 | } |
458 | | |
459 | | /* |
460 | | * OpenSSL model blocklists as anchors with all purposes being removed/rejected, |
461 | | * we account for that here. If there is an ExtendedKeyUsage without any |
462 | | * useful purposes, then treat like a blocklist. |
463 | | */ |
464 | | |
465 | 1.75k | cert = p11_attrs_merge (cert, p11_attrs_dup (trust_attrs), true); |
466 | 1.75k | return_val_if_fail (cert != NULL, NULL); |
467 | | |
468 | 1.75k | p11_dict_free (trust); |
469 | 1.75k | p11_dict_free (reject); |
470 | | |
471 | | /* |
472 | | * For the keyid field we use the SubjectKeyIdentifier extension. It |
473 | | * is already in the correct form, an OCTET STRING. |
474 | | * |
475 | | * non-critical: as recommended in RFC 5280 |
476 | | */ |
477 | | |
478 | 1.75k | ret = asn1_der_decoding_startEnd (aux, aux_der, aux_len, "keyid", &start, &end); |
479 | 1.75k | return_val_if_fail (ret == ASN1_SUCCESS || ret == ASN1_ELEMENT_NOT_FOUND, NULL); |
480 | | |
481 | 1.75k | if (ret == ASN1_SUCCESS) { |
482 | 870 | attrs = extension_attrs (parser, public_key_info, |
483 | 870 | P11_OID_SUBJECT_KEY_IDENTIFIER_STR, |
484 | 870 | P11_OID_SUBJECT_KEY_IDENTIFIER, |
485 | 870 | false, aux_der + start, (end - start) + 1); |
486 | 870 | return_val_if_fail (attrs != NULL, NULL); |
487 | 870 | sink_object (parser, attrs); |
488 | 870 | } |
489 | | |
490 | | |
491 | 1.75k | return cert; |
492 | 1.75k | } |
493 | | |
494 | | static int |
495 | | parse_openssl_trusted_certificate (p11_parser *parser, |
496 | | const unsigned char *data, |
497 | | size_t length) |
498 | 4.14k | { |
499 | 4.14k | char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; |
500 | 4.14k | CK_ATTRIBUTE *attrs; |
501 | 4.14k | CK_ATTRIBUTE public_key_info = { CKA_PUBLIC_KEY_INFO }; |
502 | 4.14k | CK_ATTRIBUTE *value; |
503 | 4.14k | char *label = NULL; |
504 | 4.14k | asn1_node cert; |
505 | 4.14k | asn1_node aux = NULL; |
506 | 4.14k | ssize_t cert_len; |
507 | 4.14k | size_t len; |
508 | 4.14k | int start; |
509 | 4.14k | int end; |
510 | 4.14k | int ret; |
511 | | |
512 | | /* |
513 | | * This OpenSSL format is weird. It's just two DER structures |
514 | | * placed end to end without any wrapping SEQ. So calculate the |
515 | | * length of the first DER TLV we see and try to parse that as |
516 | | * the X.509 certificate. |
517 | | */ |
518 | | |
519 | 4.14k | cert_len = p11_asn1_tlv_length (data, length); |
520 | 4.14k | if (cert_len <= 0) |
521 | 956 | return P11_PARSE_UNRECOGNIZED; |
522 | | |
523 | 3.19k | cert = p11_asn1_decode (parser->asn1_defs, "PKIX1.Certificate", data, cert_len, message); |
524 | 3.19k | if (cert == NULL) |
525 | 363 | return P11_PARSE_UNRECOGNIZED; |
526 | | |
527 | | /* OpenSSL sometimes outputs TRUSTED CERTIFICATE format without the CertAux supplement */ |
528 | 2.83k | if (cert_len < length) { |
529 | 1.97k | aux = p11_asn1_decode (parser->asn1_defs, "OPENSSL.CertAux", data + cert_len, |
530 | 1.97k | length - cert_len, message); |
531 | 1.97k | if (aux == NULL) { |
532 | 215 | asn1_delete_structure (&cert); |
533 | 215 | return P11_PARSE_UNRECOGNIZED; |
534 | 215 | } |
535 | 1.97k | } |
536 | | |
537 | 2.61k | attrs = certificate_attrs (parser, data, cert_len); |
538 | 2.61k | return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE); |
539 | | |
540 | | /* Cache the parsed certificate ASN.1 for later use by the builder */ |
541 | 2.61k | value = p11_attrs_find_valid (attrs, CKA_VALUE); |
542 | 2.61k | return_val_if_fail (value != NULL, P11_PARSE_FAILURE); |
543 | | |
544 | | /* Pull out the subject public key info */ |
545 | 2.61k | ret = asn1_der_decoding_startEnd (cert, data, cert_len, |
546 | 2.61k | "tbsCertificate.subjectPublicKeyInfo", &start, &end); |
547 | 2.61k | return_val_if_fail (ret == ASN1_SUCCESS, P11_PARSE_FAILURE); |
548 | | |
549 | 1.97k | public_key_info.pValue = (char *)data + start; |
550 | 1.97k | public_key_info.ulValueLen = (end - start) + 1; |
551 | | |
552 | 1.97k | p11_asn1_cache_take (parser->asn1_cache, cert, "PKIX1.Certificate", |
553 | 1.97k | value->pValue, value->ulValueLen); |
554 | | |
555 | | /* Pull the label out of the CertAux */ |
556 | 1.97k | if (aux) { |
557 | 1.75k | len = 0; |
558 | 1.75k | label = p11_asn1_read (aux, "alias", &len); |
559 | 1.75k | if (label != NULL) { |
560 | 363 | attrs = p11_attrs_take (attrs, CKA_LABEL, label, strlen (label)); |
561 | 363 | return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE); |
562 | 363 | } |
563 | | |
564 | 1.75k | attrs = build_openssl_extensions (parser, attrs, &public_key_info, aux, |
565 | 1.75k | data + cert_len, length - cert_len); |
566 | 1.75k | return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE); |
567 | 1.75k | } |
568 | | |
569 | 1.97k | sink_object (parser, attrs); |
570 | 1.97k | asn1_delete_structure (&aux); |
571 | | |
572 | 1.97k | return P11_PARSE_SUCCESS; |
573 | 1.97k | } |
574 | | |
575 | | static void |
576 | | on_pem_block (const char *type, |
577 | | const unsigned char *contents, |
578 | | size_t length, |
579 | | void *user_data) |
580 | 6.74k | { |
581 | 6.74k | p11_parser *parser = user_data; |
582 | 6.74k | int ret; |
583 | | |
584 | 6.74k | if (strcmp (type, "CERTIFICATE") == 0) { |
585 | 116 | ret = p11_parser_format_x509 (parser, contents, length); |
586 | | |
587 | 6.63k | } else if (strcmp (type, "TRUSTED CERTIFICATE") == 0) { |
588 | 4.14k | ret = parse_openssl_trusted_certificate (parser, contents, length); |
589 | | |
590 | 4.14k | } else { |
591 | 2.48k | p11_debug ("Saw unsupported or unrecognized PEM block of type %s", type); |
592 | 2.48k | ret = P11_PARSE_SUCCESS; |
593 | 2.48k | } |
594 | | |
595 | 6.74k | if (ret != P11_PARSE_SUCCESS) |
596 | 2.29k | p11_message (_("Couldn't parse PEM block of type %s"), type); |
597 | 6.74k | } |
598 | | |
599 | | int |
600 | | p11_parser_format_pem (p11_parser *parser, |
601 | | const unsigned char *data, |
602 | | size_t length) |
603 | 2.13k | { |
604 | 2.13k | int num; |
605 | | |
606 | 2.13k | num = p11_pem_parse ((const char *)data, length, on_pem_block, parser); |
607 | | |
608 | 2.13k | if (num == 0) |
609 | 1.83k | return P11_PARSE_UNRECOGNIZED; |
610 | | |
611 | 306 | return P11_PARSE_SUCCESS; |
612 | 2.13k | } |
613 | | |
614 | | int |
615 | | p11_parser_format_persist (p11_parser *parser, |
616 | | const unsigned char *data, |
617 | | size_t length) |
618 | 1.83k | { |
619 | 1.83k | CK_BBOOL modifiablev = CK_TRUE; |
620 | 1.83k | CK_ATTRIBUTE *attrs; |
621 | 1.83k | p11_array *objects; |
622 | 1.83k | bool ret; |
623 | 1.83k | int i; |
624 | | |
625 | 1.83k | CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &modifiablev, sizeof (modifiablev) }; |
626 | | |
627 | 1.83k | if (!p11_persist_magic (data, length)) |
628 | 487 | return P11_PARSE_UNRECOGNIZED; |
629 | | |
630 | 1.34k | if (!parser->persist) { |
631 | 1.34k | parser->persist = p11_persist_new (); |
632 | 1.34k | return_val_if_fail (parser->persist != NULL, P11_PARSE_UNRECOGNIZED); |
633 | 1.34k | } |
634 | | |
635 | 1.34k | objects = p11_array_new (NULL); |
636 | 1.34k | return_val_if_fail (objects != NULL, P11_PARSE_FAILURE); |
637 | | |
638 | 1.34k | ret = p11_persist_read (parser->persist, parser->basename, data, length, objects); |
639 | 1.34k | if (ret) { |
640 | 754 | if (!p11_persist_is_generated (data, length)) |
641 | 753 | modifiablev = CK_FALSE; |
642 | 78.8k | for (i = 0; i < objects->num; i++) { |
643 | 78.1k | attrs = p11_attrs_build (objects->elem[i], &modifiable, NULL); |
644 | 78.1k | sink_object (parser, attrs); |
645 | 78.1k | } |
646 | 754 | } |
647 | | |
648 | 1.34k | p11_array_free (objects); |
649 | 1.34k | return ret ? P11_PARSE_SUCCESS : P11_PARSE_UNRECOGNIZED; |
650 | 1.34k | } |
651 | | |
652 | | p11_parser * |
653 | | p11_parser_new (p11_asn1_cache *asn1_cache) |
654 | 2.14k | { |
655 | 2.14k | p11_parser parser = { 0, }; |
656 | | |
657 | 2.14k | if (asn1_cache == NULL) { |
658 | 2.14k | parser.asn1_owned = true; |
659 | 2.14k | parser.asn1_defs = p11_asn1_defs_load (); |
660 | 2.14k | } else { |
661 | 0 | parser.asn1_defs = p11_asn1_cache_defs (asn1_cache); |
662 | 0 | parser.asn1_cache = asn1_cache; |
663 | 0 | parser.asn1_owned = false; |
664 | 0 | } |
665 | | |
666 | 2.14k | parser.parsed = p11_array_new (p11_attrs_free); |
667 | 2.14k | return_val_if_fail (parser.parsed != NULL, NULL); |
668 | | |
669 | 2.14k | return memdup (&parser, sizeof (parser)); |
670 | 2.14k | } |
671 | | |
672 | | void |
673 | | p11_parser_free (p11_parser *parser) |
674 | 2.14k | { |
675 | 2.14k | return_if_fail (parser != NULL); |
676 | 2.14k | p11_persist_free (parser->persist); |
677 | 2.14k | p11_array_free (parser->parsed); |
678 | 2.14k | p11_array_free (parser->formats); |
679 | 2.14k | if (parser->asn1_owned) |
680 | 2.14k | p11_dict_free (parser->asn1_defs); |
681 | 2.14k | free (parser); |
682 | 2.14k | } |
683 | | |
684 | | p11_array * |
685 | | p11_parser_parsed (p11_parser *parser) |
686 | 0 | { |
687 | 0 | return_val_if_fail (parser != NULL, NULL); |
688 | 0 | return parser->parsed; |
689 | 0 | } |
690 | | |
691 | | void |
692 | | p11_parser_formats (p11_parser *parser, |
693 | | ...) |
694 | 2.14k | { |
695 | 2.14k | p11_array *formats; |
696 | 2.14k | parser_func func; |
697 | 2.14k | va_list va; |
698 | | |
699 | 2.14k | formats = p11_array_new (NULL); |
700 | 2.14k | return_if_fail (formats != NULL); |
701 | | |
702 | 2.14k | va_start (va, parser); |
703 | 8.58k | for (;;) { |
704 | 8.58k | func = va_arg (va, parser_func); |
705 | 8.58k | if (func == NULL) |
706 | 2.14k | break; |
707 | 6.43k | if (!p11_array_push (formats, func)) { |
708 | 0 | va_end (va); |
709 | 0 | return_if_reached (); |
710 | 0 | } |
711 | 6.43k | } |
712 | 2.14k | va_end (va); |
713 | | |
714 | 2.14k | p11_array_free (parser->formats); |
715 | 2.14k | parser->formats = formats; |
716 | 2.14k | } |
717 | | |
718 | | int |
719 | | p11_parse_memory (p11_parser *parser, |
720 | | const char *filename, |
721 | | int flags, |
722 | | const unsigned char *data, |
723 | | size_t length) |
724 | 2.14k | { |
725 | 2.14k | int ret = P11_PARSE_UNRECOGNIZED; |
726 | 2.14k | char *base; |
727 | 2.14k | int i; |
728 | | |
729 | 2.14k | return_val_if_fail (parser != NULL, P11_PARSE_FAILURE); |
730 | 2.14k | return_val_if_fail (filename != NULL, P11_PARSE_FAILURE); |
731 | 2.14k | return_val_if_fail (parser->formats != NULL, P11_PARSE_FAILURE); |
732 | | |
733 | 2.14k | p11_array_clear (parser->parsed); |
734 | 2.14k | base = p11_path_base (filename); |
735 | 2.14k | parser->basename = base; |
736 | 2.14k | parser->flags = flags; |
737 | | |
738 | 8.26k | for (i = 0; ret == P11_PARSE_UNRECOGNIZED && i < parser->formats->num; i++) |
739 | 6.11k | ret = ((parser_func)parser->formats->elem[i]) (parser, data, length); |
740 | | |
741 | 2.14k | p11_asn1_cache_flush (parser->asn1_cache); |
742 | | |
743 | 2.14k | free (base); |
744 | 2.14k | parser->basename = NULL; |
745 | 2.14k | parser->flags = 0; |
746 | | |
747 | 2.14k | return ret; |
748 | 2.14k | } |
749 | | |
750 | | int |
751 | | p11_parse_file (p11_parser *parser, |
752 | | const char *filename, |
753 | | struct stat *sb, |
754 | | int flags) |
755 | 0 | { |
756 | 0 | p11_mmap *map; |
757 | 0 | void *data; |
758 | 0 | size_t size; |
759 | 0 | int ret; |
760 | |
|
761 | 0 | return_val_if_fail (parser != NULL, P11_PARSE_FAILURE); |
762 | 0 | return_val_if_fail (filename != NULL, P11_PARSE_FAILURE); |
763 | | |
764 | 0 | map = p11_mmap_open (filename, sb, &data, &size); |
765 | 0 | if (map == NULL) { |
766 | 0 | p11_message_err (errno, _("couldn't open and map file: %s"), filename); |
767 | 0 | return P11_PARSE_FAILURE; |
768 | 0 | } |
769 | | |
770 | 0 | ret = p11_parse_memory (parser, filename, flags, data, size); |
771 | |
|
772 | 0 | p11_mmap_close (map); |
773 | 0 | return ret; |
774 | 0 | } |