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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <errno.h> 30 #include <strings.h> 31 #include <locale.h> 32 #include <stdlib.h> 33 #include "cryptoutil.h" 34 35 static int uef_interpret(char *, uentry_t **); 36 static int parse_policylist(char *, uentry_t *); 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 108 /* 109 * This routine converts a char string into a uentry_t structure 110 * The input string "buf" should be one of the following: 111 * library_name 112 * library_name:NO_RANDOM 113 * library_name:disabledlist=m1,m2,...,mk 114 * library_name:disabledlist=m1,m2,...,mk;NO_RANDOM 115 * library_name:enabledlist= 116 * library_name:enabledlist=;NO_RANDOM 117 * library_name:enabledlist=m1,m2,...,mk 118 * library_name:enabledlist=m1,m2,...,mk;NO_RANDOM 119 * metaslot:status=enabled;enabledlist=m1,m2,....;slot=<slot-description>;\ 120 * token=<token-label> 121 * 122 * Note: 123 * The mechanisms m1,..mk are in hex form. For example, "0x00000210" 124 * for CKM_MD5. 125 * 126 * For the metaslot entry, "enabledlist", "slot", "auto_key_migrate" 127 * or "token" is optional 128 */ 129 static int 130 uef_interpret(char *buf, uentry_t **ppent) 131 { 132 uentry_t *pent; 133 char *token1; 134 char *token2; 135 char *lasts; 136 int rc; 137 138 *ppent = NULL; 139 if ((token1 = strtok_r(buf, SEP_COLON, &lasts)) == NULL) { 140 /* buf is NULL */ 141 return (FAILURE); 142 }; 143 144 pent = calloc(sizeof (uentry_t), 1); 145 if (pent == NULL) { 146 cryptoerror(LOG_ERR, "parsing %s, out of memory.\n", 147 _PATH_PKCS11_CONF); 148 return (FAILURE); 149 } 150 (void) strlcpy(pent->name, token1, sizeof (pent->name)); 151 /* 152 * in case metaslot_auto_key_migrate is not specified, it should 153 * be default to true 154 */ 155 pent->flag_metaslot_auto_key_migrate = B_TRUE; 156 157 while ((token2 = strtok_r(NULL, SEP_SEMICOLON, &lasts)) != NULL) { 158 if ((rc = parse_policylist(token2, pent)) != SUCCESS) { 159 free_uentry(pent); 160 return (rc); 161 } 162 } 163 164 *ppent = pent; 165 return (SUCCESS); 166 } 167 168 169 /* 170 * This routine parses the policy list and stored the result in the argument 171 * pent. 172 * 173 * Arg buf: input only, its format should be one of the following: 174 * enabledlist= 175 * enabledlist=m1,m2,...,mk 176 * disabledlist=m1,m2,...,mk 177 * NO_RANDOM 178 * metaslot_status=enabled|disabled 179 * metaslot_token=<token-label> 180 * metaslot_slot=<slot-description. 181 * 182 * Arg pent: input/output 183 * 184 * return: SUCCESS or FAILURE 185 */ 186 static int 187 parse_policylist(char *buf, uentry_t *pent) 188 { 189 umechlist_t *phead = NULL; 190 umechlist_t *pcur = NULL; 191 umechlist_t *pmech; 192 char *next_token; 193 char *value; 194 char *lasts; 195 int count = 0; 196 int rc = SUCCESS; 197 198 if (pent == NULL) { 199 return (FAILURE); 200 } 201 202 if (strncmp(buf, EF_DISABLED, sizeof (EF_DISABLED) - 1) == 0) { 203 pent->flag_enabledlist = B_FALSE; 204 } else if (strncmp(buf, EF_ENABLED, sizeof (EF_ENABLED) - 1) == 0) { 205 pent->flag_enabledlist = B_TRUE; 206 } else if (strncmp(buf, EF_NORANDOM, sizeof (EF_NORANDOM) - 1) == 0) { 207 pent->flag_norandom = B_TRUE; 208 return (rc); 209 } else if (strncmp(buf, METASLOT_TOKEN, 210 sizeof (METASLOT_TOKEN) - 1) == 0) { 211 if (value = strpbrk(buf, SEP_EQUAL)) { 212 value++; /* get rid of = */ 213 (void) strlcpy((char *)pent->metaslot_ks_token, value, 214 sizeof (pent->metaslot_ks_token)); 215 return (SUCCESS); 216 } else { 217 cryptoerror(LOG_ERR, "failed to parse %s.\n", 218 _PATH_PKCS11_CONF); 219 return (FAILURE); 220 } 221 } else if (strncmp(buf, METASLOT_SLOT, 222 sizeof (METASLOT_SLOT) - 1) == 0) { 223 if (value = strpbrk(buf, SEP_EQUAL)) { 224 value++; /* get rid of = */ 225 (void) strlcpy((char *)pent->metaslot_ks_slot, value, 226 sizeof (pent->metaslot_ks_slot)); 227 return (SUCCESS); 228 } else { 229 cryptoerror(LOG_ERR, "failed to parse %s.\n", 230 _PATH_PKCS11_CONF); 231 return (FAILURE); 232 } 233 } else if (strncmp(buf, METASLOT_STATUS, 234 sizeof (METASLOT_STATUS) - 1) == 0) { 235 if (value = strpbrk(buf, SEP_EQUAL)) { 236 value++; /* get rid of = */ 237 if (strcmp(value, METASLOT_DISABLED) == 0) { 238 pent->flag_metaslot_enabled = B_FALSE; 239 } else if (strcmp(value, METASLOT_ENABLED) == 0) { 240 pent->flag_metaslot_enabled = B_TRUE; 241 } else { 242 cryptoerror(LOG_ERR, "failed to parse %s.\n", 243 _PATH_PKCS11_CONF); 244 return (FAILURE); 245 } 246 return (SUCCESS); 247 } else { 248 cryptoerror(LOG_ERR, "failed to parse %s.\n", 249 _PATH_PKCS11_CONF); 250 return (FAILURE); 251 } 252 } else if (strncmp(buf, METASLOT_AUTO_KEY_MIGRATE, 253 sizeof (METASLOT_AUTO_KEY_MIGRATE) - 1) == 0) { 254 if (value = strpbrk(buf, SEP_EQUAL)) { 255 value++; /* get rid of = */ 256 if (strcmp(value, METASLOT_DISABLED) == 0) { 257 pent->flag_metaslot_auto_key_migrate = B_FALSE; 258 } else if (strcmp(value, METASLOT_ENABLED) == 0) { 259 pent->flag_metaslot_auto_key_migrate = B_TRUE; 260 } else { 261 cryptoerror(LOG_ERR, "failed to parse %s.\n", 262 _PATH_PKCS11_CONF); 263 return (FAILURE); 264 } 265 return (SUCCESS); 266 } else { 267 cryptoerror(LOG_ERR, "failed to parse %s.\n", 268 _PATH_PKCS11_CONF); 269 return (FAILURE); 270 } 271 } else { 272 cryptoerror(LOG_ERR, "failed to parse %s.\n", 273 _PATH_PKCS11_CONF); 274 return (FAILURE); 275 } 276 277 if (value = strpbrk(buf, SEP_EQUAL)) { 278 value++; /* get rid of = */ 279 } 280 281 if ((next_token = strtok_r(value, SEP_COMMA, &lasts)) == NULL) { 282 if (pent->flag_enabledlist) { 283 return (SUCCESS); 284 } else { 285 cryptoerror(LOG_ERR, "failed to parse %s.\n", 286 _PATH_PKCS11_CONF); 287 return (FAILURE); 288 } 289 } 290 291 while (next_token) { 292 if ((pmech = create_umech(next_token)) == NULL) { 293 cryptoerror(LOG_ERR, "parsing %s, out of memory.\n", 294 _PATH_PKCS11_CONF); 295 rc = FAILURE; 296 break; 297 } 298 299 if (phead == NULL) { 300 phead = pcur = pmech; 301 } else { 302 pcur->next = pmech; 303 pcur = pcur->next; 304 } 305 count++; 306 next_token = strtok_r(NULL, SEP_COMMA, &lasts); 307 } 308 309 if (rc == SUCCESS) { 310 pent->policylist = phead; 311 pent->count = count; 312 } else { 313 free_umechlist(phead); 314 } 315 316 return (rc); 317 } 318 319 320 /* 321 * Create one item of type umechlist_t with the mechanism name. A NULL is 322 * returned when the input name is NULL or the heap memory is insufficient. 323 */ 324 umechlist_t * 325 create_umech(char *name) 326 { 327 umechlist_t *pmech = NULL; 328 329 if (name == NULL) { 330 return (NULL); 331 } 332 333 if ((pmech = malloc(sizeof (umechlist_t))) != NULL) { 334 (void) strlcpy(pmech->name, name, sizeof (pmech->name)); 335 pmech->next = NULL; 336 } 337 338 return (pmech); 339 } 340 341 342 void 343 free_umechlist(umechlist_t *plist) 344 { 345 umechlist_t *pnext; 346 347 while (plist != NULL) { 348 pnext = plist->next; 349 free(plist); 350 plist = pnext; 351 } 352 } 353 354 355 void 356 free_uentry(uentry_t *pent) 357 { 358 if (pent == NULL) { 359 return; 360 } else { 361 free_umechlist(pent->policylist); 362 free(pent); 363 } 364 } 365 366 367 void 368 free_uentrylist(uentrylist_t *entrylist) 369 { 370 uentrylist_t *pnext; 371 372 while (entrylist != NULL) { 373 pnext = entrylist->next; 374 free_uentry(entrylist->puent); 375 free(entrylist); 376 entrylist = pnext; 377 } 378 } 379 380 381 382 /* 383 * Duplicate an UEF mechanism list. A NULL pointer is returned if out of 384 * memory or the input argument is NULL. 385 */ 386 static umechlist_t * 387 dup_umechlist(umechlist_t *plist) 388 { 389 umechlist_t *pres = NULL; 390 umechlist_t *pcur; 391 umechlist_t *ptmp; 392 int rc = SUCCESS; 393 394 while (plist != NULL) { 395 if (!(ptmp = create_umech(plist->name))) { 396 rc = FAILURE; 397 break; 398 } 399 400 if (pres == NULL) { 401 pres = pcur = ptmp; 402 } else { 403 pcur->next = ptmp; 404 pcur = pcur->next; 405 } 406 plist = plist->next; 407 } 408 409 if (rc != SUCCESS) { 410 free_umechlist(pres); 411 return (NULL); 412 } 413 414 return (pres); 415 } 416 417 418 /* 419 * Duplicate an uentry. A NULL pointer is returned if out of memory 420 * or the input argument is NULL. 421 */ 422 static uentry_t * 423 dup_uentry(uentry_t *puent1) 424 { 425 uentry_t *puent2 = NULL; 426 427 if (puent1 == NULL) { 428 return (NULL); 429 } 430 431 if ((puent2 = malloc(sizeof (uentry_t))) == NULL) { 432 cryptoerror(LOG_STDERR, gettext("out of memory.")); 433 return (NULL); 434 } else { 435 (void) strlcpy(puent2->name, puent1->name, 436 sizeof (puent2->name)); 437 puent2->flag_norandom = puent1->flag_norandom; 438 puent2->flag_enabledlist = puent1->flag_enabledlist; 439 puent2->policylist = dup_umechlist(puent1->policylist); 440 puent2->flag_metaslot_enabled = puent1->flag_metaslot_enabled; 441 puent2->flag_metaslot_auto_key_migrate 442 = puent1->flag_metaslot_auto_key_migrate; 443 (void) memcpy(puent2->metaslot_ks_slot, 444 puent1->metaslot_ks_slot, SLOT_DESCRIPTION_SIZE); 445 (void) memcpy(puent2->metaslot_ks_token, 446 puent1->metaslot_ks_token, TOKEN_LABEL_SIZE); 447 puent2->count = puent1->count; 448 return (puent2); 449 } 450 } 451 452 /* 453 * Find the entry in the "pkcs11.conf" file with "libname" as the provider 454 * name. Return the entry if found, otherwise return NULL. 455 */ 456 uentry_t * 457 getent_uef(char *libname) 458 { 459 uentrylist_t *pliblist = NULL; 460 uentrylist_t *plib = NULL; 461 uentry_t *puent = NULL; 462 boolean_t found = B_FALSE; 463 464 if (libname == NULL) { 465 return (NULL); 466 } 467 468 if ((get_pkcs11conf_info(&pliblist)) == FAILURE) { 469 return (NULL); 470 } 471 472 plib = pliblist; 473 while (plib) { 474 if (strcmp(plib->puent->name, libname) == 0) { 475 found = B_TRUE; 476 break; 477 } else { 478 plib = plib->next; 479 } 480 } 481 482 if (found) { 483 puent = dup_uentry(plib->puent); 484 } 485 486 free_uentrylist(pliblist); 487 return (puent); 488 } 489 490 491 492 /* 493 * Retrieve the metaslot information from the pkcs11.conf file. 494 * This function returns SUCCESS if successfully done; otherwise it returns 495 * FAILURE. If successful, the caller is responsible to free the space 496 * allocated for objectstore_slot_info and objectstore_token_info. 497 */ 498 int 499 get_metaslot_info(boolean_t *status_enabled, boolean_t *migrate_enabled, 500 char **objectstore_slot_info, char **objectstore_token_info) 501 { 502 503 int rc = SUCCESS; 504 uentry_t *puent; 505 char *buf1 = NULL; 506 char *buf2 = NULL; 507 508 if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) { 509 /* metaslot entry doesn't exist */ 510 return (FAILURE); 511 } 512 513 *status_enabled = puent->flag_metaslot_enabled; 514 *migrate_enabled = puent->flag_metaslot_auto_key_migrate; 515 516 buf1 = malloc(SLOT_DESCRIPTION_SIZE); 517 if (buf1 == NULL) { 518 cryptoerror(LOG_ERR, "get_metaslot_info() - out of memory.\n"); 519 rc = FAILURE; 520 goto out; 521 } 522 (void) strcpy(buf1, (const char *) puent->metaslot_ks_slot); 523 *objectstore_slot_info = buf1; 524 525 buf2 = malloc(TOKEN_LABEL_SIZE); 526 if (objectstore_slot_info == NULL) { 527 cryptoerror(LOG_ERR, "get_metaslot_info() - out of memory.\n"); 528 rc = FAILURE; 529 goto out; 530 } 531 (void) strcpy(buf2, (const char *) puent->metaslot_ks_token); 532 *objectstore_token_info = buf2; 533 534 out: 535 if (puent != NULL) { 536 free_uentry(puent); 537 } 538 539 if (rc == FAILURE) { 540 if (buf1 != NULL) { 541 free(buf1); 542 } 543 if (buf2 != NULL) { 544 free(buf2); 545 } 546 } 547 548 return (rc); 549 } 550