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