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 <strings.h> 30 #include <errno.h> 31 #include <security/cryptoki.h> 32 #include <sys/crypto/ioctl.h> 33 #include "kernelGlobal.h" 34 #include "kernelSession.h" 35 #include "kernelObject.h" 36 37 static boolean_t 38 is_secret_key_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount) 39 { 40 int i; 41 for (i = 0; i < ulAttributeCount; i++) { 42 if (pTemplate[i].type == CKA_CLASS && 43 *(CK_OBJECT_CLASS *)(pTemplate[i].pValue) == 44 CKO_SECRET_KEY) 45 return (B_TRUE); 46 } 47 return (B_FALSE); 48 } 49 50 51 CK_RV 52 C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, 53 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey) 54 { 55 CK_RV rv = CKR_OK; 56 kernel_session_t *session_p; 57 kernel_object_t *new_objp = NULL; 58 kernel_slot_t *pslot; 59 boolean_t ses_lock_held = B_FALSE; 60 CK_BBOOL is_pri_obj; 61 CK_BBOOL is_token_obj = FALSE; 62 crypto_mech_type_t k_mech_type; 63 crypto_object_generate_key_t obj_gk; 64 int r; 65 66 if (!kernel_initialized) 67 return (CKR_CRYPTOKI_NOT_INITIALIZED); 68 69 /* Obtain the session pointer */ 70 rv = handle2session(hSession, &session_p); 71 if (rv != CKR_OK) 72 return (rv); 73 74 if ((pMechanism == NULL) || (phKey == NULL)) { 75 rv = CKR_ARGUMENTS_BAD; 76 goto failed_exit; 77 } 78 79 if ((pTemplate == NULL) && (ulCount != 0)) { 80 rv = CKR_ARGUMENTS_BAD; 81 goto failed_exit; 82 } 83 84 /* Get the kernel's internal mechanism number. */ 85 rv = kernel_mech(pMechanism->mechanism, &k_mech_type); 86 if (rv != CKR_OK) { 87 goto failed_exit; 88 } 89 90 /* Create an object wrapper in the library first */ 91 new_objp = calloc(1, sizeof (kernel_object_t)); 92 if (new_objp == NULL) { 93 rv = CKR_HOST_MEMORY; 94 goto failed_exit; 95 } 96 97 /* Process the attributes */ 98 rv = process_object_attributes(pTemplate, ulCount, 99 &obj_gk.gk_attributes, &is_token_obj); 100 if (rv != CKR_OK) { 101 goto failed_exit; 102 } 103 104 /* Cannot create a token object with a READ-ONLY session. */ 105 if (is_token_obj && session_p->ses_RO) { 106 free_object_attributes(obj_gk.gk_attributes, ulCount); 107 rv = CKR_SESSION_READ_ONLY; 108 goto failed_exit; 109 } 110 111 /* Call the CRYPTO_GENERATE_KEY ioctl */ 112 obj_gk.gk_session = session_p->k_session; 113 obj_gk.gk_count = ulCount; 114 obj_gk.gk_mechanism.cm_type = k_mech_type; 115 obj_gk.gk_mechanism.cm_param = pMechanism->pParameter; 116 obj_gk.gk_mechanism.cm_param_len = pMechanism->ulParameterLen; 117 118 while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY, &obj_gk)) < 0) { 119 if (errno != EINTR) 120 break; 121 } 122 if (r < 0) { 123 rv = CKR_FUNCTION_FAILED; 124 } else { 125 rv = crypto2pkcs11_error_number(obj_gk.gk_return_value); 126 } 127 128 free_object_attributes(obj_gk.gk_attributes, ulCount); 129 if (rv != CKR_OK) { 130 goto failed_exit; 131 } 132 133 /* Get the value of the CKA_PRIVATE attribute. */ 134 rv = get_cka_private_value(session_p, obj_gk.gk_handle, &is_pri_obj); 135 if (rv != CKR_OK) { 136 goto failed_exit; 137 } 138 139 /* 140 * Store the kernel object handle in the object wrapper and 141 * initialize the library object. 142 */ 143 new_objp->k_handle = obj_gk.gk_handle; 144 new_objp->is_lib_obj = B_FALSE; 145 new_objp->session_handle = (CK_SESSION_HANDLE)session_p; 146 new_objp->extra_attrlistp = NULL; 147 148 if (is_pri_obj) 149 new_objp->bool_attr_mask |= PRIVATE_BOOL_ON; 150 else 151 new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON; 152 153 if (is_token_obj) 154 new_objp->bool_attr_mask |= TOKEN_BOOL_ON; 155 else 156 new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON; 157 158 (void) pthread_mutex_init(&new_objp->object_mutex, NULL); 159 new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; 160 161 /* 162 * Add the new object to the slot's token object list if it is a 163 * a token object. Otherwise, add it to the session's object list. 164 */ 165 if (is_token_obj) { 166 pslot = slot_table[session_p->ses_slotid]; 167 kernel_add_token_object_to_slot(new_objp, pslot); 168 } else { 169 kernel_add_object_to_session(new_objp, session_p); 170 } 171 172 *phKey = (CK_OBJECT_HANDLE)new_objp; 173 REFRELE(session_p, ses_lock_held); 174 return (rv); 175 176 failed_exit: 177 if (new_objp != NULL) { 178 (void) free(new_objp); 179 } 180 181 REFRELE(session_p, ses_lock_held); 182 return (rv); 183 } 184 185 186 CK_RV 187 C_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, 188 CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, 189 CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, 190 CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey) 191 { 192 CK_RV rv = CKR_OK; 193 kernel_session_t *session_p; 194 kernel_object_t *new_pub_objp = NULL; 195 kernel_object_t *new_pri_objp = NULL; 196 kernel_slot_t *pslot; 197 boolean_t ses_lock_held = B_FALSE; 198 CK_BBOOL is_pri_obj1; 199 CK_BBOOL is_pri_obj2; 200 CK_BBOOL is_token_obj1 = FALSE; 201 CK_BBOOL is_token_obj2 = FALSE; 202 crypto_mech_type_t k_mech_type; 203 crypto_object_generate_key_pair_t obj_kp; 204 int r; 205 206 if (!kernel_initialized) 207 return (CKR_CRYPTOKI_NOT_INITIALIZED); 208 209 /* Obtain the session pointer. */ 210 rv = handle2session(hSession, &session_p); 211 if (rv != CKR_OK) 212 return (rv); 213 214 if ((pMechanism == NULL) || (phPublicKey == NULL) || 215 (phPrivateKey == NULL)) { 216 rv = CKR_ARGUMENTS_BAD; 217 goto failed_exit; 218 } 219 220 if ((pPublicKeyTemplate == NULL) && (ulPublicKeyAttributeCount != 0)) { 221 rv = CKR_ARGUMENTS_BAD; 222 goto failed_exit; 223 } 224 225 if ((pPrivateKeyTemplate == NULL) && 226 (ulPrivateKeyAttributeCount != 0)) { 227 rv = CKR_ARGUMENTS_BAD; 228 goto failed_exit; 229 } 230 231 /* Get the kernel's internal mechanism number. */ 232 rv = kernel_mech(pMechanism->mechanism, &k_mech_type); 233 if (rv != CKR_OK) { 234 goto failed_exit; 235 } 236 237 /* Create an object wrapper for the public key */ 238 new_pub_objp = calloc(1, sizeof (kernel_object_t)); 239 if (new_pub_objp == NULL) { 240 rv = CKR_HOST_MEMORY; 241 goto failed_exit; 242 } 243 244 /* Create an object wrapper for the private key. */ 245 new_pri_objp = calloc(1, sizeof (kernel_object_t)); 246 if (new_pri_objp == NULL) { 247 rv = CKR_HOST_MEMORY; 248 goto failed_exit; 249 } 250 251 /* Process the public key attributes. */ 252 rv = process_object_attributes(pPublicKeyTemplate, 253 ulPublicKeyAttributeCount, &obj_kp.kp_public_attributes, 254 &is_token_obj1); 255 if (rv != CKR_OK) { 256 goto failed_exit; 257 } 258 259 /* Cannot create a token object with a READ-ONLY session. */ 260 if (is_token_obj1 && session_p->ses_RO) { 261 free_object_attributes(obj_kp.kp_public_attributes, 262 ulPublicKeyAttributeCount); 263 rv = CKR_SESSION_READ_ONLY; 264 goto failed_exit; 265 } 266 267 /* Process the private key attributes. */ 268 rv = process_object_attributes(pPrivateKeyTemplate, 269 ulPrivateKeyAttributeCount, &obj_kp.kp_private_attributes, 270 &is_token_obj2); 271 if (rv != CKR_OK) { 272 free_object_attributes(obj_kp.kp_public_attributes, 273 ulPublicKeyAttributeCount); 274 goto failed_exit; 275 } 276 277 /* 278 * The public key and the private key need to contain the same 279 * attribute values for CKA_TOKEN. 280 */ 281 if (is_token_obj1 != is_token_obj2) { 282 free_object_attributes(obj_kp.kp_public_attributes, 283 ulPublicKeyAttributeCount); 284 free_object_attributes(obj_kp.kp_private_attributes, 285 ulPrivateKeyAttributeCount); 286 rv = CKR_ATTRIBUTE_VALUE_INVALID; 287 goto failed_exit; 288 } 289 290 /* Call the CRYPTO_GENERATE_KEY_PAIR ioctl. */ 291 obj_kp.kp_session = session_p-> k_session; 292 obj_kp.kp_mechanism.cm_type = k_mech_type; 293 obj_kp.kp_mechanism.cm_param = pMechanism->pParameter; 294 obj_kp.kp_mechanism.cm_param_len = pMechanism->ulParameterLen; 295 obj_kp.kp_public_count = ulPublicKeyAttributeCount; 296 obj_kp.kp_private_count = ulPrivateKeyAttributeCount; 297 298 while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY_PAIR, &obj_kp)) < 0) { 299 if (errno != EINTR) 300 break; 301 } 302 if (r < 0) { 303 rv = CKR_FUNCTION_FAILED; 304 } else { 305 rv = crypto2pkcs11_error_number(obj_kp.kp_return_value); 306 } 307 308 free_object_attributes(obj_kp.kp_public_attributes, 309 ulPublicKeyAttributeCount); 310 free_object_attributes(obj_kp.kp_private_attributes, 311 ulPrivateKeyAttributeCount); 312 313 if (rv != CKR_OK) { 314 goto failed_exit; 315 } 316 317 /* Get the CKA_PRIVATE value for the key pair. */ 318 rv = get_cka_private_value(session_p, obj_kp.kp_public_handle, 319 &is_pri_obj1); 320 if (rv != CKR_OK) { 321 goto failed_exit; 322 } 323 324 rv = get_cka_private_value(session_p, obj_kp.kp_private_handle, 325 &is_pri_obj2); 326 if (rv != CKR_OK) { 327 goto failed_exit; 328 } 329 330 /* 331 * Store the kernel public key handle into the public key object and 332 * finish the public key object initialization. 333 */ 334 new_pub_objp->is_lib_obj = B_FALSE; 335 new_pub_objp->k_handle = obj_kp.kp_public_handle; 336 new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p; 337 new_pub_objp->extra_attrlistp = NULL; 338 339 if (is_pri_obj1) 340 new_pub_objp->bool_attr_mask |= PRIVATE_BOOL_ON; 341 else 342 new_pub_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON; 343 344 if (is_token_obj1) 345 new_pub_objp->bool_attr_mask |= TOKEN_BOOL_ON; 346 else 347 new_pub_objp->bool_attr_mask &= ~TOKEN_BOOL_ON; 348 349 (void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL); 350 new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; 351 352 /* 353 * Store the kernel private key handle into the private key object 354 * and finish the private key object initialization. 355 */ 356 new_pri_objp->is_lib_obj = B_FALSE; 357 new_pri_objp->k_handle = obj_kp.kp_private_handle; 358 new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p; 359 new_pri_objp->extra_attrlistp = NULL; 360 361 if (is_pri_obj2) 362 new_pri_objp->bool_attr_mask |= PRIVATE_BOOL_ON; 363 else 364 new_pri_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON; 365 366 if (is_token_obj2) 367 new_pri_objp->bool_attr_mask |= TOKEN_BOOL_ON; 368 else 369 new_pri_objp->bool_attr_mask &= ~TOKEN_BOOL_ON; 370 371 (void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL); 372 new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; 373 374 /* 375 * Add the new pub/pri objects to the slot's token list if they are 376 * token objects. Otherwise, add them to the session's object list. 377 */ 378 if (is_token_obj1) { /* is_token_obj1 == is_token_obj2 */ 379 pslot = slot_table[session_p->ses_slotid]; 380 kernel_add_token_object_to_slot(new_pub_objp, pslot); 381 kernel_add_token_object_to_slot(new_pri_objp, pslot); 382 } else { 383 kernel_add_object_to_session(new_pub_objp, session_p); 384 kernel_add_object_to_session(new_pri_objp, session_p); 385 } 386 387 *phPublicKey = (CK_OBJECT_HANDLE)new_pub_objp; 388 *phPrivateKey = (CK_OBJECT_HANDLE)new_pri_objp; 389 REFRELE(session_p, ses_lock_held); 390 return (rv); 391 392 failed_exit: 393 if (new_pub_objp != NULL) { 394 (void) free(new_pub_objp); 395 } 396 397 if (new_pri_objp != NULL) { 398 (void) free(new_pri_objp); 399 } 400 401 REFRELE(session_p, ses_lock_held); 402 return (rv); 403 } 404 405 406 CK_RV 407 C_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, 408 CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey, 409 CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen) 410 { 411 CK_RV rv = CKR_OK; 412 kernel_session_t *session_p; 413 boolean_t ses_lock_held = B_FALSE; 414 kernel_object_t *wrappingkey_p; 415 kernel_object_t *key_p; 416 crypto_mech_type_t k_mech_type; 417 crypto_object_wrap_key_t obj_wrapkey; 418 int r; 419 420 if (!kernel_initialized) 421 return (CKR_CRYPTOKI_NOT_INITIALIZED); 422 423 if (pulWrappedKeyLen == NULL || pMechanism == NULL) { 424 return (CKR_ARGUMENTS_BAD); 425 } 426 427 /* 428 * Obtain the session pointer. Also, increment the session 429 * reference count. 430 */ 431 rv = handle2session(hSession, &session_p); 432 if (rv != CKR_OK) 433 return (rv); 434 435 /* Get the kernel's internal mechanism number. */ 436 rv = kernel_mech(pMechanism->mechanism, &k_mech_type); 437 if (rv != CKR_OK) { 438 REFRELE(session_p, ses_lock_held); 439 return (rv); 440 } 441 442 /* Obtain the wrapping key object pointer. */ 443 HANDLE2OBJECT(hWrappingKey, wrappingkey_p, rv); 444 if (rv != CKR_OK) { 445 REFRELE(session_p, ses_lock_held); 446 return (rv); 447 } 448 449 /* Obtain the to_be_wrapped key object pointer. */ 450 HANDLE2OBJECT(hKey, key_p, rv); 451 if (rv != CKR_OK) { 452 OBJ_REFRELE(wrappingkey_p); 453 REFRELE(session_p, ses_lock_held); 454 return (rv); 455 } 456 457 /* Make the CRYPTO_OBJECT_WRAP_KEY ioctl call. */ 458 obj_wrapkey.wk_session = session_p->k_session; 459 obj_wrapkey.wk_mechanism.cm_type = k_mech_type; 460 obj_wrapkey.wk_mechanism.cm_param = pMechanism->pParameter; 461 obj_wrapkey.wk_mechanism.cm_param_len = pMechanism->ulParameterLen; 462 obj_wrapkey.wk_wrapping_key.ck_format = CRYPTO_KEY_REFERENCE; 463 obj_wrapkey.wk_wrapping_key.ck_obj_id = wrappingkey_p->k_handle; 464 obj_wrapkey.wk_object_handle = key_p->k_handle; 465 obj_wrapkey.wk_wrapped_key_len = *pulWrappedKeyLen; 466 obj_wrapkey.wk_wrapped_key = (char *)pWrappedKey; 467 468 while ((r = ioctl(kernel_fd, CRYPTO_WRAP_KEY, &obj_wrapkey)) < 0) { 469 if (errno != EINTR) 470 break; 471 } 472 if (r < 0) { 473 rv = CKR_FUNCTION_FAILED; 474 } else { 475 rv = crypto2pkcs11_error_number(obj_wrapkey.wk_return_value); 476 } 477 478 /* 479 * Besides rv == CKR_OK, we will set the value of pulWrappedKeyLen 480 * when the applciation-supplied wrapped key buffer is too small. 481 * The situation that the application only asks for the length of 482 * the wrapped key is covered in rv == CKR_OK. 483 */ 484 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) { 485 *pulWrappedKeyLen = obj_wrapkey.wk_wrapped_key_len; 486 } 487 488 OBJ_REFRELE(key_p); 489 OBJ_REFRELE(wrappingkey_p); 490 REFRELE(session_p, ses_lock_held); 491 return (rv); 492 } 493 494 495 CK_RV 496 C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, 497 CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey, 498 CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate, 499 CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) 500 { 501 CK_RV rv = CKR_OK; 502 kernel_session_t *session_p; 503 kernel_object_t *unwrappingkey_p; 504 kernel_object_t *new_objp = NULL; 505 kernel_slot_t *pslot; 506 boolean_t ses_lock_held = B_FALSE; 507 CK_BBOOL is_pri_obj; 508 CK_BBOOL is_token_obj = FALSE; 509 CK_MECHANISM_INFO info; 510 uint32_t k_mi_flags; 511 CK_BYTE *clear_key_val = NULL; 512 CK_ULONG ulDataLen; 513 CK_ATTRIBUTE_PTR newTemplate = NULL; 514 CK_ULONG templ_size; 515 crypto_mech_type_t k_mech_type; 516 crypto_object_unwrap_key_t obj_unwrapkey; 517 int r; 518 519 if (!kernel_initialized) 520 return (CKR_CRYPTOKI_NOT_INITIALIZED); 521 522 if (pMechanism == NULL || pWrappedKey == NULL || phKey == NULL) { 523 return (CKR_ARGUMENTS_BAD); 524 } 525 526 if ((pTemplate == NULL) && (ulAttributeCount != 0)) { 527 return (CKR_ARGUMENTS_BAD); 528 } 529 530 /* Obtain the session pointer. */ 531 rv = handle2session(hSession, &session_p); 532 if (rv != CKR_OK) 533 return (rv); 534 535 /* Obtain the wrapping key object pointer. */ 536 HANDLE2OBJECT(hUnwrappingKey, unwrappingkey_p, rv); 537 if (rv != CKR_OK) { 538 REFRELE(session_p, ses_lock_held); 539 return (rv); 540 } 541 542 /* 543 * If the HW provider doesn't support C_UnwrapKey, we will try 544 * to emulate it in the library. 545 */ 546 pslot = slot_table[session_p->ses_slotid]; 547 if ((pslot->sl_func_list.fl_object_create == B_FALSE) && 548 (pslot->sl_func_list.fl_key_unwrap == B_FALSE)) { 549 rv = get_mechanism_info(pslot, pMechanism->mechanism, &info, 550 &k_mi_flags); 551 if (rv != CKR_OK) { 552 goto failed_exit; 553 } 554 555 /* 556 * If the mechanism flag doesn't have CKF_UNWRAP, and it's 557 * an unwrapping of a secret key object, then help this 558 * out with a decryption followed by an object creation. 559 */ 560 if (!(k_mi_flags & CRYPTO_FG_UNWRAP) && 561 (k_mi_flags & CRYPTO_FG_DECRYPT) && 562 (is_secret_key_template(pTemplate, ulAttributeCount))) { 563 564 /* First allocate space for the recovered key value */ 565 clear_key_val = malloc(ulWrappedKeyLen); 566 if (clear_key_val == NULL) { 567 rv = CKR_HOST_MEMORY; 568 goto failed_exit; 569 } 570 571 rv = kernel_decrypt_init(session_p, unwrappingkey_p, 572 pMechanism); 573 if (rv != CKR_OK) { 574 goto failed_exit; 575 } 576 577 ulDataLen = ulWrappedKeyLen; 578 rv = kernel_decrypt(session_p, pWrappedKey, 579 ulWrappedKeyLen, clear_key_val, &ulDataLen); 580 if (rv != CKR_OK) { 581 goto failed_exit; 582 } 583 584 /* Now add the CKA_VALUE attribute to template */ 585 templ_size = ulAttributeCount * sizeof (CK_ATTRIBUTE); 586 newTemplate = malloc(templ_size + 587 sizeof (CK_ATTRIBUTE)); 588 if (newTemplate == NULL) { 589 rv = CKR_HOST_MEMORY; 590 goto failed_exit; 591 } 592 593 bcopy(pTemplate, newTemplate, templ_size); 594 newTemplate[ulAttributeCount].type = CKA_VALUE; 595 newTemplate[ulAttributeCount].pValue = clear_key_val; 596 newTemplate[ulAttributeCount].ulValueLen = ulDataLen; 597 598 /* Finally create the key, based on the new template */ 599 rv = kernel_add_object(newTemplate, 600 ulAttributeCount + 1, phKey, session_p); 601 (void) free(clear_key_val); 602 (void) free(newTemplate); 603 OBJ_REFRELE(unwrappingkey_p); 604 REFRELE(session_p, ses_lock_held); 605 return (rv); 606 } else { 607 rv = CKR_FUNCTION_FAILED; 608 goto failed_exit; 609 } 610 } 611 612 /* 613 * If we come here, the HW provider must have registered the unwrapkey 614 * entry. Therefore, the unwrap key will be performed in the HW 615 * provider. 616 */ 617 rv = kernel_mech(pMechanism->mechanism, &k_mech_type); 618 if (rv != CKR_OK) { 619 goto failed_exit; 620 } 621 622 /* Create an object wrapper for the new key in the library first */ 623 new_objp = calloc(1, sizeof (kernel_object_t)); 624 if (new_objp == NULL) { 625 rv = CKR_HOST_MEMORY; 626 goto failed_exit; 627 } 628 629 /* Process the attributes */ 630 rv = process_object_attributes(pTemplate, ulAttributeCount, 631 &obj_unwrapkey.uk_attributes, &is_token_obj); 632 if (rv != CKR_OK) { 633 goto failed_exit; 634 } 635 636 /* Cannot create a token object with a READ-ONLY session. */ 637 if (is_token_obj && session_p->ses_RO) { 638 free_object_attributes(obj_unwrapkey.uk_attributes, 639 ulAttributeCount); 640 rv = CKR_SESSION_READ_ONLY; 641 goto failed_exit; 642 } 643 644 /* Make the CRYPTO_UNWRAP_KEY ioctl call. */ 645 obj_unwrapkey.uk_session = session_p->k_session; 646 obj_unwrapkey.uk_mechanism.cm_type = k_mech_type; 647 obj_unwrapkey.uk_mechanism.cm_param = pMechanism->pParameter; 648 obj_unwrapkey.uk_mechanism.cm_param_len = pMechanism->ulParameterLen; 649 obj_unwrapkey.uk_unwrapping_key.ck_format = CRYPTO_KEY_REFERENCE; 650 obj_unwrapkey.uk_unwrapping_key.ck_obj_id = unwrappingkey_p->k_handle; 651 obj_unwrapkey.uk_wrapped_key = (char *)pWrappedKey; 652 obj_unwrapkey.uk_wrapped_key_len = ulWrappedKeyLen; 653 obj_unwrapkey.uk_count = ulAttributeCount; 654 655 while ((r = ioctl(kernel_fd, CRYPTO_UNWRAP_KEY, &obj_unwrapkey)) < 0) { 656 if (errno != EINTR) 657 break; 658 } 659 if (r < 0) { 660 rv = CKR_FUNCTION_FAILED; 661 } else { 662 rv = crypto2pkcs11_error_number(obj_unwrapkey.uk_return_value); 663 } 664 665 free_object_attributes(obj_unwrapkey.uk_attributes, ulAttributeCount); 666 if (rv != CKR_OK) { 667 goto failed_exit; 668 } 669 670 /* Get the CKA_PRIVATE value for the unwrapped key. */ 671 rv = get_cka_private_value(session_p, obj_unwrapkey.uk_object_handle, 672 &is_pri_obj); 673 if (rv != CKR_OK) { 674 goto failed_exit; 675 } 676 677 /* 678 * Store the kernel object handle in the new key object wrapper and 679 * initialize it. 680 */ 681 new_objp->k_handle = obj_unwrapkey.uk_object_handle; 682 new_objp->is_lib_obj = B_FALSE; 683 new_objp->session_handle = (CK_SESSION_HANDLE)session_p; 684 new_objp->extra_attrlistp = NULL; 685 686 if (is_pri_obj) 687 new_objp->bool_attr_mask |= PRIVATE_BOOL_ON; 688 else 689 new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON; 690 691 if (is_token_obj) 692 new_objp->bool_attr_mask |= TOKEN_BOOL_ON; 693 else 694 new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON; 695 696 (void) pthread_mutex_init(&new_objp->object_mutex, NULL); 697 new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; 698 699 /* 700 * Add the new object to the slot's token object list if it is a 701 * a token object. Otherwise, add it to the session's object list. 702 */ 703 if (is_token_obj) { 704 pslot = slot_table[session_p->ses_slotid]; 705 kernel_add_token_object_to_slot(new_objp, pslot); 706 } else { 707 kernel_add_object_to_session(new_objp, session_p); 708 } 709 710 *phKey = (CK_OBJECT_HANDLE)new_objp; 711 OBJ_REFRELE(unwrappingkey_p); 712 REFRELE(session_p, ses_lock_held); 713 return (rv); 714 715 failed_exit: 716 OBJ_REFRELE(unwrappingkey_p); 717 if (new_objp != NULL) 718 (void) free(new_objp); 719 720 if (clear_key_val != NULL) 721 (void) free(clear_key_val); 722 723 if (newTemplate != NULL) 724 (void) free(newTemplate); 725 726 REFRELE(session_p, ses_lock_held); 727 return (rv); 728 } 729 730 731 CK_RV 732 C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, 733 CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, 734 CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) 735 { 736 CK_RV rv = CKR_OK; 737 kernel_session_t *session_p; 738 kernel_object_t *basekey_p; 739 kernel_object_t *new_objp; 740 kernel_slot_t *pslot; 741 boolean_t ses_lock_held = B_FALSE; 742 CK_BBOOL is_pri_obj; 743 CK_BBOOL is_token_obj = FALSE; 744 crypto_mech_type_t k_mech_type; 745 crypto_derive_key_t obj_dk; 746 int r; 747 748 if (!kernel_initialized) 749 return (CKR_CRYPTOKI_NOT_INITIALIZED); 750 751 /* Obtain the session pointer. */ 752 rv = handle2session(hSession, &session_p); 753 if (rv != CKR_OK) 754 return (rv); 755 756 if ((pMechanism == NULL) || (phKey == NULL)) { 757 REFRELE(session_p, ses_lock_held); 758 return (CKR_ARGUMENTS_BAD); 759 } 760 761 if ((pTemplate == NULL && ulAttributeCount != 0) || 762 (pTemplate != NULL && ulAttributeCount == 0)) { 763 REFRELE(session_p, ses_lock_held); 764 return (CKR_ARGUMENTS_BAD); 765 } 766 767 /* Obtain the base key object pointer. */ 768 HANDLE2OBJECT(hBaseKey, basekey_p, rv); 769 if (rv != CKR_OK) { 770 REFRELE(session_p, ses_lock_held); 771 return (rv); 772 } 773 774 /* Get the kernel's internal mechanism number. */ 775 rv = kernel_mech(pMechanism->mechanism, &k_mech_type); 776 if (rv != CKR_OK) { 777 goto failed_exit; 778 } 779 780 /* Create an object wrapper in the library for the generated key. */ 781 new_objp = calloc(1, sizeof (kernel_object_t)); 782 if (new_objp == NULL) { 783 rv = CKR_HOST_MEMORY; 784 goto failed_exit; 785 } 786 787 /* Process the attributes */ 788 rv = process_object_attributes(pTemplate, ulAttributeCount, 789 &obj_dk.dk_attributes, &is_token_obj); 790 if (rv != CKR_OK) { 791 goto failed_exit; 792 } 793 794 /* Cannot create a token object with a READ-ONLY session. */ 795 if (is_token_obj && session_p->ses_RO) { 796 free_object_attributes(obj_dk.dk_attributes, ulAttributeCount); 797 rv = CKR_SESSION_READ_ONLY; 798 goto failed_exit; 799 } 800 801 /* Call the CRYPTO_DERIVE_KEY ioctl */ 802 obj_dk.dk_session = session_p->k_session; 803 obj_dk.dk_mechanism.cm_type = k_mech_type; 804 obj_dk.dk_mechanism.cm_param = pMechanism->pParameter; 805 obj_dk.dk_mechanism.cm_param_len = pMechanism->ulParameterLen; 806 obj_dk.dk_base_key.ck_format = CRYPTO_KEY_REFERENCE; 807 obj_dk.dk_base_key.ck_obj_id = basekey_p->k_handle; 808 obj_dk.dk_count = ulAttributeCount; 809 810 while ((r = ioctl(kernel_fd, CRYPTO_DERIVE_KEY, &obj_dk)) < 0) { 811 if (errno != EINTR) 812 break; 813 } 814 if (r < 0) { 815 rv = CKR_FUNCTION_FAILED; 816 } else { 817 rv = crypto2pkcs11_error_number(obj_dk.dk_return_value); 818 } 819 820 free_object_attributes(obj_dk.dk_attributes, ulAttributeCount); 821 if (rv != CKR_OK) { 822 goto failed_exit; 823 } 824 825 /* Get the CKA_PRIVATE value for the derived key. */ 826 rv = get_cka_private_value(session_p, obj_dk.dk_object_handle, 827 &is_pri_obj); 828 if (rv != CKR_OK) { 829 goto failed_exit; 830 } 831 832 /* 833 * Store the kernel object handle into the new derived key object 834 * and finish the object initialization. 835 */ 836 new_objp->is_lib_obj = B_FALSE; 837 new_objp->k_handle = obj_dk.dk_object_handle; 838 new_objp->session_handle = (CK_SESSION_HANDLE)session_p; 839 new_objp->extra_attrlistp = NULL; 840 841 if (is_pri_obj) 842 new_objp->bool_attr_mask |= PRIVATE_BOOL_ON; 843 else 844 new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON; 845 846 if (is_token_obj) 847 new_objp->bool_attr_mask |= TOKEN_BOOL_ON; 848 else 849 new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON; 850 851 (void) pthread_mutex_init(&new_objp->object_mutex, NULL); 852 new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; 853 854 /* 855 * Add the new derived object to the slot's token list if it is a 856 * token object. Otherwise, add it to the session's object list. 857 */ 858 if (is_token_obj) { 859 pslot = slot_table[session_p->ses_slotid]; 860 kernel_add_token_object_to_slot(new_objp, pslot); 861 } else { 862 kernel_add_object_to_session(new_objp, session_p); 863 } 864 865 *phKey = (CK_OBJECT_HANDLE)new_objp; 866 OBJ_REFRELE(basekey_p); 867 REFRELE(session_p, ses_lock_held); 868 return (rv); 869 870 failed_exit: 871 OBJ_REFRELE(basekey_p); 872 if (new_objp != NULL) { 873 (void) free(new_objp); 874 } 875 876 REFRELE(session_p, ses_lock_held); 877 return (rv); 878 } 879