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 2008 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, NULL)) { 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 meta_slot_object_activate(slot_key1, gen_session, key1->isToken); 1124 key1->clones[slotnum] = slot_key1; 1125 key1->master_clone_slotnum = slotnum; 1126 slot_key1 = NULL; 1127 if (key1->isFreeObject == FREE_ENABLED) { 1128 rv = meta_freeobject_clone(session, key1); 1129 if (rv != CKR_OK) 1130 goto finish; 1131 } 1132 1133 if (doKeyPair) { 1134 meta_slot_object_activate(slot_key2, gen_session, 1135 key2->isToken); 1136 key2->clones[slotnum] = slot_key2; 1137 key2->master_clone_slotnum = slotnum; 1138 slot_key2 = NULL; 1139 if (key2->isFreeObject == FREE_ENABLED) { 1140 rv = meta_freeobject_clone(session, key2); 1141 if (rv != CKR_OK) 1142 goto finish; 1143 } 1144 } 1145 1146 finish: 1147 if (slot_key1) { 1148 meta_slot_object_dealloc(slot_key1); 1149 } 1150 1151 if (slot_key2) { 1152 meta_slot_object_dealloc(slot_key2); 1153 } 1154 1155 /* Save the session in case it can be used later */ 1156 if (rv == CKR_OK) { 1157 /* 1158 * If currently stored session is not the one being in use now, 1159 * release the previous one and store the current one 1160 */ 1161 if ((session->op1.session) && 1162 (session->op1.session != gen_session)) { 1163 meta_release_slot_session(session->op1.session); 1164 } 1165 1166 /* Save the session */ 1167 session->op1.session = gen_session; 1168 } 1169 1170 return (rv); 1171 } 1172 1173 1174 /* 1175 * meta_wrap_key 1176 * 1177 */ 1178 CK_RV 1179 meta_wrap_key(meta_session_t *session, CK_MECHANISM *pMechanism, 1180 meta_object_t *wrappingkey, meta_object_t *inputkey, CK_BYTE *wrapped_key, 1181 CK_ULONG *wrapped_key_len) 1182 { 1183 CK_RV rv, save_rv; 1184 slot_session_t *wrap_session = NULL; 1185 slot_object_t *slot_wrappingkey, *slot_inputkey; 1186 mechinfo_t **slots = NULL; 1187 unsigned long i, slotCount = 0; 1188 CK_ULONG slotnum; 1189 CK_MECHANISM_INFO mech_info; 1190 1191 /* 1192 * If the key to be wrapped is a token object, 1193 * the operation can only be done in the token object slot. 1194 */ 1195 mech_info.flags = CKF_WRAP; 1196 rv = get_slotlist_for_mech(pMechanism->mechanism, 1197 &(session->mech_support_info), &slots, &slotCount, 1198 inputkey->isToken, &mech_info); 1199 1200 if (rv != CKR_OK) { 1201 return (rv); 1202 } 1203 1204 /* Attempt to wrap key on slots until one succeeds. */ 1205 for (i = 0; i < slotCount; i++) { 1206 1207 slotnum = slots[i]->slotnum; 1208 wrap_session = NULL; 1209 1210 if (session->op1.session != NULL) { 1211 if ((session->op1.session)->slotnum == slotnum) { 1212 wrap_session = session->op1.session; 1213 /* 1214 * set it to NULL for now, assign it to 1215 * wrap_session again if it is successful 1216 */ 1217 session->op1.session = NULL; 1218 } else { 1219 wrap_session = NULL; 1220 } 1221 } 1222 1223 if (wrap_session == NULL) { 1224 rv = meta_get_slot_session(slotnum, &wrap_session, 1225 session->session_flags); 1226 if (rv != CKR_OK) { 1227 goto loop_cleanup; 1228 } 1229 } 1230 1231 rv = meta_object_get_clone(wrappingkey, slotnum, 1232 wrap_session, &slot_wrappingkey); 1233 if (rv != CKR_OK) 1234 goto loop_cleanup; 1235 1236 rv = meta_object_get_clone(inputkey, slotnum, 1237 wrap_session, &slot_inputkey); 1238 if (rv != CKR_OK) 1239 goto loop_cleanup; 1240 1241 rv = FUNCLIST(wrap_session->fw_st_id)->C_WrapKey( 1242 wrap_session->hSession, pMechanism, 1243 slot_wrappingkey->hObject, slot_inputkey->hObject, 1244 wrapped_key, wrapped_key_len); 1245 1246 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) 1247 break; 1248 1249 loop_cleanup: 1250 if (i == 0) { 1251 save_rv = rv; 1252 } 1253 1254 if (wrap_session) { 1255 meta_release_slot_session(wrap_session); 1256 wrap_session = NULL; 1257 } 1258 } 1259 if (rv != CKR_OK) { 1260 if (rv != CKR_BUFFER_TOO_SMALL) { 1261 if (i == slotCount) { 1262 rv = save_rv; 1263 } 1264 } 1265 } 1266 1267 finish: 1268 /* Save the session in case it can be used later */ 1269 if (rv == CKR_OK) { 1270 /* 1271 * If currently stored session is not the one being in use now, 1272 * release the previous one and store the current one 1273 */ 1274 if ((session->op1.session) && 1275 (session->op1.session != wrap_session)) { 1276 meta_release_slot_session(session->op1.session); 1277 } 1278 1279 /* Save the session */ 1280 session->op1.session = wrap_session; 1281 } 1282 return (rv); 1283 } 1284 1285 1286 1287 /* 1288 * meta_unwrap_key 1289 * 1290 */ 1291 CK_RV 1292 meta_unwrap_key(meta_session_t *session, 1293 CK_MECHANISM *pMechanism, meta_object_t *unwrapping_key, 1294 CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len, 1295 CK_ATTRIBUTE *template, CK_ULONG template_size, 1296 meta_object_t *unwrapped_key) 1297 { 1298 CK_RV rv, save_rv; 1299 CK_OBJECT_HANDLE hUnwrappedKey; 1300 slot_session_t *unwrap_session = NULL; 1301 slot_object_t *slot_unwrappingkey, *slot_unwrapped_key; 1302 mechinfo_t **slots = NULL; 1303 unsigned long i, slotCount = 0; 1304 CK_ULONG slotnum; 1305 CK_MECHANISM_INFO mech_info; 1306 1307 /* Can't create token objects in a read-only session. */ 1308 if ((IS_READ_ONLY_SESSION(session->session_flags)) && 1309 unwrapped_key->isToken) { 1310 return (CKR_SESSION_READ_ONLY); 1311 } 1312 1313 /* 1314 * If the the resulting unwrapped key 1315 * needs to be a token object, the operation can only 1316 * be performed in the token slot, if it is supported. 1317 */ 1318 mech_info.flags = CKF_UNWRAP; 1319 rv = get_slotlist_for_mech(pMechanism->mechanism, 1320 &(session->mech_support_info), &slots, &slotCount, 1321 unwrapped_key->isToken, &mech_info); 1322 1323 if (rv != CKR_OK) { 1324 return (rv); 1325 } 1326 1327 rv = meta_slot_object_alloc(&slot_unwrapped_key); 1328 if (rv != CKR_OK) { 1329 goto finish; 1330 } 1331 1332 /* Attempt to unwrap key on slots until one succeeds. */ 1333 for (i = 0; i < slotCount; i++) { 1334 1335 slotnum = slots[i]->slotnum; 1336 unwrap_session = NULL; 1337 1338 if (session->op1.session != NULL) { 1339 if ((session->op1.session)->slotnum == slotnum) { 1340 unwrap_session = session->op1.session; 1341 /* 1342 * set it to NULL for now, assign it to 1343 * unwrap_session again if it is successful 1344 */ 1345 session->op1.session = NULL; 1346 } else { 1347 unwrap_session = NULL; 1348 } 1349 } 1350 1351 if (unwrap_session == NULL) { 1352 rv = meta_get_slot_session(slotnum, &unwrap_session, 1353 session->session_flags); 1354 if (rv != CKR_OK) { 1355 goto loop_cleanup; 1356 } 1357 } 1358 1359 rv = meta_object_get_clone(unwrapping_key, slotnum, 1360 unwrap_session, &slot_unwrappingkey); 1361 if (rv != CKR_OK) 1362 goto loop_cleanup; 1363 1364 rv = FUNCLIST(unwrap_session->fw_st_id)->C_UnwrapKey( 1365 unwrap_session->hSession, pMechanism, 1366 slot_unwrappingkey->hObject, wrapped_key, wrapped_key_len, 1367 template, template_size, &hUnwrappedKey); 1368 1369 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) 1370 break; 1371 loop_cleanup: 1372 if (i == 0) { 1373 save_rv = rv; 1374 } 1375 1376 if (unwrap_session) { 1377 meta_release_slot_session(unwrap_session); 1378 unwrap_session = NULL; 1379 } 1380 } 1381 1382 1383 if (rv != CKR_OK) { 1384 if (rv != CKR_BUFFER_TOO_SMALL) { 1385 rv = save_rv; 1386 } 1387 goto finish; 1388 } 1389 1390 1391 slot_unwrapped_key->hObject = hUnwrappedKey; 1392 unwrapped_key->clones[slotnum] = slot_unwrapped_key; 1393 unwrapped_key->master_clone_slotnum = slotnum; 1394 rv = meta_object_get_attr(unwrap_session, 1395 slot_unwrapped_key->hObject, unwrapped_key); 1396 if (rv != CKR_OK) { 1397 goto finish; 1398 } 1399 meta_slot_object_activate(slot_unwrapped_key, unwrap_session, 1400 unwrapped_key->isToken); 1401 slot_unwrapped_key = NULL; 1402 1403 finish: 1404 if (slot_unwrapped_key) { 1405 meta_slot_object_dealloc(slot_unwrapped_key); 1406 } 1407 1408 /* Save the session in case it can be used later */ 1409 if (rv == CKR_OK) { 1410 /* 1411 * If currently stored session is not the one being in use now, 1412 * release the previous one and store the current one 1413 */ 1414 if ((session->op1.session) && 1415 (session->op1.session != unwrap_session)) { 1416 meta_release_slot_session(session->op1.session); 1417 } 1418 1419 /* Save the session */ 1420 session->op1.session = unwrap_session; 1421 } 1422 1423 return (rv); 1424 } 1425 1426 1427 /* 1428 * meta_derive_key 1429 * 1430 * Core implementation for C_DeriveKey. This function is a bit gross because 1431 * of PKCS#11 kludges that pass extra object handles in the mechanism 1432 * parameters. Normally C_DeriveKey takes a single existing key as input, 1433 * and creates a single new key as output. But a few mechanisms take 2 keys 1434 * as input, and the two SSL/TLS mechanisms create 4 keys as output. 1435 * 1436 * When an extra input key (basekey2) is set, we set *phBaseKey2 to the clone's 1437 * object handle. phBaseKey2 is provided by the caller so we don't have to 1438 * trudge down into different mechanism parameters to set it when issuing the 1439 * operation. 1440 * 1441 * For the SSL/TLS mechanisms, newKey2/newKey3/newKey4 will be set. We pull 1442 * the new handles from pMech->pParameter in order to fill in the appropriate 1443 * meta_object fields. 1444 */ 1445 CK_RV 1446 meta_derive_key(meta_session_t *session, CK_MECHANISM *pMechanism, 1447 meta_object_t *basekey1, meta_object_t *basekey2, 1448 CK_OBJECT_HANDLE *phBaseKey2, 1449 CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, 1450 meta_object_t *newKey1, meta_object_t *newKey2, 1451 meta_object_t *newKey3, meta_object_t *newKey4) 1452 { 1453 CK_RV rv, save_rv; 1454 CK_OBJECT_HANDLE hDerivedKey; 1455 1456 CK_ULONG slotnum; 1457 boolean_t isSSL = B_FALSE; 1458 boolean_t isTLSPRF = B_FALSE; 1459 mechinfo_t **slots = NULL; 1460 unsigned long i, slot_count = 0; 1461 slot_session_t *derive_session = NULL; 1462 slot_object_t *slot_basekey1 = NULL, *slot_basekey2 = NULL; 1463 slot_object_t *slotkey1 = NULL, *slotkey2 = NULL, *slotkey3 = NULL, 1464 *slotkey4 = NULL; 1465 CK_MECHANISM_INFO mech_info; 1466 CK_BBOOL current_token_value = FALSE; 1467 1468 /* 1469 * if the derived key needs to be a token object, can only 1470 * perform the derive operation in the token slot 1471 */ 1472 (void) get_template_boolean(CKA_TOKEN, pTemplate, ulAttributeCount, 1473 &(newKey1->isToken)); 1474 (void) get_template_boolean(CKA_PRIVATE, pTemplate, ulAttributeCount, 1475 &(newKey1->isPrivate)); 1476 (void) get_template_boolean(CKA_SENSITIVE, pTemplate, ulAttributeCount, 1477 &(newKey1->isSensitive)); 1478 1479 if (newKey1->isToken) 1480 current_token_value = TRUE; 1481 1482 /* Can't create token objects in a read-only session. */ 1483 if ((IS_READ_ONLY_SESSION(session->session_flags)) && 1484 newKey1->isToken) { 1485 rv = CKR_SESSION_READ_ONLY; 1486 goto finish; 1487 } 1488 1489 if (meta_freeobject_check(session, newKey1, pMechanism, pTemplate, 1490 ulAttributeCount, NULL)) { 1491 1492 if (newKey1->isPrivate && !metaslot_logged_in()) 1493 return (CKR_USER_NOT_LOGGED_IN); 1494 1495 if (!meta_freeobject_set(newKey1, pTemplate, ulAttributeCount, 1496 B_FALSE)) 1497 return (CKR_FUNCTION_FAILED); 1498 } 1499 1500 mech_info.flags = CKF_DERIVE; 1501 rv = get_slotlist_for_mech(pMechanism->mechanism, 1502 &(session->mech_support_info), &slots, &slot_count, 1503 newKey1->isToken, &mech_info); 1504 1505 if (rv != CKR_OK) { 1506 return (rv); 1507 } 1508 1509 if (pMechanism->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE || 1510 pMechanism->mechanism == CKM_TLS_KEY_AND_MAC_DERIVE) 1511 isSSL = B_TRUE; 1512 1513 else if (pMechanism->mechanism == CKM_TLS_PRF) 1514 isTLSPRF = B_TRUE; 1515 1516 rv = meta_slot_object_alloc(&slotkey1); 1517 if (isSSL) { 1518 if (rv == CKR_OK) 1519 rv = meta_slot_object_alloc(&slotkey2); 1520 if (rv == CKR_OK) 1521 rv = meta_slot_object_alloc(&slotkey3); 1522 if (rv == CKR_OK) 1523 rv = meta_slot_object_alloc(&slotkey4); 1524 } 1525 if (rv != CKR_OK) { 1526 goto finish; 1527 } 1528 1529 for (i = 0; i < slot_count; i++) { 1530 slotnum = slots[i]->slotnum; 1531 1532 derive_session = NULL; 1533 1534 if (session->op1.session != NULL) { 1535 if ((session->op1.session)->slotnum == slotnum) { 1536 derive_session = session->op1.session; 1537 /* 1538 * set it to NULL for now, assign it to 1539 * derive_session again if it is successful 1540 */ 1541 session->op1.session = NULL; 1542 } else { 1543 derive_session = NULL; 1544 } 1545 } 1546 1547 if (derive_session == NULL) { 1548 rv = meta_get_slot_session(slotnum, &derive_session, 1549 session->session_flags); 1550 if (rv != CKR_OK) { 1551 goto loop_cleanup; 1552 } 1553 } 1554 1555 rv = meta_object_get_clone(basekey1, slotnum, 1556 derive_session, &slot_basekey1); 1557 if (rv != CKR_OK) 1558 goto loop_cleanup; 1559 1560 if (basekey2) { 1561 rv = meta_object_get_clone(basekey2, slotnum, 1562 derive_session, &slot_basekey2); 1563 if (rv != CKR_OK) 1564 goto loop_cleanup; 1565 1566 /* Pass the handle somewhere in the mech params. */ 1567 *phBaseKey2 = slot_basekey2->hObject; 1568 } 1569 1570 if (newKey1->isFreeToken == FREE_ENABLED) { 1571 rv = meta_freetoken_set(slotnum, ¤t_token_value, 1572 pTemplate, ulAttributeCount); 1573 if (rv != CKR_OK) 1574 goto loop_cleanup; 1575 } 1576 1577 rv = FUNCLIST(derive_session->fw_st_id)->C_DeriveKey( 1578 derive_session->hSession, pMechanism, 1579 slot_basekey1->hObject, pTemplate, ulAttributeCount, 1580 (isSSL || isTLSPRF) ? NULL : &hDerivedKey); 1581 1582 if (rv == CKR_OK) 1583 break; 1584 loop_cleanup: 1585 if (i == 0) { 1586 save_rv = rv; 1587 } 1588 1589 if (derive_session) { 1590 meta_release_slot_session(derive_session); 1591 derive_session = NULL; 1592 } 1593 /* No need to cleanup clones, so we can reuse them later. */ 1594 } 1595 1596 if (rv != CKR_OK) { 1597 rv = save_rv; 1598 goto finish; 1599 } 1600 1601 if (isTLSPRF) 1602 goto finish; 1603 1604 /* 1605 * These SSL/TLS are unique in that the parameter in the API for 1606 * the new key is unused (NULL). Instead, there are 4 keys which 1607 * are derived, and are passed back through the mechanism params. 1608 * Both mechs use the same mechanism parameter type. 1609 */ 1610 if (isSSL) { 1611 CK_SSL3_KEY_MAT_PARAMS *keyparams; 1612 CK_SSL3_KEY_MAT_OUT *keys; 1613 1614 /* NULL checks already done by caller */ 1615 keyparams = (CK_SSL3_KEY_MAT_PARAMS*)pMechanism->pParameter; 1616 keys = keyparams->pReturnedKeyMaterial; 1617 1618 slotkey1->hObject = keys->hClientMacSecret; 1619 slotkey2->hObject = keys->hServerMacSecret; 1620 slotkey3->hObject = keys->hClientKey; 1621 slotkey4->hObject = keys->hServerKey; 1622 1623 rv = meta_object_get_attr(derive_session, 1624 slotkey1->hObject, newKey1); 1625 if (rv != CKR_OK) { 1626 goto finish; 1627 } 1628 1629 rv = meta_object_get_attr(derive_session, 1630 slotkey2->hObject, newKey2); 1631 if (rv != CKR_OK) { 1632 goto finish; 1633 } 1634 1635 rv = meta_object_get_attr(derive_session, 1636 slotkey3->hObject, newKey3); 1637 if (rv != CKR_OK) { 1638 goto finish; 1639 } 1640 1641 rv = meta_object_get_attr(derive_session, 1642 slotkey4->hObject, newKey4); 1643 if (rv != CKR_OK) { 1644 goto finish; 1645 } 1646 1647 newKey1->clones[slotnum] = slotkey1; 1648 newKey2->clones[slotnum] = slotkey2; 1649 newKey3->clones[slotnum] = slotkey3; 1650 newKey4->clones[slotnum] = slotkey4; 1651 1652 newKey1->master_clone_slotnum = slotnum; 1653 newKey2->master_clone_slotnum = slotnum; 1654 newKey3->master_clone_slotnum = slotnum; 1655 newKey4->master_clone_slotnum = slotnum; 1656 1657 meta_slot_object_activate(slotkey1, derive_session, 1658 newKey1->isToken); 1659 slotkey1 = NULL; 1660 meta_slot_object_activate(slotkey2, derive_session, 1661 newKey2->isToken); 1662 slotkey2 = NULL; 1663 meta_slot_object_activate(slotkey3, derive_session, 1664 newKey3->isToken); 1665 slotkey3 = NULL; 1666 meta_slot_object_activate(slotkey4, derive_session, 1667 newKey4->isToken); 1668 slotkey4 = NULL; 1669 1670 } else { 1671 slotkey1->hObject = hDerivedKey; 1672 newKey1->clones[slotnum] = slotkey1; 1673 newKey1->master_clone_slotnum = slotnum; 1674 1675 rv = meta_object_get_attr(derive_session, 1676 slotkey1->hObject, newKey1); 1677 if (rv != CKR_OK) { 1678 goto finish; 1679 } 1680 1681 meta_slot_object_activate(slotkey1, derive_session, 1682 newKey1->isToken); 1683 slotkey1 = NULL; 1684 } 1685 1686 if (newKey1->isFreeObject == FREE_ENABLED) 1687 (void) meta_freeobject_clone(session, newKey1); 1688 1689 1690 finish: 1691 if (slotkey1) { 1692 meta_slot_object_dealloc(slotkey1); 1693 } 1694 if (slotkey2) { 1695 meta_slot_object_dealloc(slotkey2); 1696 } 1697 if (slotkey3) { 1698 meta_slot_object_dealloc(slotkey3); 1699 } 1700 if (slotkey4) { 1701 meta_slot_object_dealloc(slotkey4); 1702 } 1703 1704 /* Save the session in case it can be used later */ 1705 if (rv == CKR_OK) { 1706 /* 1707 * If currently stored session is not the one being in use now, 1708 * release the previous one and store the current one 1709 */ 1710 if ((session->op1.session) && 1711 (session->op1.session != derive_session)) { 1712 meta_release_slot_session(session->op1.session); 1713 } 1714 1715 /* Save the session */ 1716 session->op1.session = derive_session; 1717 } 1718 1719 return (rv); 1720 } 1721 1722 1723 /* 1724 * Check the following 4 environment variables for user/application's 1725 * configuration for metaslot. User's configuration takes precedence 1726 * over the system wide configuration for metaslot 1727 * 1728 * ${METASLOT_ENABLED} 1729 * ${METASLOT_OBJECTSTORE_SLOT} 1730 * ${METASLOT_OBJECTSTORE_TOKEN} 1731 * ${METASLOT_AUTO_KEY_MIGRATE} 1732 * 1733 * ${_METASLOT_ENABLE_THRESHOLD} - private environmental variable to 1734 * enable the treshold checking which is disabled by default. 1735 * 1736 * values defined in these environment variables will be stored in the 1737 * global variable "metaslot_config". Variable threshold_chk_disabled is an 1738 * exception. 1739 */ 1740 void 1741 get_user_metaslot_config() 1742 { 1743 char *env_val = NULL; 1744 1745 /* 1746 * Check to see if any environment variable is defined 1747 * by the user for configuring metaslot. 1748 */ 1749 bzero(&metaslot_config, sizeof (metaslot_config)); 1750 1751 /* METASLOT_ENABLED */ 1752 env_val = getenv("METASLOT_ENABLED"); 1753 if (env_val) { 1754 metaslot_config.enabled_specified = B_TRUE; 1755 if (strcasecmp(env_val, TRUE_STRING) == 0) { 1756 metaslot_config.enabled = B_TRUE; 1757 } else if (strcasecmp(env_val, FALSE_STRING) == 0) { 1758 metaslot_config.enabled = B_FALSE; 1759 } else { 1760 /* value is neither 1 or 0, ignore this value */ 1761 metaslot_config.enabled_specified = B_FALSE; 1762 } 1763 } 1764 1765 /* METASLOT_AUTO_KEY_MIGRATE */ 1766 env_val = getenv("METASLOT_AUTO_KEY_MIGRATE"); 1767 if (env_val) { 1768 metaslot_config.auto_key_migrate_specified = B_TRUE; 1769 if (strcasecmp(env_val, TRUE_STRING) == 0) { 1770 metaslot_config.auto_key_migrate = B_TRUE; 1771 } else if (strcasecmp(env_val, FALSE_STRING) == 0) { 1772 metaslot_config.auto_key_migrate = B_FALSE; 1773 } else { 1774 /* value is neither 1 or 0, ignore this value */ 1775 metaslot_config.auto_key_migrate_specified = B_FALSE; 1776 } 1777 } 1778 1779 /* METASLOT_OBJECTSTORE_SLOT */ 1780 env_val = getenv("METASLOT_OBJECTSTORE_SLOT"); 1781 if (env_val) { 1782 metaslot_config.keystore_slot_specified = B_TRUE; 1783 (void) strlcpy((char *)metaslot_config.keystore_slot, env_val, 1784 SLOT_DESCRIPTION_SIZE); 1785 } 1786 1787 /* METASLOT_OBJECTSTORE_TOKEN */ 1788 env_val = getenv("METASLOT_OBJECTSTORE_TOKEN"); 1789 if (env_val) { 1790 metaslot_config.keystore_token_specified = B_TRUE; 1791 (void) strlcpy((char *)metaslot_config.keystore_token, env_val, 1792 TOKEN_LABEL_SIZE); 1793 } 1794 1795 /* _METASLOT_ENABLE_THRESHOLD */ 1796 env_val = getenv("_METASLOT_ENABLE_THRESHOLD"); 1797 if (env_val) { 1798 threshold_chk_enabled = B_TRUE; 1799 } 1800 } 1801