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 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  * Copyright 2018, Joyent, Inc.
  25  */
  26 
  27 #include <strings.h>
  28 #include <errno.h>
  29 #include <ecc_impl.h>
  30 #include <security/cryptoki.h>
  31 #include <sys/crypto/ioctl.h>
  32 #include "kernelGlobal.h"
  33 #include "kernelSession.h"
  34 #include "kernelObject.h"
  35 
  36 static boolean_t
  37 attribute_in_template(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR t, CK_ULONG cnt)
  38 {
  39         int i;
  40 
  41         for (i = 0; i < cnt; i++) {
  42                 if (t[i].type == type)
  43                         return (B_TRUE);
  44         }
  45         return (B_FALSE);
  46 }
  47 
  48 /*
  49  * This routine returns modulus bytes rounded up to the nearest 8 byte
  50  * chunk. This is so we don't have to pass in max sized buffers for
  51  * returned attributes. Every unnecessary byte that we pass in results
  52  * in a kernel allocation.
  53  */
  54 static ulong_t
  55 get_modulus_bytes(CK_ATTRIBUTE_PTR t, CK_ULONG cnt)
  56 {
  57         CK_ULONG modulus_len;
  58         int i;
  59 
  60         for (i = 0; i < cnt; i++) {
  61                 if (t[i].type == CKA_MODULUS_BITS) {
  62                         get_ulong_attr_from_template(&modulus_len, &t[i]);
  63                         /* convert from bit length to byte length */
  64                         modulus_len = (modulus_len - 1) / 64 + 1;
  65                         return (modulus_len * 8);
  66                 }
  67         }
  68         return (0);
  69 }
  70 
  71 /*
  72  * Remove specified attribute from array. Storage for the attribute's
  73  * value is freed if 'free_attr' is TRUE. Attributes are shifted so they are
  74  * contiguous within the array, i.e. the next attribute is shifted into
  75  * the position of the removed attribute. Returns TRUE if specified
  76  * attribute is removed.
  77  */
  78 static boolean_t
  79 remove_one_attribute(CK_ATTRIBUTE_PTR t, CK_ULONG type, uint_t count,
  80     boolean_t free_attr)
  81 {
  82         int i, j;
  83 
  84         for (i = 0, j = 0; i < count; i++) {
  85                 if (t[i].type == type) {
  86                         if (free_attr) {
  87                                 free(t[i].pValue);
  88                         }
  89                         continue;
  90                 }
  91                 if (i != j) {
  92                         t[j].type = t[i].type;
  93                         t[j].pValue = t[i].pValue;
  94                         t[j].ulValueLen = t[i].ulValueLen;
  95                 }
  96                 j++;
  97         }
  98         if (j == count)
  99                 return (B_FALSE);
 100 
 101         /* safety */
 102         t[j].pValue = NULL;
 103         t[j].ulValueLen = 0;
 104         return (B_TRUE);
 105 }
 106 
 107 static boolean_t
 108 is_secret_key_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount)
 109 {
 110         int i;
 111         for (i = 0; i < ulAttributeCount; i++) {
 112                 if (pTemplate[i].type == CKA_CLASS &&
 113                     *(CK_OBJECT_CLASS *)(pTemplate[i].pValue) ==
 114                     CKO_SECRET_KEY)
 115                         return (B_TRUE);
 116         }
 117         return (B_FALSE);
 118 }
 119 
 120 /*
 121  * Allocate a template with space for new_count entries and copy the
 122  * specified template into the new template.
 123  */
 124 static CK_ATTRIBUTE_PTR
 125 grow_template(CK_ATTRIBUTE_PTR old_template, CK_ULONG old_count,
 126     CK_ULONG new_count)
 127 {
 128         CK_ATTRIBUTE_PTR new_template;
 129 
 130         new_template = malloc(new_count * sizeof (CK_ATTRIBUTE));
 131         if (new_template != NULL)
 132                 bcopy(old_template, new_template,
 133                     old_count * sizeof (CK_ATTRIBUTE));
 134         return (new_template);
 135 }
 136 
 137 /*
 138  * For fixed length keys such as DES, return the length based on
 139  * the key type. For variable length keys such as AES, take the
 140  * length from the CKA_VALUE_LEN attribute.
 141  */
 142 static int
 143 get_key_len_from_template(CK_MECHANISM_PTR pMechanism,
 144     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
 145     kernel_object_t *basekey_p,  ulong_t *key_len)
 146 {
 147         boolean_t fixed_len_key = B_FALSE;
 148         ulong_t key_type;
 149         int i;
 150 
 151         for (i = 0; i < ulAttributeCount; i++) {
 152                 if (pTemplate[i].type == CKA_KEY_TYPE) {
 153                         get_ulong_attr_from_template(&key_type, &pTemplate[i]);
 154                         break;
 155                 }
 156         }
 157         /* CKA_KEY_TYPE must be present */
 158         if (i == ulAttributeCount)
 159                 return (CKR_TEMPLATE_INCOMPLETE);
 160 
 161         switch (key_type) {
 162         case CKK_DES:
 163                 *key_len = 8;
 164                 fixed_len_key = B_TRUE;
 165                 break;
 166         case CKK_DES3:
 167                 *key_len = 24;
 168                 fixed_len_key = B_TRUE;
 169                 break;
 170         case CKK_AES:
 171         case CKK_BLOWFISH:
 172                 for (i = 0; i < ulAttributeCount; i++) {
 173                         if (pTemplate[i].type == CKA_VALUE_LEN) {
 174                                 get_ulong_attr_from_template(key_len,
 175                                     &pTemplate[i]);
 176                                 break;
 177                         }
 178                 }
 179                 /* CKA_VALUE_LEN must be present */
 180                 if (i == ulAttributeCount)
 181                         return (CKR_TEMPLATE_INCOMPLETE);
 182                 break;
 183         case CKK_GENERIC_SECRET:
 184                 /*
 185                  * The key will not be truncated, so we need to
 186                  * get the max length for the mechanism.
 187                  */
 188                 if (pMechanism->mechanism == CKM_DH_PKCS_DERIVE) {
 189                         CK_ATTRIBUTE tmp;
 190 
 191                         tmp.type = CKA_PRIME;
 192                         tmp.pValue = NULL;
 193 
 194                         /* get size of attribute */
 195                         if (kernel_get_attribute(basekey_p, &tmp) != CKR_OK) {
 196                                 return (CKR_ARGUMENTS_BAD);
 197                         }
 198                         *key_len = tmp.ulValueLen;
 199                 } else if (pMechanism->mechanism == CKM_ECDH1_DERIVE) {
 200                         *key_len = EC_MAX_VALUE_LEN;
 201                 } else {
 202                         return (CKR_ARGUMENTS_BAD);
 203                 }
 204                 break;
 205         default:
 206                 return (CKR_ATTRIBUTE_VALUE_INVALID);
 207         }
 208 
 209         if (fixed_len_key && attribute_in_template(CKA_VALUE_LEN,
 210             pTemplate, ulAttributeCount))
 211                 return (CKR_TEMPLATE_INCONSISTENT);
 212 
 213         return (CKR_OK);
 214 }
 215 
 216 /* find specified attribute src template and copy to dest */
 217 static int
 218 copy_attribute(CK_ULONG type, CK_ATTRIBUTE_PTR src, CK_ULONG src_cnt,
 219     CK_ATTRIBUTE_PTR dst)
 220 {
 221         int rv, i;
 222 
 223         for (i = 0; i < src_cnt; i++) {
 224                 if (src[i].type == type) {
 225                         rv = get_string_from_template(dst, &src[i]);
 226                         break;
 227                 }
 228         }
 229         /*
 230          * The public template didn't have attribute.
 231          */
 232         if (i == src_cnt) {
 233                 rv = CKR_TEMPLATE_INCOMPLETE;
 234         }
 235         return (rv);
 236 }
 237 
 238 static void
 239 free_attributes(caddr_t p, uint_t *countp)
 240 {
 241         if (*countp > 0) {
 242                 free_object_attributes(p, *countp);
 243                 *countp = 0;
 244         }
 245 }
 246 
 247 CK_RV
 248 key_gen_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
 249     CK_ULONG ulCount, kernel_session_t *session_p,
 250     crypto_mech_type_t k_mech_type, kernel_object_t *new_objp)
 251 {
 252         crypto_nostore_generate_key_t obj_ngk;
 253         char *key_buf = NULL;
 254         CK_ATTRIBUTE_PTR newTemplate = NULL;
 255         CK_BBOOL is_token_obj = FALSE;
 256         CK_RV rv = CKR_OK;
 257         ulong_t key_len = 0;
 258         uint_t attr_count;
 259         int r;
 260 
 261         obj_ngk.ngk_in_count = 0;
 262         obj_ngk.ngk_out_count = 0;
 263 
 264         rv = get_key_len_from_template(pMechanism, pTemplate, ulCount,
 265             NULL, &key_len);
 266         if (rv != CRYPTO_SUCCESS)
 267                 goto failed_exit;
 268 
 269         if ((key_buf = malloc(key_len)) == NULL) {
 270                 rv = CKR_HOST_MEMORY;
 271                 goto failed_exit;
 272         }
 273 
 274         attr_count = ulCount + 1;
 275         newTemplate = grow_template(pTemplate, ulCount, attr_count);
 276         if (newTemplate == NULL) {
 277                 rv = CKR_HOST_MEMORY;
 278                 goto failed_exit;
 279         }
 280 
 281         /* Now add the CKA_VALUE attribute to template */
 282         newTemplate[ulCount].type = CKA_VALUE;
 283         newTemplate[ulCount].pValue = (caddr_t)key_buf;
 284         newTemplate[ulCount].ulValueLen = key_len;
 285 
 286         rv = process_object_attributes(newTemplate, attr_count - 1,
 287             &obj_ngk.ngk_in_attributes, &is_token_obj);
 288         if (rv != CKR_OK) {
 289                 goto failed_exit;
 290         }
 291         rv = process_object_attributes(&newTemplate[ulCount],
 292             1, &obj_ngk.ngk_out_attributes, &is_token_obj);
 293         if (rv != CKR_OK) {
 294                 goto failed_exit;
 295         }
 296 
 297         /* Cannot create a token object with a READ-ONLY session. */
 298         if (is_token_obj && session_p->ses_RO) {
 299                 rv = CKR_SESSION_READ_ONLY;
 300                 goto failed_exit;
 301         }
 302 
 303         /* Call the CRYPTO_NOSTORE_GENERATE_KEY ioctl */
 304         obj_ngk.ngk_session = session_p->k_session;
 305         obj_ngk.ngk_in_count = attr_count - 1;
 306         obj_ngk.ngk_out_count = 1;
 307         obj_ngk.ngk_mechanism.cm_type = k_mech_type;
 308         obj_ngk.ngk_mechanism.cm_param = pMechanism->pParameter;
 309         obj_ngk.ngk_mechanism.cm_param_len = pMechanism->ulParameterLen;
 310 
 311         while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY,
 312             &obj_ngk)) < 0) {
 313                 if (errno != EINTR)
 314                         break;
 315         }
 316         if (r < 0) {
 317                 rv = CKR_FUNCTION_FAILED;
 318         } else {
 319                 rv = crypto2pkcs11_error_number(obj_ngk.ngk_return_value);
 320         }
 321         free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count);
 322         if (rv != CKR_OK) {
 323                 goto failed_exit;
 324         }
 325 
 326         rv = get_object_attributes(&newTemplate[ulCount], 1,
 327             obj_ngk.ngk_out_attributes);
 328         free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count);
 329         if (rv != CRYPTO_SUCCESS) {
 330                 goto failed_exit;
 331         }
 332 
 333         /*
 334          * CKA_VALUE_LEN is not stored with the secret key object,
 335          * so we remove it by shifting attributes down one.
 336          */
 337         (void) remove_one_attribute(newTemplate, CKA_VALUE_LEN,
 338             attr_count, B_FALSE);
 339 
 340         rv = kernel_build_object(newTemplate, attr_count - 1,
 341             new_objp, session_p, KERNEL_GEN_KEY);
 342         if (rv != CRYPTO_SUCCESS) {
 343                 goto failed_exit;
 344         }
 345         new_objp->is_lib_obj = B_TRUE;
 346         new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
 347         free(newTemplate);
 348         freezero(key_buf, key_len);
 349         return (CKR_OK);
 350 
 351 failed_exit:
 352         free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count);
 353         free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count);
 354         freezero(key_buf, key_len);
 355         free(newTemplate);
 356         return (rv);
 357 }
 358 
 359 CK_RV
 360 C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
 361     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
 362 {
 363         CK_RV                   rv = CKR_OK;
 364         kernel_session_t        *session_p;
 365         kernel_object_t         *new_objp = NULL;
 366         kernel_slot_t           *pslot;
 367         boolean_t               ses_lock_held = B_FALSE;
 368         CK_BBOOL                is_pri_obj;
 369         CK_BBOOL                is_token_obj = FALSE;
 370         crypto_mech_type_t      k_mech_type;
 371         int r;
 372 
 373         if (!kernel_initialized)
 374                 return (CKR_CRYPTOKI_NOT_INITIALIZED);
 375 
 376         /* Obtain the session pointer */
 377         rv = handle2session(hSession, &session_p);
 378         if (rv != CKR_OK)
 379                 return (rv);
 380 
 381         if ((pMechanism == NULL) || (phKey == NULL)) {
 382                 rv = CKR_ARGUMENTS_BAD;
 383                 goto failed_exit;
 384         }
 385 
 386         if ((pTemplate == NULL) && (ulCount != 0)) {
 387                 rv = CKR_ARGUMENTS_BAD;
 388                 goto failed_exit;
 389         }
 390 
 391         /* Get the kernel's internal mechanism number. */
 392         rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
 393         if (rv != CKR_OK) {
 394                 goto failed_exit;
 395         }
 396 
 397         /* Create an object wrapper in the library first */
 398         new_objp = calloc(1, sizeof (kernel_object_t));
 399         if (new_objp == NULL) {
 400                 rv = CKR_HOST_MEMORY;
 401                 goto failed_exit;
 402         }
 403 
 404         /*
 405          * Special Case: if token does not support object creation,
 406          * but does support key generation by value, then create a session
 407          * object and initialize with value returned by token.
 408          */
 409         pslot = slot_table[session_p->ses_slotid];
 410         if (!pslot->sl_func_list.fl_object_create) {
 411                 rv = key_gen_by_value(pMechanism, pTemplate, ulCount, session_p,
 412                     k_mech_type, new_objp);
 413                 if (rv != CKR_OK)
 414                         goto failed_exit;
 415         } else {
 416                 crypto_object_generate_key_t obj_gk;
 417 
 418                 /* Process the attributes */
 419                 rv = process_object_attributes(pTemplate, ulCount,
 420                     &obj_gk.gk_attributes, &is_token_obj);
 421                 if (rv != CKR_OK) {
 422                         goto failed_exit;
 423                 }
 424                 /* Cannot create a token object with a READ-ONLY session. */
 425                 if (is_token_obj && session_p->ses_RO) {
 426                         free_object_attributes(obj_gk.gk_attributes, ulCount);
 427                         rv = CKR_SESSION_READ_ONLY;
 428                         goto failed_exit;
 429                 }
 430 
 431                 /* Call the CRYPTO_GENERATE_KEY ioctl */
 432                 obj_gk.gk_session = session_p->k_session;
 433                 obj_gk.gk_count = ulCount;
 434                 obj_gk.gk_mechanism.cm_type = k_mech_type;
 435                 obj_gk.gk_mechanism.cm_param = pMechanism->pParameter;
 436                 obj_gk.gk_mechanism.cm_param_len = pMechanism->ulParameterLen;
 437 
 438                 while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY,
 439                     &obj_gk)) < 0) {
 440                         if (errno != EINTR)
 441                                 break;
 442                 }
 443                 if (r < 0) {
 444                         rv = CKR_FUNCTION_FAILED;
 445                 } else {
 446                         rv = crypto2pkcs11_error_number(obj_gk.gk_return_value);
 447                 }
 448 
 449                 free_object_attributes(obj_gk.gk_attributes, ulCount);
 450 
 451                 if (rv != CKR_OK) {
 452                         goto failed_exit;
 453                 }
 454 
 455                 /* Get the value of the CKA_PRIVATE attribute. */
 456                 rv = get_cka_private_value(session_p, obj_gk.gk_handle,
 457                     &is_pri_obj);
 458                 if (rv != CKR_OK) {
 459                         goto failed_exit;
 460                 }
 461 
 462                 /*
 463                  * Store the kernel object handle in the object wrapper and
 464                  * initialize the library object.
 465                  */
 466                 new_objp->k_handle = obj_gk.gk_handle;
 467                 new_objp->is_lib_obj = B_FALSE;
 468                 new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
 469                 new_objp->extra_attrlistp = NULL;
 470 
 471                 if (is_pri_obj)
 472                         new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
 473                 else
 474                         new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
 475 
 476                 if (is_token_obj)
 477                         new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
 478                 else
 479                         new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
 480         }
 481 
 482         (void) pthread_mutex_init(&new_objp->object_mutex, NULL);
 483         new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
 484 
 485         /*
 486          * Add the new object to the slot's token object list if it is a
 487          * a token object. Otherwise, add it to the session's object list.
 488          */
 489         if (is_token_obj) {
 490                 pslot = slot_table[session_p->ses_slotid];
 491                 kernel_add_token_object_to_slot(new_objp, pslot);
 492         } else {
 493                 kernel_add_object_to_session(new_objp, session_p);
 494         }
 495 
 496         *phKey = (CK_OBJECT_HANDLE)new_objp;
 497         REFRELE(session_p, ses_lock_held);
 498         return (rv);
 499 
 500 failed_exit:
 501         if (new_objp != NULL) {
 502                 (void) free(new_objp);
 503         }
 504 
 505         REFRELE(session_p, ses_lock_held);
 506         return (rv);
 507 }
 508 
 509 CK_RV
 510 key_gen_rsa_by_value(CK_MECHANISM_PTR pMechanism,
 511     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
 512     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
 513     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
 514     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
 515 {
 516         crypto_nostore_generate_key_pair_t obj_nkp;
 517         CK_ATTRIBUTE_PTR pubTemplate = NULL;
 518         CK_ATTRIBUTE_PTR priTemplate = NULL;
 519         CK_RV rv = CKR_OK;
 520         CK_BBOOL is_token_obj1 = FALSE;
 521         CK_BBOOL is_token_obj2 = FALSE;
 522         uint_t pub_attr_count, pri_attr_count;
 523         uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
 524         char public_modulus[512];
 525         char public_exponent[8];
 526         char private_exponent[512];
 527         char private_modulus[512];
 528         char prime_1[512];
 529         char prime_2[512];
 530         char exponent_1[512];
 531         char exponent_2[512];
 532         char coefficient[512];
 533         CK_ULONG pub_class = CKO_PUBLIC_KEY;
 534         CK_ULONG pri_class = CKO_PRIVATE_KEY;
 535         CK_ULONG key_type;
 536         CK_ULONG modulus_bytes;
 537         boolean_t has_class, has_key_type, has_pub_exponent;
 538         int n, r;
 539 
 540         obj_nkp.nkp_in_public_count = 0;
 541         obj_nkp.nkp_out_public_count = 0;
 542         obj_nkp.nkp_in_private_count = 0;
 543         obj_nkp.nkp_out_private_count = 0;
 544 
 545         /* modulus bits must be present when generating a RSA key pair */
 546         if (!attribute_in_template(CKA_MODULUS_BITS, pPublicKeyTemplate,
 547             ulPublicKeyAttributeCount)) {
 548                 rv = CKR_TEMPLATE_INCOMPLETE;
 549                 goto failed_exit;
 550         }
 551 
 552         modulus_bytes = get_modulus_bytes(pPublicKeyTemplate,
 553             ulPublicKeyAttributeCount);
 554 
 555         /*
 556          * Add CKA_MODULUS to the public template.
 557          * This attribute must not be in the template.
 558          */
 559         if (attribute_in_template(CKA_MODULUS, pPublicKeyTemplate,
 560             ulPublicKeyAttributeCount)) {
 561                 rv = CKR_TEMPLATE_INCONSISTENT;
 562                 goto failed_exit;
 563         }
 564         has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
 565             ulPublicKeyAttributeCount);
 566         has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
 567             ulPublicKeyAttributeCount);
 568         has_pub_exponent = attribute_in_template(CKA_PUBLIC_EXPONENT,
 569             pPublicKeyTemplate, ulPublicKeyAttributeCount);
 570 
 571         pub_attr_count = ulPublicKeyAttributeCount + 1;
 572         if (!has_class)
 573                 pub_attr_count++;
 574         if (!has_key_type)
 575                 pub_attr_count++;
 576         if (!has_pub_exponent)
 577                 pub_attr_count++;
 578         pubTemplate = grow_template(pPublicKeyTemplate,
 579             ulPublicKeyAttributeCount, pub_attr_count);
 580         if (pubTemplate == NULL) {
 581                 rv = CKR_HOST_MEMORY;
 582                 goto failed_exit;
 583         }
 584 
 585         n = ulPublicKeyAttributeCount;
 586         if (!has_class) {
 587                 pubTemplate[n].type = CKA_CLASS;
 588                 pubTemplate[n].pValue = (caddr_t)&pub_class;
 589                 pubTemplate[n].ulValueLen = sizeof (pub_class);
 590                 n++;
 591         }
 592         if (!has_key_type) {
 593                 pubTemplate[n].type = CKA_KEY_TYPE;
 594                 key_type = CKK_RSA;
 595                 pubTemplate[n].pValue = (caddr_t)&key_type;
 596                 pubTemplate[n].ulValueLen = sizeof (key_type);
 597                 n++;
 598         }
 599         if (!has_pub_exponent) {
 600                 pubTemplate[n].type = CKA_PUBLIC_EXPONENT;
 601                 pubTemplate[n].pValue = (caddr_t)public_exponent;
 602                 pubTemplate[n].ulValueLen = modulus_bytes;
 603                 n++;
 604                 pub_out_attr_count++;
 605         }
 606         pubTemplate[n].type = CKA_MODULUS;
 607         pubTemplate[n].pValue = (caddr_t)public_modulus;
 608         pubTemplate[n].ulValueLen = modulus_bytes;
 609         pub_out_attr_count++;
 610 
 611         rv = process_object_attributes(pubTemplate,
 612             pub_attr_count - pub_out_attr_count,
 613             &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
 614         if (rv != CKR_OK) {
 615                 goto failed_exit;
 616         }
 617         obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
 618 
 619         rv = process_object_attributes(
 620             &pubTemplate[pub_attr_count - pub_out_attr_count],
 621             pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
 622             &is_token_obj1);
 623         if (rv != CKR_OK) {
 624                 goto failed_exit;
 625         }
 626         obj_nkp.nkp_out_public_count = pub_out_attr_count;
 627 
 628         /*
 629          * Cannot create a token object with a READ-ONLY
 630          * session.
 631          */
 632         if (is_token_obj1 && session_p->ses_RO) {
 633                 rv = CKR_SESSION_READ_ONLY;
 634                 goto failed_exit;
 635         }
 636 
 637         /*
 638          * Add CKA_MODULUS and CKA_PRIVATE_EXPONENT
 639          * to the private template. These attributes
 640          * must not be in the template.
 641          */
 642         if (attribute_in_template(CKA_PRIVATE_EXPONENT,
 643             pPrivateKeyTemplate, ulPrivateKeyAttributeCount) ||
 644             attribute_in_template(CKA_MODULUS,
 645             pPrivateKeyTemplate, ulPrivateKeyAttributeCount)) {
 646                 rv = CKR_TEMPLATE_INCONSISTENT;
 647                 goto failed_exit;
 648         }
 649         has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
 650             ulPrivateKeyAttributeCount);
 651         has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
 652             ulPrivateKeyAttributeCount);
 653 
 654         pri_attr_count = ulPrivateKeyAttributeCount + 7;
 655         if (!has_class)
 656                 pri_attr_count++;
 657         if (!has_key_type)
 658                 pri_attr_count++;
 659 
 660         /* allocate space for CKA_PUBLIC_EXPONENT */
 661         priTemplate = grow_template(pPrivateKeyTemplate,
 662             ulPrivateKeyAttributeCount, pri_attr_count + 1);
 663         if (priTemplate == NULL) {
 664                 rv = CKR_HOST_MEMORY;
 665                 goto failed_exit;
 666         }
 667         n = ulPrivateKeyAttributeCount;
 668         if (!has_class) {
 669                 priTemplate[n].type = CKA_CLASS;
 670                 priTemplate[n].pValue = (caddr_t)&pri_class;
 671                 priTemplate[n].ulValueLen = sizeof (pri_class);
 672                 n++;
 673         }
 674         if (!has_key_type) {
 675                 priTemplate[n].type = CKA_KEY_TYPE;
 676                 key_type = CKK_RSA;
 677                 priTemplate[n].pValue = (caddr_t)&key_type;
 678                 priTemplate[n].ulValueLen = sizeof (key_type);
 679                 n++;
 680         }
 681         priTemplate[n].type = CKA_MODULUS;
 682         priTemplate[n].pValue = (caddr_t)private_modulus;
 683         priTemplate[n].ulValueLen = modulus_bytes;
 684         pri_out_attr_count++;
 685 
 686         n++;
 687         priTemplate[n].type = CKA_PRIVATE_EXPONENT;
 688         priTemplate[n].pValue = (caddr_t)private_exponent;
 689         priTemplate[n].ulValueLen = modulus_bytes;
 690         pri_out_attr_count++;
 691 
 692         n++;
 693         priTemplate[n].type = CKA_PRIME_1;
 694         priTemplate[n].pValue = (caddr_t)prime_1;
 695         priTemplate[n].ulValueLen = modulus_bytes/2;
 696         pri_out_attr_count++;
 697 
 698         n++;
 699         priTemplate[n].type = CKA_PRIME_2;
 700         priTemplate[n].pValue = (caddr_t)prime_2;
 701         priTemplate[n].ulValueLen = modulus_bytes/2;
 702         pri_out_attr_count++;
 703 
 704         n++;
 705         priTemplate[n].type = CKA_EXPONENT_1;
 706         priTemplate[n].pValue = (caddr_t)exponent_1;
 707         priTemplate[n].ulValueLen = modulus_bytes/2;
 708         pri_out_attr_count++;
 709 
 710         n++;
 711         priTemplate[n].type = CKA_EXPONENT_2;
 712         priTemplate[n].pValue = (caddr_t)exponent_2;
 713         priTemplate[n].ulValueLen = modulus_bytes/2;
 714         pri_out_attr_count++;
 715 
 716         n++;
 717         priTemplate[n].type = CKA_COEFFICIENT;
 718         priTemplate[n].pValue = (caddr_t)coefficient;
 719         priTemplate[n].ulValueLen = modulus_bytes/2;
 720         pri_out_attr_count++;
 721 
 722         rv = process_object_attributes(priTemplate,
 723             pri_attr_count - pri_out_attr_count,
 724             &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
 725         if (rv != CKR_OK) {
 726                 goto failed_exit;
 727         }
 728         obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
 729 
 730         rv = process_object_attributes(
 731             &priTemplate[pri_attr_count - pri_out_attr_count],
 732             pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
 733             &is_token_obj2);
 734         if (rv != CKR_OK) {
 735                 goto failed_exit;
 736         }
 737         obj_nkp.nkp_out_private_count = pri_out_attr_count;
 738 
 739         /*
 740          * The public key and the private key need to contain the same
 741          * attribute values for CKA_TOKEN.
 742          */
 743         if (is_token_obj1 != is_token_obj2) {
 744                 rv = CKR_ATTRIBUTE_VALUE_INVALID;
 745                 goto failed_exit;
 746         }
 747 
 748         /* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
 749         obj_nkp.nkp_session = session_p-> k_session;
 750         obj_nkp.nkp_mechanism.cm_type = k_mech_type;
 751         obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
 752         obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
 753 
 754         while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
 755             &obj_nkp)) < 0) {
 756                 if (errno != EINTR)
 757                         break;
 758         }
 759         if (r < 0) {
 760                 rv = CKR_FUNCTION_FAILED;
 761         } else {
 762                 rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
 763         }
 764         free_attributes(obj_nkp.nkp_in_public_attributes,
 765             &obj_nkp.nkp_in_public_count);
 766         free_attributes(obj_nkp.nkp_in_private_attributes,
 767             &obj_nkp.nkp_in_private_count);
 768 
 769         if (rv != CKR_OK) {
 770                 goto failed_exit;
 771         }
 772 
 773         rv = get_object_attributes(
 774             &pubTemplate[pub_attr_count - pub_out_attr_count],
 775             pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
 776         if (rv == CRYPTO_SUCCESS) {
 777                 rv = get_object_attributes(
 778                     &priTemplate[pri_attr_count - pri_out_attr_count],
 779                     pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
 780         }
 781         free_attributes(obj_nkp.nkp_out_public_attributes,
 782             &obj_nkp.nkp_out_public_count);
 783         free_attributes(obj_nkp.nkp_out_private_attributes,
 784             &obj_nkp.nkp_out_private_count);
 785         if (rv != CRYPTO_SUCCESS) {
 786                 goto failed_exit;
 787         }
 788 
 789         /* store generated modulus and public exponent */
 790         rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
 791             session_p, KERNEL_GEN_KEY);
 792         if (rv != CRYPTO_SUCCESS) {
 793                 goto failed_exit;
 794         }
 795 
 796         /*
 797          * Copy CKA_PUBLIC_EXPONENT from the public template
 798          * to the private template.
 799          */
 800         rv = copy_attribute(CKA_PUBLIC_EXPONENT, pubTemplate,
 801             pub_attr_count, &priTemplate[pri_attr_count]);
 802         if (rv != CRYPTO_SUCCESS) {
 803                 goto failed_exit;
 804         }
 805 
 806         rv = kernel_build_object(priTemplate, pri_attr_count + 1, new_pri_objp,
 807             session_p, KERNEL_GEN_KEY);
 808         (void) free(priTemplate[pri_attr_count].pValue);
 809         if (rv != CRYPTO_SUCCESS) {
 810                 goto failed_exit;
 811         }
 812         (void) free(pubTemplate);
 813         (void) free(priTemplate);
 814 
 815         new_pub_objp->is_lib_obj = B_TRUE;
 816         new_pri_objp->is_lib_obj = B_TRUE;
 817         new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
 818         new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
 819         (void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
 820         new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
 821         (void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
 822         new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
 823         return (CKR_OK);
 824 
 825 failed_exit:
 826         free_attributes(obj_nkp.nkp_in_public_attributes,
 827             &obj_nkp.nkp_in_public_count);
 828         free_attributes(obj_nkp.nkp_out_public_attributes,
 829             &obj_nkp.nkp_out_public_count);
 830         free_attributes(obj_nkp.nkp_in_private_attributes,
 831             &obj_nkp.nkp_in_private_count);
 832         free_attributes(obj_nkp.nkp_out_private_attributes,
 833             &obj_nkp.nkp_out_private_count);
 834         if (pubTemplate != NULL) {
 835                 (void) free(pubTemplate);
 836         }
 837         if (priTemplate != NULL) {
 838                 (void) free(priTemplate);
 839         }
 840         return (rv);
 841 }
 842 
 843 CK_RV
 844 key_gen_dh_by_value(CK_MECHANISM_PTR pMechanism,
 845     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
 846     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
 847     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
 848     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
 849 {
 850         crypto_nostore_generate_key_pair_t obj_nkp;
 851         CK_ATTRIBUTE_PTR pubTemplate = NULL;
 852         CK_ATTRIBUTE_PTR priTemplate = NULL;
 853         CK_RV rv = CKR_OK;
 854         CK_BBOOL is_token_obj1 = FALSE;
 855         CK_BBOOL is_token_obj2 = FALSE;
 856         uint_t pub_attr_count, pri_attr_count;
 857         uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
 858         char public_value[256];
 859         char private_value[256];
 860         CK_ULONG pub_class = CKO_PUBLIC_KEY;
 861         CK_ULONG pri_class = CKO_PRIVATE_KEY;
 862         CK_ULONG key_type;
 863         boolean_t has_class, has_key_type;
 864         int n, r;
 865 
 866         obj_nkp.nkp_in_public_count = 0;
 867         obj_nkp.nkp_out_public_count = 0;
 868         obj_nkp.nkp_in_private_count = 0;
 869         obj_nkp.nkp_out_private_count = 0;
 870 
 871         /*
 872          * Add CKA_VALUE to the public template.
 873          * This attribute must not be in the template.
 874          */
 875         if (attribute_in_template(CKA_VALUE, pPublicKeyTemplate,
 876             ulPublicKeyAttributeCount)) {
 877                 rv = CKR_TEMPLATE_INCONSISTENT;
 878                 goto failed_exit;
 879         }
 880         has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
 881             ulPublicKeyAttributeCount);
 882         has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
 883             ulPublicKeyAttributeCount);
 884 
 885         pub_attr_count = ulPublicKeyAttributeCount + 1;
 886         if (!has_class)
 887                 pub_attr_count++;
 888         if (!has_key_type)
 889                 pub_attr_count++;
 890         pubTemplate = grow_template(pPublicKeyTemplate,
 891             ulPublicKeyAttributeCount, pub_attr_count);
 892         if (pubTemplate == NULL) {
 893                 rv = CKR_HOST_MEMORY;
 894                 goto failed_exit;
 895         }
 896 
 897         n = ulPublicKeyAttributeCount;
 898         if (!has_class) {
 899                 pubTemplate[n].type = CKA_CLASS;
 900                 pubTemplate[n].pValue = (caddr_t)&pub_class;
 901                 pubTemplate[n].ulValueLen = sizeof (pub_class);
 902                 n++;
 903         }
 904         if (!has_key_type) {
 905                 pubTemplate[n].type = CKA_KEY_TYPE;
 906                 key_type = CKK_DH;
 907                 pubTemplate[n].pValue = (caddr_t)&key_type;
 908                 pubTemplate[n].ulValueLen = sizeof (key_type);
 909                 n++;
 910         }
 911         pubTemplate[n].type = CKA_VALUE;
 912         pubTemplate[n].pValue = (caddr_t)public_value;
 913         pubTemplate[n].ulValueLen = sizeof (public_value);
 914         pub_out_attr_count++;
 915 
 916         rv = process_object_attributes(pubTemplate,
 917             pub_attr_count - pub_out_attr_count,
 918             &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
 919         if (rv != CKR_OK) {
 920                 goto failed_exit;
 921         }
 922         obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
 923 
 924         rv = process_object_attributes(
 925             &pubTemplate[pub_attr_count - pub_out_attr_count],
 926             pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
 927             &is_token_obj1);
 928         if (rv != CKR_OK) {
 929                 goto failed_exit;
 930         }
 931         obj_nkp.nkp_out_public_count = pub_out_attr_count;
 932 
 933         /*
 934          * Cannot create a token object with a READ-ONLY
 935          * session.
 936          */
 937         if (is_token_obj1 && session_p->ses_RO) {
 938                 rv = CKR_SESSION_READ_ONLY;
 939                 goto failed_exit;
 940         }
 941 
 942         /*
 943          * CKA_BASE, CKA_PRIME, and CKA_VALUE must not appear
 944          * in private template.
 945          */
 946         if (attribute_in_template(CKA_BASE, pPrivateKeyTemplate,
 947             ulPrivateKeyAttributeCount) ||
 948             attribute_in_template(CKA_PRIME, pPrivateKeyTemplate,
 949             ulPrivateKeyAttributeCount) ||
 950             attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
 951             ulPrivateKeyAttributeCount)) {
 952                 rv = CKR_TEMPLATE_INCONSISTENT;
 953                 goto failed_exit;
 954         }
 955 
 956         if (attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
 957             ulPrivateKeyAttributeCount)) {
 958                 rv = CKR_TEMPLATE_INCONSISTENT;
 959                 goto failed_exit;
 960         }
 961         has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
 962             ulPrivateKeyAttributeCount);
 963         has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
 964             ulPrivateKeyAttributeCount);
 965 
 966         pri_attr_count = ulPrivateKeyAttributeCount + 1;
 967         if (!has_class)
 968                 pri_attr_count++;
 969         if (!has_key_type)
 970                 pri_attr_count++;
 971 
 972         /* allocate space for CKA_BASE and CKA_PRIME */
 973         priTemplate = grow_template(pPrivateKeyTemplate,
 974             ulPrivateKeyAttributeCount, pri_attr_count + 2);
 975         if (priTemplate == NULL) {
 976                 rv = CKR_HOST_MEMORY;
 977                 goto failed_exit;
 978         }
 979         n = ulPrivateKeyAttributeCount;
 980         if (!has_class) {
 981                 priTemplate[n].type = CKA_CLASS;
 982                 priTemplate[n].pValue = (caddr_t)&pri_class;
 983                 priTemplate[n].ulValueLen = sizeof (pri_class);
 984                 n++;
 985         }
 986         if (!has_key_type) {
 987                 priTemplate[n].type = CKA_KEY_TYPE;
 988                 key_type = CKK_DH;
 989                 priTemplate[n].pValue = (caddr_t)&key_type;
 990                 priTemplate[n].ulValueLen = sizeof (key_type);
 991                 n++;
 992         }
 993         priTemplate[n].type = CKA_VALUE;
 994         priTemplate[n].pValue = (caddr_t)private_value;
 995         priTemplate[n].ulValueLen = sizeof (private_value);
 996         pri_out_attr_count++;
 997 
 998         rv = process_object_attributes(priTemplate,
 999             pri_attr_count - pri_out_attr_count,
1000             &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
1001         if (rv != CKR_OK) {
1002                 goto failed_exit;
1003         }
1004         obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
1005 
1006         rv = process_object_attributes(
1007             &priTemplate[pri_attr_count - pri_out_attr_count],
1008             pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
1009             &is_token_obj2);
1010         if (rv != CKR_OK) {
1011                 goto failed_exit;
1012         }
1013         obj_nkp.nkp_out_private_count = pri_out_attr_count;
1014 
1015         /*
1016          * The public key and the private key need to contain the same
1017          * attribute values for CKA_TOKEN.
1018          */
1019         if (is_token_obj1 != is_token_obj2) {
1020                 rv = CKR_ATTRIBUTE_VALUE_INVALID;
1021                 goto failed_exit;
1022         }
1023 
1024         /* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
1025         obj_nkp.nkp_session = session_p-> k_session;
1026         obj_nkp.nkp_mechanism.cm_type = k_mech_type;
1027         obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
1028         obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
1029 
1030         while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
1031             &obj_nkp)) < 0) {
1032                 if (errno != EINTR)
1033                         break;
1034         }
1035         if (r < 0) {
1036                 rv = CKR_FUNCTION_FAILED;
1037         } else {
1038                 rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
1039         }
1040         free_attributes(obj_nkp.nkp_in_public_attributes,
1041             &obj_nkp.nkp_in_public_count);
1042         free_attributes(obj_nkp.nkp_in_private_attributes,
1043             &obj_nkp.nkp_in_private_count);
1044 
1045         if (rv != CKR_OK) {
1046                 goto failed_exit;
1047         }
1048 
1049         rv = get_object_attributes(
1050             &pubTemplate[pub_attr_count - pub_out_attr_count],
1051             pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
1052         if (rv == CRYPTO_SUCCESS) {
1053                 rv = get_object_attributes(
1054                     &priTemplate[pri_attr_count - pri_out_attr_count],
1055                     pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
1056         }
1057         free_attributes(obj_nkp.nkp_out_public_attributes,
1058             &obj_nkp.nkp_out_public_count);
1059         free_attributes(obj_nkp.nkp_out_private_attributes,
1060             &obj_nkp.nkp_out_private_count);
1061 
1062         if (rv != CRYPTO_SUCCESS) {
1063                 goto failed_exit;
1064         }
1065 
1066         rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
1067             session_p, KERNEL_GEN_KEY);
1068         if (rv != CRYPTO_SUCCESS) {
1069                 goto failed_exit;
1070         }
1071 
1072         /*
1073          * Copy CKA_BASE and CKA_PRIME from the public template
1074          * to the private template.
1075          */
1076         rv = copy_attribute(CKA_BASE, pubTemplate, pub_attr_count,
1077             &priTemplate[pri_attr_count]);
1078         if (rv != CRYPTO_SUCCESS) {
1079                 goto failed_exit;
1080         }
1081         rv = copy_attribute(CKA_PRIME, pubTemplate, pub_attr_count,
1082             &priTemplate[pri_attr_count + 1]);
1083         if (rv != CRYPTO_SUCCESS) {
1084                 (void) free(priTemplate[pri_attr_count].pValue);
1085                 goto failed_exit;
1086         }
1087 
1088         /* +2 to account for CKA_BASE and CKA_PRIME */
1089         rv = kernel_build_object(priTemplate, pri_attr_count + 2,
1090             new_pri_objp, session_p, KERNEL_GEN_KEY);
1091         (void) free(priTemplate[pri_attr_count].pValue);
1092         (void) free(priTemplate[pri_attr_count + 1].pValue);
1093         if (rv != CRYPTO_SUCCESS) {
1094                 goto failed_exit;
1095         }
1096         (void) free(pubTemplate);
1097         (void) free(priTemplate);
1098 
1099         new_pub_objp->is_lib_obj = B_TRUE;
1100         new_pri_objp->is_lib_obj = B_TRUE;
1101         new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1102         new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1103         (void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1104         new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1105         (void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
1106         new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1107         return (CKR_OK);
1108 
1109 failed_exit:
1110         free_attributes(obj_nkp.nkp_in_public_attributes,
1111             &obj_nkp.nkp_in_public_count);
1112         free_attributes(obj_nkp.nkp_out_public_attributes,
1113             &obj_nkp.nkp_out_public_count);
1114         free_attributes(obj_nkp.nkp_in_private_attributes,
1115             &obj_nkp.nkp_in_private_count);
1116         free_attributes(obj_nkp.nkp_out_private_attributes,
1117             &obj_nkp.nkp_out_private_count);
1118         if (pubTemplate != NULL) {
1119                 (void) free(pubTemplate);
1120         }
1121         if (priTemplate != NULL) {
1122                 (void) free(priTemplate);
1123         }
1124         return (rv);
1125 }
1126 
1127 CK_RV
1128 key_gen_ec_by_value(CK_MECHANISM_PTR pMechanism,
1129     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
1130     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
1131     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
1132     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
1133 {
1134         crypto_nostore_generate_key_pair_t obj_nkp;
1135         CK_ATTRIBUTE_PTR pubTemplate = NULL;
1136         CK_ATTRIBUTE_PTR priTemplate = NULL;
1137         CK_RV rv = CKR_OK;
1138         CK_BBOOL is_token_obj1 = FALSE;
1139         CK_BBOOL is_token_obj2 = FALSE;
1140         uint_t pub_attr_count, pri_attr_count;
1141         uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
1142         char value[EC_MAX_VALUE_LEN];
1143         char point[EC_MAX_POINT_LEN];
1144         CK_ULONG pub_class = CKO_PUBLIC_KEY;
1145         CK_ULONG pri_class = CKO_PRIVATE_KEY;
1146         CK_ULONG key_type;
1147         boolean_t has_class, has_key_type;
1148         int n, r;
1149 
1150         obj_nkp.nkp_in_public_count = 0;
1151         obj_nkp.nkp_out_public_count = 0;
1152         obj_nkp.nkp_in_private_count = 0;
1153         obj_nkp.nkp_out_private_count = 0;
1154 
1155         /*
1156          * Add CKA_EC_POINT to the public template.
1157          * This is the generated value Q. This attribute
1158          * must not be in the template.
1159          */
1160         if (attribute_in_template(CKA_EC_POINT, pPublicKeyTemplate,
1161             ulPublicKeyAttributeCount)) {
1162                 rv = CKR_TEMPLATE_INCONSISTENT;
1163                 goto failed_exit;
1164         }
1165         has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
1166             ulPublicKeyAttributeCount);
1167         has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
1168             ulPublicKeyAttributeCount);
1169 
1170         pub_attr_count = ulPublicKeyAttributeCount + 1;
1171         if (!has_class)
1172                 pub_attr_count++;
1173         if (!has_key_type)
1174                 pub_attr_count++;
1175         pubTemplate = grow_template(pPublicKeyTemplate,
1176             ulPublicKeyAttributeCount, pub_attr_count);
1177         if (pubTemplate == NULL) {
1178                 rv = CKR_HOST_MEMORY;
1179                 goto failed_exit;
1180         }
1181 
1182         n = ulPublicKeyAttributeCount;
1183         if (!has_class) {
1184                 pubTemplate[n].type = CKA_CLASS;
1185                 pubTemplate[n].pValue = (caddr_t)&pub_class;
1186                 pubTemplate[n].ulValueLen = sizeof (pub_class);
1187                 n++;
1188         }
1189         if (!has_key_type) {
1190                 pubTemplate[n].type = CKA_KEY_TYPE;
1191                 key_type = CKK_EC;
1192                 pubTemplate[n].pValue = (caddr_t)&key_type;
1193                 pubTemplate[n].ulValueLen = sizeof (key_type);
1194                 n++;
1195         }
1196         pubTemplate[n].type = CKA_EC_POINT;
1197         pubTemplate[n].pValue = (caddr_t)point;
1198         pubTemplate[n].ulValueLen = sizeof (point);
1199         pub_out_attr_count++;
1200 
1201         rv = process_object_attributes(pubTemplate,
1202             pub_attr_count - pub_out_attr_count,
1203             &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
1204         if (rv != CKR_OK) {
1205                 goto failed_exit;
1206         }
1207         obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
1208 
1209         rv = process_object_attributes(
1210             &pubTemplate[pub_attr_count - pub_out_attr_count],
1211             pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
1212             &is_token_obj1);
1213         if (rv != CKR_OK) {
1214                 goto failed_exit;
1215         }
1216         obj_nkp.nkp_out_public_count = pub_out_attr_count;
1217 
1218         /*
1219          * Cannot create a token object with a READ-ONLY
1220          * session.
1221          */
1222         if (is_token_obj1 && session_p->ses_RO) {
1223                 rv = CKR_SESSION_READ_ONLY;
1224                 goto failed_exit;
1225         }
1226 
1227         /*
1228          * CKA_EC_PARAMS and CKA_VALUE must not appear in
1229          * private template.
1230          */
1231         if (attribute_in_template(CKA_EC_PARAMS, pPrivateKeyTemplate,
1232             ulPrivateKeyAttributeCount) ||
1233             attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
1234             ulPrivateKeyAttributeCount)) {
1235                 rv = CKR_TEMPLATE_INCONSISTENT;
1236                 goto failed_exit;
1237         }
1238         has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
1239             ulPrivateKeyAttributeCount);
1240         has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
1241             ulPrivateKeyAttributeCount);
1242 
1243         pri_attr_count = ulPrivateKeyAttributeCount + 1;
1244         if (!has_class)
1245                 pri_attr_count++;
1246         if (!has_key_type)
1247                 pri_attr_count++;
1248 
1249         /* allocate space for CKA_EC_PARAMS */
1250         priTemplate = grow_template(pPrivateKeyTemplate,
1251             ulPrivateKeyAttributeCount, pri_attr_count + 1);
1252         if (priTemplate == NULL) {
1253                 rv = CKR_HOST_MEMORY;
1254                 goto failed_exit;
1255         }
1256         n = ulPrivateKeyAttributeCount;
1257         if (!has_class) {
1258                 priTemplate[n].type = CKA_CLASS;
1259                 priTemplate[n].pValue = (caddr_t)&pri_class;
1260                 priTemplate[n].ulValueLen = sizeof (pri_class);
1261                 n++;
1262         }
1263         if (!has_key_type) {
1264                 priTemplate[n].type = CKA_KEY_TYPE;
1265                 key_type = CKK_EC;
1266                 priTemplate[n].pValue = (caddr_t)&key_type;
1267                 priTemplate[n].ulValueLen = sizeof (key_type);
1268                 n++;
1269         }
1270         priTemplate[n].type = CKA_VALUE;
1271         priTemplate[n].pValue = (caddr_t)value;
1272         priTemplate[n].ulValueLen = sizeof (value);
1273         pri_out_attr_count++;
1274 
1275         rv = process_object_attributes(priTemplate,
1276             pri_attr_count - pri_out_attr_count,
1277             &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
1278         if (rv != CKR_OK) {
1279                 goto failed_exit;
1280         }
1281         obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
1282 
1283         rv = process_object_attributes(
1284             &priTemplate[pri_attr_count - pri_out_attr_count],
1285             pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
1286             &is_token_obj2);
1287         if (rv != CKR_OK) {
1288                 goto failed_exit;
1289         }
1290         obj_nkp.nkp_out_private_count = pri_out_attr_count;
1291 
1292         /*
1293          * The public key and the private key need to contain the same
1294          * attribute values for CKA_TOKEN.
1295          */
1296         if (is_token_obj1 != is_token_obj2) {
1297                 rv = CKR_ATTRIBUTE_VALUE_INVALID;
1298                 goto failed_exit;
1299         }
1300 
1301         /* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
1302         obj_nkp.nkp_session = session_p-> k_session;
1303         obj_nkp.nkp_mechanism.cm_type = k_mech_type;
1304         obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
1305         obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
1306 
1307         while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
1308             &obj_nkp)) < 0) {
1309                 if (errno != EINTR)
1310                         break;
1311         }
1312         if (r < 0) {
1313                 rv = CKR_FUNCTION_FAILED;
1314         } else {
1315                 rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
1316         }
1317         free_attributes(obj_nkp.nkp_in_public_attributes,
1318             &obj_nkp.nkp_in_public_count);
1319         free_attributes(obj_nkp.nkp_in_private_attributes,
1320             &obj_nkp.nkp_in_private_count);
1321 
1322         if (rv != CKR_OK) {
1323                 goto failed_exit;
1324         }
1325 
1326         rv = get_object_attributes(
1327             &pubTemplate[pub_attr_count - pub_out_attr_count],
1328             pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
1329         if (rv == CRYPTO_SUCCESS) {
1330                 rv = get_object_attributes(
1331                     &priTemplate[pri_attr_count - pri_out_attr_count],
1332                     pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
1333         }
1334         free_attributes(obj_nkp.nkp_out_public_attributes,
1335             &obj_nkp.nkp_out_public_count);
1336         free_attributes(obj_nkp.nkp_out_private_attributes,
1337             &obj_nkp.nkp_out_private_count);
1338         if (rv != CRYPTO_SUCCESS) {
1339                 goto failed_exit;
1340         }
1341 
1342         rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
1343             session_p, KERNEL_GEN_KEY);
1344         if (rv != CRYPTO_SUCCESS) {
1345                 goto failed_exit;
1346         }
1347 
1348         /*
1349          * Copy CKA_EC_PARAMS from the public template to the
1350          * private template.
1351          */
1352         rv = copy_attribute(CKA_EC_PARAMS, pubTemplate, pub_attr_count,
1353             &priTemplate[pri_attr_count]);
1354         if (rv != CRYPTO_SUCCESS) {
1355                 goto failed_exit;
1356         }
1357 
1358         /* +1 to account for CKA_EC_PARAMS */
1359         rv = kernel_build_object(priTemplate, pri_attr_count + 1,
1360             new_pri_objp, session_p, KERNEL_GEN_KEY);
1361         (void) free(priTemplate[pri_attr_count].pValue);
1362         if (rv != CRYPTO_SUCCESS) {
1363                 goto failed_exit;
1364         }
1365         (void) free(pubTemplate);
1366         (void) free(priTemplate);
1367 
1368         new_pub_objp->is_lib_obj = B_TRUE;
1369         new_pri_objp->is_lib_obj = B_TRUE;
1370         new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1371         new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1372         (void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1373         new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1374         (void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
1375         new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1376         return (CKR_OK);
1377 
1378 failed_exit:
1379         free_attributes(obj_nkp.nkp_in_public_attributes,
1380             &obj_nkp.nkp_in_public_count);
1381         free_attributes(obj_nkp.nkp_out_public_attributes,
1382             &obj_nkp.nkp_out_public_count);
1383         free_attributes(obj_nkp.nkp_in_private_attributes,
1384             &obj_nkp.nkp_in_private_count);
1385         free_attributes(obj_nkp.nkp_out_private_attributes,
1386             &obj_nkp.nkp_out_private_count);
1387         if (pubTemplate != NULL) {
1388                 (void) free(pubTemplate);
1389         }
1390         if (priTemplate != NULL) {
1391                 (void) free(priTemplate);
1392         }
1393         return (rv);
1394 }
1395 
1396 CK_RV
1397 C_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
1398     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
1399     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
1400     CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey)
1401 {
1402         CK_RV                   rv = CKR_OK;
1403         kernel_session_t        *session_p;
1404         kernel_object_t         *new_pub_objp = NULL;
1405         kernel_object_t         *new_pri_objp = NULL;
1406         kernel_slot_t           *pslot;
1407         boolean_t               ses_lock_held = B_FALSE;
1408         CK_BBOOL                is_pri_obj1;
1409         CK_BBOOL                is_pri_obj2;
1410         CK_BBOOL                is_token_obj1 = FALSE;
1411         CK_BBOOL                is_token_obj2 = FALSE;
1412         crypto_mech_type_t      k_mech_type;
1413         int r;
1414         CK_RV (*func)(CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, CK_ULONG,
1415             CK_ATTRIBUTE_PTR, CK_ULONG, kernel_session_t *, crypto_mech_type_t,
1416             kernel_object_t *, kernel_object_t *);
1417 
1418         if (!kernel_initialized)
1419                 return (CKR_CRYPTOKI_NOT_INITIALIZED);
1420 
1421         /* Obtain the session pointer. */
1422         rv = handle2session(hSession, &session_p);
1423         if (rv != CKR_OK)
1424                 return (rv);
1425 
1426         if ((pMechanism == NULL) || (phPublicKey == NULL) ||
1427             (phPrivateKey == NULL)) {
1428                 rv = CKR_ARGUMENTS_BAD;
1429                 goto failed_exit;
1430         }
1431 
1432         if ((pPublicKeyTemplate == NULL) && (ulPublicKeyAttributeCount != 0)) {
1433                 rv = CKR_ARGUMENTS_BAD;
1434                 goto failed_exit;
1435         }
1436 
1437         if ((pPrivateKeyTemplate == NULL) &&
1438             (ulPrivateKeyAttributeCount != 0)) {
1439                 rv = CKR_ARGUMENTS_BAD;
1440                 goto failed_exit;
1441         }
1442 
1443         /* Get the kernel's internal mechanism number. */
1444         rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
1445         if (rv != CKR_OK) {
1446                 goto failed_exit;
1447         }
1448 
1449         /* Create an object wrapper for the public key */
1450         new_pub_objp = calloc(1, sizeof (kernel_object_t));
1451         if (new_pub_objp == NULL) {
1452                 rv = CKR_HOST_MEMORY;
1453                 goto failed_exit;
1454         }
1455 
1456         /* Create an object wrapper for the private key. */
1457         new_pri_objp = calloc(1, sizeof (kernel_object_t));
1458         if (new_pri_objp == NULL) {
1459                 rv = CKR_HOST_MEMORY;
1460                 goto failed_exit;
1461         }
1462 
1463         /*
1464          * Special Case: if token does not support object creation,
1465          * but does support key generation by value, then create a session
1466          * object and initialize with values returned by token.
1467          */
1468         pslot = slot_table[session_p->ses_slotid];
1469         if (!pslot->sl_func_list.fl_object_create) {
1470                 switch (pMechanism->mechanism) {
1471                 case CKM_RSA_PKCS_KEY_PAIR_GEN:
1472                         func = key_gen_rsa_by_value;
1473                         break;
1474 
1475                 case CKM_DH_PKCS_KEY_PAIR_GEN:
1476                         func = key_gen_dh_by_value;
1477                         break;
1478 
1479                 case CKM_EC_KEY_PAIR_GEN:
1480                         func = key_gen_ec_by_value;
1481                         break;
1482 
1483                 default:
1484                         rv = CKR_MECHANISM_INVALID;
1485                         goto failed_exit;
1486                 }
1487                 rv = (*func)(pMechanism, pPublicKeyTemplate,
1488                     ulPublicKeyAttributeCount, pPrivateKeyTemplate,
1489                     ulPrivateKeyAttributeCount, session_p, k_mech_type,
1490                     new_pub_objp, new_pri_objp);
1491                 if (rv != CKR_OK)
1492                         goto failed_exit;
1493         } else {
1494                 crypto_object_generate_key_pair_t obj_kp;
1495 
1496                 /* Process the public key attributes. */
1497                 rv = process_object_attributes(pPublicKeyTemplate,
1498                     ulPublicKeyAttributeCount, &obj_kp.kp_public_attributes,
1499                     &is_token_obj1);
1500                 if (rv != CKR_OK) {
1501                         goto failed_exit;
1502                 }
1503 
1504                 /* Cannot create a token object with a READ-ONLY session. */
1505                 if (is_token_obj1 && session_p->ses_RO) {
1506                         free_object_attributes(obj_kp.kp_public_attributes,
1507                             ulPublicKeyAttributeCount);
1508                         rv = CKR_SESSION_READ_ONLY;
1509                         goto failed_exit;
1510                 }
1511 
1512                 /* Process the private key attributes. */
1513                 rv = process_object_attributes(pPrivateKeyTemplate,
1514                     ulPrivateKeyAttributeCount, &obj_kp.kp_private_attributes,
1515                     &is_token_obj2);
1516                 if (rv != CKR_OK) {
1517                         free_object_attributes(obj_kp.kp_public_attributes,
1518                             ulPublicKeyAttributeCount);
1519                         goto failed_exit;
1520                 }
1521 
1522                 /*
1523                  * The public key and the private key need to contain the same
1524                  * attribute values for CKA_TOKEN.
1525                  */
1526                 if (is_token_obj1 != is_token_obj2) {
1527                         free_object_attributes(obj_kp.kp_public_attributes,
1528                             ulPublicKeyAttributeCount);
1529                         free_object_attributes(obj_kp.kp_private_attributes,
1530                             ulPrivateKeyAttributeCount);
1531                         rv = CKR_ATTRIBUTE_VALUE_INVALID;
1532                         goto failed_exit;
1533                 }
1534 
1535                 /* Call the CRYPTO_GENERATE_KEY_PAIR ioctl. */
1536                 obj_kp.kp_session = session_p-> k_session;
1537                 obj_kp.kp_mechanism.cm_type = k_mech_type;
1538                 obj_kp.kp_mechanism.cm_param = pMechanism->pParameter;
1539                 obj_kp.kp_mechanism.cm_param_len = pMechanism->ulParameterLen;
1540                 obj_kp.kp_public_count = ulPublicKeyAttributeCount;
1541                 obj_kp.kp_private_count = ulPrivateKeyAttributeCount;
1542 
1543                 while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY_PAIR,
1544                     &obj_kp)) < 0) {
1545                         if (errno != EINTR)
1546                                 break;
1547                 }
1548                 if (r < 0) {
1549                         rv = CKR_FUNCTION_FAILED;
1550                 } else {
1551                         rv = crypto2pkcs11_error_number(obj_kp.kp_return_value);
1552                 }
1553                 free_object_attributes(obj_kp.kp_public_attributes,
1554                     ulPublicKeyAttributeCount);
1555                 free_object_attributes(obj_kp.kp_private_attributes,
1556                     ulPrivateKeyAttributeCount);
1557 
1558                 if (rv != CKR_OK)
1559                         goto failed_exit;
1560 
1561                 /* Get the CKA_PRIVATE value for the key pair. */
1562                 rv = get_cka_private_value(session_p, obj_kp.kp_public_handle,
1563                     &is_pri_obj1);
1564                 if (rv != CKR_OK) {
1565                         goto failed_exit;
1566                 }
1567 
1568                 rv = get_cka_private_value(session_p, obj_kp.kp_private_handle,
1569                     &is_pri_obj2);
1570                 if (rv != CKR_OK) {
1571                         goto failed_exit;
1572                 }
1573 
1574                 /*
1575                  * Store the kernel public key handle into the public key
1576                  * object and finish the public key object initialization.
1577                  */
1578                 new_pub_objp->is_lib_obj = B_FALSE;
1579                 new_pub_objp->k_handle = obj_kp.kp_public_handle;
1580                 new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1581                 new_pub_objp->extra_attrlistp = NULL;
1582 
1583                 if (is_pri_obj1)
1584                         new_pub_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
1585                 else
1586                         new_pub_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
1587 
1588                 if (is_token_obj1)
1589                         new_pub_objp->bool_attr_mask |= TOKEN_BOOL_ON;
1590                 else
1591                         new_pub_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
1592 
1593                 (void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1594                 new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1595 
1596                 /*
1597                  * Store the kernel private key handle into the private key
1598                  * object and finish the private key object initialization.
1599                  */
1600                 new_pri_objp->is_lib_obj = B_FALSE;
1601                 new_pri_objp->k_handle = obj_kp.kp_private_handle;
1602                 new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1603                 new_pri_objp->extra_attrlistp = NULL;
1604 
1605                 if (is_pri_obj2)
1606                         new_pri_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
1607                 else
1608                         new_pri_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
1609 
1610                 if (is_token_obj2)
1611                         new_pri_objp->bool_attr_mask |= TOKEN_BOOL_ON;
1612                 else
1613                         new_pri_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
1614 
1615         }
1616         (void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
1617         new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1618 
1619         /*
1620          * Add the new pub/pri objects to the slot's token list if they are
1621          * token objects. Otherwise, add them to the session's object list.
1622          */
1623         if (is_token_obj1) { /* is_token_obj1 == is_token_obj2 */
1624                 pslot = slot_table[session_p->ses_slotid];
1625                 kernel_add_token_object_to_slot(new_pub_objp, pslot);
1626                 kernel_add_token_object_to_slot(new_pri_objp, pslot);
1627         } else {
1628                 kernel_add_object_to_session(new_pub_objp, session_p);
1629                 kernel_add_object_to_session(new_pri_objp, session_p);
1630         }
1631 
1632         *phPublicKey = (CK_OBJECT_HANDLE)new_pub_objp;
1633         *phPrivateKey = (CK_OBJECT_HANDLE)new_pri_objp;
1634         REFRELE(session_p, ses_lock_held);
1635         return (rv);
1636 
1637 failed_exit:
1638         if (new_pub_objp != NULL) {
1639                 (void) free(new_pub_objp);
1640         }
1641         if (new_pri_objp != NULL) {
1642                 (void) free(new_pri_objp);
1643         }
1644         REFRELE(session_p, ses_lock_held);
1645         return (rv);
1646 }
1647 
1648 
1649 CK_RV
1650 C_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
1651     CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey,
1652     CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen)
1653 {
1654         CK_RV                   rv = CKR_OK;
1655         kernel_session_t        *session_p;
1656         boolean_t               ses_lock_held = B_FALSE;
1657         kernel_object_t         *wrappingkey_p;
1658         kernel_object_t         *key_p;
1659         crypto_mech_type_t      k_mech_type;
1660         crypto_object_wrap_key_t obj_wrapkey;
1661         int r;
1662 
1663         if (!kernel_initialized)
1664                 return (CKR_CRYPTOKI_NOT_INITIALIZED);
1665 
1666         if (pulWrappedKeyLen == NULL || pMechanism == NULL) {
1667                 return (CKR_ARGUMENTS_BAD);
1668         }
1669 
1670         /*
1671          * Obtain the session pointer.  Also, increment the session
1672          * reference count.
1673          */
1674         rv = handle2session(hSession, &session_p);
1675         if (rv != CKR_OK)
1676                 return (rv);
1677 
1678         /* Get the kernel's internal mechanism number. */
1679         rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
1680         if (rv != CKR_OK) {
1681                 REFRELE(session_p, ses_lock_held);
1682                 return (rv);
1683         }
1684 
1685         /* Obtain the wrapping key object pointer. */
1686         HANDLE2OBJECT(hWrappingKey, wrappingkey_p, rv);
1687         if (rv != CKR_OK) {
1688                 REFRELE(session_p, ses_lock_held);
1689                 return (rv);
1690         }
1691 
1692         /* Obtain the to_be_wrapped key object pointer. */
1693         HANDLE2OBJECT(hKey, key_p, rv);
1694         if (rv != CKR_OK) {
1695                 OBJ_REFRELE(wrappingkey_p);
1696                 REFRELE(session_p, ses_lock_held);
1697                 return (rv);
1698         }
1699 
1700         /* Make the CRYPTO_OBJECT_WRAP_KEY ioctl call. */
1701         obj_wrapkey.wk_session = session_p->k_session;
1702         obj_wrapkey.wk_mechanism.cm_type = k_mech_type;
1703         obj_wrapkey.wk_mechanism.cm_param = pMechanism->pParameter;
1704         obj_wrapkey.wk_mechanism.cm_param_len = pMechanism->ulParameterLen;
1705         obj_wrapkey.wk_wrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
1706         obj_wrapkey.wk_wrapping_key.ck_obj_id = wrappingkey_p->k_handle;
1707         obj_wrapkey.wk_object_handle = key_p->k_handle;
1708         obj_wrapkey.wk_wrapped_key_len = *pulWrappedKeyLen;
1709         obj_wrapkey.wk_wrapped_key = (char *)pWrappedKey;
1710 
1711         while ((r = ioctl(kernel_fd, CRYPTO_WRAP_KEY, &obj_wrapkey)) < 0) {
1712                 if (errno != EINTR)
1713                         break;
1714         }
1715         if (r < 0) {
1716                 rv = CKR_FUNCTION_FAILED;
1717         } else {
1718                 rv = crypto2pkcs11_error_number(obj_wrapkey.wk_return_value);
1719         }
1720 
1721         /*
1722          * Besides rv == CKR_OK, we will set the value of pulWrappedKeyLen
1723          * when the applciation-supplied wrapped key buffer is too small.
1724          * The situation that the application only asks for the length of
1725          * the wrapped key is covered in rv == CKR_OK.
1726          */
1727         if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
1728                 *pulWrappedKeyLen = obj_wrapkey.wk_wrapped_key_len;
1729         }
1730 
1731         OBJ_REFRELE(key_p);
1732         OBJ_REFRELE(wrappingkey_p);
1733         REFRELE(session_p, ses_lock_held);
1734         return (rv);
1735 }
1736 
1737 
1738 CK_RV
1739 C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
1740     CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey,
1741     CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate,
1742     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
1743 {
1744         CK_RV                   rv = CKR_OK;
1745         kernel_session_t        *session_p;
1746         kernel_object_t         *unwrappingkey_p;
1747         kernel_object_t         *new_objp = NULL;
1748         kernel_slot_t           *pslot;
1749         boolean_t               ses_lock_held = B_FALSE;
1750         CK_BBOOL                is_pri_obj;
1751         CK_BBOOL                is_token_obj = FALSE;
1752         CK_MECHANISM_INFO       info;
1753         uint32_t                k_mi_flags;
1754         CK_BYTE                 *clear_key_val = NULL;
1755         CK_ULONG                ulDataLen;
1756         CK_ATTRIBUTE_PTR        newTemplate = NULL;
1757         crypto_mech_type_t      k_mech_type;
1758         crypto_object_unwrap_key_t obj_unwrapkey;
1759         int r;
1760 
1761         if (!kernel_initialized)
1762                 return (CKR_CRYPTOKI_NOT_INITIALIZED);
1763 
1764         if (pMechanism == NULL || pWrappedKey == NULL || phKey == NULL) {
1765                 return (CKR_ARGUMENTS_BAD);
1766         }
1767 
1768         if ((pTemplate == NULL) && (ulAttributeCount != 0)) {
1769                 return (CKR_ARGUMENTS_BAD);
1770         }
1771 
1772         /* Obtain the session pointer. */
1773         rv = handle2session(hSession, &session_p);
1774         if (rv != CKR_OK)
1775                 return (rv);
1776 
1777         /* Obtain the wrapping key object pointer. */
1778         HANDLE2OBJECT(hUnwrappingKey, unwrappingkey_p, rv);
1779         if (rv != CKR_OK) {
1780                 REFRELE(session_p, ses_lock_held);
1781                 return (rv);
1782         }
1783 
1784         /*
1785          * If the HW provider doesn't support C_UnwrapKey, we will try
1786          * to emulate it in the library.
1787          */
1788         pslot = slot_table[session_p->ses_slotid];
1789         if ((!pslot->sl_func_list.fl_object_create) &&
1790             (!pslot->sl_func_list.fl_key_unwrap)) {
1791                 rv = get_mechanism_info(pslot, pMechanism->mechanism, &info,
1792                     &k_mi_flags);
1793                 if (rv != CKR_OK) {
1794                         goto failed_exit;
1795                 }
1796 
1797                 /*
1798                  * If the mechanism flag doesn't have CKF_UNWRAP, and it's
1799                  * an unwrapping of a secret key object, then help this
1800                  * out with a decryption followed by an object creation.
1801                  */
1802                 if (!(k_mi_flags & CRYPTO_FG_UNWRAP) &&
1803                     (k_mi_flags & CRYPTO_FG_DECRYPT) &&
1804                     (is_secret_key_template(pTemplate, ulAttributeCount))) {
1805 
1806                         /* First allocate space for the recovered key value */
1807                         clear_key_val = malloc(ulWrappedKeyLen);
1808                         if (clear_key_val == NULL) {
1809                                 rv = CKR_HOST_MEMORY;
1810                                 goto failed_exit;
1811                         }
1812 
1813                         rv = kernel_decrypt_init(session_p, unwrappingkey_p,
1814                             pMechanism);
1815                         if (rv != CKR_OK) {
1816                                 goto failed_exit;
1817                         }
1818 
1819                         ulDataLen = ulWrappedKeyLen;
1820                         rv = kernel_decrypt(session_p, pWrappedKey,
1821                             ulWrappedKeyLen, clear_key_val, &ulDataLen);
1822                         if (rv != CKR_OK) {
1823                                 goto failed_exit;
1824                         }
1825 
1826                         newTemplate = grow_template(pTemplate, ulAttributeCount,
1827                             ulAttributeCount + 1);
1828                         if (newTemplate == NULL) {
1829                                 rv = CKR_HOST_MEMORY;
1830                                 goto failed_exit;
1831                         }
1832                         /* Now add the CKA_VALUE attribute to template */
1833                         newTemplate[ulAttributeCount].type = CKA_VALUE;
1834                         newTemplate[ulAttributeCount].pValue = clear_key_val;
1835                         newTemplate[ulAttributeCount].ulValueLen = ulDataLen;
1836 
1837                         /* Finally create the key, based on the new template */
1838                         rv = kernel_add_object(newTemplate,
1839                             ulAttributeCount + 1, phKey, session_p);
1840                         (void) free(clear_key_val);
1841                         (void) free(newTemplate);
1842                         OBJ_REFRELE(unwrappingkey_p);
1843                         REFRELE(session_p, ses_lock_held);
1844                         return (rv);
1845                 } else {
1846                         rv = CKR_FUNCTION_FAILED;
1847                         goto failed_exit;
1848                 }
1849         }
1850 
1851         /*
1852          * If we come here, the HW provider must have registered the unwrapkey
1853          * entry.  Therefore, the unwrap key will be performed in the HW
1854          * provider.
1855          */
1856         rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
1857         if (rv != CKR_OK) {
1858                 goto failed_exit;
1859         }
1860 
1861         /* Create an object wrapper for the new key in the library first */
1862         new_objp = calloc(1, sizeof (kernel_object_t));
1863         if (new_objp == NULL) {
1864                 rv = CKR_HOST_MEMORY;
1865                 goto failed_exit;
1866         }
1867 
1868         /* Process the attributes */
1869         rv = process_object_attributes(pTemplate, ulAttributeCount,
1870             &obj_unwrapkey.uk_attributes, &is_token_obj);
1871         if (rv != CKR_OK) {
1872                 goto failed_exit;
1873         }
1874 
1875         /* Cannot create a token object with a READ-ONLY session. */
1876         if (is_token_obj && session_p->ses_RO) {
1877                 free_object_attributes(obj_unwrapkey.uk_attributes,
1878                     ulAttributeCount);
1879                 rv = CKR_SESSION_READ_ONLY;
1880                 goto failed_exit;
1881         }
1882 
1883         /* Make the CRYPTO_UNWRAP_KEY ioctl call. */
1884         obj_unwrapkey.uk_session = session_p->k_session;
1885         obj_unwrapkey.uk_mechanism.cm_type = k_mech_type;
1886         obj_unwrapkey.uk_mechanism.cm_param = pMechanism->pParameter;
1887         obj_unwrapkey.uk_mechanism.cm_param_len = pMechanism->ulParameterLen;
1888         obj_unwrapkey.uk_unwrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
1889         obj_unwrapkey.uk_unwrapping_key.ck_obj_id = unwrappingkey_p->k_handle;
1890         obj_unwrapkey.uk_wrapped_key = (char *)pWrappedKey;
1891         obj_unwrapkey.uk_wrapped_key_len = ulWrappedKeyLen;
1892         obj_unwrapkey.uk_count = ulAttributeCount;
1893 
1894         while ((r = ioctl(kernel_fd, CRYPTO_UNWRAP_KEY, &obj_unwrapkey)) < 0) {
1895                 if (errno != EINTR)
1896                         break;
1897         }
1898         if (r < 0) {
1899                 rv = CKR_FUNCTION_FAILED;
1900         } else {
1901                 rv = crypto2pkcs11_error_number(obj_unwrapkey.uk_return_value);
1902         }
1903 
1904         free_object_attributes(obj_unwrapkey.uk_attributes, ulAttributeCount);
1905         if (rv != CKR_OK) {
1906                 goto failed_exit;
1907         }
1908 
1909         /* Get the CKA_PRIVATE value for the unwrapped key. */
1910         rv = get_cka_private_value(session_p, obj_unwrapkey.uk_object_handle,
1911             &is_pri_obj);
1912         if (rv != CKR_OK) {
1913                 goto failed_exit;
1914         }
1915 
1916         /*
1917          * Store the kernel object handle in the new key object wrapper and
1918          * initialize it.
1919          */
1920         new_objp->k_handle = obj_unwrapkey.uk_object_handle;
1921         new_objp->is_lib_obj = B_FALSE;
1922         new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1923         new_objp->extra_attrlistp = NULL;
1924 
1925         if (is_pri_obj)
1926                 new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
1927         else
1928                 new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
1929 
1930         if (is_token_obj)
1931                 new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
1932         else
1933                 new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
1934 
1935         (void) pthread_mutex_init(&new_objp->object_mutex, NULL);
1936         new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1937 
1938         /*
1939          * Add the new object to the slot's token object list if it is a
1940          * a token object. Otherwise, add it to the session's object list.
1941          */
1942         if (is_token_obj) {
1943                 pslot = slot_table[session_p->ses_slotid];
1944                 kernel_add_token_object_to_slot(new_objp, pslot);
1945         } else {
1946                 kernel_add_object_to_session(new_objp, session_p);
1947         }
1948 
1949         *phKey = (CK_OBJECT_HANDLE)new_objp;
1950         OBJ_REFRELE(unwrappingkey_p);
1951         REFRELE(session_p, ses_lock_held);
1952         return (rv);
1953 
1954 failed_exit:
1955         OBJ_REFRELE(unwrappingkey_p);
1956         if (new_objp != NULL)
1957                 (void) free(new_objp);
1958 
1959         if (clear_key_val != NULL)
1960                 (void) free(clear_key_val);
1961 
1962         if (newTemplate != NULL)
1963                 (void) free(newTemplate);
1964 
1965         REFRELE(session_p, ses_lock_held);
1966         return (rv);
1967 }
1968 
1969 /*
1970  * Get sufficient attributes from a base key to pass by value in a
1971  * crypto_key structure. Storage for attributes is allocated.
1972  * For EC public keys, it is CKA_EC_PARAMS and CKA_EC_POINT.
1973  * For EC private keys, it is CKA_EC_PARAMS and CKA_VALUE.
1974  */
1975 static int
1976 get_base_key_attributes(kernel_object_t *base_key, crypto_key_t *key_by_value)
1977 {
1978         CK_ATTRIBUTE tmp;
1979         crypto_object_attribute_t *attrs = NULL;
1980         biginteger_t *big;
1981         int i, count = 0, rv;
1982 
1983         switch (base_key->key_type) {
1984         case CKK_EC:
1985                 count = 2;
1986                 attrs = malloc(count * sizeof (crypto_object_attribute_t));
1987                 if (attrs == NULL) {
1988                         rv = CKR_HOST_MEMORY;
1989                         goto out;
1990                 }
1991                 bzero(attrs, count * sizeof (crypto_object_attribute_t));
1992 
1993                 (void) pthread_mutex_lock(&base_key->object_mutex);
1994 
1995                 if (!base_key->is_lib_obj) {
1996                         rv = CRYPTO_ARGUMENTS_BAD;
1997                         goto out;
1998                 }
1999 
2000                 if (base_key->class != CKO_PUBLIC_KEY &&
2001                     base_key->class != CKO_PRIVATE_KEY) {
2002                         rv = CRYPTO_ARGUMENTS_BAD;
2003                         goto out;
2004                 }
2005 
2006                 /*
2007                  * Both public and private EC keys should have
2008                  * a CKA_EC_PARAMS attribute.
2009                  */
2010                 tmp.type = CKA_EC_PARAMS;
2011                 tmp.pValue = NULL;
2012 
2013                 /* get size of attribute */
2014                 rv = kernel_get_attribute(base_key, &tmp);
2015                 if (rv != CKR_OK) {
2016                         goto out;
2017                 }
2018 
2019                 tmp.pValue = malloc(tmp.ulValueLen);
2020                 if (tmp.pValue == NULL) {
2021                         rv = CKR_HOST_MEMORY;
2022                         goto out;
2023                 }
2024                 rv = kernel_get_attribute(base_key, &tmp);
2025                 if (rv != CKR_OK) {
2026                         free(tmp.pValue);
2027                         goto out;
2028                 }
2029                 attrs[0].oa_type = tmp.type;
2030                 attrs[0].oa_value = tmp.pValue;
2031                 attrs[0].oa_value_len = tmp.ulValueLen;
2032 
2033                 switch (base_key->class) {
2034                 case CKO_PUBLIC_KEY:
2035                         big = OBJ_PUB_EC_POINT(base_key);
2036                         tmp.type = CKA_EC_POINT;
2037                         break;
2038 
2039                 case CKO_PRIVATE_KEY:
2040                         big = OBJ_PRI_EC_VALUE(base_key);
2041                         tmp.type = CKA_VALUE;
2042                         break;
2043 
2044                 default:
2045                         rv = CKR_ATTRIBUTE_TYPE_INVALID;
2046                         goto out;
2047                 }
2048                 tmp.ulValueLen = big->big_value_len;
2049                 tmp.pValue = malloc(tmp.ulValueLen);
2050                 if (tmp.pValue == NULL) {
2051                         rv = CKR_HOST_MEMORY;
2052                         goto out;
2053                 }
2054                 rv = kernel_get_attribute(base_key, &tmp);
2055                 if (rv != CKR_OK) {
2056                         free(tmp.pValue);
2057                         goto out;
2058                 }
2059                 attrs[1].oa_type = tmp.type;
2060                 attrs[1].oa_value = tmp.pValue;
2061                 attrs[1].oa_value_len = tmp.ulValueLen;
2062                 key_by_value->ck_attrs = attrs;
2063                 key_by_value->ck_count = 2;
2064                 break;
2065 
2066         case CKK_DH:
2067                 count = 3;
2068                 attrs = malloc(count * sizeof (crypto_object_attribute_t));
2069                 if (attrs == NULL) {
2070                         rv = CKR_HOST_MEMORY;
2071                         goto out;
2072                 }
2073                 bzero(attrs, count * sizeof (crypto_object_attribute_t));
2074 
2075                 (void) pthread_mutex_lock(&base_key->object_mutex);
2076 
2077                 if (!base_key->is_lib_obj) {
2078                         rv = CRYPTO_ARGUMENTS_BAD;
2079                         goto out;
2080                 }
2081 
2082                 if (base_key->class != CKO_PRIVATE_KEY) {
2083                         rv = CRYPTO_ARGUMENTS_BAD;
2084                         goto out;
2085                 }
2086                 tmp.type = CKA_BASE;
2087                 tmp.pValue = NULL;
2088 
2089                 /* get size of attribute */
2090                 rv = kernel_get_attribute(base_key, &tmp);
2091                 if (rv != CKR_OK) {
2092                         goto out;
2093                 }
2094 
2095                 tmp.pValue = malloc(tmp.ulValueLen);
2096                 if (tmp.pValue == NULL) {
2097                         rv = CKR_HOST_MEMORY;
2098                         goto out;
2099                 }
2100                 rv = kernel_get_attribute(base_key, &tmp);
2101                 if (rv != CKR_OK) {
2102                         free(tmp.pValue);
2103                         goto out;
2104                 }
2105                 attrs[0].oa_type = tmp.type;
2106                 attrs[0].oa_value = tmp.pValue;
2107                 attrs[0].oa_value_len = tmp.ulValueLen;
2108 
2109                 tmp.type = CKA_PRIME;
2110                 tmp.pValue = NULL;
2111 
2112                 /* get size of attribute */
2113                 rv = kernel_get_attribute(base_key, &tmp);
2114                 if (rv != CKR_OK) {
2115                         goto out;
2116                 }
2117 
2118                 tmp.pValue = malloc(tmp.ulValueLen);
2119                 if (tmp.pValue == NULL) {
2120                         rv = CKR_HOST_MEMORY;
2121                         goto out;
2122                 }
2123                 rv = kernel_get_attribute(base_key, &tmp);
2124                 if (rv != CKR_OK) {
2125                         free(tmp.pValue);
2126                         goto out;
2127                 }
2128                 attrs[1].oa_type = tmp.type;
2129                 attrs[1].oa_value = tmp.pValue;
2130                 attrs[1].oa_value_len = tmp.ulValueLen;
2131 
2132                 big = OBJ_PRI_DH_VALUE(base_key);
2133                 tmp.type = CKA_VALUE;
2134 
2135                 tmp.ulValueLen = big->big_value_len;
2136                 tmp.pValue = malloc(tmp.ulValueLen);
2137                 if (tmp.pValue == NULL) {
2138                         rv = CKR_HOST_MEMORY;
2139                         goto out;
2140                 }
2141                 rv = kernel_get_attribute(base_key, &tmp);
2142                 if (rv != CKR_OK) {
2143                         free(tmp.pValue);
2144                         goto out;
2145                 }
2146                 attrs[2].oa_type = tmp.type;
2147                 attrs[2].oa_value = tmp.pValue;
2148                 attrs[2].oa_value_len = tmp.ulValueLen;
2149                 key_by_value->ck_attrs = attrs;
2150                 key_by_value->ck_count = 3;
2151                 break;
2152 
2153         default:
2154                 rv = CKR_ATTRIBUTE_TYPE_INVALID;
2155                 goto out;
2156         }
2157         (void) pthread_mutex_unlock(&base_key->object_mutex);
2158         return (CKR_OK);
2159 
2160 out:
2161         (void) pthread_mutex_unlock(&base_key->object_mutex);
2162         if (attrs != NULL) {
2163                 for (i = 0; i < count; i++) {
2164                         if (attrs[i].oa_value != NULL)
2165                                 free(attrs[i].oa_value);
2166                 }
2167                 free(attrs);
2168         }
2169         return (rv);
2170 }
2171 
2172 CK_RV
2173 derive_key_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
2174     CK_ULONG ulAttributeCount, kernel_session_t *session_p,
2175     crypto_mech_type_t k_mech_type, kernel_object_t *basekey_p,
2176     kernel_object_t *new_objp)
2177 {
2178         crypto_nostore_derive_key_t obj_ndk;
2179         char *key_buf = NULL;
2180         CK_ATTRIBUTE_PTR newTemplate = NULL;
2181         CK_BBOOL is_token_obj = FALSE;
2182         CK_RV rv = CKR_OK;
2183         CK_ULONG secret_class = CKO_SECRET_KEY;
2184         ulong_t key_len = 0;
2185         uint_t attr_count = 0;
2186         boolean_t removed;
2187         boolean_t has_class;
2188         int r, n;
2189 
2190         obj_ndk.ndk_in_count = 0;
2191         obj_ndk.ndk_out_count = 0;
2192         obj_ndk.ndk_base_key.ck_count = 0;
2193 
2194         rv = get_key_len_from_template(pMechanism, pTemplate, ulAttributeCount,
2195             basekey_p, &key_len);
2196         if (rv != CKR_OK) {
2197                 goto failed_exit;
2198         }
2199 
2200         if ((key_buf = malloc(key_len)) == NULL) {
2201                 rv = CKR_HOST_MEMORY;
2202                 goto failed_exit;
2203         }
2204 
2205         has_class = attribute_in_template(CKA_CLASS, pTemplate,
2206             ulAttributeCount);
2207 
2208         attr_count = ulAttributeCount + 1;
2209         if (!has_class)
2210                 attr_count++;
2211 
2212         newTemplate = grow_template(pTemplate, ulAttributeCount, attr_count);
2213         if (newTemplate == NULL) {
2214                 rv = CKR_HOST_MEMORY;
2215                 goto failed_exit;
2216         }
2217 
2218         n = ulAttributeCount;
2219         if (!has_class) {
2220                 newTemplate[n].type = CKA_CLASS;
2221                 newTemplate[n].pValue = (caddr_t)&secret_class;
2222                 newTemplate[n].ulValueLen = sizeof (secret_class);
2223                 n++;
2224         }
2225 
2226         /* Add CKA_VALUE to the template */
2227         newTemplate[n].type = CKA_VALUE;
2228         newTemplate[n].pValue = (caddr_t)key_buf;
2229         newTemplate[n].ulValueLen = key_len;
2230 
2231         rv = process_object_attributes(newTemplate, attr_count - 1,
2232             &obj_ndk.ndk_in_attributes, &is_token_obj);
2233         if (rv != CKR_OK) {
2234                 goto failed_exit;
2235         }
2236         obj_ndk.ndk_in_count = attr_count - 1;
2237 
2238         rv = process_object_attributes(&newTemplate[attr_count - 1],
2239             1, &obj_ndk.ndk_out_attributes, &is_token_obj);
2240         if (rv != CKR_OK) {
2241                 goto failed_exit;
2242         }
2243         obj_ndk.ndk_out_count = 1;
2244 
2245         /* Cannot create a token object with a READ-ONLY session. */
2246         if (is_token_obj && session_p->ses_RO) {
2247                 rv = CKR_SESSION_READ_ONLY;
2248                 goto failed_exit;
2249         }
2250 
2251         obj_ndk.ndk_session = session_p->k_session;
2252         obj_ndk.ndk_mechanism.cm_type = k_mech_type;
2253         obj_ndk.ndk_mechanism.cm_param = pMechanism->pParameter;
2254         obj_ndk.ndk_mechanism.cm_param_len = pMechanism->ulParameterLen;
2255 
2256         /*
2257          * Obtain the attributes of base key and pass them by value.
2258          */
2259         rv = get_base_key_attributes(basekey_p, &obj_ndk.ndk_base_key);
2260         if (rv != CKR_OK) {
2261                 goto failed_exit;
2262         }
2263 
2264         obj_ndk.ndk_base_key.ck_format = CRYPTO_KEY_ATTR_LIST;
2265 
2266         while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_DERIVE_KEY,
2267             &obj_ndk)) < 0) {
2268                 if (errno != EINTR)
2269                         break;
2270         }
2271         if (r < 0) {
2272                 rv = CKR_FUNCTION_FAILED;
2273         } else {
2274                 rv = crypto2pkcs11_error_number(obj_ndk.ndk_return_value);
2275         }
2276         free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count);
2277         free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs,
2278             &obj_ndk.ndk_base_key.ck_count);
2279         if (rv != CKR_OK) {
2280                 goto failed_exit;
2281         }
2282 
2283         rv = get_object_attributes(&newTemplate[attr_count - 1],
2284             1, obj_ndk.ndk_out_attributes);
2285         free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count);
2286         if (rv != CRYPTO_SUCCESS) {
2287                 goto failed_exit;
2288         }
2289 
2290         removed = remove_one_attribute(newTemplate, CKA_VALUE_LEN,
2291             attr_count, B_FALSE);
2292 
2293         rv = kernel_build_object(newTemplate, removed ? attr_count - 1 :
2294             attr_count, new_objp, session_p, KERNEL_GEN_KEY);
2295         if (rv != CRYPTO_SUCCESS) {
2296                 goto failed_exit;
2297         }
2298 
2299         free(key_buf);
2300         free(newTemplate);
2301         new_objp->is_lib_obj = B_TRUE;
2302         new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
2303         return (CKR_OK);
2304 
2305 failed_exit:
2306         if (key_buf != NULL)
2307                 free(key_buf);
2308         if (newTemplate != NULL)
2309                 free(newTemplate);
2310         free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count);
2311         free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count);
2312         free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs,
2313             &obj_ndk.ndk_base_key.ck_count);
2314         return (rv);
2315 }
2316 
2317 CK_RV
2318 C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
2319     CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
2320     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
2321 {
2322         CK_RV                   rv = CKR_OK;
2323         kernel_session_t        *session_p;
2324         kernel_object_t         *basekey_p;
2325         kernel_object_t         *new_objp;
2326         kernel_slot_t           *pslot;
2327         boolean_t               ses_lock_held = B_FALSE;
2328         CK_BBOOL                is_pri_obj;
2329         CK_BBOOL                is_token_obj = FALSE;
2330         crypto_mech_type_t      k_mech_type;
2331         int r;
2332 
2333         if (!kernel_initialized)
2334                 return (CKR_CRYPTOKI_NOT_INITIALIZED);
2335 
2336         /* Obtain the session pointer. */
2337         rv = handle2session(hSession, &session_p);
2338         if (rv != CKR_OK)
2339                 return (rv);
2340 
2341         if (pMechanism == NULL) {
2342                 REFRELE(session_p, ses_lock_held);
2343                 return (CKR_ARGUMENTS_BAD);
2344         }
2345 
2346         if ((pTemplate == NULL && ulAttributeCount != 0) ||
2347             (pTemplate != NULL && ulAttributeCount == 0)) {
2348                 REFRELE(session_p, ses_lock_held);
2349                 return (CKR_ARGUMENTS_BAD);
2350         }
2351 
2352         /* Obtain the base key object pointer. */
2353         HANDLE2OBJECT(hBaseKey, basekey_p, rv);
2354         if (rv != CKR_OK) {
2355                 REFRELE(session_p, ses_lock_held);
2356                 return (rv);
2357         }
2358 
2359         /* Get the kernel's internal mechanism number. */
2360         rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
2361         if (rv != CKR_OK) {
2362                 goto failed_exit;
2363         }
2364 
2365         /* Create an object wrapper in the library for the generated key. */
2366         new_objp = calloc(1, sizeof (kernel_object_t));
2367         if (new_objp == NULL) {
2368                 rv = CKR_HOST_MEMORY;
2369                 goto failed_exit;
2370         }
2371 
2372         /*
2373          * Special Case: if token does not support object creation,
2374          * but does support key derivation by value, then create a session
2375          * object and initialize with values returned by token.
2376          */
2377         pslot = slot_table[session_p->ses_slotid];
2378         if (!pslot->sl_func_list.fl_object_create) {
2379                 rv = derive_key_by_value(pMechanism, pTemplate,
2380                     ulAttributeCount, session_p, k_mech_type, basekey_p,
2381                     new_objp);
2382                 if (rv != CKR_OK)
2383                         goto failed_exit;
2384         } else {
2385                 crypto_derive_key_t obj_dk;
2386 
2387                 rv = process_object_attributes(pTemplate, ulAttributeCount,
2388                     &obj_dk.dk_attributes, &is_token_obj);
2389                 if (rv != CKR_OK) {
2390                         goto failed_exit;
2391                 }
2392 
2393                 /* Cannot create a token object with a READ-ONLY session. */
2394                 if (is_token_obj && session_p->ses_RO) {
2395                         free_object_attributes(obj_dk.dk_attributes,
2396                             ulAttributeCount);
2397                         rv = CKR_SESSION_READ_ONLY;
2398                         goto failed_exit;
2399                 }
2400 
2401                 obj_dk.dk_session = session_p->k_session;
2402                 obj_dk.dk_mechanism.cm_type = k_mech_type;
2403                 obj_dk.dk_mechanism.cm_param = pMechanism->pParameter;
2404                 obj_dk.dk_mechanism.cm_param_len = pMechanism->ulParameterLen;
2405                 obj_dk.dk_base_key.ck_format = CRYPTO_KEY_REFERENCE;
2406                 obj_dk.dk_base_key.ck_obj_id = basekey_p->k_handle;
2407                 obj_dk.dk_count = ulAttributeCount;
2408 
2409                 while ((r = ioctl(kernel_fd, CRYPTO_DERIVE_KEY, &obj_dk)) < 0) {
2410                         if (errno != EINTR)
2411                                 break;
2412                 }
2413                 if (r < 0) {
2414                         rv = CKR_FUNCTION_FAILED;
2415                 } else {
2416                         rv = crypto2pkcs11_error_number(obj_dk.dk_return_value);
2417                 }
2418 
2419                 free_object_attributes(obj_dk.dk_attributes, ulAttributeCount);
2420                 if (rv != CKR_OK) {
2421                         goto failed_exit;
2422                 }
2423 
2424                 /* Get the CKA_PRIVATE value for the derived key. */
2425                 rv = get_cka_private_value(session_p, obj_dk.dk_object_handle,
2426                     &is_pri_obj);
2427                 if (rv != CKR_OK) {
2428                         goto failed_exit;
2429                 }
2430 
2431                 /*
2432                  * Store the kernel object handle into the new derived key
2433                  * object and finish the object initialization.
2434                  */
2435                 new_objp->is_lib_obj = B_FALSE;
2436                 new_objp->k_handle = obj_dk.dk_object_handle;
2437                 new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
2438                 new_objp->extra_attrlistp = NULL;
2439 
2440                 if (is_pri_obj)
2441                         new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
2442                 else
2443                         new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
2444 
2445                 if (is_token_obj)
2446                         new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
2447                 else
2448                         new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
2449         }
2450         (void) pthread_mutex_init(&new_objp->object_mutex, NULL);
2451         new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
2452 
2453         /*
2454          * Add the new derived object to the slot's token list if it is a
2455          * token object. Otherwise, add it to the session's object list.
2456          */
2457         if (is_token_obj) {
2458                 pslot = slot_table[session_p->ses_slotid];
2459                 kernel_add_token_object_to_slot(new_objp, pslot);
2460         } else {
2461                 kernel_add_object_to_session(new_objp, session_p);
2462         }
2463 
2464         *phKey = (CK_OBJECT_HANDLE)new_objp;
2465         OBJ_REFRELE(basekey_p);
2466         REFRELE(session_p, ses_lock_held);
2467         return (rv);
2468 
2469 failed_exit:
2470         OBJ_REFRELE(basekey_p);
2471         if (new_objp != NULL) {
2472                 (void) free(new_objp);
2473         }
2474 
2475         REFRELE(session_p, ses_lock_held);
2476         return (rv);
2477 }