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