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