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 REFRELE(session_p, ses_lock_held); 453 return (rv); 454 } 455 456 /* Make the CRYPTO_OBJECT_WRAP_KEY ioctl call. */ 457 obj_wrapkey.wk_session = session_p->k_session; 458 obj_wrapkey.wk_mechanism.cm_type = k_mech_type; 459 obj_wrapkey.wk_mechanism.cm_param = pMechanism->pParameter; 460 obj_wrapkey.wk_mechanism.cm_param_len = pMechanism->ulParameterLen; 461 obj_wrapkey.wk_wrapping_key.ck_format = CRYPTO_KEY_REFERENCE; 462 obj_wrapkey.wk_wrapping_key.ck_obj_id = wrappingkey_p->k_handle; 463 obj_wrapkey.wk_object_handle = key_p->k_handle; 464 obj_wrapkey.wk_wrapped_key_len = *pulWrappedKeyLen; 465 obj_wrapkey.wk_wrapped_key = (char *)pWrappedKey; 466 467 while ((r = ioctl(kernel_fd, CRYPTO_WRAP_KEY, &obj_wrapkey)) < 0) { 468 if (errno != EINTR) 469 break; 470 } 471 if (r < 0) { 472 rv = CKR_FUNCTION_FAILED; 473 } else { 474 rv = crypto2pkcs11_error_number(obj_wrapkey.wk_return_value); 475 } 476 477 /* 478 * Besides rv == CKR_OK, we will set the value of pulWrappedKeyLen 479 * when the applciation-supplied wrapped key buffer is too small. 480 * The situation that the application only asks for the length of 481 * the wrapped key is covered in rv == CKR_OK. 482 */ 483 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) { 484 *pulWrappedKeyLen = obj_wrapkey.wk_wrapped_key_len; 485 } 486 487 REFRELE(session_p, ses_lock_held); 488 return (rv); 489 } 490 491 492 CK_RV 493 C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, 494 CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey, 495 CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate, 496 CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) 497 { 498 CK_RV rv = CKR_OK; 499 kernel_session_t *session_p; 500 kernel_object_t *unwrappingkey_p; 501 kernel_object_t *new_objp = NULL; 502 kernel_slot_t *pslot; 503 boolean_t ses_lock_held = B_FALSE; 504 CK_BBOOL is_pri_obj; 505 CK_BBOOL is_token_obj = FALSE; 506 CK_MECHANISM_INFO info; 507 uint32_t k_mi_flags; 508 CK_BYTE *clear_key_val = NULL; 509 CK_ULONG ulDataLen; 510 CK_ATTRIBUTE_PTR newTemplate = NULL; 511 CK_ULONG templ_size; 512 crypto_mech_type_t k_mech_type; 513 crypto_object_unwrap_key_t obj_unwrapkey; 514 int r; 515 516 if (!kernel_initialized) 517 return (CKR_CRYPTOKI_NOT_INITIALIZED); 518 519 if (pMechanism == NULL || pWrappedKey == NULL || phKey == NULL) { 520 return (CKR_ARGUMENTS_BAD); 521 } 522 523 if ((pTemplate == NULL) && (ulAttributeCount != 0)) { 524 return (CKR_ARGUMENTS_BAD); 525 } 526 527 /* Obtain the session pointer. */ 528 rv = handle2session(hSession, &session_p); 529 if (rv != CKR_OK) 530 return (rv); 531 532 /* Obtain the wrapping key object pointer. */ 533 HANDLE2OBJECT(hUnwrappingKey, unwrappingkey_p, rv); 534 if (rv != CKR_OK) { 535 goto failed_exit; 536 } 537 538 /* 539 * If the HW provider doesn't support C_UnwrapKey, we will try 540 * to emulate it in the library. 541 */ 542 pslot = slot_table[session_p->ses_slotid]; 543 if ((pslot->sl_func_list.fl_object_create == B_FALSE) && 544 (pslot->sl_func_list.fl_key_unwrap == B_FALSE)) { 545 rv = get_mechanism_info(pslot, pMechanism->mechanism, &info, 546 &k_mi_flags); 547 if (rv != CKR_OK) { 548 goto failed_exit; 549 } 550 551 /* 552 * If the mechanism flag doesn't have CKF_UNWRAP, and it's 553 * an unwrapping of a secret key object, then help this 554 * out with a decryption followed by an object creation. 555 */ 556 if (!(k_mi_flags & CRYPTO_FG_UNWRAP) && 557 (k_mi_flags & CRYPTO_FG_DECRYPT) && 558 (is_secret_key_template(pTemplate, ulAttributeCount))) { 559 560 /* First allocate space for the recovered key value */ 561 clear_key_val = malloc(ulWrappedKeyLen); 562 if (clear_key_val == NULL) { 563 rv = CKR_HOST_MEMORY; 564 goto failed_exit; 565 } 566 567 rv = kernel_decrypt_init(session_p, unwrappingkey_p, 568 pMechanism); 569 if (rv != CKR_OK) { 570 goto failed_exit; 571 } 572 573 ulDataLen = ulWrappedKeyLen; 574 rv = kernel_decrypt(session_p, pWrappedKey, 575 ulWrappedKeyLen, clear_key_val, &ulDataLen); 576 if (rv != CKR_OK) { 577 goto failed_exit; 578 } 579 580 /* Now add the CKA_VALUE attribute to template */ 581 templ_size = ulAttributeCount * sizeof (CK_ATTRIBUTE); 582 newTemplate = malloc(templ_size + 583 sizeof (CK_ATTRIBUTE)); 584 if (newTemplate == NULL) { 585 rv = CKR_HOST_MEMORY; 586 goto failed_exit; 587 } 588 589 bcopy(pTemplate, newTemplate, templ_size); 590 newTemplate[ulAttributeCount].type = CKA_VALUE; 591 newTemplate[ulAttributeCount].pValue = clear_key_val; 592 newTemplate[ulAttributeCount].ulValueLen = ulDataLen; 593 594 /* Finally create the key, based on the new template */ 595 rv = kernel_add_object(newTemplate, 596 ulAttributeCount + 1, phKey, session_p); 597 (void) free(clear_key_val); 598 (void) free(newTemplate); 599 REFRELE(session_p, ses_lock_held); 600 return (rv); 601 } else { 602 rv = CKR_FUNCTION_FAILED; 603 goto failed_exit; 604 } 605 } 606 607 /* 608 * If we come here, the HW provider must have registered the unwrapkey 609 * entry. Therefore, the unwrap key will be performed in the HW 610 * provider. 611 */ 612 rv = kernel_mech(pMechanism->mechanism, &k_mech_type); 613 if (rv != CKR_OK) { 614 goto failed_exit; 615 } 616 617 /* Create an object wrapper for the new key in the library first */ 618 new_objp = calloc(1, sizeof (kernel_object_t)); 619 if (new_objp == NULL) { 620 rv = CKR_HOST_MEMORY; 621 goto failed_exit; 622 } 623 624 /* Process the attributes */ 625 rv = process_object_attributes(pTemplate, ulAttributeCount, 626 &obj_unwrapkey.uk_attributes, &is_token_obj); 627 if (rv != CKR_OK) { 628 goto failed_exit; 629 } 630 631 /* Cannot create a token object with a READ-ONLY session. */ 632 if (is_token_obj && session_p->ses_RO) { 633 free_object_attributes(obj_unwrapkey.uk_attributes, 634 ulAttributeCount); 635 rv = CKR_SESSION_READ_ONLY; 636 goto failed_exit; 637 } 638 639 /* Make the CRYPTO_UNWRAP_KEY ioctl call. */ 640 obj_unwrapkey.uk_session = session_p->k_session; 641 obj_unwrapkey.uk_mechanism.cm_type = k_mech_type; 642 obj_unwrapkey.uk_mechanism.cm_param = pMechanism->pParameter; 643 obj_unwrapkey.uk_mechanism.cm_param_len = pMechanism->ulParameterLen; 644 obj_unwrapkey.uk_unwrapping_key.ck_format = CRYPTO_KEY_REFERENCE; 645 obj_unwrapkey.uk_unwrapping_key.ck_obj_id = unwrappingkey_p->k_handle; 646 obj_unwrapkey.uk_wrapped_key = (char *)pWrappedKey; 647 obj_unwrapkey.uk_wrapped_key_len = ulWrappedKeyLen; 648 obj_unwrapkey.uk_count = ulAttributeCount; 649 650 while ((r = ioctl(kernel_fd, CRYPTO_UNWRAP_KEY, &obj_unwrapkey)) < 0) { 651 if (errno != EINTR) 652 break; 653 } 654 if (r < 0) { 655 rv = CKR_FUNCTION_FAILED; 656 } else { 657 rv = crypto2pkcs11_error_number(obj_unwrapkey.uk_return_value); 658 } 659 660 free_object_attributes(obj_unwrapkey.uk_attributes, ulAttributeCount); 661 if (rv != CKR_OK) { 662 goto failed_exit; 663 } 664 665 /* Get the CKA_PRIVATE value for the unwrapped key. */ 666 rv = get_cka_private_value(session_p, obj_unwrapkey.uk_object_handle, 667 &is_pri_obj); 668 if (rv != CKR_OK) { 669 goto failed_exit; 670 } 671 672 /* 673 * Store the kernel object handle in the new key object wrapper and 674 * initialize it. 675 */ 676 new_objp->k_handle = obj_unwrapkey.uk_object_handle; 677 new_objp->is_lib_obj = B_FALSE; 678 new_objp->session_handle = (CK_SESSION_HANDLE)session_p; 679 new_objp->extra_attrlistp = NULL; 680 681 if (is_pri_obj) 682 new_objp->bool_attr_mask |= PRIVATE_BOOL_ON; 683 else 684 new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON; 685 686 if (is_token_obj) 687 new_objp->bool_attr_mask |= TOKEN_BOOL_ON; 688 else 689 new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON; 690 691 (void) pthread_mutex_init(&new_objp->object_mutex, NULL); 692 new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; 693 694 /* 695 * Add the new object to the slot's token object list if it is a 696 * a token object. Otherwise, add it to the session's object list. 697 */ 698 if (is_token_obj) { 699 pslot = slot_table[session_p->ses_slotid]; 700 kernel_add_token_object_to_slot(new_objp, pslot); 701 } else { 702 kernel_add_object_to_session(new_objp, session_p); 703 } 704 705 *phKey = (CK_OBJECT_HANDLE)new_objp; 706 REFRELE(session_p, ses_lock_held); 707 return (rv); 708 709 failed_exit: 710 if (new_objp != NULL) 711 (void) free(new_objp); 712 713 if (clear_key_val != NULL) 714 (void) free(clear_key_val); 715 716 if (newTemplate != NULL) 717 (void) free(newTemplate); 718 719 REFRELE(session_p, ses_lock_held); 720 return (rv); 721 } 722 723 724 CK_RV 725 C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, 726 CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, 727 CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) 728 { 729 CK_RV rv = CKR_OK; 730 kernel_session_t *session_p; 731 kernel_object_t *basekey_p; 732 kernel_object_t *new_objp; 733 kernel_slot_t *pslot; 734 boolean_t ses_lock_held = B_FALSE; 735 CK_BBOOL is_pri_obj; 736 CK_BBOOL is_token_obj = FALSE; 737 crypto_mech_type_t k_mech_type; 738 crypto_derive_key_t obj_dk; 739 int r; 740 741 if (!kernel_initialized) 742 return (CKR_CRYPTOKI_NOT_INITIALIZED); 743 744 /* Obtain the session pointer. */ 745 rv = handle2session(hSession, &session_p); 746 if (rv != CKR_OK) 747 return (rv); 748 749 if ((pMechanism == NULL) || (phKey == NULL)) { 750 rv = CKR_ARGUMENTS_BAD; 751 goto failed_exit; 752 } 753 754 if ((pTemplate == NULL && ulAttributeCount != 0) || 755 (pTemplate != NULL && ulAttributeCount == 0)) { 756 rv = CKR_ARGUMENTS_BAD; 757 goto failed_exit; 758 } 759 760 /* Obtain the base key object pointer. */ 761 HANDLE2OBJECT(hBaseKey, basekey_p, rv); 762 if (rv != CKR_OK) { 763 goto failed_exit; 764 } 765 766 /* Get the kernel's internal mechanism number. */ 767 rv = kernel_mech(pMechanism->mechanism, &k_mech_type); 768 if (rv != CKR_OK) { 769 goto failed_exit; 770 } 771 772 /* Create an object wrapper in the library for the generated key. */ 773 new_objp = calloc(1, sizeof (kernel_object_t)); 774 if (new_objp == NULL) { 775 rv = CKR_HOST_MEMORY; 776 goto failed_exit; 777 } 778 779 /* Process the attributes */ 780 rv = process_object_attributes(pTemplate, ulAttributeCount, 781 &obj_dk.dk_attributes, &is_token_obj); 782 if (rv != CKR_OK) { 783 goto failed_exit; 784 } 785 786 /* Cannot create a token object with a READ-ONLY session. */ 787 if (is_token_obj && session_p->ses_RO) { 788 free_object_attributes(obj_dk.dk_attributes, ulAttributeCount); 789 rv = CKR_SESSION_READ_ONLY; 790 goto failed_exit; 791 } 792 793 /* Call the CRYPTO_DERIVE_KEY ioctl */ 794 obj_dk.dk_session = session_p->k_session; 795 obj_dk.dk_mechanism.cm_type = k_mech_type; 796 obj_dk.dk_mechanism.cm_param = pMechanism->pParameter; 797 obj_dk.dk_mechanism.cm_param_len = pMechanism->ulParameterLen; 798 obj_dk.dk_base_key.ck_format = CRYPTO_KEY_REFERENCE; 799 obj_dk.dk_base_key.ck_obj_id = basekey_p->k_handle; 800 obj_dk.dk_count = ulAttributeCount; 801 802 while ((r = ioctl(kernel_fd, CRYPTO_DERIVE_KEY, &obj_dk)) < 0) { 803 if (errno != EINTR) 804 break; 805 } 806 if (r < 0) { 807 rv = CKR_FUNCTION_FAILED; 808 } else { 809 rv = crypto2pkcs11_error_number(obj_dk.dk_return_value); 810 } 811 812 free_object_attributes(obj_dk.dk_attributes, ulAttributeCount); 813 if (rv != CKR_OK) { 814 goto failed_exit; 815 } 816 817 /* Get the CKA_PRIVATE value for the derived key. */ 818 rv = get_cka_private_value(session_p, obj_dk.dk_object_handle, 819 &is_pri_obj); 820 if (rv != CKR_OK) { 821 goto failed_exit; 822 } 823 824 /* 825 * Store the kernel object handle into the new derived key object 826 * and finish the object initialization. 827 */ 828 new_objp->is_lib_obj = B_FALSE; 829 new_objp->k_handle = obj_dk.dk_object_handle; 830 new_objp->session_handle = (CK_SESSION_HANDLE)session_p; 831 new_objp->extra_attrlistp = NULL; 832 833 if (is_pri_obj) 834 new_objp->bool_attr_mask |= PRIVATE_BOOL_ON; 835 else 836 new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON; 837 838 if (is_token_obj) 839 new_objp->bool_attr_mask |= TOKEN_BOOL_ON; 840 else 841 new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON; 842 843 (void) pthread_mutex_init(&new_objp->object_mutex, NULL); 844 new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; 845 846 /* 847 * Add the new derived object to the slot's token list if it is a 848 * token object. Otherwise, add it to the session's object list. 849 */ 850 if (is_token_obj) { 851 pslot = slot_table[session_p->ses_slotid]; 852 kernel_add_token_object_to_slot(new_objp, pslot); 853 } else { 854 kernel_add_object_to_session(new_objp, session_p); 855 } 856 857 *phKey = (CK_OBJECT_HANDLE)new_objp; 858 REFRELE(session_p, ses_lock_held); 859 return (rv); 860 861 failed_exit: 862 if (new_objp != NULL) { 863 (void) free(new_objp); 864 } 865 866 REFRELE(session_p, ses_lock_held); 867 return (rv); 868 } 869