xref: /illumos-gate/usr/src/lib/libcryptoutil/common/config_parsing.c (revision 5bbb4db2c3f208d12bf0fd11769728f9e5ba66a2)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 #include <stdio.h>
28 #include <errno.h>
29 #include <strings.h>
30 #include <locale.h>
31 #include <stdlib.h>
32 #include "cryptoutil.h"
33 
34 static int uef_interpret(char *, uentry_t **);
35 static int parse_policylist(char *, uentry_t *);
36 
37 /*
38  * Retrieve the user-level provider info from the pkcs11.conf file.
39  * If successful, the result is returned from the ppliblist argument.
40  * This function returns SUCCESS if successfully done; otherwise it returns
41  * FAILURE.
42  */
43 int
44 get_pkcs11conf_info(uentrylist_t **ppliblist)
45 {
46 	FILE *pfile;
47 	char buffer[BUFSIZ];
48 	size_t len;
49 	uentry_t *pent;
50 	uentrylist_t *pentlist;
51 	uentrylist_t *pcur;
52 	int rc = SUCCESS;
53 
54 	*ppliblist = NULL;
55 	if ((pfile = fopen(_PATH_PKCS11_CONF, "rF")) == NULL) {
56 		cryptoerror(LOG_ERR, "failed to open %s.\n", _PATH_PKCS11_CONF);
57 		return (FAILURE);
58 	}
59 
60 	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
61 		if (buffer[0] == '#' || buffer[0] == ' ' ||
62 		    buffer[0] == '\n'|| buffer[0] == '\t') {
63 			continue;   /* ignore comment lines */
64 		}
65 
66 		len = strlen(buffer);
67 		if (buffer[len-1] == '\n') { /* get rid of trailing '\n' */
68 			len--;
69 		}
70 		buffer[len] = '\0';
71 
72 		if ((rc = uef_interpret(buffer,  &pent)) != SUCCESS) {
73 			break;
74 		}
75 
76 		/* append pent into ppliblist */
77 		pentlist = malloc(sizeof (uentrylist_t));
78 		if (pentlist == NULL) {
79 			cryptoerror(LOG_ERR, "parsing %s, out of memory.\n",
80 			    _PATH_PKCS11_CONF);
81 			free_uentry(pent);
82 			rc = FAILURE;
83 			break;
84 		}
85 		pentlist->puent = pent;
86 		pentlist->next = NULL;
87 
88 		if (*ppliblist == NULL) {
89 			*ppliblist = pcur = pentlist;
90 		} else {
91 			pcur->next = pentlist;
92 			pcur = pcur->next;
93 		}
94 	}
95 
96 	(void) fclose(pfile);
97 
98 	if (rc != SUCCESS) {
99 		free_uentrylist(*ppliblist);
100 		*ppliblist = NULL;
101 	}
102 
103 	return (rc);
104 }
105 
106 
107 /*
108  * This routine converts a char string into a uentry_t structure
109  * The input string "buf" should be one of the following:
110  *	library_name
111  *	library_name:NO_RANDOM
112  *	library_name:disabledlist=m1,m2,...,mk
113  *	library_name:disabledlist=m1,m2,...,mk;NO_RANDOM
114  *	library_name:enabledlist=
115  *	library_name:enabledlist=;NO_RANDOM
116  *	library_name:enabledlist=m1,m2,...,mk
117  *	library_name:enabledlist=m1,m2,...,mk;NO_RANDOM
118  *	metaslot:status=enabled;enabledlist=m1,m2,....;slot=<slot-description>;\
119  *	token=<token-label>
120  *
121  * Note:
122  *	The mechanisms m1,..mk are in hex form. For example, "0x00000210"
123  *	for CKM_MD5.
124  *
125  *	For the metaslot entry, "enabledlist", "slot", "auto_key_migrate"
126  * 	or "token" is optional
127  */
128 static int
129 uef_interpret(char *buf, uentry_t **ppent)
130 {
131 	uentry_t *pent;
132 	char	*token1;
133 	char	*token2;
134 	char	*lasts;
135 	int	rc;
136 
137 	*ppent = NULL;
138 	if ((token1 = strtok_r(buf, SEP_COLON, &lasts)) == NULL) {
139 		/* buf is NULL */
140 		return (FAILURE);
141 	};
142 
143 	pent = calloc(sizeof (uentry_t), 1);
144 	if (pent == NULL) {
145 		cryptoerror(LOG_ERR, "parsing %s, out of memory.\n",
146 		    _PATH_PKCS11_CONF);
147 		return (FAILURE);
148 	}
149 	(void) strlcpy(pent->name, token1, sizeof (pent->name));
150 	/*
151 	 * in case metaslot_auto_key_migrate is not specified, it should
152 	 * be default to true
153 	 */
154 	pent->flag_metaslot_auto_key_migrate = B_TRUE;
155 
156 	while ((token2 = strtok_r(NULL, SEP_SEMICOLON, &lasts)) != NULL) {
157 		if ((rc = parse_policylist(token2, pent)) != SUCCESS) {
158 			free_uentry(pent);
159 			return (rc);
160 		}
161 	}
162 
163 	*ppent = pent;
164 	return (SUCCESS);
165 }
166 
167 
168 /*
169  * This routine parses the policy list and stored the result in the argument
170  * pent.
171  *
172  * 	Arg buf: input only, its format should be one of the following:
173  *     		enabledlist=
174  *		enabledlist=m1,m2,...,mk
175  *		disabledlist=m1,m2,...,mk
176  *		NO_RANDOM
177  *		metaslot_status=enabled|disabled
178  *		metaslot_token=<token-label>
179  *		metaslot_slot=<slot-description.
180  *
181  *	Arg pent: input/output
182  *
183  *      return: SUCCESS or FAILURE
184  */
185 static int
186 parse_policylist(char *buf, uentry_t *pent)
187 {
188 	umechlist_t *phead = NULL;
189 	umechlist_t *pcur = NULL;
190 	umechlist_t *pmech;
191 	char *next_token;
192 	char *value;
193 	char *lasts;
194 	int count = 0;
195 	int rc = SUCCESS;
196 
197 	if (pent == NULL) {
198 		return (FAILURE);
199 	}
200 
201 	if (strncmp(buf, EF_DISABLED, sizeof (EF_DISABLED) - 1) == 0) {
202 		pent->flag_enabledlist = B_FALSE;
203 	} else if (strncmp(buf, EF_ENABLED, sizeof (EF_ENABLED) - 1) == 0) {
204 		pent->flag_enabledlist = B_TRUE;
205 	} else if (strncmp(buf, EF_NORANDOM, sizeof (EF_NORANDOM) - 1) == 0) {
206 		pent->flag_norandom = B_TRUE;
207 		return (rc);
208 	} else if (strncmp(buf, METASLOT_TOKEN,
209 	    sizeof (METASLOT_TOKEN) - 1) == 0) {
210 		if (value = strpbrk(buf, SEP_EQUAL)) {
211 			value++; /* get rid of = */
212 			(void) strlcpy((char *)pent->metaslot_ks_token, value,
213 			    sizeof (pent->metaslot_ks_token));
214 			return (SUCCESS);
215 		} else {
216 			cryptoerror(LOG_ERR, "failed to parse %s.\n",
217 			    _PATH_PKCS11_CONF);
218 			return (FAILURE);
219 		}
220 	} else if (strncmp(buf, METASLOT_SLOT,
221 	    sizeof (METASLOT_SLOT) - 1) == 0) {
222 		if (value = strpbrk(buf, SEP_EQUAL)) {
223 			value++; /* get rid of = */
224 			(void) strlcpy((char *)pent->metaslot_ks_slot, value,
225 			    sizeof (pent->metaslot_ks_slot));
226 			return (SUCCESS);
227 		} else {
228 			cryptoerror(LOG_ERR, "failed to parse %s.\n",
229 			    _PATH_PKCS11_CONF);
230 			return (FAILURE);
231 		}
232 	} else if (strncmp(buf, METASLOT_STATUS,
233 	    sizeof (METASLOT_STATUS) - 1) == 0) {
234 		if (value = strpbrk(buf, SEP_EQUAL)) {
235 			value++; /* get rid of = */
236 			if (strcmp(value, DISABLED_KEYWORD) == 0) {
237 				pent->flag_metaslot_enabled = B_FALSE;
238 			} else if (strcmp(value, ENABLED_KEYWORD) == 0) {
239 				pent->flag_metaslot_enabled = B_TRUE;
240 			} else {
241 				cryptoerror(LOG_ERR, "failed to parse %s.\n",
242 				    _PATH_PKCS11_CONF);
243 				return (FAILURE);
244 			}
245 			return (SUCCESS);
246 		} else {
247 			cryptoerror(LOG_ERR, "failed to parse %s.\n",
248 			    _PATH_PKCS11_CONF);
249 			return (FAILURE);
250 		}
251 	} else if (strncmp(buf, METASLOT_AUTO_KEY_MIGRATE,
252 	    sizeof (METASLOT_AUTO_KEY_MIGRATE) - 1) == 0) {
253 		if (value = strpbrk(buf, SEP_EQUAL)) {
254 			value++; /* get rid of = */
255 			if (strcmp(value, DISABLED_KEYWORD) == 0) {
256 				pent->flag_metaslot_auto_key_migrate = B_FALSE;
257 			} else if (strcmp(value, ENABLED_KEYWORD) == 0) {
258 				pent->flag_metaslot_auto_key_migrate = B_TRUE;
259 			} else {
260 				cryptoerror(LOG_ERR, "failed to parse %s.\n",
261 				    _PATH_PKCS11_CONF);
262 				return (FAILURE);
263 			}
264 			return (SUCCESS);
265 		} else {
266 			cryptoerror(LOG_ERR, "failed to parse %s.\n",
267 			    _PATH_PKCS11_CONF);
268 			return (FAILURE);
269 		}
270 	} else {
271 		cryptoerror(LOG_ERR, "failed to parse %s.\n",
272 		    _PATH_PKCS11_CONF);
273 		return (FAILURE);
274 	}
275 
276 	if (value = strpbrk(buf, SEP_EQUAL)) {
277 		value++; /* get rid of = */
278 	}
279 
280 	if ((next_token = strtok_r(value, SEP_COMMA, &lasts)) == NULL) {
281 		if (pent->flag_enabledlist) {
282 			return (SUCCESS);
283 		} else {
284 			cryptoerror(LOG_ERR, "failed to parse %s.\n",
285 			    _PATH_PKCS11_CONF);
286 			return (FAILURE);
287 		}
288 	}
289 
290 	while (next_token) {
291 		if ((pmech = create_umech(next_token)) == NULL) {
292 			cryptoerror(LOG_ERR, "parsing %s, out of memory.\n",
293 			    _PATH_PKCS11_CONF);
294 			rc = FAILURE;
295 			break;
296 		}
297 
298 		if (phead == NULL) {
299 			phead = pcur = pmech;
300 		} else {
301 			pcur->next = pmech;
302 			pcur = pcur->next;
303 		}
304 		count++;
305 		next_token = strtok_r(NULL, SEP_COMMA, &lasts);
306 	}
307 
308 	if (rc == SUCCESS) {
309 		pent->policylist = phead;
310 		pent->count = count;
311 	} else {
312 		free_umechlist(phead);
313 	}
314 
315 	return (rc);
316 }
317 
318 
319 /*
320  * Create one item of type umechlist_t with the mechanism name.  A NULL is
321  * returned when the input name is NULL or the heap memory is insufficient.
322  */
323 umechlist_t *
324 create_umech(char *name)
325 {
326 	umechlist_t *pmech = NULL;
327 
328 	if (name == NULL) {
329 		return (NULL);
330 	}
331 
332 	if ((pmech = malloc(sizeof (umechlist_t))) != NULL) {
333 		(void) strlcpy(pmech->name, name, sizeof (pmech->name));
334 		pmech->next = NULL;
335 	}
336 
337 	return (pmech);
338 }
339 
340 
341 void
342 free_umechlist(umechlist_t *plist)
343 {
344 	umechlist_t *pnext;
345 
346 	while (plist != NULL) {
347 		pnext = plist->next;
348 		free(plist);
349 		plist = pnext;
350 	}
351 }
352 
353 
354 void
355 free_uentry(uentry_t  *pent)
356 {
357 	if (pent == NULL) {
358 		return;
359 	} else {
360 		free_umechlist(pent->policylist);
361 		free(pent);
362 	}
363 }
364 
365 
366 void
367 free_uentrylist(uentrylist_t *entrylist)
368 {
369 	uentrylist_t *pnext;
370 
371 	while (entrylist != NULL) {
372 		pnext = entrylist->next;
373 		free_uentry(entrylist->puent);
374 		free(entrylist);
375 		entrylist = pnext;
376 	}
377 }
378 
379 
380 
381 /*
382  * Duplicate an UEF mechanism list.  A NULL pointer is returned if out of
383  * memory or the input argument is NULL.
384  */
385 static umechlist_t *
386 dup_umechlist(umechlist_t *plist)
387 {
388 	umechlist_t *pres = NULL;
389 	umechlist_t *pcur;
390 	umechlist_t *ptmp;
391 	int rc = SUCCESS;
392 
393 	while (plist != NULL) {
394 		if (!(ptmp = create_umech(plist->name))) {
395 			rc = FAILURE;
396 			break;
397 		}
398 
399 		if (pres == NULL) {
400 			pres = pcur = ptmp;
401 		} else {
402 			pcur->next = ptmp;
403 			pcur = pcur->next;
404 		}
405 		plist = plist->next;
406 	}
407 
408 	if (rc != SUCCESS) {
409 		free_umechlist(pres);
410 		return (NULL);
411 	}
412 
413 	return (pres);
414 }
415 
416 
417 /*
418  * Duplicate an uentry.  A NULL pointer is returned if out of memory
419  * or the input argument is NULL.
420  */
421 static uentry_t *
422 dup_uentry(uentry_t *puent1)
423 {
424 	uentry_t *puent2 = NULL;
425 
426 	if (puent1 == NULL) {
427 		return (NULL);
428 	}
429 
430 	if ((puent2 = malloc(sizeof (uentry_t))) == NULL) {
431 		cryptoerror(LOG_STDERR, gettext("out of memory."));
432 		return (NULL);
433 	} else {
434 		(void) strlcpy(puent2->name, puent1->name,
435 		    sizeof (puent2->name));
436 		puent2->flag_norandom = puent1->flag_norandom;
437 		puent2->flag_enabledlist = puent1->flag_enabledlist;
438 		puent2->policylist = dup_umechlist(puent1->policylist);
439 		puent2->flag_metaslot_enabled = puent1->flag_metaslot_enabled;
440 		puent2->flag_metaslot_auto_key_migrate
441 		    = puent1->flag_metaslot_auto_key_migrate;
442 		(void) memcpy(puent2->metaslot_ks_slot,
443 		    puent1->metaslot_ks_slot, SLOT_DESCRIPTION_SIZE);
444 		(void) memcpy(puent2->metaslot_ks_token,
445 		    puent1->metaslot_ks_token, TOKEN_LABEL_SIZE);
446 		puent2->count = puent1->count;
447 		return (puent2);
448 	}
449 }
450 
451 /*
452  * Find the entry in the "pkcs11.conf" file with "libname" as the provider
453  * name. Return the entry if found, otherwise return NULL.
454  */
455 uentry_t *
456 getent_uef(char *libname)
457 {
458 	uentrylist_t	*pliblist = NULL;
459 	uentrylist_t	*plib = NULL;
460 	uentry_t	*puent = NULL;
461 	boolean_t	found = B_FALSE;
462 
463 	if (libname == NULL) {
464 		return (NULL);
465 	}
466 
467 	if ((get_pkcs11conf_info(&pliblist)) == FAILURE) {
468 		return (NULL);
469 	}
470 
471 	plib = pliblist;
472 	while (plib) {
473 		if (strcmp(plib->puent->name, libname) == 0) {
474 			found = B_TRUE;
475 			break;
476 		} else {
477 			plib = plib->next;
478 		}
479 	}
480 
481 	if (found) {
482 		puent = dup_uentry(plib->puent);
483 	}
484 
485 	free_uentrylist(pliblist);
486 	return (puent);
487 }
488 
489 
490 
491 /*
492  * Retrieve the metaslot information from the pkcs11.conf file.
493  * This function returns SUCCESS if successfully done; otherwise it returns
494  * FAILURE.   If successful, the caller is responsible to free the space
495  * allocated for objectstore_slot_info and objectstore_token_info.
496  */
497 int
498 get_metaslot_info(boolean_t  *status_enabled, boolean_t *migrate_enabled,
499     char **objectstore_slot_info, char **objectstore_token_info)
500 {
501 
502 	int rc = SUCCESS;
503 	uentry_t *puent;
504 	char *buf1 = NULL;
505 	char *buf2 = NULL;
506 
507 	if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) {
508 		/* metaslot entry doesn't exist */
509 		return (FAILURE);
510 	}
511 
512 	*status_enabled = puent->flag_metaslot_enabled;
513 	*migrate_enabled = puent->flag_metaslot_auto_key_migrate;
514 
515 	buf1 = malloc(SLOT_DESCRIPTION_SIZE);
516 	if (buf1 == NULL) {
517 		cryptoerror(LOG_ERR, "get_metaslot_info() - out of memory.\n");
518 		rc = FAILURE;
519 		goto out;
520 	}
521 	(void) strcpy(buf1, (const char *) puent->metaslot_ks_slot);
522 	*objectstore_slot_info = buf1;
523 
524 	buf2 = malloc(TOKEN_LABEL_SIZE);
525 	if (objectstore_slot_info == NULL) {
526 		cryptoerror(LOG_ERR, "get_metaslot_info() - out of memory.\n");
527 		rc = FAILURE;
528 		goto out;
529 	}
530 	(void) strcpy(buf2, (const char *) puent->metaslot_ks_token);
531 	*objectstore_token_info = buf2;
532 
533 out:
534 	if (puent != NULL) {
535 		free_uentry(puent);
536 	}
537 
538 	if (rc == FAILURE) {
539 		if (buf1 != NULL) {
540 			free(buf1);
541 		}
542 		if (buf2 != NULL) {
543 			free(buf2);
544 		}
545 	}
546 
547 	return (rc);
548 }
549 
550 static CK_RV
551 parse_fips_mode(char *buf, int *mode)
552 {
553 
554 	char *value;
555 
556 	if (strncmp(buf, EF_FIPS_STATUS, sizeof (EF_FIPS_STATUS) - 1) == 0) {
557 		if (value = strpbrk(buf, SEP_EQUAL)) {
558 			value++; /* get rid of = */
559 			if (strcmp(value, DISABLED_KEYWORD) == 0) {
560 				*mode = CRYPTO_FIPS_MODE_DISABLED;
561 			} else if (strcmp(value, ENABLED_KEYWORD) == 0) {
562 				*mode = CRYPTO_FIPS_MODE_ENABLED;
563 			} else {
564 				cryptoerror(LOG_ERR,
565 				    "failed to parse kcf.conf file.\n");
566 				return (CKR_FUNCTION_FAILED);
567 			}
568 			return (CKR_OK);
569 		} else {
570 			return (CKR_FUNCTION_FAILED);
571 		}
572 	} else {
573 		/* should not come here */
574 		return (CKR_FUNCTION_FAILED);
575 	}
576 
577 }
578 
579 static boolean_t
580 is_fips(char *name)
581 {
582 	if (strcmp(name, FIPS_KEYWORD) == 0) {
583 		return (B_TRUE);
584 	} else {
585 		return (B_FALSE);
586 	}
587 }
588 
589 CK_RV
590 get_fips_mode(int *mode)
591 {
592 	FILE	*pfile = NULL;
593 	char	buffer[BUFSIZ];
594 	int	len;
595 	CK_RV	rc = CKR_OK;
596 	int found = 0;
597 	char *token1;
598 
599 	if ((pfile = fopen(_PATH_KCF_CONF, "r")) == NULL) {
600 		cryptoerror(LOG_DEBUG,
601 		    "failed to open the kcf.conf file for read only.");
602 		*mode = CRYPTO_FIPS_MODE_DISABLED;
603 		return (CKR_OK);
604 	}
605 
606 	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
607 		if (buffer[0] == '#' || buffer[0] == ' ' ||
608 		    buffer[0] == '\n'|| buffer[0] == '\t') {
609 			continue;   /* ignore comment lines */
610 		}
611 
612 		len = strlen(buffer);
613 		if (buffer[len - 1] == '\n') { /* get rid of trailing '\n' */
614 			len--;
615 		}
616 		buffer[len] = '\0';
617 
618 		/* Get provider name */
619 		if ((token1 = strtok(buffer, SEP_COLON)) ==
620 		    NULL) { /* buf is NULL */
621 			return (CKR_FUNCTION_FAILED);
622 		};
623 
624 		if (is_fips(token1)) {
625 			if ((rc = parse_fips_mode(buffer + strlen(token1) + 1,
626 			    mode)) != CKR_OK) {
627 				goto out;
628 			} else {
629 				found++;
630 				break;
631 			}
632 		} else {
633 			continue;
634 		}
635 	}
636 
637 	if (!found) {
638 		*mode = CRYPTO_FIPS_MODE_DISABLED;
639 	}
640 
641 out:
642 	(void) fclose(pfile);
643 	return (rc);
644 }
645