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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <cryptoutil.h> 30 #include <errno.h> 31 #include <fcntl.h> 32 #include <stdio.h> 33 #include <strings.h> 34 #include "metaGlobal.h" 35 36 /* 37 * meta_operation_init 38 * 39 */ 40 CK_RV 41 meta_operation_init(int optype, meta_session_t *session, 42 CK_MECHANISM *pMechanism, meta_object_t *key) 43 { 44 CK_RV rv, save_rv; 45 mechinfo_t **supporting_slots; 46 CK_ULONG slotnum; 47 unsigned long i, slotCount = 0; 48 slot_session_t *init_session = NULL; 49 50 /* 51 * If an operation is already active, cleanup existing operation 52 * and start a new one. 53 */ 54 if (session->op1.type != OP_UNUSED) { 55 meta_operation_cleanup(session, session->op1.type, B_FALSE); 56 } 57 58 /* 59 * Get a list of capable slots. 60 * 61 * If the specified mechanism is used in this session last time, 62 * the list of capable slots is already retrieved. We can save 63 * some processing, and just use that list of slots. 64 */ 65 if (((session->mech_support_info).mech != pMechanism->mechanism) || 66 ((session->mech_support_info).num_supporting_slots == 0)) { 67 (session->mech_support_info).mech = pMechanism->mechanism; 68 rv = meta_mechManager_get_slots(&(session->mech_support_info), 69 B_FALSE); 70 if (rv != CKR_OK) { 71 goto finish; 72 } 73 } 74 75 rv = CKR_FUNCTION_FAILED; 76 77 /* The following 2 assignment is just to make the code more readable */ 78 slotCount = (session->mech_support_info).num_supporting_slots; 79 supporting_slots = (session->mech_support_info).supporting_slots; 80 81 /* Attempt to initialize operation on slots until one succeeds. */ 82 for (i = 0; i < slotCount; i++) { 83 slot_object_t *init_key; 84 CK_SLOT_ID fw_st_id; 85 86 init_session = NULL; 87 88 slotnum = supporting_slots[i]->slotnum; 89 90 /* 91 * An actual session with the underlying slot is required 92 * for the operation. When the operation is successfully 93 * completed, the underlying session with the slot 94 * is not released back to the list of available sessions 95 * pool. This will help if the next operation can 96 * also be done on the same slot, because it avoids 97 * one extra trip to the session pool to get an idle session. 98 * If the operation can't be done on that slot, 99 * we release the session back to the session pool then. 100 */ 101 if (session->op1.session != NULL) { 102 103 if ((session->op1.session)->slotnum == slotnum) { 104 init_session = session->op1.session; 105 /* 106 * set it to NULL for now, assign it to 107 * init_session again if it is successful 108 */ 109 session->op1.session = NULL; 110 } else { 111 init_session = NULL; 112 } 113 114 } 115 116 if (!init_session) { 117 rv = meta_get_slot_session(slotnum, &init_session, 118 session->session_flags); 119 if (rv != CKR_OK) { 120 goto loop_cleanup; 121 } 122 } 123 124 /* if necessary, ensure a clone of the obj exists in slot */ 125 if (optype != OP_DIGEST) { 126 rv = meta_object_get_clone(key, slotnum, init_session, 127 &init_key); 128 129 if (rv != CKR_OK) { 130 goto loop_cleanup; 131 } 132 } 133 134 fw_st_id = init_session->fw_st_id; 135 switch (optype) { 136 case OP_ENCRYPT: 137 rv = FUNCLIST(fw_st_id)->C_EncryptInit( 138 init_session->hSession, pMechanism, 139 init_key->hObject); 140 break; 141 case OP_DECRYPT: 142 rv = FUNCLIST(fw_st_id)->C_DecryptInit( 143 init_session->hSession, pMechanism, 144 init_key->hObject); 145 break; 146 case OP_DIGEST: 147 rv = FUNCLIST(fw_st_id)->C_DigestInit( 148 init_session->hSession, pMechanism); 149 break; 150 case OP_SIGN: 151 rv = FUNCLIST(fw_st_id)->C_SignInit( 152 init_session->hSession, pMechanism, 153 init_key->hObject); 154 break; 155 case OP_VERIFY: 156 rv = FUNCLIST(fw_st_id)->C_VerifyInit( 157 init_session->hSession, pMechanism, 158 init_key->hObject); 159 break; 160 case OP_SIGNRECOVER: 161 rv = FUNCLIST(fw_st_id)->C_SignRecoverInit( 162 init_session->hSession, pMechanism, 163 init_key->hObject); 164 break; 165 case OP_VERIFYRECOVER: 166 rv = FUNCLIST(fw_st_id)->C_VerifyRecoverInit( 167 init_session->hSession, pMechanism, 168 init_key->hObject); 169 break; 170 171 default: 172 /*NOTREACHED*/ 173 rv = CKR_FUNCTION_FAILED; 174 break; 175 } 176 177 if (rv == CKR_OK) 178 break; 179 180 loop_cleanup: 181 if (i == 0) { 182 save_rv = rv; 183 } 184 185 if (init_session) { 186 meta_release_slot_session(init_session); 187 init_session = NULL; 188 } 189 190 } 191 192 if (rv == CKR_OK) { 193 194 /* 195 * If currently stored session is not the one being in use now, 196 * release the previous one and store the current one 197 */ 198 if ((session->op1.session) && 199 (session->op1.session != init_session)) { 200 meta_release_slot_session(session->op1.session); 201 } 202 203 /* Save the session */ 204 session->op1.session = init_session; 205 session->op1.type = optype; 206 } else { 207 rv = save_rv; 208 } 209 210 finish: 211 return (rv); 212 } 213 214 /* 215 * meta_do_operation 216 * 217 * NOTES: 218 * 219 * 1) The spec says you cannot do a C_Encrypt after a C_EncUpdate, 220 * but we don't explicitly enforce it here (ie, disallow doing MODE_SINGLE 221 * after a MODE_UPDATE). Instead, we just assume the underlying provider 222 * will catch the problem and return an appropriate error. 223 * 224 * 2) Note that the Verify operations are a little unusual, due to the 225 * PKCS#11 API. For C_Verify, the last two arguments are used as inputs, 226 * unlike the other single pass operations (where they are outputs). For 227 * C_VerifyFinal, in/inLen are passed instead of out/outLen like the other 228 * Final operations. 229 * 230 * 3) C_DigestKey is the only crypto operation that uses an object after 231 * the operation has been initialized. No other callers should provide 232 * this argument (use NULL). 233 */ 234 CK_RV 235 meta_do_operation(int optype, int mode, 236 meta_session_t *session, meta_object_t *object, 237 CK_BYTE *in, CK_ULONG inLen, CK_BYTE *out, CK_ULONG *outLen) 238 { 239 CK_RV rv; 240 CK_SESSION_HANDLE hSession; 241 CK_SLOT_ID fw_st_id; 242 slot_session_t *slot_session = NULL; 243 slot_object_t *slot_object = NULL; 244 245 boolean_t shutdown, finished_normally; 246 247 if (optype != session->op1.type) { 248 return (CKR_OPERATION_NOT_INITIALIZED); 249 } 250 251 slot_session = session->op1.session; 252 253 if (slot_session) { 254 hSession = slot_session->hSession; 255 fw_st_id = slot_session->fw_st_id; 256 } else { 257 /* should never be here */ 258 return (CKR_FUNCTION_FAILED); 259 } 260 261 262 /* Do the operation... */ 263 switch (optype | mode) { 264 case OP_ENCRYPT | MODE_SINGLE: 265 rv = FUNCLIST(fw_st_id)->C_Encrypt(hSession, in, 266 inLen, out, outLen); 267 break; 268 case OP_ENCRYPT | MODE_UPDATE: 269 rv = FUNCLIST(fw_st_id)->C_EncryptUpdate(hSession, in, 270 inLen, out, outLen); 271 break; 272 case OP_ENCRYPT | MODE_FINAL: 273 rv = FUNCLIST(fw_st_id)->C_EncryptFinal(hSession, out, 274 outLen); 275 break; 276 277 case OP_DECRYPT | MODE_SINGLE: 278 rv = FUNCLIST(fw_st_id)->C_Decrypt(hSession, in, 279 inLen, out, outLen); 280 break; 281 case OP_DECRYPT | MODE_UPDATE: 282 rv = FUNCLIST(fw_st_id)->C_DecryptUpdate(hSession, in, 283 inLen, out, outLen); 284 break; 285 case OP_DECRYPT | MODE_FINAL: 286 rv = FUNCLIST(fw_st_id)->C_DecryptFinal(hSession, out, 287 outLen); 288 break; 289 290 case OP_DIGEST | MODE_SINGLE: 291 rv = FUNCLIST(fw_st_id)->C_Digest(hSession, in, inLen, 292 out, outLen); 293 break; 294 case OP_DIGEST | MODE_UPDATE: 295 /* noOutputForOp = TRUE; */ 296 rv = FUNCLIST(fw_st_id)->C_DigestUpdate(hSession, in, 297 inLen); 298 break; 299 case OP_DIGEST | MODE_UPDATE_WITHKEY: 300 /* noOutputForOp = TRUE; */ 301 /* 302 * For C_DigestKey, a key is provided and 303 * we need the clone. 304 */ 305 rv = meta_object_get_clone(object, 306 slot_session->slotnum, slot_session, &slot_object); 307 if (rv == CKR_OK) 308 rv = FUNCLIST(fw_st_id)->C_DigestKey(hSession, 309 slot_object->hObject); 310 break; 311 case OP_DIGEST | MODE_FINAL: 312 rv = FUNCLIST(fw_st_id)->C_DigestFinal(hSession, out, 313 outLen); 314 break; 315 316 317 case OP_SIGN | MODE_SINGLE: 318 rv = FUNCLIST(fw_st_id)->C_Sign(hSession, in, inLen, 319 out, outLen); 320 break; 321 case OP_SIGN | MODE_UPDATE: 322 /* noOutputForOp = TRUE; */ 323 rv = FUNCLIST(fw_st_id)->C_SignUpdate(hSession, in, 324 inLen); 325 break; 326 case OP_SIGN | MODE_FINAL: 327 rv = FUNCLIST(fw_st_id)->C_SignFinal(hSession, out, 328 outLen); 329 break; 330 331 case OP_VERIFY | MODE_SINGLE: 332 /* noOutputForOp = TRUE; */ 333 /* Yes, use *outLen not outLen (think in2/in2Len) */ 334 rv = FUNCLIST(fw_st_id)->C_Verify(hSession, in, 335 inLen, out, *outLen); 336 break; 337 case OP_VERIFY | MODE_UPDATE: 338 /* noOutputForOp = TRUE; */ 339 rv = FUNCLIST(fw_st_id)->C_VerifyUpdate(hSession, in, 340 inLen); 341 break; 342 case OP_VERIFY | MODE_FINAL: 343 /* noOutputForOp = TRUE; */ 344 /* Yes, use in/inLen instead of out/outLen */ 345 rv = FUNCLIST(fw_st_id)->C_VerifyFinal(hSession, in, 346 inLen); 347 break; 348 349 case OP_SIGNRECOVER | MODE_SINGLE: 350 rv = FUNCLIST(fw_st_id)->C_SignRecover(hSession, in, 351 inLen, out, outLen); 352 break; 353 case OP_VERIFYRECOVER | MODE_SINGLE: 354 rv = FUNCLIST(fw_st_id)->C_VerifyRecover(hSession, in, 355 inLen, out, outLen); 356 break; 357 358 default: 359 rv = CKR_FUNCTION_FAILED; 360 } 361 362 363 364 /* 365 * Mark the operation type as inactive if an abnormal error 366 * happens, or if the operation normally results in an inactive 367 * operation state. 368 * 369 * NOTE: The spec isn't very explicit about what happens when you 370 * call C_FooFinal (or C_Foo) with a NULL output buffer (to get the 371 * output size), but there is no output. Technically this should be 372 * no different than the normal case (ie, when there is output), and 373 * the operation should remain active until the second call actually 374 * terminates it. However, one could make the case that there is no 375 * need for a second call, since no data is available. This presents 376 * dilemma for metaslot, because we don't know if the operation is 377 * going to remain active or not. We will assume a strict reading of 378 * the spec, the operation will remain active. 379 */ 380 if (rv == CKR_BUFFER_TOO_SMALL || 381 (rv == CKR_OK && out == NULL && optype != OP_VERIFY)) { 382 /* Leave op active for retry (with larger buffer). */ 383 shutdown = B_FALSE; 384 } else if (rv != CKR_OK) { 385 shutdown = B_TRUE; 386 finished_normally = B_FALSE; 387 } else { /* CKR_OK */ 388 if (mode == MODE_SINGLE || mode == MODE_FINAL) { 389 shutdown = B_TRUE; 390 finished_normally = B_TRUE; 391 } else { /* mode == MODE_UPDATE */ 392 shutdown = B_FALSE; 393 } 394 } 395 396 if (shutdown) 397 meta_operation_cleanup(session, optype, finished_normally); 398 399 return (rv); 400 } 401 402 /* 403 * meta_operation_cleanup 404 * 405 * Cleans up an operation in the specified session. 406 * If the operation did not finish normally, it will force 407 * the operation to terminate. 408 */ 409 void 410 meta_operation_cleanup(meta_session_t *session, int optype, 411 boolean_t finished_normally) 412 { 413 operation_info_t *op; 414 CK_SESSION_HANDLE hSession; 415 CK_SLOT_ID fw_st_id; 416 417 if (!finished_normally) { 418 CK_BYTE dummy_buf[8]; 419 420 if (session->op1.type == optype) 421 op = &session->op1; 422 else 423 return; 424 425 hSession = op->session->hSession; 426 fw_st_id = op->session->fw_st_id; 427 428 /* 429 * There's no simple, reliable way to abort an 430 * operation. So, we'll force the operation to finish. 431 * 432 * We are here either because we need to abort either after 433 * C_xxxxxInit() or C_xxxxxUpdate(). 434 * 435 * We will call C_xxxxxUpdate() with invalid argument to 436 * force the operation to abort. According to the PKCS#11 437 * spec, any call to C_xxxxxUpdate() returns in an error 438 * will terminate the current operation. 439 */ 440 441 switch (optype) { 442 case OP_ENCRYPT: 443 (void) FUNCLIST(fw_st_id)->C_EncryptUpdate(hSession, 444 NULL, 8, dummy_buf, NULL); 445 break; 446 case OP_DECRYPT: 447 (void) FUNCLIST(fw_st_id)->C_DecryptUpdate(hSession, 448 NULL, 8, dummy_buf, NULL); 449 break; 450 case OP_DIGEST: 451 (void) FUNCLIST(fw_st_id)->C_DigestUpdate(hSession, 452 NULL, 8); 453 break; 454 case OP_SIGN: 455 (void) FUNCLIST(fw_st_id)->C_SignUpdate(hSession, 456 NULL, 8); 457 break; 458 case OP_SIGNRECOVER: 459 (void) FUNCLIST(fw_st_id)->C_SignRecover(hSession, 460 NULL, 8, dummy_buf, NULL); 461 break; 462 case OP_VERIFY: 463 (void) FUNCLIST(fw_st_id)->C_VerifyUpdate(hSession, 464 NULL, 8); 465 break; 466 case OP_VERIFYRECOVER: 467 (void) FUNCLIST(fw_st_id)->C_VerifyRecover(hSession, 468 NULL, 8, dummy_buf, NULL); 469 break; 470 default: 471 /*NOTREACHED*/ 472 break; 473 } 474 meta_release_slot_session(session->op1.session); 475 session->op1.session = NULL; 476 } 477 478 session->op1.type = OP_UNUSED; 479 } 480 481 /* 482 * Gets the list of slots that supports the specified mechanism. 483 * 484 * If "token_only", check if the keystore slot supports the specified mech, 485 * if so, return that slot only 486 * 487 * Otherwise, get list of all slots that support the mech. 488 * 489 */ 490 static CK_RV 491 get_slotlist_for_mech(CK_MECHANISM_TYPE mech_type, 492 mech_support_info_t *mech_support_info, 493 mechinfo_t ***slots, unsigned long *slot_count, boolean_t token_only) 494 { 495 boolean_t mech_supported = B_FALSE; 496 CK_RV rv = CKR_OK; 497 498 if (token_only) { 499 rv = meta_mechManager_slot_supports_mech(mech_type, 500 get_keystore_slotnum(), &mech_supported, 501 &((mech_support_info->supporting_slots)[0]), B_FALSE); 502 503 if (rv != CKR_OK) { 504 return (rv); 505 } 506 507 if (mech_supported) { 508 mech_support_info->mech = mech_type; 509 /* 510 * Want to leave this at 0, that way, when 511 * other operation needs to 512 * use this mechanism, but not just for the 513 * keystore slot, we will look at other slots 514 */ 515 mech_support_info->num_supporting_slots = 0; 516 *slots = mech_support_info->supporting_slots; 517 *slot_count = 1; 518 } else { 519 rv = CKR_FUNCTION_FAILED; 520 } 521 } else { 522 /* 523 * Get a list of slots that support this mech . 524 * 525 * If the specified mechanism is used last time, 526 * the list of capable slots is already retrieved. 527 * We can save some processing, and just use that list of slots. 528 */ 529 if ((mech_support_info->mech != mech_type) || 530 (mech_support_info->num_supporting_slots == 0)) { 531 mech_support_info->mech = mech_type; 532 rv = meta_mechManager_get_slots(mech_support_info, 533 B_FALSE); 534 if (rv != CKR_OK) { 535 return (CKR_FUNCTION_FAILED); 536 } 537 } 538 *slots = mech_support_info->supporting_slots; 539 *slot_count = mech_support_info->num_supporting_slots; 540 } 541 return (rv); 542 } 543 544 /* 545 * meta_generate_keys 546 * 547 * Generates symmetric (k1=key, k2=null) or asymmetric (k1=pub, k2=priv) keys. 548 * 549 */ 550 CK_RV 551 meta_generate_keys(meta_session_t *session, CK_MECHANISM *pMechanism, 552 CK_ATTRIBUTE *k1Template, CK_ULONG k1AttrCount, meta_object_t *key1, 553 CK_ATTRIBUTE *k2Template, CK_ULONG k2AttrCount, meta_object_t *key2) 554 { 555 CK_RV rv, save_rv; 556 slot_session_t *gen_session = NULL; 557 slot_object_t *slot_key1 = NULL, *slot_key2 = NULL; 558 mechinfo_t **slots = NULL; 559 unsigned long i, slotCount = 0; 560 boolean_t doKeyPair = B_FALSE, token_only = B_FALSE; 561 CK_ULONG slotnum; 562 563 (void) get_template_boolean(CKA_TOKEN, k1Template, k1AttrCount, 564 &(key1->isToken)); 565 if (key2) { 566 (void) get_template_boolean(CKA_TOKEN, k2Template, k2AttrCount, 567 &(key2->isToken)); 568 doKeyPair = B_TRUE; 569 } 570 571 /* Can't create token objects in a read-only session. */ 572 if ((IS_READ_ONLY_SESSION(session->session_flags)) && 573 ((key1->isToken) || ((key2) && (key2->isToken)))) { 574 return (CKR_SESSION_READ_ONLY); 575 } 576 577 if ((key1->isToken) || ((doKeyPair) && (key2->isToken))) { 578 /* 579 * Token objects can only be generated in the token object 580 * slot. If token object slot doesn't support generating 581 * the key, it will just not be done 582 */ 583 token_only = B_TRUE; 584 } 585 586 rv = get_slotlist_for_mech(pMechanism->mechanism, 587 &(session->mech_support_info), &slots, &slotCount, token_only); 588 589 if (rv != CKR_OK) { 590 goto finish; 591 } 592 593 rv = meta_slot_object_alloc(&slot_key1); 594 if (doKeyPair && rv == CKR_OK) 595 rv = meta_slot_object_alloc(&slot_key2); 596 if (rv != CKR_OK) 597 goto finish; 598 599 /* Attempt to generate key on slots until one succeeds. */ 600 for (i = 0; i < slotCount; i++) { 601 CK_SESSION_HANDLE hSession; 602 CK_SLOT_ID fw_st_id; 603 604 gen_session = NULL; 605 606 slotnum = slots[i]->slotnum; 607 608 if (session->op1.session != NULL) { 609 if ((session->op1.session)->slotnum == slotnum) { 610 gen_session = session->op1.session; 611 /* 612 * set it to NULL for now, assign it to 613 * gen_session again if it is successful 614 */ 615 session->op1.session = NULL; 616 } else { 617 gen_session = NULL; 618 } 619 } 620 621 if (gen_session == NULL) { 622 rv = meta_get_slot_session(slotnum, &gen_session, 623 session->session_flags); 624 if (rv != CKR_OK) { 625 goto loop_cleanup; 626 } 627 } 628 629 fw_st_id = gen_session->fw_st_id; 630 hSession = gen_session->hSession; 631 if (doKeyPair) { 632 rv = FUNCLIST(fw_st_id)->C_GenerateKeyPair(hSession, 633 pMechanism, k1Template, k1AttrCount, 634 k2Template, k2AttrCount, 635 &slot_key1->hObject, &slot_key2->hObject); 636 } else { 637 rv = FUNCLIST(fw_st_id)->C_GenerateKey(hSession, 638 pMechanism, k1Template, k1AttrCount, 639 &slot_key1->hObject); 640 } 641 642 if (rv == CKR_OK) 643 break; 644 645 loop_cleanup: 646 if (i == 0) { 647 save_rv = rv; 648 } 649 650 if (gen_session) { 651 meta_release_slot_session(gen_session); 652 gen_session = NULL; 653 } 654 } 655 if (rv != CKR_OK) { 656 rv = save_rv; 657 goto finish; 658 } 659 660 661 rv = meta_object_get_attr(gen_session, slot_key1->hObject, key1); 662 if (rv != CKR_OK) { 663 goto finish; 664 } 665 666 if (key2) { 667 rv = meta_object_get_attr(gen_session, slot_key2->hObject, 668 key2); 669 if (rv != CKR_OK) { 670 goto finish; 671 } 672 } 673 674 meta_slot_object_activate(slot_key1, gen_session, key1->isToken); 675 key1->clones[slotnum] = slot_key1; 676 key1->master_clone_slotnum = slotnum; 677 slot_key1 = NULL; 678 679 if (doKeyPair) { 680 meta_slot_object_activate(slot_key2, gen_session, 681 key2->isToken); 682 key2->clones[slotnum] = slot_key2; 683 key2->master_clone_slotnum = slotnum; 684 slot_key2 = NULL; 685 } 686 687 finish: 688 if (slot_key1) { 689 meta_slot_object_dealloc(slot_key1); 690 } 691 692 if (slot_key2) { 693 meta_slot_object_dealloc(slot_key2); 694 } 695 696 /* Save the session in case it can be used later */ 697 if (rv == CKR_OK) { 698 /* 699 * If currently stored session is not the one being in use now, 700 * release the previous one and store the current one 701 */ 702 if ((session->op1.session) && 703 (session->op1.session != gen_session)) { 704 meta_release_slot_session(session->op1.session); 705 } 706 707 /* Save the session */ 708 session->op1.session = gen_session; 709 } 710 711 return (rv); 712 } 713 714 715 /* 716 * meta_wrap_key 717 * 718 */ 719 CK_RV 720 meta_wrap_key(meta_session_t *session, CK_MECHANISM *pMechanism, 721 meta_object_t *wrappingkey, meta_object_t *inputkey, CK_BYTE *wrapped_key, 722 CK_ULONG *wrapped_key_len) 723 { 724 CK_RV rv, save_rv; 725 slot_session_t *wrap_session = NULL; 726 slot_object_t *slot_wrappingkey, *slot_inputkey; 727 mechinfo_t **slots = NULL; 728 unsigned long i, slotCount = 0; 729 CK_ULONG slotnum; 730 731 /* 732 * If the key to be wrapped is a token object, 733 * the operation can only be done in the token object slot. 734 */ 735 rv = get_slotlist_for_mech(pMechanism->mechanism, 736 &(session->mech_support_info), &slots, &slotCount, 737 inputkey->isToken); 738 739 if (rv != CKR_OK) { 740 return (rv); 741 } 742 743 /* Attempt to wrap key on slots until one succeeds. */ 744 for (i = 0; i < slotCount; i++) { 745 746 slotnum = slots[i]->slotnum; 747 wrap_session = NULL; 748 749 if (session->op1.session != NULL) { 750 if ((session->op1.session)->slotnum == slotnum) { 751 wrap_session = session->op1.session; 752 /* 753 * set it to NULL for now, assign it to 754 * wrap_session again if it is successful 755 */ 756 session->op1.session = NULL; 757 } else { 758 wrap_session = NULL; 759 } 760 } 761 762 if (wrap_session == NULL) { 763 rv = meta_get_slot_session(slotnum, &wrap_session, 764 session->session_flags); 765 if (rv != CKR_OK) { 766 goto loop_cleanup; 767 } 768 } 769 770 rv = meta_object_get_clone(wrappingkey, slotnum, 771 wrap_session, &slot_wrappingkey); 772 if (rv != CKR_OK) 773 goto loop_cleanup; 774 775 rv = meta_object_get_clone(inputkey, slotnum, 776 wrap_session, &slot_inputkey); 777 if (rv != CKR_OK) 778 goto loop_cleanup; 779 780 rv = FUNCLIST(wrap_session->fw_st_id)->C_WrapKey( 781 wrap_session->hSession, pMechanism, 782 slot_wrappingkey->hObject, slot_inputkey->hObject, 783 wrapped_key, wrapped_key_len); 784 785 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) 786 break; 787 788 loop_cleanup: 789 if (i == 0) { 790 save_rv = rv; 791 } 792 793 if (wrap_session) { 794 meta_release_slot_session(wrap_session); 795 wrap_session = NULL; 796 } 797 } 798 if (rv != CKR_OK) { 799 if (rv != CKR_BUFFER_TOO_SMALL) { 800 if (i == slotCount) { 801 rv = save_rv; 802 } 803 } 804 } 805 806 finish: 807 /* Save the session in case it can be used later */ 808 if (rv == CKR_OK) { 809 /* 810 * If currently stored session is not the one being in use now, 811 * release the previous one and store the current one 812 */ 813 if ((session->op1.session) && 814 (session->op1.session != wrap_session)) { 815 meta_release_slot_session(session->op1.session); 816 } 817 818 /* Save the session */ 819 session->op1.session = wrap_session; 820 } 821 return (rv); 822 } 823 824 825 826 /* 827 * meta_unwrap_key 828 * 829 */ 830 CK_RV 831 meta_unwrap_key(meta_session_t *session, 832 CK_MECHANISM *pMechanism, meta_object_t *unwrapping_key, 833 CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len, 834 CK_ATTRIBUTE *template, CK_ULONG template_size, 835 meta_object_t *unwrapped_key) 836 { 837 CK_RV rv, save_rv; 838 CK_OBJECT_HANDLE hUnwrappedKey; 839 slot_session_t *unwrap_session = NULL; 840 slot_object_t *slot_unwrappingkey, *slot_unwrapped_key; 841 mechinfo_t **slots = NULL; 842 unsigned long i, slotCount = 0; 843 CK_ULONG slotnum; 844 845 /* Can't create token objects in a read-only session. */ 846 if ((IS_READ_ONLY_SESSION(session->session_flags)) && 847 unwrapped_key->isToken) { 848 return (CKR_SESSION_READ_ONLY); 849 } 850 851 /* 852 * If the the resulting unwrapped key 853 * needs to be a token object, the operation can only 854 * be performed in the token slot, if it is supported. 855 */ 856 rv = get_slotlist_for_mech(pMechanism->mechanism, 857 &(session->mech_support_info), &slots, &slotCount, 858 unwrapped_key->isToken); 859 860 if (rv != CKR_OK) { 861 return (rv); 862 } 863 864 rv = meta_slot_object_alloc(&slot_unwrapped_key); 865 if (rv != CKR_OK) { 866 goto finish; 867 } 868 869 /* Attempt to unwrap key on slots until one succeeds. */ 870 for (i = 0; i < slotCount; i++) { 871 872 slotnum = slots[i]->slotnum; 873 unwrap_session = NULL; 874 875 if (session->op1.session != NULL) { 876 if ((session->op1.session)->slotnum == slotnum) { 877 unwrap_session = session->op1.session; 878 /* 879 * set it to NULL for now, assign it to 880 * unwrap_session again if it is successful 881 */ 882 session->op1.session = NULL; 883 } else { 884 unwrap_session = NULL; 885 } 886 } 887 888 if (unwrap_session == NULL) { 889 rv = meta_get_slot_session(slotnum, &unwrap_session, 890 session->session_flags); 891 if (rv != CKR_OK) { 892 goto loop_cleanup; 893 } 894 } 895 896 rv = meta_object_get_clone(unwrapping_key, slotnum, 897 unwrap_session, &slot_unwrappingkey); 898 if (rv != CKR_OK) 899 goto loop_cleanup; 900 901 rv = FUNCLIST(unwrap_session->fw_st_id)->C_UnwrapKey( 902 unwrap_session->hSession, pMechanism, 903 slot_unwrappingkey->hObject, wrapped_key, wrapped_key_len, 904 template, template_size, &hUnwrappedKey); 905 906 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) 907 break; 908 loop_cleanup: 909 if (i == 0) { 910 save_rv = rv; 911 } 912 913 if (unwrap_session) { 914 meta_release_slot_session(unwrap_session); 915 unwrap_session = NULL; 916 } 917 } 918 919 920 if (rv != CKR_OK) { 921 if (rv != CKR_BUFFER_TOO_SMALL) { 922 rv = save_rv; 923 } 924 goto finish; 925 } 926 927 928 slot_unwrapped_key->hObject = hUnwrappedKey; 929 unwrapped_key->clones[slotnum] = slot_unwrapped_key; 930 unwrapped_key->master_clone_slotnum = slotnum; 931 rv = meta_object_get_attr(unwrap_session, 932 slot_unwrapped_key->hObject, unwrapped_key); 933 if (rv != CKR_OK) { 934 goto finish; 935 } 936 meta_slot_object_activate(slot_unwrapped_key, unwrap_session, 937 unwrapped_key->isToken); 938 slot_unwrapped_key = NULL; 939 940 finish: 941 if (slot_unwrapped_key) { 942 meta_slot_object_dealloc(slot_unwrapped_key); 943 } 944 945 /* Save the session in case it can be used later */ 946 if (rv == CKR_OK) { 947 /* 948 * If currently stored session is not the one being in use now, 949 * release the previous one and store the current one 950 */ 951 if ((session->op1.session) && 952 (session->op1.session != unwrap_session)) { 953 meta_release_slot_session(session->op1.session); 954 } 955 956 /* Save the session */ 957 session->op1.session = unwrap_session; 958 } 959 960 return (rv); 961 } 962 963 964 /* 965 * meta_derive_key 966 * 967 * Core implementation for C_DeriveKey. This function is a bit gross because 968 * of PKCS#11 kludges that pass extra object handles in the mechanism 969 * parameters. Normally C_DeriveKey takes a single existing key as input, 970 * and creates a single new key as output. But a few mechanisms take 2 keys 971 * as input, and the two SSL/TLS mechanisms create 4 keys as output. 972 * 973 * When an extra input key (basekey2) is set, we set *phBaseKey2 to the clone's 974 * object handle. phBaseKey2 is provided by the caller so we don't have to 975 * trudge down into different mechanism parameters to set it when issuing the 976 * operation. 977 * 978 * For the SSL/TLS mechanisms, newKey2/newKey3/newKey4 will be set. We pull 979 * the new handles from pMech->pParameter in order to fill in the appropriate 980 * meta_object fields. 981 */ 982 CK_RV 983 meta_derive_key(meta_session_t *session, CK_MECHANISM *pMechanism, 984 meta_object_t *basekey1, meta_object_t *basekey2, 985 CK_OBJECT_HANDLE *phBaseKey2, 986 CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, 987 meta_object_t *newKey1, meta_object_t *newKey2, 988 meta_object_t *newKey3, meta_object_t *newKey4) 989 { 990 CK_RV rv, save_rv; 991 CK_OBJECT_HANDLE hDerivedKey; 992 993 CK_ULONG slotnum; 994 boolean_t isSSL = B_FALSE; 995 mechinfo_t **slots = NULL; 996 unsigned long i, slot_count = 0; 997 slot_session_t *derive_session = NULL; 998 slot_object_t *slot_basekey1 = NULL, *slot_basekey2 = NULL; 999 slot_object_t *slotkey1 = NULL, *slotkey2 = NULL, 1000 *slotkey3 = NULL, *slotkey4 = NULL; 1001 1002 1003 /* 1004 * if the derived key needs to be a token object, can only 1005 * perform the derive operation in the token slot 1006 */ 1007 (void) get_template_boolean(CKA_TOKEN, pTemplate, ulAttributeCount, 1008 &(newKey1->isToken)); 1009 1010 /* Can't create token objects in a read-only session. */ 1011 if ((IS_READ_ONLY_SESSION(session->session_flags)) && 1012 newKey1->isToken) { 1013 rv = CKR_SESSION_READ_ONLY; 1014 goto finish; 1015 } 1016 1017 rv = get_slotlist_for_mech(pMechanism->mechanism, 1018 &(session->mech_support_info), &slots, &slot_count, 1019 newKey1->isToken); 1020 1021 if (rv != CKR_OK) { 1022 return (rv); 1023 } 1024 1025 if (pMechanism->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE || 1026 pMechanism->mechanism == CKM_TLS_KEY_AND_MAC_DERIVE) { 1027 isSSL = B_TRUE; 1028 } 1029 1030 rv = meta_slot_object_alloc(&slotkey1); 1031 if (isSSL) { 1032 if (rv == CKR_OK) 1033 rv = meta_slot_object_alloc(&slotkey2); 1034 if (rv == CKR_OK) 1035 rv = meta_slot_object_alloc(&slotkey3); 1036 if (rv == CKR_OK) 1037 rv = meta_slot_object_alloc(&slotkey4); 1038 } 1039 if (rv != CKR_OK) { 1040 goto finish; 1041 } 1042 1043 for (i = 0; i < slot_count; i++) { 1044 slotnum = slots[i]->slotnum; 1045 1046 derive_session = NULL; 1047 1048 if (session->op1.session != NULL) { 1049 if ((session->op1.session)->slotnum == slotnum) { 1050 derive_session = session->op1.session; 1051 /* 1052 * set it to NULL for now, assign it to 1053 * derive_session again if it is successful 1054 */ 1055 session->op1.session = NULL; 1056 } else { 1057 derive_session = NULL; 1058 } 1059 } 1060 1061 if (derive_session == NULL) { 1062 rv = meta_get_slot_session(slotnum, &derive_session, 1063 session->session_flags); 1064 if (rv != CKR_OK) { 1065 goto loop_cleanup; 1066 } 1067 } 1068 1069 rv = meta_object_get_clone(basekey1, slotnum, 1070 derive_session, &slot_basekey1); 1071 if (rv != CKR_OK) 1072 goto loop_cleanup; 1073 1074 if (basekey2) { 1075 rv = meta_object_get_clone(basekey2, slotnum, 1076 derive_session, &slot_basekey2); 1077 if (rv != CKR_OK) 1078 goto loop_cleanup; 1079 1080 /* Pass the handle somewhere in the mech params. */ 1081 *phBaseKey2 = slot_basekey2->hObject; 1082 } 1083 1084 rv = FUNCLIST(derive_session->fw_st_id)->C_DeriveKey( 1085 derive_session->hSession, pMechanism, 1086 slot_basekey1->hObject, pTemplate, ulAttributeCount, 1087 isSSL ? NULL : &hDerivedKey); 1088 1089 if (rv == CKR_OK) 1090 break; 1091 loop_cleanup: 1092 if (i == 0) { 1093 save_rv = rv; 1094 } 1095 1096 if (derive_session) { 1097 meta_release_slot_session(derive_session); 1098 derive_session = NULL; 1099 } 1100 /* No need to cleanup clones, so we can reuse them later. */ 1101 } 1102 1103 if (rv != CKR_OK) { 1104 rv = save_rv; 1105 goto finish; 1106 } 1107 1108 /* 1109 * These SSL/TLS are unique in that the parameter in the API for 1110 * the new key is unused (NULL). Instead, there are 4 keys which 1111 * are derived, and are passed back through the mechanism params. 1112 * Both mechs use the same mechanism parameter type. 1113 */ 1114 if (isSSL) { 1115 CK_SSL3_KEY_MAT_PARAMS *keyparams; 1116 CK_SSL3_KEY_MAT_OUT *keys; 1117 1118 /* NULL checks already done by caller */ 1119 keyparams = (CK_SSL3_KEY_MAT_PARAMS*)pMechanism->pParameter; 1120 keys = keyparams->pReturnedKeyMaterial; 1121 1122 slotkey1->hObject = keys->hClientMacSecret; 1123 slotkey2->hObject = keys->hServerMacSecret; 1124 slotkey3->hObject = keys->hClientKey; 1125 slotkey4->hObject = keys->hServerKey; 1126 1127 rv = meta_object_get_attr(derive_session, 1128 slotkey1->hObject, newKey1); 1129 if (rv != CKR_OK) { 1130 goto finish; 1131 } 1132 1133 rv = meta_object_get_attr(derive_session, 1134 slotkey2->hObject, newKey2); 1135 if (rv != CKR_OK) { 1136 goto finish; 1137 } 1138 1139 rv = meta_object_get_attr(derive_session, 1140 slotkey3->hObject, newKey3); 1141 if (rv != CKR_OK) { 1142 goto finish; 1143 } 1144 1145 rv = meta_object_get_attr(derive_session, 1146 slotkey4->hObject, newKey4); 1147 if (rv != CKR_OK) { 1148 goto finish; 1149 } 1150 1151 newKey1->clones[slotnum] = slotkey1; 1152 newKey2->clones[slotnum] = slotkey2; 1153 newKey3->clones[slotnum] = slotkey3; 1154 newKey4->clones[slotnum] = slotkey4; 1155 1156 newKey1->master_clone_slotnum = slotnum; 1157 newKey2->master_clone_slotnum = slotnum; 1158 newKey3->master_clone_slotnum = slotnum; 1159 newKey4->master_clone_slotnum = slotnum; 1160 1161 meta_slot_object_activate(slotkey1, derive_session, 1162 newKey1->isToken); 1163 slotkey1 = NULL; 1164 meta_slot_object_activate(slotkey2, derive_session, 1165 newKey2->isToken); 1166 slotkey2 = NULL; 1167 meta_slot_object_activate(slotkey3, derive_session, 1168 newKey3->isToken); 1169 slotkey3 = NULL; 1170 meta_slot_object_activate(slotkey4, derive_session, 1171 newKey4->isToken); 1172 slotkey4 = NULL; 1173 1174 } else { 1175 slotkey1->hObject = hDerivedKey; 1176 newKey1->clones[slotnum] = slotkey1; 1177 newKey1->master_clone_slotnum = slotnum; 1178 1179 rv = meta_object_get_attr(derive_session, 1180 slotkey1->hObject, newKey1); 1181 if (rv != CKR_OK) { 1182 goto finish; 1183 } 1184 meta_slot_object_activate(slotkey1, derive_session, 1185 newKey1->isToken); 1186 slotkey1 = NULL; 1187 } 1188 1189 1190 finish: 1191 if (slotkey1) { 1192 meta_slot_object_dealloc(slotkey1); 1193 } 1194 if (slotkey2) { 1195 meta_slot_object_dealloc(slotkey2); 1196 } 1197 if (slotkey3) { 1198 meta_slot_object_dealloc(slotkey3); 1199 } 1200 if (slotkey4) { 1201 meta_slot_object_dealloc(slotkey4); 1202 } 1203 1204 /* Save the session in case it can be used later */ 1205 if (rv == CKR_OK) { 1206 /* 1207 * If currently stored session is not the one being in use now, 1208 * release the previous one and store the current one 1209 */ 1210 if ((session->op1.session) && 1211 (session->op1.session != derive_session)) { 1212 meta_release_slot_session(session->op1.session); 1213 } 1214 1215 /* Save the session */ 1216 session->op1.session = derive_session; 1217 } 1218 1219 return (rv); 1220 } 1221 1222 1223 /* 1224 * Check the following 4 environment variables for user/application's 1225 * configuration for metaslot. User's configuration takes precedence 1226 * over the system wide configuration for metaslot 1227 * 1228 * ${METASLOT_ENABLED} 1229 * ${METASLOT_OBJECTSTORE_SLOT} 1230 * ${METASLOT_OBJECTSTORE_TOKEN} 1231 * ${METASLOT_AUTO_KEY_MIGRATE} 1232 * 1233 * values defined in these environment variables will be stored in the 1234 * global variable "metaslot_config" 1235 */ 1236 void 1237 get_user_metaslot_config() 1238 { 1239 char *env_val = NULL; 1240 1241 /* 1242 * Check to see if any environment variable is defined 1243 * by the user for configuring metaslot. 1244 */ 1245 bzero(&metaslot_config, sizeof (metaslot_config)); 1246 1247 /* METASLOT_ENABLED */ 1248 env_val = getenv("METASLOT_ENABLED"); 1249 if (env_val) { 1250 metaslot_config.enabled_specified = B_TRUE; 1251 if (strcasecmp(env_val, TRUE_STRING) == 0) { 1252 metaslot_config.enabled = B_TRUE; 1253 } else if (strcasecmp(env_val, FALSE_STRING) == 0) { 1254 metaslot_config.enabled = B_FALSE; 1255 } else { 1256 /* value is neither 1 or 0, ignore this value */ 1257 metaslot_config.enabled_specified = B_FALSE; 1258 } 1259 } 1260 1261 /* METASLOT_AUTO_KEY_MIGRATE */ 1262 env_val = getenv("METASLOT_AUTO_KEY_MIGRATE"); 1263 if (env_val) { 1264 metaslot_config.auto_key_migrate_specified = B_TRUE; 1265 if (strcasecmp(env_val, TRUE_STRING) == 0) { 1266 metaslot_config.auto_key_migrate = B_TRUE; 1267 } else if (strcasecmp(env_val, FALSE_STRING) == 0) { 1268 metaslot_config.auto_key_migrate = B_FALSE; 1269 } else { 1270 /* value is neither 1 or 0, ignore this value */ 1271 metaslot_config.auto_key_migrate_specified = B_FALSE; 1272 } 1273 } 1274 1275 /* METASLOT_OBJECTSTORE_SLOT */ 1276 env_val = getenv("METASLOT_OBJECTSTORE_SLOT"); 1277 if (env_val) { 1278 metaslot_config.keystore_slot_specified = B_TRUE; 1279 (void) strlcpy((char *)metaslot_config.keystore_slot, env_val, 1280 SLOT_DESCRIPTION_SIZE); 1281 } 1282 1283 /* METASLOT_OBJECTSTORE_TOKEN */ 1284 env_val = getenv("METASLOT_OBJECTSTORE_TOKEN"); 1285 if (env_val) { 1286 metaslot_config.keystore_token_specified = B_TRUE; 1287 (void) strlcpy((char *)metaslot_config.keystore_token, env_val, 1288 TOKEN_LABEL_SIZE); 1289 } 1290 } 1291