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