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 #include <cryptoutil.h> 27 #include <errno.h> 28 #include <fcntl.h> 29 #include <stdio.h> 30 #include <strings.h> 31 #include "metaGlobal.h" 32 33 extern cipher_mechs_threshold_t meta_mechs_threshold[]; 34 static boolean_t threshold_chk_enabled = B_FALSE; 35 36 CK_RV 37 meta_operation_init_defer(CK_FLAGS optype, meta_session_t *session, 38 CK_MECHANISM *pMechanism, meta_object_t *key) 39 { 40 41 if (session->init.pMech == NULL) { 42 session->init.pMech = malloc(sizeof (CK_MECHANISM)); 43 if (session->init.pMech == NULL) 44 return (CKR_HOST_MEMORY); 45 46 (void) memcpy(session->init.pMech, pMechanism, 47 sizeof (CK_MECHANISM)); 48 49 if ((pMechanism->ulParameterLen > 0) && 50 (pMechanism->pParameter != NULL)) { 51 session->init.pMech->pParameter = 52 malloc(pMechanism->ulParameterLen); 53 if (session->init.pMech->pParameter == NULL) { 54 free(session->init.pMech); 55 session->init.pMech = NULL; 56 return (CKR_HOST_MEMORY); 57 } 58 (void) memcpy(session->init.pMech->pParameter, 59 pMechanism->pParameter, pMechanism->ulParameterLen); 60 } else { 61 session->init.pMech->pParameter = NULL; 62 } 63 } else { /* reuse it */ 64 if ((pMechanism->ulParameterLen > 0) && 65 (pMechanism->pParameter != NULL)) { 66 if (pMechanism->ulParameterLen != 67 session->init.pMech->ulParameterLen) { 68 if (session->init.pMech->pParameter != NULL) 69 free(session->init.pMech->pParameter); 70 session->init.pMech->pParameter = 71 malloc(pMechanism->ulParameterLen); 72 if (session->init.pMech->pParameter == NULL) { 73 free(session->init.pMech); 74 session->init.pMech = NULL; 75 return (CKR_HOST_MEMORY); 76 } 77 } /* otherwise reuse it */ 78 (void) memcpy(session->init.pMech->pParameter, 79 pMechanism->pParameter, pMechanism->ulParameterLen); 80 } else { 81 /* 82 * free the previous pParameter if not yet freed 83 * because we don't need it now. 84 */ 85 if (session->init.pMech->pParameter != NULL) { 86 free(session->init.pMech->pParameter); 87 session->init.pMech->pParameter = NULL; 88 } 89 } 90 /* copy the rest of data */ 91 session->init.pMech->mechanism = 92 pMechanism->mechanism; 93 session->init.pMech->ulParameterLen = 94 pMechanism->ulParameterLen; 95 } 96 97 session->init.session = session; 98 session->init.optype = optype; 99 session->init.key = key; 100 session->init.done = B_FALSE; 101 session->init.app = B_TRUE; 102 return (CKR_OK); 103 } 104 105 /* 106 * meta_operation_init 107 * 108 */ 109 CK_RV 110 meta_operation_init(CK_FLAGS optype, meta_session_t *session, 111 CK_MECHANISM *pMechanism, meta_object_t *key) 112 { 113 CK_RV rv, save_rv; 114 mechinfo_t **supporting_slots; 115 CK_ULONG slotnum; 116 unsigned long i, slotCount = 0; 117 slot_session_t *init_session = NULL; 118 CK_MECHANISM_INFO mech_info; 119 120 /* 121 * If an operation is already active, cleanup existing operation 122 * and start a new one. 123 */ 124 if (session->op1.type != 0) { 125 CK_MECHANISM mech; 126 if ((optype == CKF_ENCRYPT) || (optype == CKF_DECRYPT) || 127 (optype == CKF_DIGEST)) { 128 mech = *pMechanism; 129 130 if ((pMechanism->ulParameterLen > 0) && 131 (pMechanism->pParameter != NULL)) { 132 mech.pParameter = 133 malloc(pMechanism->ulParameterLen); 134 if (mech.pParameter == NULL) { 135 return (CKR_HOST_MEMORY); 136 } 137 (void) memcpy(mech.pParameter, 138 pMechanism->pParameter, 139 pMechanism->ulParameterLen); 140 } else { 141 mech.pParameter = NULL; 142 mech.ulParameterLen = 0; 143 } 144 145 meta_operation_cleanup(session, session->op1.type, 146 B_FALSE); 147 rv = meta_operation_init_defer(optype, session, 148 &mech, key); 149 if (mech.pParameter != NULL) { 150 free(mech.pParameter); 151 } 152 if (rv != CKR_OK) 153 return (rv); 154 } else { 155 meta_operation_cleanup(session, session->op1.type, 156 B_FALSE); 157 } 158 159 } 160 161 mech_info.flags = optype; 162 163 /* 164 * Get a list of capable slots. 165 * 166 * If the specified mechanism is used in this session last time, 167 * the list of capable slots is already retrieved. We can save 168 * some processing, and just use that list of slots. 169 */ 170 if (((session->mech_support_info).mech != pMechanism->mechanism) || 171 ((session->mech_support_info).num_supporting_slots == 0)) { 172 (session->mech_support_info).mech = pMechanism->mechanism; 173 rv = meta_mechManager_get_slots(&(session->mech_support_info), 174 B_FALSE, &mech_info); 175 if (rv != CKR_OK) { 176 goto finish; 177 } 178 } 179 180 rv = CKR_FUNCTION_FAILED; 181 182 /* The following 2 assignment is just to make the code more readable */ 183 slotCount = (session->mech_support_info).num_supporting_slots; 184 supporting_slots = (session->mech_support_info).supporting_slots; 185 186 /* Attempt to initialize operation on slots until one succeeds. */ 187 for (i = 0; i < slotCount; i++) { 188 slot_object_t *init_key; 189 CK_SLOT_ID fw_st_id; 190 191 init_session = NULL; 192 193 slotnum = supporting_slots[i]->slotnum; 194 195 /* 196 * An actual session with the underlying slot is required 197 * for the operation. When the operation is successfully 198 * completed, the underlying session with the slot 199 * is not released back to the list of available sessions 200 * pool. This will help if the next operation can 201 * also be done on the same slot, because it avoids 202 * one extra trip to the session pool to get an idle session. 203 * If the operation can't be done on that slot, 204 * we release the session back to the session pool then. 205 */ 206 if (session->op1.session != NULL) { 207 208 if ((session->op1.session)->slotnum == slotnum) { 209 init_session = session->op1.session; 210 /* 211 * set it to NULL for now, assign it to 212 * init_session again if it is successful 213 */ 214 session->op1.session = NULL; 215 } else { 216 init_session = NULL; 217 } 218 219 } 220 221 if (!init_session) { 222 rv = meta_get_slot_session(slotnum, &init_session, 223 session->session_flags); 224 if (rv != CKR_OK) { 225 goto loop_cleanup; 226 } 227 } 228 229 /* if necessary, ensure a clone of the obj exists in slot */ 230 if (optype != CKF_DIGEST) { 231 rv = meta_object_get_clone(key, slotnum, init_session, 232 &init_key); 233 234 if (rv != CKR_OK) { 235 goto loop_cleanup; 236 } 237 } 238 239 fw_st_id = init_session->fw_st_id; 240 switch (optype) { 241 case CKF_ENCRYPT: 242 rv = FUNCLIST(fw_st_id)->C_EncryptInit( 243 init_session->hSession, pMechanism, 244 init_key->hObject); 245 break; 246 case CKF_DECRYPT: 247 rv = FUNCLIST(fw_st_id)->C_DecryptInit( 248 init_session->hSession, pMechanism, 249 init_key->hObject); 250 break; 251 case CKF_DIGEST: 252 rv = FUNCLIST(fw_st_id)->C_DigestInit( 253 init_session->hSession, pMechanism); 254 break; 255 case CKF_SIGN: 256 rv = FUNCLIST(fw_st_id)->C_SignInit( 257 init_session->hSession, pMechanism, 258 init_key->hObject); 259 break; 260 case CKF_VERIFY: 261 rv = FUNCLIST(fw_st_id)->C_VerifyInit( 262 init_session->hSession, pMechanism, 263 init_key->hObject); 264 break; 265 case CKF_SIGN_RECOVER: 266 rv = FUNCLIST(fw_st_id)->C_SignRecoverInit( 267 init_session->hSession, pMechanism, 268 init_key->hObject); 269 break; 270 case CKF_VERIFY_RECOVER: 271 rv = FUNCLIST(fw_st_id)->C_VerifyRecoverInit( 272 init_session->hSession, pMechanism, 273 init_key->hObject); 274 break; 275 276 default: 277 /*NOTREACHED*/ 278 rv = CKR_FUNCTION_FAILED; 279 break; 280 } 281 282 if (rv == CKR_OK) 283 break; 284 285 loop_cleanup: 286 if (i == 0) { 287 save_rv = rv; 288 } 289 290 if (init_session) { 291 meta_release_slot_session(init_session); 292 init_session = NULL; 293 } 294 295 } 296 297 if (rv == CKR_OK) { 298 299 /* 300 * If currently stored session is not the one being in use now, 301 * release the previous one and store the current one 302 */ 303 if ((session->op1.session) && 304 (session->op1.session != init_session)) { 305 meta_release_slot_session(session->op1.session); 306 } 307 308 /* Save the session */ 309 session->op1.session = init_session; 310 session->op1.type = optype; 311 312 session->init.slotnum = slotnum; 313 session->init.done = B_TRUE; 314 } else { 315 rv = save_rv; 316 } 317 318 finish: 319 return (rv); 320 } 321 322 /* 323 * meta_operation_init_softtoken() 324 * It will always do the crypto init operation on softtoken slot. 325 */ 326 CK_RV 327 meta_operation_init_softtoken(CK_FLAGS optype, meta_session_t *session, 328 CK_MECHANISM *pMechanism, meta_object_t *key) 329 { 330 CK_RV rv = CKR_FUNCTION_FAILED; 331 slot_session_t *init_session = NULL; 332 slot_object_t *init_key; 333 CK_SLOT_ID fw_st_id; 334 CK_ULONG softtoken_slot_num; 335 336 softtoken_slot_num = get_softtoken_slotnum(); 337 /* 338 * If an operation is already active, cleanup existing operation 339 * and start a new one. 340 */ 341 if (session->op1.type != 0) { 342 CK_MECHANISM mech; 343 mech = *pMechanism; 344 345 if ((pMechanism->ulParameterLen > 0) && 346 (pMechanism->pParameter != NULL)) { 347 mech.pParameter = 348 malloc(pMechanism->ulParameterLen); 349 if (mech.pParameter == NULL) { 350 return (CKR_HOST_MEMORY); 351 } 352 (void) memcpy(mech.pParameter, 353 pMechanism->pParameter, pMechanism->ulParameterLen); 354 } else { 355 mech.pParameter = NULL; 356 mech.ulParameterLen = 0; 357 } 358 359 meta_operation_cleanup(session, session->op1.type, B_FALSE); 360 rv = meta_operation_init_defer(optype, session, &mech, 361 key); 362 if (mech.pParameter != NULL) { 363 free(mech.pParameter); 364 } 365 if (rv != CKR_OK) 366 return (rv); 367 } 368 369 /* 370 * An actual session with the underlying slot is required 371 * for the operation. When the operation is successfully 372 * completed, the underlying session with the slot 373 * is not released back to the list of available sessions 374 * pool. This will help if the next operation can 375 * also be done on the same slot, because it avoids 376 * one extra trip to the session pool to get an idle session. 377 * If the operation can't be done on that slot, 378 * we release the session back to the session pool. 379 */ 380 if (session->op1.session != NULL) { 381 if ((session->op1.session)->slotnum == 382 softtoken_slot_num) { 383 init_session = session->op1.session; 384 /* 385 * set it to NULL for now, assign it to 386 * init_session again if it is successful 387 */ 388 session->op1.session = NULL; 389 } else { 390 init_session = NULL; 391 } 392 } 393 394 if (init_session == NULL) { 395 /* get the active session from softtoken slot */ 396 rv = meta_get_slot_session(softtoken_slot_num, 397 &init_session, session->session_flags); 398 if (rv != CKR_OK) { 399 goto finish; 400 } 401 } 402 403 /* if necessary, ensure a clone of the obj exists in softtoken slot */ 404 if (optype != CKF_DIGEST) { 405 rv = meta_object_get_clone(key, softtoken_slot_num, 406 init_session, &init_key); 407 408 if (rv != CKR_OK) { 409 if (init_session != NULL) { 410 meta_release_slot_session(init_session); 411 init_session = NULL; 412 } 413 goto finish; 414 } 415 } 416 417 fw_st_id = init_session->fw_st_id; 418 419 /* 420 * Currently, we only support offloading encrypt, decrypt 421 * and digest operations to softtoken based on kernel 422 * threshold for the supported mechanisms. 423 */ 424 switch (optype) { 425 case CKF_ENCRYPT: 426 rv = FUNCLIST(fw_st_id)->C_EncryptInit( 427 init_session->hSession, pMechanism, 428 init_key->hObject); 429 break; 430 case CKF_DECRYPT: 431 rv = FUNCLIST(fw_st_id)->C_DecryptInit( 432 init_session->hSession, pMechanism, 433 init_key->hObject); 434 break; 435 case CKF_DIGEST: 436 rv = FUNCLIST(fw_st_id)->C_DigestInit( 437 init_session->hSession, pMechanism); 438 break; 439 440 default: 441 /*NOTREACHED*/ 442 rv = CKR_FUNCTION_FAILED; 443 break; 444 } 445 446 if (rv == CKR_OK) { 447 448 /* 449 * If currently stored session is not the one being in use now, 450 * release the previous one and store the current one 451 */ 452 if ((session->op1.session) && 453 (session->op1.session != init_session)) { 454 meta_release_slot_session(session->op1.session); 455 } 456 457 /* Save the session */ 458 session->op1.session = init_session; 459 session->op1.type = optype; 460 /* 461 * The init.done flag will be checked by the meta_do_operation() 462 * to indicate whether the C_xxxInit has been done against 463 * softtoken. 464 */ 465 session->init.done = B_TRUE; 466 session->init.slotnum = softtoken_slot_num; 467 } 468 469 finish: 470 return (rv); 471 } 472 473 int 474 meta_GetThreshold(CK_MECHANISM_TYPE mechanism) 475 { 476 477 int i; 478 479 for (i = 0; i < MAX_NUM_THRESHOLD; i++) { 480 if (mechanism == meta_mechs_threshold[i].mech_type) 481 return (meta_mechs_threshold[i].mech_threshold); 482 } 483 484 /* no matching mechanism */ 485 return (0); 486 } 487 488 /* 489 * meta_do_operation 490 * 491 * NOTES: 492 * 493 * 1) The spec says you cannot do a C_Encrypt after a C_EncUpdate, 494 * but we don't explicitly enforce it here (ie, disallow doing MODE_SINGLE 495 * after a MODE_UPDATE). Instead, we just assume the underlying provider 496 * will catch the problem and return an appropriate error. 497 * 498 * 2) Note that the Verify operations are a little unusual, due to the 499 * PKCS#11 API. For C_Verify, the last two arguments are used as inputs, 500 * unlike the other single pass operations (where they are outputs). For 501 * C_VerifyFinal, in/inLen are passed instead of out/outLen like the other 502 * Final operations. 503 * 504 * 3) C_DigestKey is the only crypto operation that uses an object after 505 * the operation has been initialized. No other callers should provide 506 * this argument (use NULL). 507 */ 508 CK_RV 509 meta_do_operation(CK_FLAGS optype, int mode, 510 meta_session_t *session, meta_object_t *object, 511 CK_BYTE *in, CK_ULONG inLen, CK_BYTE *out, CK_ULONG *outLen) 512 { 513 CK_RV rv; 514 CK_SESSION_HANDLE hSession; 515 CK_SLOT_ID fw_st_id; 516 slot_session_t *slot_session = NULL; 517 slot_object_t *slot_object = NULL; 518 int threshold = 0; 519 520 boolean_t shutdown, finished_normally; 521 522 /* 523 * We've deferred the init for encrypt, decrypt and digest 524 * operations. As we know the size of the input data now, we 525 * can decide where to perform the real init operation based 526 * on the kernel cipher-specific thresholds for certain 527 * supported mechanisms. 528 */ 529 if ((optype == CKF_ENCRYPT) || (optype == CKF_DECRYPT) || 530 (optype == CKF_DIGEST)) { 531 if (Tmp_GetThreshold != NULL) { 532 if (!session->init.app) { 533 return (CKR_OPERATION_NOT_INITIALIZED); 534 } 535 threshold = meta_GetThreshold( 536 session->init.pMech->mechanism); 537 } 538 539 if ((threshold_chk_enabled == B_FALSE) || (inLen > threshold)) { 540 if ((session->init.app) && (!session->init.done)) { 541 /* 542 * Call real init operation only if the 543 * application has called C_xxxInit 544 * but the real init operation has not 545 * been done. 546 */ 547 rv = meta_operation_init(optype, 548 session->init.session, 549 session->init.pMech, 550 session->init.key); 551 if (rv != CKR_OK) 552 goto exit; 553 } else if (!session->init.app) { 554 /* 555 * This checking detects the case that 556 * application calls C_En(De)Crypt/Digest 557 * directly without calling C_xxxInit. 558 */ 559 return (CKR_OPERATION_NOT_INITIALIZED); 560 } 561 } else { 562 /* 563 * The size of the input data is smaller than the 564 * threshold so we'll use softoken to perform the 565 * crypto operation for better performance reason. 566 */ 567 if ((session->init.app) && (!session->init.done)) { 568 /* 569 * Call real init operation only if the 570 * application has called C_xxxInit 571 * but the real init operation has not 572 * been done. 573 */ 574 rv = meta_operation_init_softtoken(optype, 575 session->init.session, 576 session->init.pMech, 577 session->init.key); 578 if (rv != CKR_OK) { 579 /* 580 * In case the operation fails in 581 * softtoken, go back to use the 582 * original slot again. 583 */ 584 rv = meta_operation_init(optype, 585 session->init.session, 586 session->init.pMech, 587 session->init.key); 588 if (rv != CKR_OK) 589 goto exit; 590 } 591 } else if (!session->init.app) { 592 /* 593 * This checking detects the case that 594 * application calls C_En(De)Crypt/Digest 595 * directly without calling C_xxxInit. 596 */ 597 return (CKR_OPERATION_NOT_INITIALIZED); 598 } 599 } 600 } else if (optype != session->op1.type) { 601 return (CKR_OPERATION_NOT_INITIALIZED); 602 } 603 604 slot_session = session->op1.session; 605 606 if (slot_session) { 607 hSession = slot_session->hSession; 608 fw_st_id = slot_session->fw_st_id; 609 } else { 610 /* should never be here */ 611 rv = CKR_FUNCTION_FAILED; 612 goto exit; 613 } 614 615 /* Do the operation... */ 616 if (optype == CKF_ENCRYPT && mode == MODE_SINGLE) { 617 rv = FUNCLIST(fw_st_id)->C_Encrypt(hSession, in, 618 inLen, out, outLen); 619 } else if (optype == CKF_ENCRYPT && mode == MODE_UPDATE) { 620 rv = FUNCLIST(fw_st_id)->C_EncryptUpdate(hSession, in, 621 inLen, out, outLen); 622 } else if (optype == CKF_ENCRYPT && mode == MODE_FINAL) { 623 rv = FUNCLIST(fw_st_id)->C_EncryptFinal(hSession, out, 624 outLen); 625 626 } else if (optype == CKF_DECRYPT && mode == MODE_SINGLE) { 627 rv = FUNCLIST(fw_st_id)->C_Decrypt(hSession, in, 628 inLen, out, outLen); 629 } else if (optype == CKF_DECRYPT && mode == MODE_UPDATE) { 630 rv = FUNCLIST(fw_st_id)->C_DecryptUpdate(hSession, in, 631 inLen, out, outLen); 632 } else if (optype == CKF_DECRYPT && mode == MODE_FINAL) { 633 rv = FUNCLIST(fw_st_id)->C_DecryptFinal(hSession, out, 634 outLen); 635 636 } else if (optype == CKF_DIGEST && mode == MODE_SINGLE) { 637 rv = FUNCLIST(fw_st_id)->C_Digest(hSession, in, inLen, 638 out, outLen); 639 } else if (optype == CKF_DIGEST && mode == MODE_UPDATE) { 640 /* noOutputForOp = TRUE; */ 641 rv = FUNCLIST(fw_st_id)->C_DigestUpdate(hSession, in, 642 inLen); 643 } else if (optype == CKF_DIGEST && mode == MODE_UPDATE_WITHKEY) { 644 /* noOutputForOp = TRUE; */ 645 /* 646 * For C_DigestKey, a key is provided and 647 * we need the clone. 648 */ 649 rv = meta_object_get_clone(object, 650 slot_session->slotnum, slot_session, &slot_object); 651 if (rv == CKR_OK) 652 rv = FUNCLIST(fw_st_id)->C_DigestKey(hSession, 653 slot_object->hObject); 654 } else if (optype == CKF_DIGEST && mode == MODE_FINAL) { 655 rv = FUNCLIST(fw_st_id)->C_DigestFinal(hSession, out, 656 outLen); 657 658 } else if (optype == CKF_SIGN && mode == MODE_SINGLE) { 659 rv = FUNCLIST(fw_st_id)->C_Sign(hSession, in, inLen, 660 out, outLen); 661 } else if (optype == CKF_SIGN && mode == MODE_UPDATE) { 662 /* noOutputForOp = TRUE; */ 663 rv = FUNCLIST(fw_st_id)->C_SignUpdate(hSession, in, 664 inLen); 665 } else if (optype == CKF_SIGN && mode == MODE_FINAL) { 666 rv = FUNCLIST(fw_st_id)->C_SignFinal(hSession, out, 667 outLen); 668 669 } else if (optype == CKF_VERIFY && mode == MODE_SINGLE) { 670 /* noOutputForOp = TRUE; */ 671 /* Yes, use *outLen not outLen (think in2/in2Len) */ 672 rv = FUNCLIST(fw_st_id)->C_Verify(hSession, in, 673 inLen, out, *outLen); 674 } else if (optype == CKF_VERIFY && mode == MODE_UPDATE) { 675 /* noOutputForOp = TRUE; */ 676 rv = FUNCLIST(fw_st_id)->C_VerifyUpdate(hSession, in, 677 inLen); 678 } else if (optype == CKF_VERIFY && mode == MODE_FINAL) { 679 /* noOutputForOp = TRUE; */ 680 /* Yes, use in/inLen instead of out/outLen */ 681 rv = FUNCLIST(fw_st_id)->C_VerifyFinal(hSession, in, 682 inLen); 683 684 } else if (optype == CKF_SIGN_RECOVER && mode == MODE_SINGLE) { 685 rv = FUNCLIST(fw_st_id)->C_SignRecover(hSession, in, 686 inLen, out, outLen); 687 } else if (optype == CKF_VERIFY_RECOVER && mode == MODE_SINGLE) { 688 rv = FUNCLIST(fw_st_id)->C_VerifyRecover(hSession, in, 689 inLen, out, outLen); 690 691 } else { 692 rv = CKR_FUNCTION_FAILED; 693 } 694 695 696 /* 697 * Mark the operation type as inactive if an abnormal error 698 * happens, or if the operation normally results in an inactive 699 * operation state. 700 * 701 * NOTE: The spec isn't very explicit about what happens when you 702 * call C_FooFinal (or C_Foo) with a NULL output buffer (to get the 703 * output size), but there is no output. Technically this should be 704 * no different than the normal case (ie, when there is output), and 705 * the operation should remain active until the second call actually 706 * terminates it. However, one could make the case that there is no 707 * need for a second call, since no data is available. This presents 708 * dilemma for metaslot, because we don't know if the operation is 709 * going to remain active or not. We will assume a strict reading of 710 * the spec, the operation will remain active. 711 */ 712 exit: 713 if (rv == CKR_BUFFER_TOO_SMALL || 714 (rv == CKR_OK && out == NULL && optype != CKF_VERIFY)) { 715 /* Leave op active for retry (with larger buffer). */ 716 shutdown = B_FALSE; 717 } else if (rv != CKR_OK) { 718 shutdown = B_TRUE; 719 finished_normally = B_FALSE; 720 } else { /* CKR_OK */ 721 if (mode == MODE_SINGLE || mode == MODE_FINAL) { 722 shutdown = B_TRUE; 723 finished_normally = B_TRUE; 724 } else { /* mode == MODE_UPDATE */ 725 shutdown = B_FALSE; 726 } 727 } 728 729 if (shutdown) { 730 if (mode == MODE_SINGLE || mode == MODE_FINAL) { 731 session->init.app = B_FALSE; 732 } 733 734 meta_operation_cleanup(session, optype, finished_normally); 735 } 736 737 return (rv); 738 } 739 740 void 741 free_session_mechanism(meta_session_t *session) 742 { 743 if (session->init.pMech != NULL) { 744 if (session->init.pMech->pParameter != NULL) { 745 free(session->init.pMech->pParameter); 746 session->init.pMech->pParameter = NULL; 747 session->init.pMech->ulParameterLen = 0; 748 } 749 free(session->init.pMech); 750 session->init.pMech = NULL; 751 } 752 } 753 754 /* 755 * meta_operation_cleanup 756 * 757 * Cleans up an operation in the specified session. 758 * If the operation did not finish normally, it will force 759 * the operation to terminate. 760 */ 761 void 762 meta_operation_cleanup(meta_session_t *session, CK_FLAGS optype, 763 boolean_t finished_normally) 764 { 765 operation_info_t *op; 766 CK_SESSION_HANDLE hSession; 767 CK_SLOT_ID fw_st_id; 768 769 if (!finished_normally) { 770 CK_BYTE dummy_buf[8]; 771 772 if (session->op1.type == optype) { 773 op = &session->op1; 774 } else { 775 if ((optype == CKF_ENCRYPT) || 776 (optype == CKF_DECRYPT) || 777 (optype == CKF_DIGEST)) { 778 session->op1.type = 0; 779 session->init.app = B_FALSE; 780 session->init.done = B_FALSE; 781 free_session_mechanism(session); 782 } 783 return; 784 } 785 786 hSession = op->session->hSession; 787 fw_st_id = op->session->fw_st_id; 788 789 /* 790 * There's no simple, reliable way to abort an 791 * operation. So, we'll force the operation to finish. 792 * 793 * We are here either because we need to abort either after 794 * C_xxxxxInit() or C_xxxxxUpdate(). 795 * 796 * We will call C_xxxxxUpdate() with invalid argument to 797 * force the operation to abort. According to the PKCS#11 798 * spec, any call to C_xxxxxUpdate() returns in an error 799 * will terminate the current operation. 800 */ 801 802 switch (optype) { 803 case CKF_ENCRYPT: 804 (void) FUNCLIST(fw_st_id)->C_EncryptUpdate(hSession, 805 NULL, 8, dummy_buf, NULL); 806 break; 807 case CKF_DECRYPT: 808 (void) FUNCLIST(fw_st_id)->C_DecryptUpdate(hSession, 809 NULL, 8, dummy_buf, NULL); 810 break; 811 case CKF_DIGEST: 812 (void) FUNCLIST(fw_st_id)->C_DigestUpdate(hSession, 813 NULL, 8); 814 break; 815 case CKF_SIGN: 816 (void) FUNCLIST(fw_st_id)->C_SignUpdate(hSession, 817 NULL, 8); 818 break; 819 case CKF_SIGN_RECOVER: 820 (void) FUNCLIST(fw_st_id)->C_SignRecover(hSession, 821 NULL, 8, dummy_buf, NULL); 822 break; 823 case CKF_VERIFY: 824 (void) FUNCLIST(fw_st_id)->C_VerifyUpdate(hSession, 825 NULL, 8); 826 break; 827 case CKF_VERIFY_RECOVER: 828 (void) FUNCLIST(fw_st_id)->C_VerifyRecover(hSession, 829 NULL, 8, dummy_buf, NULL); 830 break; 831 default: 832 /*NOTREACHED*/ 833 break; 834 } 835 meta_release_slot_session(session->op1.session); 836 session->op1.session = NULL; 837 } 838 839 if ((optype == CKF_ENCRYPT) || (optype == CKF_DECRYPT) || 840 (optype == CKF_DIGEST)) { 841 session->init.done = B_FALSE; 842 free_session_mechanism(session); 843 } 844 session->op1.type = 0; 845 } 846 847 /* 848 * Gets the list of slots that supports the specified mechanism. 849 * 850 * If "token_only", check if the keystore slot supports the specified mech, 851 * if so, return that slot only 852 * 853 * Otherwise, get list of all slots that support the mech. 854 * 855 */ 856 static CK_RV 857 get_slotlist_for_mech(CK_MECHANISM_TYPE mech_type, 858 mech_support_info_t *mech_support_info, 859 mechinfo_t ***slots, unsigned long *slot_count, boolean_t token_only, 860 CK_MECHANISM_INFO *mech_info) 861 { 862 boolean_t mech_supported = B_FALSE; 863 CK_RV rv = CKR_OK; 864 865 if (token_only) { 866 rv = meta_mechManager_slot_supports_mech(mech_type, 867 get_keystore_slotnum(), &mech_supported, 868 &((mech_support_info->supporting_slots)[0]), B_FALSE, 869 mech_info); 870 871 if (rv != CKR_OK) { 872 return (rv); 873 } 874 875 if (mech_supported) { 876 mech_support_info->mech = mech_type; 877 /* 878 * Want to leave this at 0, that way, when 879 * other operation needs to 880 * use this mechanism, but not just for the 881 * keystore slot, we will look at other slots 882 */ 883 mech_support_info->num_supporting_slots = 0; 884 *slots = mech_support_info->supporting_slots; 885 *slot_count = 1; 886 } else { 887 rv = CKR_FUNCTION_FAILED; 888 } 889 } else { 890 /* 891 * Get a list of slots that support this mech . 892 * 893 * If the specified mechanism is used last time, 894 * the list of capable slots is already retrieved. 895 * We can save some processing, and just use that list of slots. 896 */ 897 if ((mech_support_info->mech != mech_type) || 898 (mech_support_info->num_supporting_slots == 0)) { 899 mech_support_info->mech = mech_type; 900 rv = meta_mechManager_get_slots(mech_support_info, 901 B_FALSE, mech_info); 902 if (rv != CKR_OK) { 903 return (CKR_FUNCTION_FAILED); 904 } 905 } 906 *slots = mech_support_info->supporting_slots; 907 *slot_count = mech_support_info->num_supporting_slots; 908 } 909 return (rv); 910 } 911 912 /* 913 * meta_generate_keys 914 * 915 * Generates symmetric (k1=key, k2=null) or asymmetric (k1=pub, k2=priv) keys. 916 * 917 */ 918 CK_RV 919 meta_generate_keys(meta_session_t *session, CK_MECHANISM *pMechanism, 920 CK_ATTRIBUTE *k1Template, CK_ULONG k1AttrCount, meta_object_t *key1, 921 CK_ATTRIBUTE *k2Template, CK_ULONG k2AttrCount, meta_object_t *key2) 922 { 923 CK_RV rv, save_rv; 924 slot_session_t *gen_session = NULL; 925 slot_object_t *slot_key1 = NULL, *slot_key2 = NULL; 926 mechinfo_t **slots = NULL; 927 unsigned long i, slotCount = 0; 928 boolean_t doKeyPair = B_FALSE, token_only = B_FALSE; 929 CK_ULONG slotnum; 930 CK_MECHANISM_INFO mech_info; 931 /* 932 * Since the keygen call is in a loop, it is performance-wise useful 933 * to keep track of the token value 934 */ 935 CK_BBOOL current_token1_value = FALSE, current_token2_value = FALSE; 936 937 (void) get_template_boolean(CKA_TOKEN, k1Template, k1AttrCount, 938 &(key1->isToken)); 939 (void) get_template_boolean(CKA_SENSITIVE, k1Template, k1AttrCount, 940 &(key1->isSensitive)); 941 (void) get_template_boolean(CKA_PRIVATE, k1Template, k1AttrCount, 942 &(key1->isPrivate)); 943 944 if (!get_template_boolean(CKA_EXTRACTABLE, k1Template, k1AttrCount, 945 &(key1->isExtractable))) 946 key1->isExtractable = B_TRUE; 947 948 if (key1->isToken) 949 current_token1_value = TRUE; 950 951 mech_info.flags = CKF_GENERATE; 952 953 if (key2) { 954 (void) get_template_boolean(CKA_TOKEN, k2Template, k2AttrCount, 955 &(key2->isToken)); 956 (void) get_template_boolean(CKA_SENSITIVE, k2Template, 957 k2AttrCount, &(key2->isSensitive)); 958 (void) get_template_boolean(CKA_PRIVATE, k2Template, 959 k2AttrCount, &(key2->isPrivate)); 960 961 if (!get_template_boolean(CKA_EXTRACTABLE, k2Template, 962 k2AttrCount, &(key2->isExtractable))) 963 key2->isExtractable = B_TRUE; 964 965 if (key2->isToken) 966 current_token2_value = TRUE; 967 968 doKeyPair = B_TRUE; 969 mech_info.flags = CKF_GENERATE_KEY_PAIR; 970 } 971 972 973 /* Can't create token objects in a read-only session. */ 974 if ((IS_READ_ONLY_SESSION(session->session_flags)) && 975 ((key1->isToken) || ((key2) && (key2->isToken)))) { 976 return (CKR_SESSION_READ_ONLY); 977 } 978 979 if (meta_freeobject_check(session, key1, pMechanism, k1Template, 980 k1AttrCount, 0)) { 981 982 if ((key1->isPrivate || (doKeyPair && key2->isPrivate)) && 983 !metaslot_logged_in()) 984 return (CKR_USER_NOT_LOGGED_IN); 985 986 if (!meta_freeobject_set(key1, k1Template, k1AttrCount, 987 B_FALSE)) 988 return (CKR_FUNCTION_FAILED); 989 990 if (doKeyPair) { 991 key2->isFreeObject = FREE_ALLOWED_KEY; 992 if (!meta_freeobject_set(key2, k2Template, k2AttrCount, 993 B_FALSE)) 994 return (CKR_FUNCTION_FAILED); 995 } 996 997 } else if (doKeyPair) { 998 /* 999 * If this is a keypair operation, the second key cannot be 1000 * a FreeObject if the first is not. Both keys will have the 1001 * same fate when it comes to provider choices 1002 */ 1003 key2->isFreeObject = FREE_DISABLED; 1004 key2->isFreeToken = FREE_DISABLED; 1005 } 1006 1007 if ((key1->isToken) || ((doKeyPair) && (key2->isToken))) { 1008 /* 1009 * Token objects can only be generated in the token object 1010 * slot. If token object slot doesn't support generating 1011 * the key, it will just not be done. 1012 */ 1013 token_only = B_TRUE; 1014 } 1015 1016 rv = get_slotlist_for_mech(pMechanism->mechanism, 1017 &(session->mech_support_info), &slots, &slotCount, token_only, 1018 &mech_info); 1019 1020 if (rv != CKR_OK) { 1021 goto finish; 1022 } 1023 1024 rv = meta_slot_object_alloc(&slot_key1); 1025 if (doKeyPair && rv == CKR_OK) 1026 rv = meta_slot_object_alloc(&slot_key2); 1027 if (rv != CKR_OK) 1028 goto finish; 1029 1030 /* Attempt to generate key on slots until one succeeds. */ 1031 for (i = 0; i < slotCount; i++) { 1032 CK_SESSION_HANDLE hSession; 1033 CK_SLOT_ID fw_st_id; 1034 1035 gen_session = NULL; 1036 1037 slotnum = slots[i]->slotnum; 1038 1039 if (session->op1.session != NULL) { 1040 if ((session->op1.session)->slotnum == slotnum) { 1041 gen_session = session->op1.session; 1042 /* 1043 * set it to NULL for now, assign it to 1044 * gen_session again if it is successful 1045 */ 1046 session->op1.session = NULL; 1047 } else { 1048 gen_session = NULL; 1049 } 1050 } 1051 1052 if (gen_session == NULL) { 1053 rv = meta_get_slot_session(slotnum, &gen_session, 1054 session->session_flags); 1055 if (rv != CKR_OK) { 1056 goto loop_cleanup; 1057 } 1058 } 1059 1060 /* 1061 * If this is a freetoken, make sure the templates are 1062 * approriate for the slot being used. 1063 */ 1064 if (key1->isFreeToken == FREE_ENABLED) { 1065 rv = meta_freetoken_set(slotnum, 1066 ¤t_token1_value, k1Template, k1AttrCount); 1067 if (rv != CKR_OK) 1068 goto loop_cleanup; 1069 } 1070 1071 if (doKeyPair && key2->isFreeToken == FREE_ENABLED) { 1072 rv = meta_freetoken_set(slotnum, 1073 ¤t_token2_value, k2Template, k2AttrCount); 1074 if (rv != CKR_OK) 1075 goto loop_cleanup; 1076 } 1077 1078 fw_st_id = gen_session->fw_st_id; 1079 hSession = gen_session->hSession; 1080 1081 if (doKeyPair) { 1082 rv = FUNCLIST(fw_st_id)->C_GenerateKeyPair(hSession, 1083 pMechanism, k1Template, k1AttrCount, 1084 k2Template, k2AttrCount, 1085 &slot_key1->hObject, &slot_key2->hObject); 1086 } else { 1087 rv = FUNCLIST(fw_st_id)->C_GenerateKey(hSession, 1088 pMechanism, k1Template, k1AttrCount, 1089 &slot_key1->hObject); 1090 } 1091 1092 if (rv == CKR_OK) 1093 break; 1094 1095 loop_cleanup: 1096 if (i == 0) { 1097 save_rv = rv; 1098 } 1099 1100 if (gen_session) { 1101 meta_release_slot_session(gen_session); 1102 gen_session = NULL; 1103 } 1104 } 1105 if (rv != CKR_OK) { 1106 rv = save_rv; 1107 goto finish; 1108 } 1109 1110 rv = meta_object_get_attr(gen_session, slot_key1->hObject, key1); 1111 if (rv != CKR_OK) { 1112 goto finish; 1113 } 1114 1115 if (key2) { 1116 rv = meta_object_get_attr(gen_session, slot_key2->hObject, 1117 key2); 1118 if (rv != CKR_OK) { 1119 goto finish; 1120 } 1121 } 1122 1123 /* Allow FreeToken to activate onto token obj list */ 1124 if (key1->isFreeToken == FREE_ENABLED) 1125 key1->isToken = B_TRUE; 1126 1127 meta_slot_object_activate(slot_key1, gen_session, key1->isToken); 1128 key1->clones[slotnum] = slot_key1; 1129 key1->master_clone_slotnum = slotnum; 1130 slot_key1 = NULL; 1131 if (key1->isFreeObject == FREE_ENABLED) { 1132 rv = meta_freeobject_clone(session, key1); 1133 if (rv != CKR_OK) 1134 goto finish; 1135 } 1136 1137 if (doKeyPair) { 1138 /* Allow FreeToken to activate onto token obj list */ 1139 if (key2->isFreeToken == FREE_ENABLED) 1140 key2->isToken = B_TRUE; 1141 1142 meta_slot_object_activate(slot_key2, gen_session, 1143 key2->isToken); 1144 key2->clones[slotnum] = slot_key2; 1145 key2->master_clone_slotnum = slotnum; 1146 slot_key2 = NULL; 1147 if (key2->isFreeObject == FREE_ENABLED) { 1148 rv = meta_freeobject_clone(session, key2); 1149 if (rv != CKR_OK) 1150 goto finish; 1151 } 1152 } 1153 1154 finish: 1155 if (slot_key1) { 1156 meta_slot_object_dealloc(slot_key1); 1157 } 1158 1159 if (slot_key2) { 1160 meta_slot_object_dealloc(slot_key2); 1161 } 1162 1163 /* Save the session in case it can be used later */ 1164 if (rv == CKR_OK) { 1165 /* 1166 * If currently stored session is not the one being in use now, 1167 * release the previous one and store the current one 1168 */ 1169 if ((session->op1.session) && 1170 (session->op1.session != gen_session)) { 1171 meta_release_slot_session(session->op1.session); 1172 } 1173 1174 /* Save the session */ 1175 session->op1.session = gen_session; 1176 } 1177 1178 return (rv); 1179 } 1180 1181 1182 /* 1183 * meta_wrap_key 1184 * 1185 */ 1186 CK_RV 1187 meta_wrap_key(meta_session_t *session, CK_MECHANISM *pMechanism, 1188 meta_object_t *wrappingkey, meta_object_t *inputkey, CK_BYTE *wrapped_key, 1189 CK_ULONG *wrapped_key_len) 1190 { 1191 CK_RV rv, save_rv; 1192 slot_session_t *wrap_session = NULL; 1193 slot_object_t *slot_wrappingkey, *slot_inputkey; 1194 mechinfo_t **slots = NULL; 1195 unsigned long i, slotCount = 0; 1196 CK_ULONG slotnum; 1197 CK_MECHANISM_INFO mech_info; 1198 1199 /* 1200 * If the key to be wrapped is a token object, 1201 * the operation can only be done in the token object slot. 1202 */ 1203 mech_info.flags = CKF_WRAP; 1204 rv = get_slotlist_for_mech(pMechanism->mechanism, 1205 &(session->mech_support_info), &slots, &slotCount, 1206 inputkey->isToken, &mech_info); 1207 1208 if (rv != CKR_OK) { 1209 return (rv); 1210 } 1211 1212 /* Attempt to wrap key on slots until one succeeds. */ 1213 for (i = 0; i < slotCount; i++) { 1214 1215 slotnum = slots[i]->slotnum; 1216 wrap_session = NULL; 1217 1218 if (session->op1.session != NULL) { 1219 if ((session->op1.session)->slotnum == slotnum) { 1220 wrap_session = session->op1.session; 1221 /* 1222 * set it to NULL for now, assign it to 1223 * wrap_session again if it is successful 1224 */ 1225 session->op1.session = NULL; 1226 } else { 1227 wrap_session = NULL; 1228 } 1229 } 1230 1231 if (wrap_session == NULL) { 1232 rv = meta_get_slot_session(slotnum, &wrap_session, 1233 session->session_flags); 1234 if (rv != CKR_OK) { 1235 goto loop_cleanup; 1236 } 1237 } 1238 1239 rv = meta_object_get_clone(wrappingkey, slotnum, 1240 wrap_session, &slot_wrappingkey); 1241 if (rv != CKR_OK) 1242 goto loop_cleanup; 1243 1244 rv = meta_object_get_clone(inputkey, slotnum, 1245 wrap_session, &slot_inputkey); 1246 if (rv != CKR_OK) 1247 goto loop_cleanup; 1248 1249 rv = FUNCLIST(wrap_session->fw_st_id)->C_WrapKey( 1250 wrap_session->hSession, pMechanism, 1251 slot_wrappingkey->hObject, slot_inputkey->hObject, 1252 wrapped_key, wrapped_key_len); 1253 1254 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) 1255 break; 1256 1257 loop_cleanup: 1258 if (i == 0) { 1259 save_rv = rv; 1260 } 1261 1262 if (wrap_session) { 1263 meta_release_slot_session(wrap_session); 1264 wrap_session = NULL; 1265 } 1266 } 1267 if (rv != CKR_OK) { 1268 if (rv != CKR_BUFFER_TOO_SMALL) { 1269 if (i == slotCount) { 1270 rv = save_rv; 1271 } 1272 } 1273 } 1274 1275 finish: 1276 /* Save the session in case it can be used later */ 1277 if (rv == CKR_OK) { 1278 /* 1279 * If currently stored session is not the one being in use now, 1280 * release the previous one and store the current one 1281 */ 1282 if ((session->op1.session) && 1283 (session->op1.session != wrap_session)) { 1284 meta_release_slot_session(session->op1.session); 1285 } 1286 1287 /* Save the session */ 1288 session->op1.session = wrap_session; 1289 } 1290 return (rv); 1291 } 1292 1293 1294 1295 /* 1296 * meta_unwrap_key 1297 * 1298 */ 1299 CK_RV 1300 meta_unwrap_key(meta_session_t *session, 1301 CK_MECHANISM *pMechanism, meta_object_t *unwrapping_key, 1302 CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len, 1303 CK_ATTRIBUTE *template, CK_ULONG template_size, 1304 meta_object_t *unwrapped_key) 1305 { 1306 CK_RV rv, save_rv; 1307 CK_OBJECT_HANDLE hUnwrappedKey; 1308 slot_session_t *unwrap_session = NULL; 1309 slot_object_t *slot_unwrappingkey, *slot_unwrapped_key; 1310 mechinfo_t **slots = NULL; 1311 unsigned long i, slotCount = 0; 1312 CK_ULONG slotnum; 1313 CK_MECHANISM_INFO mech_info; 1314 1315 /* Can't create token objects in a read-only session. */ 1316 if ((IS_READ_ONLY_SESSION(session->session_flags)) && 1317 unwrapped_key->isToken) { 1318 return (CKR_SESSION_READ_ONLY); 1319 } 1320 1321 /* 1322 * If the the resulting unwrapped key 1323 * needs to be a token object, the operation can only 1324 * be performed in the token slot, if it is supported. 1325 */ 1326 mech_info.flags = CKF_UNWRAP; 1327 rv = get_slotlist_for_mech(pMechanism->mechanism, 1328 &(session->mech_support_info), &slots, &slotCount, 1329 unwrapped_key->isToken, &mech_info); 1330 1331 if (rv != CKR_OK) { 1332 return (rv); 1333 } 1334 1335 rv = meta_slot_object_alloc(&slot_unwrapped_key); 1336 if (rv != CKR_OK) { 1337 goto finish; 1338 } 1339 1340 /* Attempt to unwrap key on slots until one succeeds. */ 1341 for (i = 0; i < slotCount; i++) { 1342 1343 slotnum = slots[i]->slotnum; 1344 unwrap_session = NULL; 1345 1346 if (session->op1.session != NULL) { 1347 if ((session->op1.session)->slotnum == slotnum) { 1348 unwrap_session = session->op1.session; 1349 /* 1350 * set it to NULL for now, assign it to 1351 * unwrap_session again if it is successful 1352 */ 1353 session->op1.session = NULL; 1354 } else { 1355 unwrap_session = NULL; 1356 } 1357 } 1358 1359 if (unwrap_session == NULL) { 1360 rv = meta_get_slot_session(slotnum, &unwrap_session, 1361 session->session_flags); 1362 if (rv != CKR_OK) { 1363 goto loop_cleanup; 1364 } 1365 } 1366 1367 rv = meta_object_get_clone(unwrapping_key, slotnum, 1368 unwrap_session, &slot_unwrappingkey); 1369 if (rv != CKR_OK) 1370 goto loop_cleanup; 1371 1372 rv = FUNCLIST(unwrap_session->fw_st_id)->C_UnwrapKey( 1373 unwrap_session->hSession, pMechanism, 1374 slot_unwrappingkey->hObject, wrapped_key, wrapped_key_len, 1375 template, template_size, &hUnwrappedKey); 1376 1377 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) 1378 break; 1379 loop_cleanup: 1380 if (i == 0) { 1381 save_rv = rv; 1382 } 1383 1384 if (unwrap_session) { 1385 meta_release_slot_session(unwrap_session); 1386 unwrap_session = NULL; 1387 } 1388 } 1389 1390 1391 if (rv != CKR_OK) { 1392 if (rv != CKR_BUFFER_TOO_SMALL) { 1393 rv = save_rv; 1394 } 1395 goto finish; 1396 } 1397 1398 1399 slot_unwrapped_key->hObject = hUnwrappedKey; 1400 unwrapped_key->clones[slotnum] = slot_unwrapped_key; 1401 unwrapped_key->master_clone_slotnum = slotnum; 1402 rv = meta_object_get_attr(unwrap_session, 1403 slot_unwrapped_key->hObject, unwrapped_key); 1404 if (rv != CKR_OK) { 1405 goto finish; 1406 } 1407 meta_slot_object_activate(slot_unwrapped_key, unwrap_session, 1408 unwrapped_key->isToken); 1409 slot_unwrapped_key = NULL; 1410 1411 finish: 1412 if (slot_unwrapped_key) { 1413 meta_slot_object_dealloc(slot_unwrapped_key); 1414 } 1415 1416 /* Save the session in case it can be used later */ 1417 if (rv == CKR_OK) { 1418 /* 1419 * If currently stored session is not the one being in use now, 1420 * release the previous one and store the current one 1421 */ 1422 if ((session->op1.session) && 1423 (session->op1.session != unwrap_session)) { 1424 meta_release_slot_session(session->op1.session); 1425 } 1426 1427 /* Save the session */ 1428 session->op1.session = unwrap_session; 1429 } 1430 1431 return (rv); 1432 } 1433 1434 1435 /* 1436 * meta_derive_key 1437 * 1438 * Core implementation for C_DeriveKey. This function is a bit gross because 1439 * of PKCS#11 kludges that pass extra object handles in the mechanism 1440 * parameters. Normally C_DeriveKey takes a single existing key as input, 1441 * and creates a single new key as output. But a few mechanisms take 2 keys 1442 * as input, and the two SSL/TLS mechanisms create 4 keys as output. 1443 * 1444 * When an extra input key (basekey2) is set, we set *phBaseKey2 to the clone's 1445 * object handle. phBaseKey2 is provided by the caller so we don't have to 1446 * trudge down into different mechanism parameters to set it when issuing the 1447 * operation. 1448 * 1449 * For the SSL/TLS mechanisms, newKey2/newKey3/newKey4 will be set. We pull 1450 * the new handles from pMech->pParameter in order to fill in the appropriate 1451 * meta_object fields. 1452 */ 1453 CK_RV 1454 meta_derive_key(meta_session_t *session, CK_MECHANISM *pMechanism, 1455 meta_object_t *basekey1, meta_object_t *basekey2, 1456 CK_OBJECT_HANDLE *phBaseKey2, 1457 CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, 1458 meta_object_t *newKey1, meta_object_t *newKey2, 1459 meta_object_t *newKey3, meta_object_t *newKey4) 1460 { 1461 CK_RV rv, save_rv; 1462 CK_OBJECT_HANDLE hDerivedKey; 1463 1464 CK_ULONG slotnum; 1465 boolean_t isSSL = B_FALSE; 1466 boolean_t isTLSPRF = B_FALSE; 1467 mechinfo_t **slots = NULL; 1468 unsigned long i, slot_count = 0; 1469 slot_session_t *derive_session = NULL; 1470 slot_object_t *slot_basekey1 = NULL, *slot_basekey2 = NULL; 1471 slot_object_t *slotkey1 = NULL, *slotkey2 = NULL, *slotkey3 = NULL, 1472 *slotkey4 = NULL; 1473 CK_MECHANISM_INFO mech_info; 1474 CK_BBOOL current_token_value = FALSE; 1475 1476 /* 1477 * if the derived key needs to be a token object, can only 1478 * perform the derive operation in the token slot 1479 */ 1480 (void) get_template_boolean(CKA_TOKEN, pTemplate, ulAttributeCount, 1481 &(newKey1->isToken)); 1482 (void) get_template_boolean(CKA_PRIVATE, pTemplate, ulAttributeCount, 1483 &(newKey1->isPrivate)); 1484 (void) get_template_boolean(CKA_SENSITIVE, pTemplate, ulAttributeCount, 1485 &(newKey1->isSensitive)); 1486 1487 if (newKey1->isToken) 1488 current_token_value = TRUE; 1489 1490 /* Can't create token objects in a read-only session. */ 1491 if ((IS_READ_ONLY_SESSION(session->session_flags)) && 1492 newKey1->isToken) { 1493 rv = CKR_SESSION_READ_ONLY; 1494 goto finish; 1495 } 1496 1497 if (meta_freeobject_check(session, newKey1, pMechanism, pTemplate, 1498 ulAttributeCount, 0)) { 1499 1500 if (newKey1->isPrivate && !metaslot_logged_in()) 1501 return (CKR_USER_NOT_LOGGED_IN); 1502 1503 if (!meta_freeobject_set(newKey1, pTemplate, ulAttributeCount, 1504 B_FALSE)) 1505 return (CKR_FUNCTION_FAILED); 1506 } 1507 1508 mech_info.flags = CKF_DERIVE; 1509 rv = get_slotlist_for_mech(pMechanism->mechanism, 1510 &(session->mech_support_info), &slots, &slot_count, 1511 newKey1->isToken, &mech_info); 1512 1513 if (rv != CKR_OK) { 1514 return (rv); 1515 } 1516 1517 if (pMechanism->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE || 1518 pMechanism->mechanism == CKM_TLS_KEY_AND_MAC_DERIVE) 1519 isSSL = B_TRUE; 1520 1521 else if (pMechanism->mechanism == CKM_TLS_PRF) 1522 isTLSPRF = B_TRUE; 1523 1524 rv = meta_slot_object_alloc(&slotkey1); 1525 if (isSSL) { 1526 if (rv == CKR_OK) 1527 rv = meta_slot_object_alloc(&slotkey2); 1528 if (rv == CKR_OK) 1529 rv = meta_slot_object_alloc(&slotkey3); 1530 if (rv == CKR_OK) 1531 rv = meta_slot_object_alloc(&slotkey4); 1532 } 1533 if (rv != CKR_OK) { 1534 goto finish; 1535 } 1536 1537 for (i = 0; i < slot_count; i++) { 1538 slotnum = slots[i]->slotnum; 1539 1540 derive_session = NULL; 1541 1542 if (session->op1.session != NULL) { 1543 if ((session->op1.session)->slotnum == slotnum) { 1544 derive_session = session->op1.session; 1545 /* 1546 * set it to NULL for now, assign it to 1547 * derive_session again if it is successful 1548 */ 1549 session->op1.session = NULL; 1550 } else { 1551 derive_session = NULL; 1552 } 1553 } 1554 1555 if (derive_session == NULL) { 1556 rv = meta_get_slot_session(slotnum, &derive_session, 1557 session->session_flags); 1558 if (rv != CKR_OK) { 1559 goto loop_cleanup; 1560 } 1561 } 1562 1563 rv = meta_object_get_clone(basekey1, slotnum, 1564 derive_session, &slot_basekey1); 1565 if (rv != CKR_OK) 1566 goto loop_cleanup; 1567 1568 if (basekey2) { 1569 rv = meta_object_get_clone(basekey2, slotnum, 1570 derive_session, &slot_basekey2); 1571 if (rv != CKR_OK) 1572 goto loop_cleanup; 1573 1574 /* Pass the handle somewhere in the mech params. */ 1575 *phBaseKey2 = slot_basekey2->hObject; 1576 } 1577 1578 if (newKey1->isFreeToken == FREE_ENABLED) { 1579 rv = meta_freetoken_set(slotnum, ¤t_token_value, 1580 pTemplate, ulAttributeCount); 1581 if (rv != CKR_OK) 1582 goto loop_cleanup; 1583 } 1584 1585 rv = FUNCLIST(derive_session->fw_st_id)->C_DeriveKey( 1586 derive_session->hSession, pMechanism, 1587 slot_basekey1->hObject, pTemplate, ulAttributeCount, 1588 (isSSL || isTLSPRF) ? NULL : &hDerivedKey); 1589 1590 if (rv == CKR_OK) 1591 break; 1592 loop_cleanup: 1593 if (i == 0) { 1594 save_rv = rv; 1595 } 1596 1597 if (derive_session) { 1598 meta_release_slot_session(derive_session); 1599 derive_session = NULL; 1600 } 1601 /* No need to cleanup clones, so we can reuse them later. */ 1602 } 1603 1604 if (rv != CKR_OK) { 1605 rv = save_rv; 1606 goto finish; 1607 } 1608 1609 if (isTLSPRF) 1610 goto finish; 1611 1612 /* 1613 * These SSL/TLS are unique in that the parameter in the API for 1614 * the new key is unused (NULL). Instead, there are 4 keys which 1615 * are derived, and are passed back through the mechanism params. 1616 * Both mechs use the same mechanism parameter type. 1617 */ 1618 if (isSSL) { 1619 CK_SSL3_KEY_MAT_PARAMS *keyparams; 1620 CK_SSL3_KEY_MAT_OUT *keys; 1621 1622 /* NULL checks already done by caller */ 1623 keyparams = (CK_SSL3_KEY_MAT_PARAMS*)pMechanism->pParameter; 1624 keys = keyparams->pReturnedKeyMaterial; 1625 1626 slotkey1->hObject = keys->hClientMacSecret; 1627 slotkey2->hObject = keys->hServerMacSecret; 1628 slotkey3->hObject = keys->hClientKey; 1629 slotkey4->hObject = keys->hServerKey; 1630 1631 rv = meta_object_get_attr(derive_session, 1632 slotkey1->hObject, newKey1); 1633 if (rv != CKR_OK) { 1634 goto finish; 1635 } 1636 1637 rv = meta_object_get_attr(derive_session, 1638 slotkey2->hObject, newKey2); 1639 if (rv != CKR_OK) { 1640 goto finish; 1641 } 1642 1643 rv = meta_object_get_attr(derive_session, 1644 slotkey3->hObject, newKey3); 1645 if (rv != CKR_OK) { 1646 goto finish; 1647 } 1648 1649 rv = meta_object_get_attr(derive_session, 1650 slotkey4->hObject, newKey4); 1651 if (rv != CKR_OK) { 1652 goto finish; 1653 } 1654 1655 newKey1->clones[slotnum] = slotkey1; 1656 newKey2->clones[slotnum] = slotkey2; 1657 newKey3->clones[slotnum] = slotkey3; 1658 newKey4->clones[slotnum] = slotkey4; 1659 1660 newKey1->master_clone_slotnum = slotnum; 1661 newKey2->master_clone_slotnum = slotnum; 1662 newKey3->master_clone_slotnum = slotnum; 1663 newKey4->master_clone_slotnum = slotnum; 1664 1665 meta_slot_object_activate(slotkey1, derive_session, 1666 newKey1->isToken); 1667 slotkey1 = NULL; 1668 meta_slot_object_activate(slotkey2, derive_session, 1669 newKey2->isToken); 1670 slotkey2 = NULL; 1671 meta_slot_object_activate(slotkey3, derive_session, 1672 newKey3->isToken); 1673 slotkey3 = NULL; 1674 meta_slot_object_activate(slotkey4, derive_session, 1675 newKey4->isToken); 1676 slotkey4 = NULL; 1677 1678 } else { 1679 slotkey1->hObject = hDerivedKey; 1680 newKey1->clones[slotnum] = slotkey1; 1681 newKey1->master_clone_slotnum = slotnum; 1682 1683 rv = meta_object_get_attr(derive_session, 1684 slotkey1->hObject, newKey1); 1685 if (rv != CKR_OK) { 1686 goto finish; 1687 } 1688 1689 /* Allow FreeToken to activate onto token obj list */ 1690 if (newKey1->isFreeToken == FREE_ENABLED) 1691 newKey1->isToken = B_TRUE; 1692 1693 meta_slot_object_activate(slotkey1, derive_session, 1694 newKey1->isToken); 1695 slotkey1 = NULL; 1696 } 1697 1698 if (newKey1->isFreeObject == FREE_ENABLED) 1699 (void) meta_freeobject_clone(session, newKey1); 1700 1701 1702 finish: 1703 if (slotkey1) { 1704 meta_slot_object_dealloc(slotkey1); 1705 } 1706 if (slotkey2) { 1707 meta_slot_object_dealloc(slotkey2); 1708 } 1709 if (slotkey3) { 1710 meta_slot_object_dealloc(slotkey3); 1711 } 1712 if (slotkey4) { 1713 meta_slot_object_dealloc(slotkey4); 1714 } 1715 1716 /* Save the session in case it can be used later */ 1717 if (rv == CKR_OK) { 1718 /* 1719 * If currently stored session is not the one being in use now, 1720 * release the previous one and store the current one 1721 */ 1722 if ((session->op1.session) && 1723 (session->op1.session != derive_session)) { 1724 meta_release_slot_session(session->op1.session); 1725 } 1726 1727 /* Save the session */ 1728 session->op1.session = derive_session; 1729 } 1730 1731 return (rv); 1732 } 1733 1734 1735 /* 1736 * Check the following 4 environment variables for user/application's 1737 * configuration for metaslot. User's configuration takes precedence 1738 * over the system wide configuration for metaslot 1739 * 1740 * ${METASLOT_ENABLED} 1741 * ${METASLOT_OBJECTSTORE_SLOT} 1742 * ${METASLOT_OBJECTSTORE_TOKEN} 1743 * ${METASLOT_AUTO_KEY_MIGRATE} 1744 * 1745 * ${_METASLOT_ENABLE_THRESHOLD} - private environmental variable to 1746 * enable the treshold checking which is disabled by default. 1747 * 1748 * values defined in these environment variables will be stored in the 1749 * global variable "metaslot_config". Variable threshold_chk_disabled is an 1750 * exception. 1751 */ 1752 void 1753 get_user_metaslot_config() 1754 { 1755 char *env_val = NULL; 1756 1757 /* 1758 * Check to see if any environment variable is defined 1759 * by the user for configuring metaslot. 1760 */ 1761 bzero(&metaslot_config, sizeof (metaslot_config)); 1762 1763 /* METASLOT_ENABLED */ 1764 env_val = getenv("METASLOT_ENABLED"); 1765 if (env_val) { 1766 metaslot_config.enabled_specified = B_TRUE; 1767 if (strcasecmp(env_val, TRUE_STRING) == 0) { 1768 metaslot_config.enabled = B_TRUE; 1769 } else if (strcasecmp(env_val, FALSE_STRING) == 0) { 1770 metaslot_config.enabled = B_FALSE; 1771 } else { 1772 /* value is neither 1 or 0, ignore this value */ 1773 metaslot_config.enabled_specified = B_FALSE; 1774 } 1775 } 1776 1777 /* METASLOT_AUTO_KEY_MIGRATE */ 1778 env_val = getenv("METASLOT_AUTO_KEY_MIGRATE"); 1779 if (env_val) { 1780 metaslot_config.auto_key_migrate_specified = B_TRUE; 1781 if (strcasecmp(env_val, TRUE_STRING) == 0) { 1782 metaslot_config.auto_key_migrate = B_TRUE; 1783 } else if (strcasecmp(env_val, FALSE_STRING) == 0) { 1784 metaslot_config.auto_key_migrate = B_FALSE; 1785 } else { 1786 /* value is neither 1 or 0, ignore this value */ 1787 metaslot_config.auto_key_migrate_specified = B_FALSE; 1788 } 1789 } 1790 1791 /* METASLOT_OBJECTSTORE_SLOT */ 1792 env_val = getenv("METASLOT_OBJECTSTORE_SLOT"); 1793 if (env_val) { 1794 metaslot_config.keystore_slot_specified = B_TRUE; 1795 (void) strlcpy((char *)metaslot_config.keystore_slot, env_val, 1796 SLOT_DESCRIPTION_SIZE); 1797 } 1798 1799 /* METASLOT_OBJECTSTORE_TOKEN */ 1800 env_val = getenv("METASLOT_OBJECTSTORE_TOKEN"); 1801 if (env_val) { 1802 metaslot_config.keystore_token_specified = B_TRUE; 1803 (void) strlcpy((char *)metaslot_config.keystore_token, env_val, 1804 TOKEN_LABEL_SIZE); 1805 } 1806 1807 /* _METASLOT_ENABLE_THRESHOLD */ 1808 env_val = getenv("_METASLOT_ENABLE_THRESHOLD"); 1809 if (env_val) { 1810 threshold_chk_enabled = B_TRUE; 1811 } 1812 } 1813