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