Coverage Report

Created: 2026-08-11 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}