Coverage Report

Created: 2026-07-16 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/p11-kit/common/persist.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2013 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 "asn1.h"
38
#include "attrs.h"
39
#include "constants.h"
40
#include "debug.h"
41
#include "lexer.h"
42
#include "message.h"
43
#include "pem.h"
44
#include "persist.h"
45
#include "pkcs11.h"
46
#include "pkcs11i.h"
47
#include "pkcs11x.h"
48
#include "types.h"
49
#include "url.h"
50
51
#include "basic.asn.h"
52
53
#include <libtasn1.h>
54
55
#include <assert.h>
56
#include <stdlib.h>
57
#include <string.h>
58
59
#ifdef ENABLE_NLS
60
#include <libintl.h>
61
0
#define _(x) dgettext(PACKAGE_NAME, x)
62
#else
63
#define _(x) (x)
64
#endif
65
66
172k
#define PERSIST_HEADER "p11-kit-object-v1"
67
68
struct _p11_persist {
69
  p11_dict *constants;
70
  asn1_node asn1_defs;
71
};
72
73
bool
74
p11_persist_magic (const unsigned char *data,
75
                   size_t length)
76
2.80k
{
77
2.80k
  return (strnstr ((char *)data, "[" PERSIST_HEADER "]", length) != NULL);
78
2.80k
}
79
80
bool
81
p11_persist_is_generated (const unsigned char *data,
82
        size_t length)
83
1.38k
{
84
1.38k
  static const char comment[] =
85
1.38k
    "# This file has been auto-generated and written by p11-kit.";
86
1.38k
  return length >= sizeof (comment) - 1 &&
87
457
    memcmp ((const char *)data, comment, sizeof (comment) - 1) == 0;
88
1.38k
}
89
90
p11_persist *
91
p11_persist_new (void)
92
2.24k
{
93
2.24k
  p11_persist *persist;
94
95
2.24k
  persist = calloc (1, sizeof (p11_persist));
96
2.24k
  return_val_if_fail (persist != NULL, NULL);
97
98
2.24k
  persist->constants = p11_constant_reverse (true);
99
2.24k
  if (persist->constants == NULL) {
100
0
    free (persist);
101
0
    return_val_if_reached (NULL);
102
0
  }
103
104
2.24k
  return persist;
105
2.24k
}
106
107
void
108
p11_persist_free (p11_persist *persist)
109
3.36k
{
110
3.36k
  if (!persist)
111
1.11k
    return;
112
2.24k
  p11_dict_free (persist->constants);
113
2.24k
  asn1_delete_structure (&persist->asn1_defs);
114
2.24k
  free (persist);
115
2.24k
}
116
117
struct constant {
118
  CK_ULONG value;
119
  const char *string;
120
};
121
122
static bool
123
parse_string (p11_lexer *lexer,
124
              CK_ATTRIBUTE *attr)
125
10.7k
{
126
10.7k
  const char *value;
127
10.7k
  const char *end;
128
10.7k
  size_t length;
129
10.7k
  unsigned char *data;
130
131
10.7k
  value = lexer->tok.field.value;
132
10.7k
  end = value + strlen (value);
133
134
  /* Not a string/binary value */
135
10.7k
  if (end - value < 2 || value[0] != '\"' || *(end - 1) != '\"')
136
8.98k
    return false;
137
138
  /* Note that we don't skip whitespace when decoding, as you might in other URLs */
139
1.76k
  data = p11_url_decode (value + 1, end - 1, "", &length);
140
1.76k
  if (data == NULL) {
141
64
    p11_lexer_msg(lexer, "bad encoding of attribute value");
142
64
    return false;
143
64
  }
144
145
1.70k
  attr->pValue = data;
146
1.70k
  attr->ulValueLen = length;
147
1.70k
  return true;
148
1.76k
}
149
150
static void
151
format_string (CK_ATTRIBUTE *attr,
152
               p11_buffer *buf)
153
0
{
154
0
  const unsigned char *value;
155
156
0
  assert (attr->ulValueLen != CK_UNAVAILABLE_INFORMATION);
157
158
0
  p11_buffer_add (buf, "\"", 1);
159
0
  value = attr->pValue;
160
0
  p11_url_encode (value, value + attr->ulValueLen, P11_URL_VERBATIM " ", buf);
161
0
  p11_buffer_add (buf, "\"", 1);
162
0
}
163
164
static bool
165
parse_bool (p11_lexer *lexer,
166
            CK_ATTRIBUTE *attr)
167
9.04k
{
168
9.04k
  const char *value = lexer->tok.field.value;
169
9.04k
  CK_BBOOL boolean;
170
171
9.04k
  if (strcmp (value, "true") == 0) {
172
194
    boolean = CK_TRUE;
173
174
8.85k
  } else if (strcmp (value, "false") == 0) {
175
1.00k
    boolean = CK_FALSE;
176
177
7.85k
  } else {
178
    /* Not a valid boolean value */
179
7.85k
    return false;
180
7.85k
  }
181
182
1.19k
  attr->pValue = memdup (&boolean, sizeof (boolean));
183
1.19k
  return_val_if_fail (attr->pValue != NULL, false);
184
1.19k
  attr->ulValueLen = sizeof (boolean);
185
1.19k
  return true;
186
1.19k
}
187
188
static bool
189
format_bool (CK_ATTRIBUTE *attr,
190
             p11_buffer *buf)
191
0
{
192
0
  const CK_BBOOL *value;
193
194
0
  if (attr->ulValueLen != sizeof (CK_BBOOL))
195
0
    return false;
196
197
0
  switch (attr->type) {
198
0
  case CKA_TOKEN:
199
0
  case CKA_PRIVATE:
200
0
  case CKA_TRUSTED:
201
0
  case CKA_SENSITIVE:
202
0
  case CKA_ENCRYPT:
203
0
  case CKA_DECRYPT:
204
0
  case CKA_WRAP:
205
0
  case CKA_UNWRAP:
206
0
  case CKA_SIGN:
207
0
  case CKA_SIGN_RECOVER:
208
0
  case CKA_VERIFY:
209
0
  case CKA_VERIFY_RECOVER:
210
0
  case CKA_DERIVE:
211
0
  case CKA_EXTRACTABLE:
212
0
  case CKA_LOCAL:
213
0
  case CKA_NEVER_EXTRACTABLE:
214
0
  case CKA_ALWAYS_SENSITIVE:
215
0
  case CKA_MODIFIABLE:
216
0
  case CKA_SECONDARY_AUTH:
217
0
  case CKA_ALWAYS_AUTHENTICATE:
218
0
  case CKA_WRAP_WITH_TRUSTED:
219
0
  case CKA_RESET_ON_INIT:
220
0
  case CKA_HAS_RESET:
221
0
  case CKA_COLOR:
222
0
  case CKA_X_DISTRUSTED:
223
0
  case CKA_NSS_MOZILLA_CA_POLICY:
224
0
    break;
225
0
  default:
226
0
    return false;
227
0
  }
228
229
0
  value = attr->pValue;
230
0
  if (*value == CK_TRUE)
231
0
    p11_buffer_add (buf, "true", -1);
232
0
  else if (*value == CK_FALSE)
233
0
    p11_buffer_add (buf, "false", -1);
234
0
  else
235
0
    return false;
236
237
0
  return true;
238
0
}
239
240
static bool
241
parse_ulong (p11_lexer *lexer,
242
             CK_ATTRIBUTE *attr)
243
7.85k
{
244
7.85k
  unsigned long value;
245
7.85k
  char *end;
246
247
7.85k
  end = NULL;
248
7.85k
  value = strtoul (lexer->tok.field.value, &end, 10);
249
250
  /* Not a valid number value */
251
7.85k
  if (!end || *end != '\0')
252
655
    return false;
253
254
7.19k
  attr->pValue = memdup (&value, sizeof (CK_ULONG));
255
7.19k
  return_val_if_fail (attr->pValue != NULL, false);
256
7.19k
  attr->ulValueLen = sizeof (CK_ULONG);
257
7.19k
  return true;
258
7.19k
}
259
260
static bool
261
format_ulong (CK_ATTRIBUTE *attr,
262
              p11_buffer *buf)
263
0
{
264
0
  char string[sizeof (CK_ULONG) * 4];
265
0
  const CK_ULONG *value;
266
267
0
  if (attr->ulValueLen != sizeof (CK_ULONG))
268
0
    return false;
269
270
0
  switch (attr->type) {
271
0
  case CKA_CERTIFICATE_CATEGORY:
272
0
  case CKA_CERTIFICATE_TYPE:
273
0
  case CKA_CLASS:
274
0
  case CKA_JAVA_MIDP_SECURITY_DOMAIN:
275
0
  case CKA_KEY_GEN_MECHANISM:
276
0
  case CKA_KEY_TYPE:
277
0
  case CKA_MECHANISM_TYPE:
278
0
  case CKA_MODULUS_BITS:
279
0
  case CKA_PRIME_BITS:
280
0
  case CKA_SUB_PRIME_BITS:
281
0
  case CKA_VALUE_BITS:
282
0
  case CKA_VALUE_LEN:
283
0
  case CKA_NSS_TRUST_DIGITAL_SIGNATURE:
284
0
  case CKA_NSS_TRUST_NON_REPUDIATION:
285
0
  case CKA_NSS_TRUST_KEY_ENCIPHERMENT:
286
0
  case CKA_NSS_TRUST_DATA_ENCIPHERMENT:
287
0
  case CKA_NSS_TRUST_KEY_AGREEMENT:
288
0
  case CKA_NSS_TRUST_KEY_CERT_SIGN:
289
0
  case CKA_NSS_TRUST_CRL_SIGN:
290
0
  case CKA_NSS_TRUST_SERVER_AUTH:
291
0
  case CKA_NSS_TRUST_CLIENT_AUTH:
292
0
  case CKA_NSS_TRUST_CODE_SIGNING:
293
0
  case CKA_NSS_TRUST_EMAIL_PROTECTION:
294
0
  case CKA_NSS_TRUST_IPSEC_END_SYSTEM:
295
0
  case CKA_NSS_TRUST_IPSEC_TUNNEL:
296
0
  case CKA_NSS_TRUST_IPSEC_USER:
297
0
  case CKA_NSS_TRUST_TIME_STAMPING:
298
0
  case CKA_NSS_TRUST_STEP_UP_APPROVED:
299
0
  case CKA_TRUST_SERVER_AUTH:
300
0
  case CKA_TRUST_CLIENT_AUTH:
301
0
  case CKA_TRUST_CODE_SIGNING:
302
0
  case CKA_TRUST_EMAIL_PROTECTION:
303
0
  case CKA_TRUST_TIME_STAMPING:
304
0
  case CKA_X_ASSERTION_TYPE:
305
0
  case CKA_AUTH_PIN_FLAGS:
306
0
  case CKA_HW_FEATURE_TYPE:
307
0
  case CKA_PIXEL_X:
308
0
  case CKA_PIXEL_Y:
309
0
  case CKA_RESOLUTION:
310
0
  case CKA_CHAR_ROWS:
311
0
  case CKA_CHAR_COLUMNS:
312
0
  case CKA_BITS_PER_PIXEL:
313
0
    break;
314
0
  default:
315
0
    return false;
316
0
  }
317
318
0
  value = attr->pValue;
319
0
  snprintf (string, sizeof (string), "%lu", *value);
320
321
0
  p11_buffer_add (buf, string, -1);
322
0
  return true;
323
0
}
324
325
static bool
326
parse_constant (p11_persist *persist,
327
                p11_lexer *lexer,
328
                CK_ATTRIBUTE *attr)
329
11.3k
{
330
11.3k
  CK_ULONG value;
331
332
11.3k
  value = p11_constant_resolve (persist->constants, lexer->tok.field.value);
333
334
  /* Not a valid constant */
335
11.3k
  if (value == CKA_INVALID)
336
10.7k
    return false;
337
338
567
  attr->pValue = memdup (&value, sizeof (CK_ULONG));
339
567
  return_val_if_fail (attr->pValue != NULL, false);
340
567
  attr->ulValueLen = sizeof (CK_ULONG);
341
567
  return true;
342
567
}
343
344
static bool
345
format_constant (CK_ATTRIBUTE *attr,
346
                 p11_buffer *buf)
347
0
{
348
0
  const p11_constant *table;
349
0
  const CK_ULONG *value;
350
0
  const char *nick;
351
352
0
  if (attr->ulValueLen != sizeof (CK_ULONG))
353
0
    return false;
354
355
0
  switch (attr->type) {
356
0
  case CKA_NSS_TRUST_DIGITAL_SIGNATURE:
357
0
  case CKA_NSS_TRUST_NON_REPUDIATION:
358
0
  case CKA_NSS_TRUST_KEY_ENCIPHERMENT:
359
0
  case CKA_NSS_TRUST_DATA_ENCIPHERMENT:
360
0
  case CKA_NSS_TRUST_KEY_AGREEMENT:
361
0
  case CKA_NSS_TRUST_KEY_CERT_SIGN:
362
0
  case CKA_NSS_TRUST_CRL_SIGN:
363
0
  case CKA_NSS_TRUST_SERVER_AUTH:
364
0
  case CKA_NSS_TRUST_CLIENT_AUTH:
365
0
  case CKA_NSS_TRUST_CODE_SIGNING:
366
0
  case CKA_NSS_TRUST_EMAIL_PROTECTION:
367
0
  case CKA_NSS_TRUST_IPSEC_END_SYSTEM:
368
0
  case CKA_NSS_TRUST_IPSEC_TUNNEL:
369
0
  case CKA_NSS_TRUST_IPSEC_USER:
370
0
  case CKA_NSS_TRUST_TIME_STAMPING:
371
0
  case CKA_TRUST_SERVER_AUTH:
372
0
  case CKA_TRUST_CLIENT_AUTH:
373
0
  case CKA_TRUST_CODE_SIGNING:
374
0
  case CKA_TRUST_EMAIL_PROTECTION:
375
0
  case CKA_TRUST_TIME_STAMPING:
376
0
    table = p11_constant_trusts;
377
0
    break;
378
0
  case CKA_CLASS:
379
0
    table = p11_constant_classes;
380
0
    break;
381
0
  case CKA_CERTIFICATE_TYPE:
382
0
    table = p11_constant_certs;
383
0
    break;
384
0
  case CKA_KEY_TYPE:
385
0
    table = p11_constant_keys;
386
0
    break;
387
0
  case CKA_X_ASSERTION_TYPE:
388
0
    table = p11_constant_asserts;
389
0
    break;
390
0
  case CKA_CERTIFICATE_CATEGORY:
391
0
    table = p11_constant_categories;
392
0
    break;
393
0
  case CKA_KEY_GEN_MECHANISM:
394
0
  case CKA_MECHANISM_TYPE:
395
0
    table = p11_constant_mechanisms;
396
0
    break;
397
0
  case CKA_PROFILE_ID:
398
0
    table = p11_constant_profiles;
399
0
    break;
400
0
  default:
401
0
    table = NULL;
402
0
  };
403
404
0
  if (!table)
405
0
    return false;
406
407
0
  value = attr->pValue;
408
0
  nick = p11_constant_nick (table, *value);
409
410
0
  if (!nick)
411
0
    return false;
412
413
0
  p11_buffer_add (buf, nick, -1);
414
0
  return true;
415
0
}
416
417
static bool
418
parse_oid (p11_persist *persist,
419
           p11_lexer *lexer,
420
           CK_ATTRIBUTE *attr)
421
655
{
422
655
  char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, };
423
655
  asn1_node asn;
424
655
  size_t length;
425
655
  char *value;
426
655
  int ret;
427
428
655
  value = lexer->tok.field.value;
429
655
  length = strlen (value);
430
431
  /* Not an OID value? */
432
655
  if (length < 4 ||
433
551
      strchr (value, '.') == NULL ||
434
472
      strspn (value, "0123456790.") != length ||
435
430
      strstr (value, "..") != NULL ||
436
429
      value[0] == '.' || value[0] == '0' ||
437
427
      value[length - 1] == '.' ||
438
426
      strchr (value, '.') == strrchr (value, '.')) {
439
234
    return false;
440
234
  }
441
442
421
  if (!persist->asn1_defs) {
443
22
    ret = asn1_array2tree (basic_asn1_tab, &persist->asn1_defs, message);
444
22
    if (ret != ASN1_SUCCESS) {
445
0
      p11_debug_precond ("failed to load BASIC definitions: %s: %s\n",
446
0
                         asn1_strerror (ret), message);
447
0
      return false;
448
0
    }
449
22
  }
450
451
421
  ret = asn1_create_element (persist->asn1_defs, "BASIC.ObjectIdentifier", &asn);
452
421
  if (ret != ASN1_SUCCESS) {
453
0
    p11_debug_precond ("failed to create ObjectIdentifier element: %s\n",
454
0
                       asn1_strerror (ret));
455
0
    return false;
456
0
  }
457
458
421
  ret = asn1_write_value (asn, "", value, 1);
459
421
  if (ret == ASN1_VALUE_NOT_VALID) {
460
0
    p11_lexer_msg (lexer, "invalid oid value");
461
0
    asn1_delete_structure (&asn);
462
0
    return false;
463
0
  }
464
421
  return_val_if_fail (ret == ASN1_SUCCESS, false);
465
466
421
  attr->pValue = p11_asn1_encode (asn, &length);
467
421
  if (attr->pValue == NULL) {
468
3
    asn1_delete_structure (&asn);
469
3
    return_val_if_reached (false);
470
3
  }
471
418
  attr->ulValueLen = length;
472
473
418
  asn1_delete_structure (&asn);
474
418
  return true;
475
421
}
476
477
static bool
478
format_oid (p11_persist *persist,
479
            CK_ATTRIBUTE *attr,
480
            p11_buffer *buf)
481
0
{
482
0
  char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, };
483
0
  asn1_node asn;
484
0
  char *data;
485
0
  size_t len;
486
0
  int ret;
487
488
0
  if (attr->type != CKA_OBJECT_ID || attr->ulValueLen == 0)
489
0
    return false;
490
491
0
  if (!persist->asn1_defs) {
492
0
    ret = asn1_array2tree (basic_asn1_tab, &persist->asn1_defs, message);
493
0
    if (ret != ASN1_SUCCESS) {
494
0
      p11_debug_precond ("failed to load BASIC definitions: %s: %s\n",
495
0
                         asn1_strerror (ret), message);
496
0
      return false;
497
0
    }
498
0
  }
499
500
0
  ret = asn1_create_element (persist->asn1_defs, "BASIC.ObjectIdentifier", &asn);
501
0
  if (ret != ASN1_SUCCESS) {
502
0
    p11_debug_precond ("failed to create ObjectIdentifier element: %s\n",
503
0
                       asn1_strerror (ret));
504
0
    return false;
505
0
  }
506
507
0
  ret = asn1_der_decoding (&asn, attr->pValue, attr->ulValueLen, message);
508
0
  if (ret != ASN1_SUCCESS) {
509
0
    p11_message (_("invalid oid value: %s"), message);
510
0
    asn1_delete_structure (&asn);
511
0
    return false;
512
0
  }
513
514
0
  data = p11_asn1_read (asn, "", &len);
515
0
  asn1_delete_structure (&asn);
516
0
  return_val_if_fail (data != NULL, false);
517
518
0
  p11_buffer_add (buf, data, len - 1);
519
0
  free (data);
520
521
0
  return true;
522
0
}
523
524
static bool
525
parse_value (p11_persist *persist,
526
             p11_lexer *lexer,
527
             CK_ATTRIBUTE *attr)
528
11.3k
{
529
11.3k
  return parse_constant (persist, lexer, attr) ||
530
10.7k
         parse_string (lexer, attr) ||
531
9.04k
         parse_bool (lexer, attr) ||
532
7.85k
         parse_ulong (lexer, attr) ||
533
655
         parse_oid (persist, lexer, attr);
534
11.3k
}
535
536
static void
537
format_value (p11_persist *persist,
538
              CK_ATTRIBUTE *attr,
539
              p11_buffer *buf)
540
0
{
541
0
  assert (attr->ulValueLen != CK_UNAVAILABLE_INFORMATION);
542
543
0
  if (format_bool (attr, buf) ||
544
0
      format_constant (attr, buf) ||
545
0
      format_ulong (attr, buf) ||
546
0
      format_oid (persist, attr, buf))
547
0
    return;
548
549
  /* Everything else as string */
550
0
  format_string (attr, buf);
551
0
}
552
553
static bool
554
field_to_attribute (p11_persist *persist,
555
                    p11_lexer *lexer,
556
                    CK_ATTRIBUTE **attrs)
557
11.3k
{
558
11.3k
  CK_ATTRIBUTE attr = { 0, };
559
11.3k
  char *end;
560
561
11.3k
  end = NULL;
562
11.3k
  attr.type = strtoul (lexer->tok.field.name, &end, 10);
563
564
  /* Not a valid number value, probably a constant */
565
11.3k
  if (!end || *end != '\0') {
566
1.51k
    attr.type = p11_constant_resolve (persist->constants, lexer->tok.field.name);
567
1.51k
    if (attr.type == CKA_INVALID || !p11_constant_name (p11_constant_types, attr.type)) {
568
45
      p11_lexer_msg (lexer, "invalid or unsupported attribute");
569
45
      return false;
570
45
    }
571
  /* Reject numerical value that matches CKA_INVALID */
572
9.84k
  } else if (attr.type == CKA_INVALID) {
573
2
    p11_lexer_msg (lexer, "invalid attribute");
574
2
    return false;
575
2
  }
576
577
11.3k
  if (!parse_value (persist, lexer, &attr)) {
578
237
    p11_lexer_msg (lexer, "invalid value");
579
237
    return false;
580
237
  }
581
582
  /* Ignore recursive attributes */
583
11.0k
  if (IS_ATTRIBUTE_ARRAY (&attr)) {
584
632
    free (attr.pValue);
585
632
    return true;
586
632
  }
587
588
10.4k
  *attrs = p11_attrs_take (*attrs, attr.type,
589
10.4k
                           attr.pValue, attr.ulValueLen);
590
10.4k
  if (*attrs == NULL) {
591
0
    free (attr.pValue);
592
0
    return_val_if_reached (false);
593
0
  }
594
595
10.4k
  return true;
596
10.4k
}
597
598
static CK_ATTRIBUTE *
599
certificate_to_attributes (const unsigned char *der,
600
                           size_t length)
601
2.37k
{
602
2.37k
  CK_OBJECT_CLASS klassv = CKO_CERTIFICATE;
603
2.37k
  CK_CERTIFICATE_TYPE x509 = CKC_X_509;
604
605
2.37k
  CK_ATTRIBUTE klass = { CKA_CLASS, &klassv, sizeof (klassv) };
606
2.37k
  CK_ATTRIBUTE certificate_type = { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) };
607
2.37k
  CK_ATTRIBUTE value = { CKA_VALUE, (void *)der, length };
608
609
2.37k
  return p11_attrs_build (NULL, &klass, &certificate_type, &value, NULL);
610
2.37k
}
611
612
static CK_ATTRIBUTE *
613
public_key_to_attributes (const unsigned char *der,
614
                          size_t length)
615
289
{
616
  /* Eventually we might choose to contribute a class here ... */
617
289
  CK_ATTRIBUTE public_key = { CKA_PUBLIC_KEY_INFO, (void *)der, length };
618
289
  return p11_attrs_build (NULL, &public_key, NULL);
619
289
}
620
621
typedef struct {
622
  p11_lexer *lexer;
623
  CK_ATTRIBUTE *attrs;
624
  bool result;
625
} parse_block;
626
627
static void
628
on_pem_block (const char *type,
629
              const unsigned char *contents,
630
              size_t length,
631
              void *user_data)
632
72.0k
{
633
72.0k
  parse_block *pb = user_data;
634
72.0k
  CK_ATTRIBUTE *attrs;
635
636
72.0k
  if (strcmp (type, "CERTIFICATE") == 0) {
637
2.37k
    attrs = certificate_to_attributes (contents, length);
638
2.37k
    pb->attrs = p11_attrs_merge (pb->attrs, attrs, false);
639
2.37k
    pb->result = pb->attrs != NULL;
640
69.6k
  } else if (strcmp (type, "PUBLIC KEY") == 0) {
641
289
    attrs = public_key_to_attributes (contents, length);
642
289
    pb->attrs = p11_attrs_merge (pb->attrs, attrs, false);
643
289
    pb->result = pb->attrs != NULL;
644
69.4k
  } else {
645
69.4k
    p11_lexer_msg (pb->lexer, "unsupported pem block in store");
646
69.4k
    pb->result = false;
647
69.4k
  }
648
72.0k
}
649
650
static bool
651
pem_to_attributes (p11_lexer *lexer,
652
                   CK_ATTRIBUTE **attrs)
653
2.99k
{
654
2.99k
  parse_block pb = { lexer, *attrs, false };
655
2.99k
  unsigned int count;
656
657
2.99k
  count = p11_pem_parse (lexer->tok.pem.begin,
658
2.99k
                         lexer->tok.pem.length,
659
2.99k
                         on_pem_block, &pb);
660
661
2.99k
  *attrs = pb.attrs;
662
663
2.99k
  if (count == 0) {
664
174
    p11_lexer_msg (lexer, "invalid pem block");
665
174
    return false;
666
174
  }
667
668
  /* The lexer should have only matched one block */
669
2.82k
  return_val_if_fail (count == 1, false);
670
2.78k
  return pb.result;
671
2.82k
}
672
673
bool
674
p11_persist_read (p11_persist *persist,
675
                  const char *filename,
676
                  const unsigned char *data,
677
                  size_t length,
678
                  p11_array *objects)
679
2.24k
{
680
2.24k
  p11_lexer lexer;
681
2.24k
  CK_ATTRIBUTE *attrs;
682
2.24k
  bool failed;
683
2.24k
  bool skip;
684
685
2.24k
  return_val_if_fail (persist != NULL, false);
686
2.24k
  return_val_if_fail (objects != NULL, false);
687
688
2.24k
  skip = false;
689
2.24k
  attrs = NULL;
690
2.24k
  failed = false;
691
692
2.24k
  p11_lexer_init (&lexer, filename, (const char *)data, length);
693
190k
  while (p11_lexer_next (&lexer, &failed)) {
694
188k
    switch (lexer.tok_type) {
695
172k
    case TOK_SECTION:
696
172k
      if (attrs != NULL && !p11_array_push (objects, attrs)) {
697
0
        p11_attrs_free (attrs);
698
0
        p11_lexer_done (&lexer);
699
0
        return_val_if_reached (false);
700
0
      }
701
172k
      attrs = NULL;
702
172k
      if (strcmp (lexer.tok.section.name, PERSIST_HEADER) != 0) {
703
11.9k
        p11_lexer_msg (&lexer, "unrecognized or invalid section header");
704
11.9k
        skip = true;
705
160k
      } else {
706
160k
        attrs = p11_attrs_build (NULL, NULL);
707
160k
        if (attrs == NULL) {
708
0
          p11_lexer_done (&lexer);
709
0
          return_val_if_reached (false);
710
0
        }
711
160k
        skip = false;
712
160k
      }
713
172k
      failed = false;
714
172k
      break;
715
12.3k
    case TOK_FIELD:
716
12.3k
      if (skip) {
717
918
        failed = false;
718
11.3k
      } else if (attrs == NULL) {
719
20
        p11_lexer_msg (&lexer, "attribute before p11-kit section header");
720
20
        failed = true;
721
11.3k
      } else {
722
11.3k
        failed = !field_to_attribute (persist, &lexer, &attrs);
723
11.3k
      }
724
12.3k
      break;
725
3.27k
    case TOK_PEM:
726
3.27k
      if (skip) {
727
260
        failed = false;
728
3.01k
      } else if (attrs == NULL) {
729
17
        p11_lexer_msg (&lexer, "pem block before p11-kit section header");
730
17
        failed = true;
731
2.99k
      } else {
732
2.99k
        failed = !pem_to_attributes (&lexer, &attrs);
733
2.99k
      }
734
3.27k
      break;
735
0
    default:
736
0
      assert_not_reached ();
737
188k
    }
738
739
188k
    if (failed)
740
662
      break;
741
188k
  }
742
743
2.24k
  if (attrs != NULL) {
744
1.73k
    if (failed)
745
693
      p11_attrs_free (attrs);
746
1.04k
    else if (!p11_array_push (objects, attrs)) {
747
0
      p11_attrs_free (attrs);
748
0
      p11_lexer_done (&lexer);
749
0
      return_val_if_reached (false);
750
0
    }
751
1.73k
    attrs = NULL;
752
1.73k
  }
753
754
2.24k
  p11_lexer_done (&lexer);
755
2.24k
  return !failed;
756
2.24k
}
757
758
static CK_ATTRIBUTE *
759
find_certificate_value (CK_ATTRIBUTE *attrs)
760
0
{
761
0
  CK_OBJECT_CLASS klass;
762
0
  CK_CERTIFICATE_TYPE type;
763
764
0
  if (!p11_attrs_find_ulong (attrs, CKA_CLASS, &klass) ||
765
0
      klass != CKO_CERTIFICATE)
766
0
    return NULL;
767
0
  if (!p11_attrs_find_ulong (attrs, CKA_CERTIFICATE_TYPE, &type) ||
768
0
      type != CKC_X_509)
769
0
    return NULL;
770
0
  return p11_attrs_find_valid (attrs, CKA_VALUE);
771
0
}
772
773
bool
774
p11_persist_write (p11_persist *persist,
775
                   CK_ATTRIBUTE *attrs,
776
                   p11_buffer *buf)
777
0
{
778
0
  char string[sizeof (CK_ULONG) * 4];
779
0
  CK_ATTRIBUTE *cert_value;
780
0
  CK_ATTRIBUTE *spki_value;
781
0
  const char *nick;
782
0
  int i;
783
784
0
  cert_value = find_certificate_value (attrs);
785
0
  spki_value = p11_attrs_find_valid (attrs, CKA_PUBLIC_KEY_INFO);
786
787
0
  p11_buffer_add (buf, "[" PERSIST_HEADER "]\n", -1);
788
789
0
  for (i = 0; !p11_attrs_terminator (attrs + i); i++) {
790
791
    /* These are written later? */
792
0
    if (cert_value != NULL &&
793
0
        (attrs[i].type == CKA_CLASS ||
794
0
         attrs[i].type == CKA_CERTIFICATE_TYPE ||
795
0
         attrs[i].type == CKA_VALUE))
796
0
      continue;
797
798
    /* These are written later? */
799
0
    if (spki_value != NULL &&
800
0
        attrs[i].type == CKA_PUBLIC_KEY_INFO)
801
0
      continue;
802
803
    /* These are never written */
804
0
    if (attrs[i].type == CKA_TOKEN ||
805
0
        attrs[i].type == CKA_X_ORIGIN ||
806
0
        attrs[i].type == CKA_X_GENERATED)
807
0
      continue;
808
809
0
    if (attrs[i].ulValueLen == CK_UNAVAILABLE_INFORMATION)
810
0
      continue;
811
812
0
    nick = p11_constant_nick (p11_constant_types, attrs[i].type);
813
0
    if (nick == NULL) {
814
0
      snprintf (string, sizeof (string), "%lu", attrs[i].type);
815
0
      nick = string;
816
0
    }
817
818
0
    p11_buffer_add (buf, nick, -1);
819
0
    p11_buffer_add (buf, ": ", 2);
820
0
    format_value (persist, attrs + i, buf);
821
0
    p11_buffer_add (buf, "\n", 1);
822
0
  }
823
824
0
  if (cert_value != NULL) {
825
0
    if (!p11_pem_write (cert_value->pValue, cert_value->ulValueLen, "CERTIFICATE", buf))
826
0
      return_val_if_reached (false);
827
0
  } else if (spki_value != NULL) {
828
0
    if (!p11_pem_write (spki_value->pValue, spki_value->ulValueLen, "PUBLIC KEY", buf))
829
0
      return_val_if_reached (false);
830
0
  }
831
832
0
  p11_buffer_add (buf, "\n", 1);
833
0
  return p11_buffer_ok (buf);
834
0
}
835
836
bool
837
p11_persist_check (p11_persist *persist,
838
       const char *filename,
839
       const unsigned char *data,
840
       size_t length)
841
0
{
842
0
  p11_lexer lexer;
843
0
  CK_ATTRIBUTE *attrs;
844
0
  bool failed;
845
0
  bool skip;
846
847
0
  return_val_if_fail (persist != NULL, false);
848
849
0
  skip = false;
850
0
  attrs = NULL;
851
0
  failed = false;
852
853
0
  p11_lexer_init (&lexer, filename, (const char *)data, length);
854
0
  while (p11_lexer_next (&lexer, NULL)) {
855
0
    switch (lexer.tok_type) {
856
0
    case TOK_SECTION:
857
0
      if (attrs)
858
0
        p11_attrs_free (attrs);
859
0
      attrs = NULL;
860
0
      if (strcmp (lexer.tok.section.name, PERSIST_HEADER) != 0) {
861
0
        p11_lexer_msg (&lexer, "unrecognized or invalid section header");
862
0
        skip = true;
863
0
      } else {
864
0
        attrs = p11_attrs_build (NULL, NULL);
865
0
        if (attrs == NULL) {
866
0
          p11_lexer_done (&lexer);
867
0
          return_val_if_reached (false);
868
0
        }
869
0
        skip = false;
870
0
      }
871
0
      break;
872
0
    case TOK_FIELD:
873
0
      if (!skip && !attrs) {
874
0
        p11_lexer_msg (&lexer, "attribute before p11-kit section header");
875
0
        failed = true;
876
0
      } else if (!field_to_attribute (persist, &lexer, &attrs)) {
877
0
        failed = true;
878
0
      }
879
0
      break;
880
0
    case TOK_PEM:
881
0
      if (!skip && !attrs) {
882
0
        p11_lexer_msg (&lexer, "pem block before p11-kit section header");
883
0
        failed = true;
884
0
      } else if (!pem_to_attributes (&lexer, &attrs)) {
885
0
        failed = true;
886
0
      }
887
0
      break;
888
0
    default:
889
0
      assert_not_reached ();
890
0
    }
891
0
  }
892
893
0
  p11_attrs_free (attrs);
894
0
  p11_lexer_done (&lexer);
895
0
  return !failed;
896
0
}