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