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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright (c) 2018, Joyent, Inc.
  24  */
  25 
  26 
  27 #include <stdlib.h>
  28 #include <string.h>
  29 #include <strings.h>
  30 #include <errno.h>
  31 #include <fcntl.h>
  32 #include <sys/types.h>
  33 #include <sys/stat.h>
  34 #include "metaGlobal.h"
  35 
  36 /* Size of the template for creating key used for wrap/unwrap */
  37 #define WRAP_KEY_TEMPLATE_SIZE  7
  38 
  39 /*
  40  * Information necessary to create keys for C_WrapKey/C_UnwrapKey
  41  */
  42 typedef struct _wrap_info {
  43         CK_OBJECT_CLASS         class; /* class of the key for wrap/unwrap */
  44         CK_KEY_TYPE             key_type; /* key type of key for wrap/unwrap */
  45         CK_ULONG                key_length; /* length of key */
  46         CK_MECHANISM_TYPE       mech_type; /* mech used for wrap/unwrap */
  47         CK_ULONG                iv_length; /* length of iv for mech */
  48 
  49         boolean_t               src_supports;
  50         boolean_t               dst_supports;
  51 } wrap_info_t;
  52 
  53 extern pthread_rwlock_t meta_sessionlist_lock;
  54 extern meta_session_t *meta_sessionlist_head;
  55 
  56 static wrap_info_t common_wrap_info[] = {
  57         {CKO_SECRET_KEY, CKK_AES, 16, CKM_AES_CBC_PAD, 16, B_FALSE, B_FALSE},
  58         {CKO_SECRET_KEY, CKK_DES3, 24, CKM_DES3_CBC_PAD, 8, B_FALSE, B_FALSE},
  59         {CKO_SECRET_KEY, CKK_DES, 8, CKM_DES_CBC_PAD, 8, B_FALSE, B_FALSE},
  60 };
  61 
  62 static unsigned int num_common_wrap_info =
  63     sizeof (common_wrap_info) / sizeof (wrap_info_t);
  64 
  65 static wrap_info_t special_wrap_info[] = {
  66         {CKO_SECRET_KEY, CKK_SKIPJACK, 12,  CKM_SKIPJACK_WRAP, 0,
  67             B_FALSE, B_FALSE},
  68         {CKO_SECRET_KEY, CKK_BATON, 40, CKM_BATON_WRAP, 0,
  69             B_FALSE, B_FALSE},
  70         {CKO_SECRET_KEY, CKK_JUNIPER, 40, CKM_JUNIPER_WRAP, 0,
  71             B_FALSE, B_FALSE},
  72 };
  73 static unsigned int num_special_wrap_info =
  74     sizeof (special_wrap_info) / sizeof (wrap_info_t);
  75 
  76 static wrap_info_t rsa_wrap_info[] = {
  77         {CKO_PUBLIC_KEY, CKK_RSA, 0,  CKM_RSA_PKCS, 0,
  78             B_FALSE, B_FALSE},
  79         {CKO_PUBLIC_KEY, CKK_RSA, 0, CKM_RSA_X_509, 0,
  80             B_FALSE, B_FALSE},
  81 };
  82 static unsigned int num_rsa_wrap_info =
  83     sizeof (rsa_wrap_info) / sizeof (wrap_info_t);
  84 
  85 
  86 static pthread_rwlock_t meta_objectclose_lock;
  87 static pthread_rwlock_t tokenobject_list_lock;
  88 static meta_object_t *tokenobject_list_head;
  89 
  90 CK_BBOOL falsevalue = FALSE;
  91 CK_BBOOL truevalue = TRUE;
  92 
  93 /*
  94  * Public and private exponent, and Module value for
  95  * creating the RSA public/private key.
  96  *
  97  */
  98 static CK_BYTE PubExpo[3] = {0x01, 0x00, 0x01};
  99 CK_BYTE PriExpo[128] = {
 100         0x8e, 0xc9, 0x70, 0x57, 0x6b, 0xcd, 0xfb, 0xa9,
 101         0x19, 0xad, 0xcd, 0x91, 0x69, 0xd5, 0x52, 0xec,
 102         0x72, 0x1e, 0x45, 0x15, 0x06, 0xdc, 0x65, 0x2d,
 103         0x98, 0xc4, 0xce, 0x33, 0x54, 0x15, 0x70, 0x8d,
 104         0xfa, 0x65, 0xea, 0x53, 0x44, 0xf3, 0x3e, 0x3f,
 105         0xb4, 0x4c, 0x60, 0xd5, 0x01, 0x2d, 0xa4, 0x12,
 106         0x99, 0xbf, 0x3f, 0x0b, 0xcd, 0xbb, 0x24, 0x10,
 107         0x60, 0x30, 0x5e, 0x58, 0xf8, 0x59, 0xaa, 0xd1,
 108         0x63, 0x3b, 0xbc, 0xcb, 0x94, 0x58, 0x38, 0x24,
 109         0xfc, 0x65, 0x25, 0xc5, 0xa6, 0x51, 0xa2, 0x2e,
 110         0xf1, 0x5e, 0xf5, 0xc1, 0xf5, 0x46, 0xf7, 0xbd,
 111         0xc7, 0x62, 0xa8, 0xe2, 0x27, 0xd6, 0x94, 0x5b,
 112         0xd3, 0xa2, 0xb5, 0x76, 0x42, 0x67, 0x6b, 0x86,
 113         0x91, 0x97, 0x4d, 0x07, 0x92, 0x00, 0x4a, 0xdf,
 114         0x0b, 0x65, 0x64, 0x05, 0x03, 0x48, 0x27, 0xeb,
 115         0xce, 0x9a, 0x49, 0x7f, 0x3e, 0x10, 0xe0, 0x01};
 116 
 117 static CK_BYTE Modulus[128] = {
 118         0x94, 0x32, 0xb9, 0x12, 0x1d, 0x68, 0x2c, 0xda,
 119         0x2b, 0xe0, 0xe4, 0x97, 0x1b, 0x4d, 0xdc, 0x43,
 120         0xdf, 0x38, 0x6e, 0x7b, 0x9f, 0x07, 0x58, 0xae,
 121         0x9d, 0x82, 0x1e, 0xc7, 0xbc, 0x92, 0xbf, 0xd3,
 122         0xce, 0x00, 0xbb, 0x91, 0xc9, 0x79, 0x06, 0x03,
 123         0x1f, 0xbc, 0x9f, 0x94, 0x75, 0x29, 0x5f, 0xd7,
 124         0xc5, 0xf3, 0x73, 0x8a, 0xa4, 0x35, 0x43, 0x7a,
 125         0x00, 0x32, 0x97, 0x3e, 0x86, 0xef, 0x70, 0x6f,
 126         0x18, 0x56, 0x15, 0xaa, 0x6a, 0x87, 0xe7, 0x8d,
 127         0x7d, 0xdd, 0x1f, 0xa4, 0xe4, 0x31, 0xd4, 0x7a,
 128         0x8c, 0x0e, 0x20, 0xd2, 0x23, 0xf5, 0x57, 0x3c,
 129         0x1b, 0xa8, 0x44, 0xa4, 0x57, 0x8f, 0x33, 0x52,
 130         0xad, 0x83, 0xae, 0x4a, 0x97, 0xa6, 0x1e, 0xa6,
 131         0x2b, 0xfa, 0xea, 0xeb, 0x6e, 0x71, 0xb8, 0xb6,
 132         0x0a, 0x36, 0xed, 0x83, 0xce, 0xb0, 0xdf, 0xc1,
 133         0xd4, 0x3a, 0xe9, 0x99, 0x6f, 0xf3, 0x96, 0xb7};
 134 
 135 static CK_RV
 136 meta_clone_template_setup(meta_object_t *object,
 137     const generic_attr_t *attributes, size_t num_attributes);
 138 
 139 /*
 140  * meta_objectManager_initialize
 141  *
 142  * Called from meta_Initialize.  Initializes all the variables used
 143  * by the object manager.
 144  */
 145 CK_RV
 146 meta_objectManager_initialize()
 147 {
 148         if (pthread_rwlock_init(&meta_objectclose_lock, NULL) != 0) {
 149                 return (CKR_FUNCTION_FAILED);
 150         }
 151 
 152         if (pthread_rwlock_init(&tokenobject_list_lock, NULL) != 0) {
 153                 (void) pthread_rwlock_destroy(&meta_objectclose_lock);
 154                 return (CKR_FUNCTION_FAILED);
 155         }
 156 
 157         tokenobject_list_head = NULL;
 158 
 159         return (CKR_OK);
 160 }
 161 
 162 void
 163 meta_objectManager_finalize()
 164 {
 165         /*
 166          * If there are still any token object in the list, need to
 167          * deactivate all of them.
 168          */
 169         (void) meta_token_object_deactivate(ALL_TOKEN);
 170 
 171         (void) pthread_rwlock_destroy(&meta_objectclose_lock);
 172         (void) pthread_rwlock_destroy(&tokenobject_list_lock);
 173 }
 174 
 175 
 176 
 177 /*
 178  * meta_handle2object
 179  *
 180  * Convert a CK_OBJECT_HANDLE to the corresponding metaobject. If
 181  * successful, a reader-lock on the object will be held to indicate
 182  * that it's in use. Call OBJRELEASE() when finished.
 183  *
 184  */
 185 CK_RV
 186 meta_handle2object(CK_OBJECT_HANDLE hObject, meta_object_t **object)
 187 {
 188         meta_object_t *tmp_object = (meta_object_t *)(hObject);
 189 
 190         /* Check for bad args (eg CK_INVALID_HANDLE, which is 0/NULL). */
 191         if (tmp_object == NULL) {
 192                 *object = NULL;
 193                 return (CKR_OBJECT_HANDLE_INVALID);
 194         }
 195 
 196 
 197         /* Lock to ensure the magic-check + read-lock is atomic. */
 198         (void) pthread_rwlock_rdlock(&meta_objectclose_lock);
 199 
 200         if (tmp_object->magic_marker != METASLOT_OBJECT_MAGIC) {
 201                 (void) pthread_rwlock_unlock(&meta_objectclose_lock);
 202                 *object = NULL;
 203                 return (CKR_OBJECT_HANDLE_INVALID);
 204         }
 205         (void) pthread_rwlock_rdlock(&tmp_object->object_lock);
 206         (void) pthread_rwlock_unlock(&meta_objectclose_lock);
 207 
 208         *object = tmp_object;
 209         return (CKR_OK);
 210 }
 211 
 212 
 213 /*
 214  * meta_object_alloc
 215  *
 216  * Creates a new metaobject, but does not yet add it to the object list.
 217  * Once the caller has finished initializing the object (by setting
 218  * object attributes), meta_object_add should be called. This two-step
 219  * process prevents others from seeing the object until fully intitialized.
 220  *
 221  */
 222 CK_RV
 223 meta_object_alloc(meta_session_t *session, meta_object_t **object)
 224 {
 225         meta_object_t *new_object;
 226         CK_ULONG num_slots;
 227 
 228         /* Allocate memory for the object. */
 229         new_object = calloc(1, sizeof (meta_object_t));
 230         if (new_object == NULL)
 231                 return (CKR_HOST_MEMORY);
 232 
 233         num_slots = meta_slotManager_get_slotcount();
 234 
 235         new_object->clones = calloc(num_slots, sizeof (slot_object_t *));
 236         if (new_object->clones == NULL) {
 237                 free(new_object);
 238                 return (CKR_HOST_MEMORY);
 239         }
 240 
 241         new_object->tried_create_clone = calloc(num_slots, sizeof (boolean_t));
 242         if (new_object->tried_create_clone == NULL) {
 243                 free(new_object->clones);
 244                 free(new_object);
 245                 return (CKR_HOST_MEMORY);
 246         }
 247 
 248         /* Initialize the object fields. */
 249         new_object->magic_marker = METASLOT_OBJECT_MAGIC;
 250         (void) pthread_rwlock_init(&new_object->object_lock, NULL);
 251         (void) pthread_rwlock_init(&new_object->attribute_lock, NULL);
 252         (void) pthread_mutex_init(&new_object->clone_create_lock, NULL);
 253         (void) pthread_mutex_init(&new_object->isClosingObject_lock, NULL);
 254         new_object->creator_session = session;
 255 
 256         *object = new_object;
 257 
 258         return (CKR_OK);
 259 }
 260 
 261 
 262 /*
 263  * meta_object_get_attr
 264  *
 265  * Get attribute values to fill in attribute values
 266  * being kept in the metaslot object.  The following 4 attributes
 267  * in the meta_object_t structure will be filled in:
 268  * isToken, isPrivate, isSensitive, isExtractable
 269  *
 270  * It's basically an easy way to do a C_GetAttributeValue.
 271  * So, the hSession argument is assumed
 272  * to be valid, and the pointer to meta_object_t is also assumed
 273  * to be valid.
 274  */
 275 CK_RV
 276 meta_object_get_attr(slot_session_t *slot_session, CK_OBJECT_HANDLE hObject,
 277     meta_object_t *object)
 278 {
 279         CK_BBOOL is_sensitive = object->isSensitive;
 280         CK_BBOOL is_extractable = object->isExtractable;
 281         CK_BBOOL is_token = B_FALSE, is_private = B_FALSE;
 282         CK_KEY_TYPE keytype;
 283         CK_OBJECT_CLASS class;
 284         CK_ATTRIBUTE attrs[3];
 285         CK_RV rv;
 286         CK_SESSION_HANDLE hSession = slot_session->hSession;
 287         CK_SLOT_ID fw_st_id = slot_session->fw_st_id;
 288         int count = 1;
 289 
 290         attrs[0].type = CKA_CLASS;
 291         attrs[0].pValue = &class;
 292         attrs[0].ulValueLen = sizeof (class);
 293 
 294         if (object->isFreeObject != FREE_ENABLED) {
 295                 attrs[1].type = CKA_TOKEN;
 296                 attrs[1].pValue = &is_token;
 297                 attrs[1].ulValueLen = sizeof (is_token);
 298                 count++;
 299         }
 300 
 301         /*
 302          * If this is a freeobject, we already know the Private value
 303          * and we don't want to overwrite it with the wrong value
 304          */
 305         if (object->isFreeObject <= FREE_DISABLED) {
 306                 attrs[count].type = CKA_PRIVATE;
 307                 attrs[count].pValue = &is_private;
 308                 attrs[count].ulValueLen = sizeof (is_private);
 309                 count++;
 310         } else
 311                 is_private = object->isPrivate;
 312 
 313         rv = FUNCLIST(fw_st_id)->C_GetAttributeValue(hSession, hObject,
 314             attrs, count);
 315         if (rv != CKR_OK) {
 316                 return (rv);
 317         }
 318 
 319         count = 0;
 320         switch (class) {
 321         case CKO_PRIVATE_KEY:
 322         case CKO_SECRET_KEY:
 323                 /* Only need to check these for private & secret keys */
 324                 attrs[0].type = CKA_EXTRACTABLE;
 325                 attrs[0].pValue = &is_extractable;
 326                 attrs[0].ulValueLen = sizeof (is_extractable);
 327                 count = 1;
 328 
 329                 /*
 330                  * If this is a freeobject, we already know the Sensitive
 331                  * value and we don't want to overwrite it with the wrong
 332                  * value.
 333                  */
 334 
 335                 if (object->isFreeObject <= FREE_DISABLED) {
 336                         attrs[1].type = CKA_SENSITIVE;
 337                         attrs[1].pValue = &is_sensitive;
 338                         attrs[1].ulValueLen = sizeof (is_sensitive);
 339                         count = 2;
 340 
 341                         /*
 342                          * We only need the key type if this is the first
 343                          * time we've looked at the object
 344                          */
 345                         if (object->isFreeObject == FREE_UNCHECKED) {
 346                                 attrs[2].type = CKA_KEY_TYPE;
 347                                 attrs[2].pValue = &keytype;
 348                                 attrs[2].ulValueLen = sizeof (keytype);
 349                                 count = 3;
 350                         }
 351                 }
 352 
 353                 break;
 354 
 355         case CKO_PUBLIC_KEY:
 356                 if (object->isFreeObject == FREE_UNCHECKED) {
 357                         attrs[count].type = CKA_KEY_TYPE;
 358                         attrs[count].pValue = &keytype;
 359                         attrs[count].ulValueLen = sizeof (keytype);
 360                         count++;
 361                 }
 362                 is_sensitive = CK_FALSE;
 363                 is_extractable = CK_TRUE;
 364                 break;
 365 
 366         default:
 367                 object->isFreeObject = FREE_DISABLED;
 368                 is_sensitive = CK_FALSE;
 369                 is_extractable = CK_TRUE;
 370         };
 371 
 372         if (count > 0) {
 373                 rv = FUNCLIST(fw_st_id)->C_GetAttributeValue(hSession, hObject,
 374                     attrs, count);
 375                 if (rv != CKR_OK) {
 376                         return (rv);
 377                 }
 378 
 379                 if (object->isFreeObject == FREE_UNCHECKED) {
 380                         if (keytype == CKK_EC || keytype == CKK_RSA ||
 381                             keytype == CKK_DH) {
 382                                 if (metaslot_config.auto_key_migrate) {
 383                                         object->isFreeObject = FREE_DISABLED;
 384                                         object->isFreeToken = FREE_DISABLED;
 385                                 }
 386 
 387                                 object->isFreeObject = FREE_ENABLED;
 388                                 if (is_token)
 389                                         object->isFreeToken = FREE_ENABLED;
 390                         } else
 391                                 object->isFreeObject = FREE_DISABLED;
 392 
 393                 }
 394 
 395         }
 396 
 397         object->isToken = is_token;
 398         object->isPrivate = is_private;
 399         object->isSensitive = is_sensitive;
 400         object->isExtractable = is_extractable;
 401 
 402         return (CKR_OK);
 403 }
 404 
 405 
 406 /*
 407  * meta_object_activate
 408  *
 409  * Add a new metaobject to the list of objects. See also meta_object_create,
 410  * which would be called to create an object before it is added.
 411  */
 412 void
 413 meta_object_activate(meta_object_t *new_object)
 414 {
 415         pthread_rwlock_t *list_lock;
 416         meta_object_t **list_head;
 417 
 418         /*
 419          * For session objects, we keep the list in the session that created
 420          * this object, because this object will be destroyed when that session
 421          * is closed.
 422          *
 423          * For token objects, the list is global (ie, not associated with any
 424          * particular session).
 425          */
 426         if (new_object->isToken) {
 427                 list_lock = &tokenobject_list_lock;
 428                 list_head = &tokenobject_list_head;
 429         } else {
 430                 list_lock = &new_object->creator_session->object_list_lock;
 431                 list_head = &new_object->creator_session->object_list_head;
 432         }
 433 
 434         /* Add object to the list of objects. */
 435         (void) pthread_rwlock_wrlock(list_lock);
 436         INSERT_INTO_LIST(*list_head, new_object);
 437         (void) pthread_rwlock_unlock(list_lock);
 438 }
 439 
 440 
 441 /*
 442  * meta_object_deactivate
 443  *
 444  * Removes the object from the list of valid meta objects.  Note
 445  * that this function does not clean up any allocated
 446  * resources (memory, object clones, etc).   Cleaning up of
 447  * allocated resources is done by calling the meta_object_dealloc()
 448  *
 449  */
 450 CK_RV
 451 meta_object_deactivate(meta_object_t *object, boolean_t have_list_lock,
 452     boolean_t have_object_lock)
 453 {
 454         pthread_rwlock_t *list_lock;
 455         meta_object_t **list_head;
 456 
 457         if (!have_object_lock) {
 458                 (void) pthread_rwlock_rdlock(&object->object_lock);
 459         }
 460 
 461         (void) pthread_mutex_lock(&object->isClosingObject_lock);
 462         if (object->isClosingObject) {
 463                 /* Lost a delete race. */
 464                 (void) pthread_mutex_unlock(&object->isClosingObject_lock);
 465                 OBJRELEASE(object);
 466                 return (CKR_OBJECT_HANDLE_INVALID);
 467         }
 468         object->isClosingObject = B_TRUE;
 469         (void) pthread_mutex_unlock(&object->isClosingObject_lock);
 470 
 471         if (object->isToken || (object->isFreeToken == FREE_ENABLED)) {
 472                 list_lock = &tokenobject_list_lock;
 473                 list_head = &tokenobject_list_head;
 474         } else {
 475                 list_lock = &object->creator_session->object_list_lock;
 476                 list_head = &object->creator_session->object_list_head;
 477         }
 478 
 479         /*
 480          * Remove object from the object list. Once removed, it will not
 481          * be possible for another thread to begin using the object.
 482          */
 483         (void) pthread_rwlock_wrlock(&meta_objectclose_lock);
 484         if (!have_list_lock) {
 485                 (void) pthread_rwlock_wrlock(list_lock);
 486         }
 487 
 488 
 489         object->magic_marker = METASLOT_OBJECT_BADMAGIC;
 490         /*
 491          * Can't use the regular REMOVE_FROM_LIST() function because
 492          * that will miss the "error cleanup" situation where object is not yet
 493          * in the list (object->next == NULL && object->prev == NULL)
 494          */
 495         if (*list_head == object) {
 496                 /* Object is the first one in the list */
 497                 if (object->next) {
 498                         *list_head = object->next;
 499                         object->next->prev = NULL;
 500                 } else {
 501                         /* Object is the only one in the list */
 502                         *list_head = NULL;
 503                 }
 504         } else if (object->next != NULL || object->prev != NULL) {
 505                 if (object->next) {
 506                         object->prev->next = object->next;
 507                         object->next->prev = object->prev;
 508                 } else {
 509                         /* Object is the last one in the list */
 510                         object->prev->next = NULL;
 511                 }
 512         }
 513 
 514         if (!have_list_lock) {
 515                 (void) pthread_rwlock_unlock(list_lock);
 516         }
 517         (void) pthread_rwlock_unlock(&meta_objectclose_lock);
 518 
 519         /*
 520          * Wait for anyone already using object to finish, by obtaining
 521          * a writer-lock (need to release our reader-lock first). Once we
 522          * get the write lock, we can just release it and finish cleaning
 523          * up the object.
 524          */
 525         (void) pthread_rwlock_unlock(&object->object_lock); /* rdlock */
 526         (void) pthread_rwlock_wrlock(&object->object_lock);
 527         (void) pthread_rwlock_unlock(&object->object_lock); /* wrlock */
 528 
 529 
 530         return (CKR_OK);
 531 }
 532 
 533 
 534 /*
 535  * meta_object_dealloc
 536  *
 537  * Performs final object cleanup, releasing any allocated memory and
 538  * destroying any clones on other slots. Caller is assumed to have
 539  * called meta_object_deactivate() before this function.
 540  *
 541  * Caller is assumed to have only reference to object, but should have
 542  * released any lock.
 543  *
 544  * If "nukeSourceObj" argument is true, we will actually delete the
 545  * object from the underlying slot.
 546  */
 547 CK_RV
 548 meta_object_dealloc(meta_session_t *session, meta_object_t *object,
 549     boolean_t nukeSourceObj)
 550 {
 551         CK_RV rv, save_rv = CKR_OK;
 552         CK_ULONG slotnum, num_slots;
 553         CK_ULONG i;
 554 
 555         /* First, delete all the clones of this object on other slots. */
 556         num_slots = meta_slotManager_get_slotcount();
 557         for (slotnum = 0; slotnum < num_slots; slotnum++) {
 558                 slot_session_t *obj_session;
 559                 slot_object_t *clone;
 560 
 561                 clone = object->clones[slotnum];
 562                 if (clone == NULL)
 563                         continue;
 564                 if (nukeSourceObj || (!object->isToken &&
 565                     !(object->isFreeToken == FREE_ENABLED &&
 566                     get_keystore_slotnum() == slotnum))) {
 567 
 568                         rv = meta_get_slot_session(slotnum, &obj_session,
 569                             (session == NULL) ?
 570                             object->creator_session->session_flags :
 571                             session->session_flags);
 572 
 573                         if (rv == CKR_OK) {
 574                                 rv = FUNCLIST(obj_session->fw_st_id)->\
 575                                     C_DestroyObject(obj_session->hSession,
 576                                     clone->hObject);
 577 
 578                                 meta_release_slot_session(obj_session);
 579                                 if ((rv != CKR_OK) && (save_rv == CKR_OK)) {
 580                                         save_rv = rv;
 581                                 }
 582                         }
 583 
 584                 }
 585 
 586                 meta_slot_object_deactivate(clone);
 587                 meta_slot_object_dealloc(clone);
 588 
 589                 object->clones[slotnum] = NULL;
 590         }
 591 
 592         /* Now erase and delete any attributes in the metaobject. */
 593         dealloc_attributes(object->attributes, object->num_attributes);
 594 
 595         free(object->clones);
 596         free(object->tried_create_clone);
 597 
 598         if (object->clone_template) {
 599                 for (i = 0; i < object->clone_template_size; i++) {
 600                         freezero((object->clone_template)[i].pValue,
 601                             (object->clone_template)[i].ulValueLen);
 602                 }
 603                 free(object->clone_template);
 604         }
 605 
 606         /* Cleanup remaining object fields. */
 607         (void) pthread_rwlock_destroy(&object->object_lock);
 608         (void) pthread_rwlock_destroy(&object->attribute_lock);
 609         (void) pthread_mutex_destroy(&object->isClosingObject_lock);
 610         (void) pthread_mutex_destroy(&object->clone_create_lock);
 611 
 612         meta_object_delay_free(object);
 613 
 614         return (save_rv);
 615 }
 616 
 617 
 618 /*
 619  * meta_slot_object_alloc
 620  */
 621 CK_RV
 622 meta_slot_object_alloc(slot_object_t **object) {
 623         slot_object_t *new_object;
 624 
 625         new_object = calloc(1, sizeof (slot_object_t));
 626         if (new_object == NULL)
 627                 return (CKR_HOST_MEMORY);
 628 
 629         *object = new_object;
 630         return (CKR_OK);
 631 }
 632 
 633 
 634 /*
 635  * meta_slot_object_activate
 636  */
 637 void
 638 meta_slot_object_activate(slot_object_t *object,
 639         slot_session_t *creator_session, boolean_t isToken)
 640 {
 641         object->creator_session = creator_session;
 642 
 643         if (isToken) {
 644                 extern slot_data_t *slots;
 645                 slot_data_t *slot;
 646 
 647                 slot = &(slots[object->creator_session->slotnum]);
 648 
 649                 (void) pthread_rwlock_wrlock(&slot->tokenobject_list_lock);
 650                 INSERT_INTO_LIST(slot->tokenobject_list_head, object);
 651                 (void) pthread_rwlock_unlock(&slot->tokenobject_list_lock);
 652         } else {
 653                 slot_session_t *session = object->creator_session;
 654 
 655                 /* Add to session's list of session objects. */
 656                 (void) pthread_rwlock_wrlock(&session->object_list_lock);
 657                 INSERT_INTO_LIST(session->object_list_head, object);
 658                 (void) pthread_rwlock_unlock(&session->object_list_lock);
 659         }
 660 
 661         /*
 662          * This set tells the slot object that we are in the token list,
 663          * but does not cause harm with the metaobject knowing the object
 664          * isn't a token, but a freetoken
 665          */
 666 
 667         object->isToken = isToken;
 668 }
 669 
 670 
 671 /*
 672  * meta_slot_object_deactivate
 673  *
 674  * Remove the specified slot object from the appropriate object list.
 675  */
 676 void
 677 meta_slot_object_deactivate(slot_object_t *object)
 678 {
 679         slot_object_t **list_head;
 680         pthread_rwlock_t *list_lock;
 681 
 682         if (object->isToken) {
 683                 extern slot_data_t *slots;
 684                 slot_data_t *slot;
 685 
 686                 slot = &(slots[object->creator_session->slotnum]);
 687 
 688                 list_head = &slot->tokenobject_list_head;
 689                 list_lock = &slot->tokenobject_list_lock;
 690         } else {
 691                 list_head = &object->creator_session->object_list_head;
 692                 list_lock = &object->creator_session->object_list_lock;
 693         }
 694 
 695         (void) pthread_rwlock_wrlock(list_lock);
 696         REMOVE_FROM_LIST(*list_head, object);
 697         (void) pthread_rwlock_unlock(list_lock);
 698 }
 699 
 700 
 701 /*
 702  * meta_slot_object_dealloc
 703  */
 704 void
 705 meta_slot_object_dealloc(slot_object_t *object)
 706 {
 707         /* Not much cleanup for slot objects, unlike meta objects... */
 708         free(object);
 709 }
 710 
 711 
 712 /*
 713  * meta_object_copyin
 714  *
 715  * When a key is generated/derived/unwrapped, the attribute values
 716  * created by the token are not immediately read into our copy of the
 717  * attributes. We defer this work until we actually need to know.
 718  */
 719 CK_RV
 720 meta_object_copyin(meta_object_t *object)
 721 {
 722         CK_RV rv = CKR_OK;
 723         slot_session_t *session = NULL;
 724         CK_ATTRIBUTE *attrs = NULL, *attrs_with_val = NULL;
 725         slot_object_t *slot_object = NULL;
 726         CK_ULONG num_attrs = 0, i, num_attrs_with_val;
 727         CK_SESSION_HANDLE hSession;
 728         CK_SLOT_ID fw_st_id;
 729 
 730         /* Make sure no one else is looking at attributes. */
 731         (void) pthread_rwlock_wrlock(&object->attribute_lock);
 732 
 733         /* Did we just lose a copyin race with another thread */
 734         if (object->attributes != NULL) {
 735                 goto finish;
 736         }
 737 
 738         slot_object = object->clones[object->master_clone_slotnum];
 739 
 740         rv = meta_get_slot_session(object->master_clone_slotnum, &session,
 741             object->creator_session->session_flags);
 742         if (rv != CKR_OK) {
 743                 goto finish;
 744         }
 745 
 746         /*
 747          * first, get the master template of all the attributes
 748          * for this object
 749          */
 750         rv = get_master_attributes_by_object(session, slot_object,
 751             &(object->attributes), &(object->num_attributes));
 752         if (rv != CKR_OK) {
 753                 goto finish;
 754         }
 755 
 756         /*
 757          * Get value for each attribute items.
 758          *
 759          * Some attributes are required by the given object type.
 760          * Some are optional.  Get all the values first, and then
 761          * make sure we have value for all required values,
 762          */
 763         attrs = calloc(object->num_attributes, sizeof (CK_ATTRIBUTE));
 764         if (attrs == NULL) {
 765                 rv = CKR_HOST_MEMORY;
 766                 goto finish;
 767         }
 768 
 769 
 770         for (i = 0; i < object->num_attributes; i++) {
 771                 attrs[i].type =
 772                     ((object->attributes[i]).attribute).type;
 773         }
 774         num_attrs = object->num_attributes;
 775 
 776         hSession = session->hSession;
 777         fw_st_id = session->fw_st_id;
 778 
 779         /* first, call C_GetAttributeValue() to get size for each attribute */
 780         rv = FUNCLIST(fw_st_id)->C_GetAttributeValue(hSession,
 781             slot_object->hObject, attrs, num_attrs);
 782         /*
 783          * If the return value is not CKR_OK, allow it to be
 784          * CKR_ATTRIBUTE_TYPE_INVALID for now.
 785          * Some attributes defined in PKCS#11 version 2.11
 786          * might not be defined in earlier versions.  We will
 787          * TRY to work with those providers if the attribute
 788          * is optional.
 789          */
 790         if ((rv != CKR_OK) && (rv != CKR_ATTRIBUTE_TYPE_INVALID)) {
 791                 rv = CKR_FUNCTION_FAILED; /* make sure rv is appropriate */
 792                 goto finish;
 793         }
 794 
 795         /*
 796          * allocate space.
 797          * Since we don't know how many attributes have
 798          * values at this time, just assume all of them
 799          * have values so we save one loop to count the number
 800          * of attributes that have value.
 801          */
 802         attrs_with_val = calloc(num_attrs, sizeof (CK_ATTRIBUTE));
 803         if (attrs_with_val == NULL) {
 804                 rv = CKR_HOST_MEMORY;
 805                 goto finish;
 806         }
 807 
 808 
 809         num_attrs_with_val = 0;
 810         for (i = 0; i < num_attrs; i++) {
 811                 if (!(((CK_LONG)(attrs[i].ulValueLen)) > 0)) {
 812                         /* if it isn't an optional attr, len should be > 0 */
 813                         if (!object->attributes[i].canBeEmptyValue) {
 814                                 rv = CKR_FUNCTION_FAILED;
 815                                 goto finish;
 816                         }
 817                 } else {
 818                         attrs_with_val[num_attrs_with_val].type = attrs[i].type;
 819                         attrs_with_val[num_attrs_with_val].ulValueLen =
 820                             attrs[i].ulValueLen;
 821                         attrs_with_val[num_attrs_with_val].pValue =
 822                             malloc(attrs[i].ulValueLen);
 823                         if (attrs_with_val[num_attrs_with_val].pValue == NULL) {
 824                                 rv = CKR_HOST_MEMORY;
 825                                 goto finish;
 826                         }
 827                         num_attrs_with_val++;
 828                 }
 829         }
 830 
 831         rv = FUNCLIST(fw_st_id)->C_GetAttributeValue(hSession,
 832             slot_object->hObject, attrs_with_val, num_attrs_with_val);
 833         if (rv != CKR_OK) {
 834                 goto finish;
 835         }
 836 
 837         /* store these values into the meta object */
 838         for (i = 0; i < num_attrs_with_val; i++) {
 839                 rv = attribute_set_value(&(attrs_with_val[i]),
 840                     object->attributes, object->num_attributes);
 841                 if (rv != CKR_OK) {
 842                         goto finish;
 843                 }
 844         }
 845 
 846 finish:
 847         (void) pthread_rwlock_unlock(&object->attribute_lock);
 848 
 849         if (session)
 850                 meta_release_slot_session(session);
 851 
 852         if (attrs) {
 853                 for (i = 0; i < num_attrs; i++) {
 854                         if (attrs[i].pValue != NULL) {
 855                                 free(attrs[i].pValue);
 856                         }
 857                 }
 858                 free(attrs);
 859         }
 860 
 861         if (attrs_with_val) {
 862                 for (i = 0; i < num_attrs; i++) {
 863                         if (attrs_with_val[i].pValue != NULL) {
 864                                 freezero(attrs_with_val[i].pValue,
 865                                     attrs_with_val[i].ulValueLen);
 866                         }
 867                 }
 868                 free(attrs_with_val);
 869         }
 870         return (rv);
 871 }
 872 
 873 /*
 874  * Create an object to be used for wrapping and unwrapping.
 875  * The same template will be used for all wrapping/unwrapping keys all
 876  * the time
 877  */
 878 
 879 static CK_RV
 880 create_wrap_unwrap_key(slot_session_t *slot_session, CK_OBJECT_HANDLE *hObject,
 881     wrap_info_t *wrap_info, char *key_data, CK_ULONG key_len)
 882 {
 883 
 884         CK_OBJECT_CLASS objclass;
 885         CK_KEY_TYPE keytype;
 886         CK_RV rv = CKR_OK;
 887         int i;
 888         CK_ATTRIBUTE template[WRAP_KEY_TEMPLATE_SIZE];
 889 
 890         i = 0;
 891         objclass = wrap_info->class;
 892         template[i].type = CKA_CLASS;
 893         template[i].pValue = &objclass;
 894         template[i].ulValueLen = sizeof (objclass);
 895 
 896         i++;
 897         keytype = wrap_info->key_type;
 898         template[i].type = CKA_KEY_TYPE;
 899         template[i].pValue = &keytype;
 900         template[i].ulValueLen = sizeof (keytype);
 901 
 902         i++;
 903         template[i].type = CKA_TOKEN;
 904         template[i].pValue = &falsevalue;
 905         template[i].ulValueLen = sizeof (falsevalue);
 906 
 907 
 908         if (objclass == CKO_SECRET_KEY) {
 909                 i++;
 910                 template[i].type = CKA_VALUE;
 911                 template[i].pValue = key_data;
 912                 template[i].ulValueLen = key_len;
 913 
 914                 i++;
 915                 template[i].type = CKA_WRAP;
 916                 template[i].pValue = &truevalue;
 917                 template[i].ulValueLen = sizeof (truevalue);
 918 
 919                 i++;
 920                 template[i].type = CKA_UNWRAP;
 921                 template[i].pValue = &truevalue;
 922                 template[i].ulValueLen = sizeof (truevalue);
 923         } else {
 924                 /* Modulus is the same for rsa public and private key */
 925                 i++;
 926                 template[i].type = CKA_MODULUS;
 927                 template[i].pValue = Modulus;
 928                 template[i].ulValueLen = sizeof (Modulus);
 929 
 930                 if (objclass == CKO_PUBLIC_KEY) {
 931                         /* RSA public key */
 932                         i++;
 933                         template[i].type = CKA_PUBLIC_EXPONENT;
 934                         template[i].pValue = PubExpo;
 935                         template[i].ulValueLen = sizeof (PubExpo);
 936 
 937                         i++;
 938                         template[i].type = CKA_WRAP;
 939                         template[i].pValue = &truevalue;
 940                         template[i].ulValueLen = sizeof (truevalue);
 941                 } else {
 942                         /* RSA private key */
 943                         i++;
 944                         template[i].type = CKA_PRIVATE_EXPONENT;
 945                         template[i].pValue = PriExpo;
 946                         template[i].ulValueLen = sizeof (PriExpo);
 947 
 948                         i++;
 949                         template[i].type = CKA_UNWRAP;
 950                         template[i].pValue = &truevalue;
 951                         template[i].ulValueLen = sizeof (truevalue);
 952                 }
 953         }
 954 
 955         rv = FUNCLIST(slot_session->fw_st_id)->C_CreateObject(
 956             slot_session->hSession, template, i + 1, hObject);
 957 
 958         return (rv);
 959 }
 960 
 961 
 962 /*
 963  * Create a clone of a non-sensitive and extractable object.
 964  * If the template required for creating the clone doesn't exist,
 965  * it will be retrieved from the master clone.
 966  */
 967 static CK_RV
 968 clone_by_create(meta_object_t *object, slot_object_t *new_clone,
 969     slot_session_t *dst_slot_session)
 970 {
 971         CK_RV rv;
 972         int free_token_index = -1;
 973 
 974         if (object->attributes == NULL) {
 975                 rv = meta_object_copyin(object);
 976                 if (rv != CKR_OK) {
 977                         return (rv);
 978                 }
 979         }
 980 
 981         if (object->clone_template == NULL) {
 982                 rv = meta_clone_template_setup(object, object->attributes,
 983                     object->num_attributes);
 984                 if (rv != CKR_OK) {
 985                         return (rv);
 986                 }
 987         }
 988 
 989         if (object->isFreeToken == FREE_ENABLED) {
 990                 if (dst_slot_session->slotnum == get_keystore_slotnum())
 991                         free_token_index = set_template_boolean(CKA_TOKEN,
 992                             object->clone_template,
 993                             object->clone_template_size, B_FALSE, &truevalue);
 994                 else
 995                         free_token_index = set_template_boolean(CKA_TOKEN,
 996                             object->clone_template,
 997                             object->clone_template_size, B_FALSE, &falsevalue);
 998         }
 999 
1000         /* Create the clone... */
1001         rv = FUNCLIST(dst_slot_session->fw_st_id)->C_CreateObject(
1002             dst_slot_session->hSession, object->clone_template,
1003             object->clone_template_size, &(new_clone->hObject));
1004 
1005         if (free_token_index != -1) {
1006                         free_token_index = set_template_boolean(CKA_TOKEN,
1007                             object->clone_template, object->clone_template_size,
1008                             B_FALSE, &falsevalue);
1009         }
1010 
1011         if (rv != CKR_OK) {
1012                 return (rv);
1013         }
1014 
1015         return (CKR_OK);
1016 }
1017 
1018 /*
1019  * Goes through the list of wraping mechanisms, and returns the first
1020  * one that is supported by both the source and the destination slot.
1021  * If none of the mechanisms are supported by both slot, return the
1022  * first mechanism that's supported by the source slot
1023  */
1024 static CK_RV
1025 find_best_match_wrap_mech(wrap_info_t *wrap_info, int num_info,
1026         CK_ULONG src_slotnum, CK_ULONG dst_slotnum, int *first_both_mech,
1027         int *first_src_mech)
1028 {
1029 
1030         int i;
1031         boolean_t src_supports, dst_supports;
1032         CK_RV rv;
1033         CK_MECHANISM_INFO mech_info;
1034 
1035         mech_info.flags = CKF_WRAP;
1036 
1037         for (i = 0; i < num_info; i++) {
1038                 src_supports = B_FALSE;
1039                 dst_supports = B_FALSE;
1040 
1041                 rv = meta_mechManager_slot_supports_mech(
1042                     (wrap_info[i]).mech_type, src_slotnum,
1043                     &src_supports, NULL, B_FALSE, &mech_info);
1044                 if (rv != CKR_OK) {
1045                         return (rv);
1046                 }
1047 
1048                 rv = meta_mechManager_slot_supports_mech(
1049                     (wrap_info[i]).mech_type, dst_slotnum,
1050                     &dst_supports, NULL, B_FALSE, &mech_info);
1051                 if (rv != CKR_OK) {
1052                         return (rv);
1053                 }
1054 
1055                 /* both source and destination supports the mech */
1056                 if ((src_supports) && (dst_supports)) {
1057                         *first_both_mech = i;
1058                         return (CKR_OK);
1059                 }
1060 
1061                 if ((src_supports) && (*first_src_mech == -1)) {
1062                         *first_src_mech = i;
1063                 }
1064         }
1065         return (CKR_OK);
1066 }
1067 
1068 /*
1069  * Determine the wrapping/unwrapping mechanism to be used
1070  *
1071  * If possible, select a mechanism that's supported by both source
1072  * and destination slot.  If none of the mechanisms are supported
1073  * by both slot, then, select the first one supported by
1074  * the source slot.
1075  */
1076 
1077 static CK_RV
1078 get_wrap_mechanism(CK_OBJECT_CLASS obj_class, CK_KEY_TYPE key_type,
1079     CK_ULONG src_slotnum, CK_ULONG dst_slotnum, wrap_info_t *wrap_info)
1080 {
1081         wrap_info_t *wrap_info_to_search = NULL;
1082         unsigned int num_wrap_info;
1083         CK_RV rv;
1084         int i;
1085         boolean_t src_supports = B_FALSE, dst_supports = B_FALSE;
1086         int first_src_mech, rsa_first_src_mech, first_both_mech;
1087         CK_MECHANISM_INFO mech_info;
1088 
1089         mech_info.flags = CKF_WRAP;
1090 
1091         if ((obj_class == CKO_PRIVATE_KEY) && (key_type == CKK_KEA)) {
1092                 /*
1093                  * only SKIPJACK keys can be used for wrapping
1094                  * KEA private keys
1095                  */
1096 
1097                 for (i = 0; i < num_special_wrap_info; i++) {
1098                         if ((special_wrap_info[i]).mech_type
1099                             != CKM_SKIPJACK_WRAP) {
1100                                 continue;
1101                         }
1102 
1103                         src_supports = B_FALSE;
1104                         dst_supports = B_FALSE;
1105 
1106                         rv = meta_mechManager_slot_supports_mech(
1107                             (special_wrap_info[i]).mech_type, src_slotnum,
1108                             &src_supports, NULL, B_FALSE, &mech_info);
1109                         if (rv != CKR_OK) {
1110                                 goto finish;
1111                         }
1112 
1113                         rv = meta_mechManager_slot_supports_mech(
1114                             (special_wrap_info[i]).mech_type, dst_slotnum,
1115                             &dst_supports, NULL, B_FALSE, &mech_info);
1116                         if (rv != CKR_OK) {
1117                                 goto finish;
1118                         }
1119 
1120                         if (src_supports) {
1121                                 /*
1122                                  * both src and dst supports the mech or
1123                                  * only the src supports the mech
1124                                  */
1125                                 (void) memcpy(wrap_info,
1126                                     &(special_wrap_info[i]),
1127                                     sizeof (wrap_info_t));
1128 
1129                                 wrap_info->src_supports = src_supports;
1130                                 wrap_info->dst_supports = dst_supports;
1131                                 rv = CKR_OK;
1132                                 goto finish;
1133                         }
1134 
1135                 }
1136 
1137                 /*
1138                  * if we are here, that means neither the source slot
1139                  * nor the destination slots supports CKM_SKIPJACK_WRAP.
1140                  */
1141                 rv = CKR_FUNCTION_FAILED;
1142                 goto finish;
1143         }
1144 
1145         if ((key_type == CKK_SKIPJACK) || (key_type == CKK_BATON) ||
1146             (key_type == CKK_JUNIPER)) {
1147                 /* special key types */
1148                 wrap_info_to_search = special_wrap_info;
1149                 num_wrap_info = num_special_wrap_info;
1150         } else {
1151                 /* use the regular wrapping mechanisms */
1152                 wrap_info_to_search = common_wrap_info;
1153                 num_wrap_info = num_common_wrap_info;
1154         }
1155 
1156         first_both_mech = -1;
1157         first_src_mech = -1;
1158 
1159         rv = find_best_match_wrap_mech(wrap_info_to_search, num_wrap_info,
1160             src_slotnum, dst_slotnum, &first_both_mech, &first_src_mech);
1161         if (rv != CKR_OK) {
1162                 goto finish;
1163         }
1164 
1165         if (first_both_mech != -1) {
1166                 (void) memcpy(wrap_info,
1167                     &(wrap_info_to_search[first_both_mech]),
1168                     sizeof (wrap_info_t));
1169 
1170                 wrap_info->src_supports = B_TRUE;
1171                 wrap_info->dst_supports = B_TRUE;
1172                 rv = CKR_OK;
1173                 goto finish;
1174         }
1175 
1176         /*
1177          * If we are here, we did not find a mechanism that's supported
1178          * by both source and destination slot.
1179          *
1180          * If it is a secret key, can also try to wrap it with
1181          * a RSA public key
1182          */
1183         if (obj_class == CKO_SECRET_KEY) {
1184                 first_both_mech = -1;
1185                 rsa_first_src_mech = -1;
1186 
1187                 rv = find_best_match_wrap_mech(rsa_wrap_info,
1188                     num_rsa_wrap_info, src_slotnum, dst_slotnum,
1189                     &first_both_mech, &rsa_first_src_mech);
1190 
1191                 if (rv != CKR_OK) {
1192                         goto finish;
1193                 }
1194 
1195                 if (first_both_mech > -1) {
1196                         (void) memcpy(wrap_info,
1197                             &(rsa_wrap_info[first_both_mech]),
1198                             sizeof (wrap_info_t));
1199 
1200                         wrap_info->src_supports = B_TRUE;
1201                         wrap_info->dst_supports = B_TRUE;
1202                         rv = CKR_OK;
1203                         goto finish;
1204                 }
1205         }
1206 
1207         /*
1208          * if we are here, that means none of the mechanisms are supported
1209          * by both the source and the destination
1210          */
1211         if (first_src_mech > -1) {
1212                 /* source slot support one of the secret key mechs */
1213                 (void) memcpy(wrap_info,
1214                     &(wrap_info_to_search[first_src_mech]),
1215                     sizeof (wrap_info_t));
1216                 wrap_info->src_supports = B_TRUE;
1217                 wrap_info->dst_supports = B_FALSE;
1218                 rv = CKR_OK;
1219         } else if (rsa_first_src_mech > -1) {
1220                 /* source slot support one of the RSA mechs */
1221                 (void) memcpy(wrap_info, &(rsa_wrap_info[rsa_first_src_mech]),
1222                     sizeof (wrap_info_t));
1223 
1224                 wrap_info->src_supports = B_TRUE;
1225                 wrap_info->dst_supports = B_FALSE;
1226                 rv = CKR_OK;
1227         } else {
1228                 /* neither source nor destination support any wrap mechs */
1229                 rv = CKR_FUNCTION_FAILED;
1230         }
1231 
1232 finish:
1233         return (rv);
1234 }
1235 
1236 
1237 /*
1238  * This is called if the object to be cloned is a sensitive object
1239  */
1240 static CK_RV
1241 clone_by_wrap(meta_object_t *object, slot_object_t *new_clone,
1242     slot_session_t *dst_slot_session)
1243 {
1244         slot_session_t *src_slot_session = NULL;
1245         CK_OBJECT_HANDLE wrappingKey = NULL, unwrappingKey = NULL;
1246         CK_MECHANISM wrappingMech;
1247         CK_BYTE *wrappedKey = NULL;
1248         CK_ULONG wrappedKeyLen = 0;
1249         slot_object_t *slot_object = NULL;
1250         CK_RV rv = CKR_OK;
1251         CK_OBJECT_HANDLE unwrapped_obj;
1252         meta_object_t *tmp_meta_obj = NULL;
1253         slot_object_t *tmp_slot_obj = NULL;
1254         CK_OBJECT_CLASS obj_class;
1255         CK_KEY_TYPE key_type;
1256         meta_session_t *tmp_meta_session = NULL;
1257         CK_ATTRIBUTE unwrap_template[4];
1258         char key_data[1024]; /* should be big enough for any key size */
1259         char ivbuf[1024]; /* should be big enough for any mech */
1260         wrap_info_t wrap_info;
1261         CK_ULONG key_len, unwrap_template_size;
1262 
1263         slot_object = object->clones[object->master_clone_slotnum];
1264 
1265         rv = meta_get_slot_session(object->master_clone_slotnum,
1266             &src_slot_session, object->creator_session->session_flags);
1267         if (rv != CKR_OK) {
1268                 return (rv);
1269         }
1270 
1271         /*
1272          * get the object class and key type for unwrap template
1273          * This information will also be used for determining
1274          * which wrap mechanism and which key to use for
1275          * doing the wrapping
1276          */
1277         unwrap_template[0].type = CKA_CLASS;
1278         unwrap_template[0].pValue = &obj_class;
1279         unwrap_template[0].ulValueLen = sizeof (obj_class);
1280 
1281         unwrap_template[1].type = CKA_KEY_TYPE;
1282         unwrap_template[1].pValue = &key_type;
1283         unwrap_template[1].ulValueLen = sizeof (key_type);
1284 
1285         rv = FUNCLIST(src_slot_session->fw_st_id)->C_GetAttributeValue(
1286             src_slot_session->hSession, slot_object->hObject,
1287             unwrap_template, 2);
1288         if (rv != CKR_OK) {
1289                 goto finish;
1290         }
1291 
1292         rv = get_wrap_mechanism(obj_class, key_type, src_slot_session->slotnum,
1293             dst_slot_session->slotnum, &wrap_info);
1294         if (rv != CKR_OK) {
1295                 goto finish;
1296         }
1297 
1298         /*
1299          * read number of bytes required from random device for
1300          * creating a secret key for wrapping and unwrapping
1301          */
1302         if (wrap_info.class == CKO_SECRET_KEY) {
1303 
1304                 /*
1305                  * /dev/urandom will be used for generating the key used
1306                  * for doing the wrap/unwrap.  It's should be ok to
1307                  * use /dev/urandom because this key is used for this
1308                  * one time operation only.  It doesn't need to be stored.
1309                  */
1310                 key_len = wrap_info.key_length;
1311                 if (pkcs11_get_urandom(key_data, key_len) < 0) {
1312                         rv = CKR_FUNCTION_FAILED;
1313                         goto finish;
1314                 }
1315 
1316                 if (wrap_info.iv_length > 0) {
1317                         if (pkcs11_get_urandom(
1318                             ivbuf, wrap_info.iv_length) < 0) {
1319                                 rv = CKR_FUNCTION_FAILED;
1320                                 goto finish;
1321                         }
1322                 }
1323         }
1324 
1325         /* create the wrapping key */
1326         rv = create_wrap_unwrap_key(src_slot_session, &wrappingKey,
1327             &wrap_info, key_data, key_len);
1328         if (rv != CKR_OK) {
1329                 goto finish;
1330         }
1331 
1332         wrappingMech.mechanism = wrap_info.mech_type;
1333         wrappingMech.pParameter = ((wrap_info.iv_length > 0) ? ivbuf : NULL);
1334         wrappingMech.ulParameterLen = wrap_info.iv_length;
1335 
1336         /* get the size of the wrapped key */
1337         rv = FUNCLIST(src_slot_session->fw_st_id)->C_WrapKey(
1338             src_slot_session->hSession, &wrappingMech,
1339             wrappingKey, slot_object->hObject, NULL, &wrappedKeyLen);
1340 
1341         if (rv != CKR_OK) {
1342                 goto finish;
1343         }
1344 
1345         wrappedKey = malloc(wrappedKeyLen * sizeof (CK_BYTE));
1346         if (wrappedKey == NULL) {
1347                 rv = CKR_HOST_MEMORY;
1348                 goto finish;
1349         }
1350 
1351         /* do the actual key wrapping */
1352         rv = FUNCLIST(src_slot_session->fw_st_id)->C_WrapKey(
1353             src_slot_session->hSession, &wrappingMech,
1354             wrappingKey, slot_object->hObject, wrappedKey, &wrappedKeyLen);
1355 
1356         if (rv != CKR_OK) {
1357                 goto finish;
1358         }
1359 
1360         /* explicitly force the unwrapped object to be not sensitive */
1361         unwrap_template[2].type = CKA_SENSITIVE;
1362         unwrap_template[2].pValue = &falsevalue;
1363         unwrap_template[2].ulValueLen = sizeof (falsevalue);
1364 
1365         unwrap_template[3].type = CKA_TOKEN;
1366         unwrap_template[3].pValue = &falsevalue;
1367         unwrap_template[3].ulValueLen = sizeof (falsevalue);
1368 
1369         unwrap_template_size =
1370             sizeof (unwrap_template) / sizeof (CK_ATTRIBUTE);
1371 
1372         if (!wrap_info.dst_supports) {
1373                 /*
1374                  * if we know for sure that the destination slot doesn't
1375                  * support the wrapping mechanism, no point in trying.
1376                  * go directly to unwrap in source slot, and create key
1377                  * in destination
1378                  */
1379                 goto unwrap_in_source;
1380         }
1381 
1382         /* create the unwrapping key in destination slot */
1383         if (wrap_info.key_type == CKK_RSA) {
1384                 /* for RSA key, the unwrapping key need to be private key */
1385                 wrap_info.class = CKO_PRIVATE_KEY;
1386         }
1387         rv = create_wrap_unwrap_key(dst_slot_session,
1388             &unwrappingKey, &wrap_info, key_data, key_len);
1389         if (rv != CKR_OK) {
1390                 goto finish;
1391         }
1392 
1393         rv = FUNCLIST(dst_slot_session->fw_st_id)->C_UnwrapKey(
1394             dst_slot_session->hSession, &wrappingMech,
1395             unwrappingKey, wrappedKey, wrappedKeyLen, unwrap_template,
1396             unwrap_template_size, &(new_clone->hObject));
1397 
1398         if (rv != CKR_OK) {
1399 unwrap_in_source:
1400 
1401                 /*
1402                  * There seemed to be a problem with unwrapping in the
1403                  * destination slot.
1404                  * Try to do the unwrap in the src slot so it becomes
1405                  * a non-sensitive object, then, get all the attributes
1406                  * and create the object in the destination slot
1407                  */
1408 
1409 
1410                 if (wrap_info.class == CKO_SECRET_KEY) {
1411                         /* unwrap with same key used for wrapping */
1412                         rv = FUNCLIST(src_slot_session->fw_st_id)->C_UnwrapKey(
1413                             src_slot_session->hSession,
1414                             &wrappingMech, wrappingKey, wrappedKey,
1415                             wrappedKeyLen, unwrap_template,
1416                             unwrap_template_size, &(unwrapped_obj));
1417                 } else {
1418                         /*
1419                          * If the object is wrapping with RSA public key, need
1420                          * need to create RSA private key for unwrapping
1421                          */
1422                         wrap_info.class = CKO_PRIVATE_KEY;
1423                         rv = create_wrap_unwrap_key(src_slot_session,
1424                             &unwrappingKey, &wrap_info, key_data, key_len);
1425                         if (rv != CKR_OK) {
1426                                 goto finish;
1427                         }
1428                         rv = FUNCLIST(src_slot_session->fw_st_id)->C_UnwrapKey(
1429                             src_slot_session->hSession,
1430                             &wrappingMech, unwrappingKey, wrappedKey,
1431                             wrappedKeyLen, unwrap_template,
1432                             unwrap_template_size, &(unwrapped_obj));
1433                 }
1434 
1435 
1436                 if (rv != CKR_OK) {
1437                         goto finish;
1438                 }
1439 
1440                 rv = meta_session_alloc(&tmp_meta_session);
1441                 if (rv != CKR_OK) {
1442                         goto finish;
1443                 }
1444 
1445                 tmp_meta_session->session_flags = CKF_SERIAL_SESSION;
1446 
1447                 rv = meta_object_alloc(tmp_meta_session, &tmp_meta_obj);
1448                 if (rv != CKR_OK) {
1449                         goto finish;
1450                 }
1451 
1452                 rv = meta_slot_object_alloc(&tmp_slot_obj);
1453                 if (rv != CKR_OK) {
1454                         goto finish;
1455                 }
1456 
1457                 tmp_meta_obj->master_clone_slotnum = src_slot_session->slotnum;
1458                 tmp_slot_obj->hObject = unwrapped_obj;
1459                 tmp_meta_obj->clones[tmp_meta_obj->master_clone_slotnum]
1460                     = tmp_slot_obj;
1461                 meta_slot_object_activate(tmp_slot_obj, src_slot_session,
1462                     B_FALSE);
1463                 tmp_slot_obj = NULL;
1464 
1465                 rv = clone_by_create(tmp_meta_obj, new_clone,
1466                     dst_slot_session);
1467                 if (rv != CKR_OK) {
1468                         goto finish;
1469                 }
1470         }
1471 
1472 finish:
1473         if (unwrappingKey) {
1474                 (void) FUNCLIST(dst_slot_session->fw_st_id)->C_DestroyObject(
1475                     dst_slot_session->hSession, unwrappingKey);
1476         }
1477 
1478         if (wrappingKey) {
1479                 (void) FUNCLIST(src_slot_session->fw_st_id)->C_DestroyObject(
1480                     src_slot_session->hSession, wrappingKey);
1481         }
1482 
1483         if (tmp_slot_obj) {
1484                 (void) meta_slot_object_dealloc(tmp_slot_obj);
1485         }
1486 
1487         if (tmp_meta_obj) {
1488                 (void) meta_object_dealloc(tmp_meta_session, tmp_meta_obj,
1489                     B_TRUE);
1490         }
1491 
1492         if (tmp_meta_session) {
1493                 (void) meta_session_dealloc(tmp_meta_session);
1494         }
1495 
1496         if (wrappedKey) {
1497                 freezero(wrappedKey, wrappedKeyLen);
1498         }
1499 
1500         if (src_slot_session) {
1501                 meta_release_slot_session(src_slot_session);
1502         }
1503 
1504         return (rv);
1505 
1506 }
1507 
1508 
1509 /*
1510  * meta_object_get_clone
1511  *
1512  * Creates a "clone" of a metaobject on the specified slot. A clone is a
1513  * copy of the object.
1514  *
1515  * Clones are cached, so that they can be reused with subsequent operations.
1516  */
1517 CK_RV
1518 meta_object_get_clone(meta_object_t *object,
1519         CK_ULONG slot_num, slot_session_t *slot_session,
1520         slot_object_t **clone)
1521 {
1522         CK_RV rv = CKR_OK;
1523         slot_object_t *newclone = NULL;
1524 
1525         /* Does a clone already exist? */
1526         if (object->clones[slot_num] != NULL) {
1527                 *clone = object->clones[slot_num];
1528                 return (CKR_OK);
1529         }
1530 
1531         if ((object->isSensitive) && (object->isToken) &&
1532             (!metaslot_auto_key_migrate)) {
1533                 /*
1534                  * if the object is a sensitive token object, and auto
1535                  * key migrate is not allowed, will not create the clone
1536                  * in another slot
1537                  */
1538                 return (CKR_FUNCTION_FAILED);
1539         }
1540 
1541         /* object attributes can't be extracted and attributes are not known */
1542         if ((!object->isExtractable) && (object->attributes == NULL)) {
1543                 return (CKR_FUNCTION_FAILED);
1544         }
1545 
1546         (void) pthread_mutex_lock(&object->clone_create_lock);
1547 
1548         /* Maybe someone just created one? */
1549         if (object->clones[slot_num] != NULL) {
1550                 *clone = object->clones[slot_num];
1551                 goto finish;
1552         }
1553 
1554         /*
1555          * has an attempt already been made to create this object in
1556          * slot?  If yes, and there's no clone, as indicated above,
1557          * that means this object can't be created in this slot.
1558          */
1559         if (object->tried_create_clone[slot_num]) {
1560                 (void) pthread_mutex_unlock(&object->clone_create_lock);
1561                 return (CKR_FUNCTION_FAILED);
1562         }
1563 
1564         rv = meta_slot_object_alloc(&newclone);
1565         if (rv != CKR_OK)
1566                 goto finish;
1567 
1568         object->tried_create_clone[slot_num] = B_TRUE;
1569 
1570         /*
1571          * If this object is sensitive and we do not have not copied in the
1572          * attributes via FreeObject functionality, then we need to wrap it off
1573          * the provider.  If we do have attributes, we can just create the
1574          * clone
1575          */
1576 
1577         if (object->isSensitive && object->attributes == NULL) {
1578                 rv = clone_by_wrap(object, newclone, slot_session);
1579         } else {
1580                 rv = clone_by_create(object, newclone, slot_session);
1581         }
1582 
1583         if (rv != CKR_OK) {
1584                 goto finish;
1585         }
1586 
1587         object->clones[slot_num] = newclone;
1588         meta_slot_object_activate(newclone, slot_session, object->isToken);
1589 
1590         *clone = newclone;
1591         newclone = NULL;
1592 finish:
1593         (void) pthread_mutex_unlock(&object->clone_create_lock);
1594 
1595         if (newclone)
1596                 meta_slot_object_dealloc(newclone);
1597 
1598         return (rv);
1599 }
1600 
1601 
1602 /*
1603  * meta_setup_clone_template
1604  *
1605  * Create a clone template for the specified object.
1606  */
1607 static CK_RV
1608 meta_clone_template_setup(meta_object_t *object,
1609     const generic_attr_t *attributes, size_t num_attributes)
1610 {
1611         CK_RV rv = CKR_OK;
1612         CK_ATTRIBUTE *clone_template;
1613         size_t i, c = 0;
1614 
1615         clone_template = malloc(num_attributes * sizeof (CK_ATTRIBUTE));
1616         if (clone_template == NULL) {
1617                 rv = CKR_HOST_MEMORY;
1618                 goto finish;
1619         }
1620 
1621         /* Don't allow attributes to change while we look at them. */
1622         (void) pthread_rwlock_rdlock(&object->attribute_lock);
1623 
1624         for (i = 0; i < num_attributes; i++) {
1625                 if (!attributes[i].isCloneAttr ||
1626                     (attributes[i].attribute.type == CKA_TOKEN &&
1627                     object->isFreeToken == FREE_DISABLED)) {
1628                         continue;
1629                 }
1630                 if ((!(attributes[i].hasValueForClone)) &&
1631                     (attributes[i].canBeEmptyValue)) {
1632                         continue;
1633                 }
1634 
1635                 clone_template[c].type = attributes[i].attribute.type;
1636                 clone_template[c].ulValueLen =
1637                     attributes[i].attribute.ulValueLen;
1638                 /* Allocate space to store the attribute value. */
1639                 clone_template[c].pValue = malloc(clone_template[c].ulValueLen);
1640                 if (clone_template[c].pValue == NULL) {
1641                         free(clone_template);
1642                         rv = CKR_HOST_MEMORY;
1643                         (void) pthread_rwlock_unlock(&object->attribute_lock);
1644                         goto finish;
1645                 }
1646 
1647                 (void) memcpy(clone_template[c].pValue,
1648                     object->attributes[i].attribute.pValue,
1649                     clone_template[c].ulValueLen);
1650                 c++;
1651         }
1652 
1653         (void) pthread_rwlock_unlock(&object->attribute_lock);
1654 
1655         object->clone_template = clone_template;
1656         object->clone_template_size = c;
1657 
1658 finish:
1659         return (rv);
1660 }
1661 
1662 
1663 /*
1664  * meta_object_find_by_handle
1665  *
1666  * Search for an existing metaobject, using the object handle of a clone
1667  * on a particular slot.
1668  *
1669  * Returns a matching metaobject, or NULL if no match was found.
1670  */
1671 meta_object_t *
1672 meta_object_find_by_handle(CK_OBJECT_HANDLE hObject, CK_ULONG slotnum,
1673     boolean_t token_only)
1674 {
1675         meta_object_t *object = NULL, *tmp_obj;
1676         meta_session_t *session;
1677 
1678         if (!token_only) {
1679                 (void) pthread_rwlock_rdlock(&meta_sessionlist_lock);
1680                 session = meta_sessionlist_head;
1681                 while (session != NULL) {
1682                         /* lock the objects list while we look at it */
1683                         (void) pthread_rwlock_rdlock(
1684                             &(session->object_list_lock));
1685                         tmp_obj = session->object_list_head;
1686                         while (tmp_obj != NULL) {
1687                                 slot_object_t *slot_object;
1688 
1689                                 (void) pthread_rwlock_rdlock(
1690                                     &(tmp_obj->object_lock));
1691                                 slot_object = tmp_obj->clones[slotnum];
1692                                 if (slot_object != NULL) {
1693                                         if (slot_object->hObject == hObject) {
1694                                                 object = tmp_obj;
1695                                         }
1696                                 }
1697                                 (void) pthread_rwlock_unlock(
1698                                     &(tmp_obj->object_lock));
1699                                 if (object != NULL) {
1700                                         break;
1701                                 }
1702                                 tmp_obj = tmp_obj->next;
1703                         }
1704                         (void) pthread_rwlock_unlock(
1705                             &(session->object_list_lock));
1706                         if (object != NULL) {
1707                                 break;
1708                         }
1709                         session = session->next;
1710                 }
1711                 (void) pthread_rwlock_unlock(&meta_sessionlist_lock);
1712         }
1713 
1714         if (object != NULL) {
1715                 /* found the object, no need to look further */
1716                 return (object);
1717         }
1718 
1719         /*
1720          * Look at list of token objects
1721          */
1722         (void) pthread_rwlock_rdlock(&tokenobject_list_lock);
1723         tmp_obj = tokenobject_list_head;
1724 
1725         while (tmp_obj != NULL) {
1726                 slot_object_t *slot_object;
1727 
1728                 (void) pthread_rwlock_rdlock(&(tmp_obj->object_lock));
1729                 slot_object = tmp_obj->clones[slotnum];
1730                 if (slot_object != NULL) {
1731                         if (slot_object->hObject == hObject)
1732                                 object = tmp_obj;
1733                 }
1734                 (void) pthread_rwlock_unlock(&(tmp_obj->object_lock));
1735                 if (object != NULL) {
1736                         break;
1737                 }
1738                 tmp_obj = tmp_obj->next;
1739         }
1740         (void) pthread_rwlock_unlock(&tokenobject_list_lock);
1741 
1742         return (object);
1743 }
1744 
1745 CK_RV
1746 meta_token_object_deactivate(token_obj_type_t token_type)
1747 {
1748         meta_object_t *object, *tmp_object;
1749         CK_RV save_rv = CKR_OK, rv;
1750 
1751         /* get a write lock on the token object list */
1752         (void) pthread_rwlock_wrlock(&tokenobject_list_lock);
1753 
1754         object = tokenobject_list_head;
1755 
1756         /* go through each object and delete the one with matching type */
1757         while (object != NULL) {
1758                 tmp_object = object->next;
1759 
1760                 if ((token_type == ALL_TOKEN) ||
1761                     ((object->isPrivate) && (token_type == PRIVATE_TOKEN)) ||
1762                     ((!object->isPrivate) && (token_type == PUBLIC_TOKEN))) {
1763                         rv = meta_object_deactivate(object, B_TRUE, B_FALSE);
1764                         if ((rv != CKR_OK) && (save_rv == CKR_OK)) {
1765                                 save_rv = rv;
1766                                 goto finish;
1767                         }
1768                         rv = meta_object_dealloc(NULL, object, B_FALSE);
1769                         if ((rv != CKR_OK) && (save_rv == CKR_OK)) {
1770                                 save_rv = rv;
1771                                 goto finish;
1772                         }
1773                 }
1774                 object = tmp_object;
1775         }
1776 finish:
1777         (void) pthread_rwlock_unlock(&tokenobject_list_lock);
1778         return (save_rv);
1779 }
1780 
1781 /*
1782  * This function adds the to-be-freed meta object to a linked list.
1783  * When the number of objects queued in the linked list reaches the
1784  * maximum threshold MAX_OBJ_TO_BE_FREED, it will free the first
1785  * object (FIFO) in the list.
1786  */
1787 void
1788 meta_object_delay_free(meta_object_t *objp)
1789 {
1790         meta_object_t *tmp;
1791 
1792         (void) pthread_mutex_lock(&obj_delay_freed.obj_to_be_free_mutex);
1793 
1794         /* Add the newly deleted object at the end of the list */
1795         objp->next = NULL;
1796         if (obj_delay_freed.first == NULL) {
1797                 obj_delay_freed.last = objp;
1798                 obj_delay_freed.first = objp;
1799         } else {
1800                 obj_delay_freed.last->next = objp;
1801                 obj_delay_freed.last = objp;
1802         }
1803 
1804         if (++obj_delay_freed.count >= MAX_OBJ_TO_BE_FREED) {
1805                 /*
1806                  * Free the first object in the list only if
1807                  * the total count reaches maximum threshold.
1808                  */
1809                 obj_delay_freed.count--;
1810                 tmp = obj_delay_freed.first->next;
1811                 free(obj_delay_freed.first);
1812                 obj_delay_freed.first = tmp;
1813         }
1814         (void) pthread_mutex_unlock(&obj_delay_freed.obj_to_be_free_mutex);
1815 }
1816 
1817 
1818 /*
1819  * This function checks if the object passed can be a freeobject.
1820  *
1821  * If there is more than one provider that supports the supported freeobject
1822  * mechanisms then allow freeobjects to be an option.
1823  */
1824 
1825 boolean_t
1826 meta_freeobject_check(meta_session_t *session, meta_object_t *object,
1827     CK_MECHANISM *pMech, CK_ATTRIBUTE *tmpl, CK_ULONG tmpl_len,
1828     CK_KEY_TYPE keytype)
1829 {
1830         mech_support_info_t *info = &(session->mech_support_info);
1831 
1832         /*
1833          * If key migration is turned off, or the object does not has any of
1834          * the required flags and there is only one slot, then we don't need
1835          * FreeObjects.
1836          */
1837         if (!metaslot_auto_key_migrate ||
1838             (!object->isToken && !object->isSensitive &&
1839             meta_slotManager_get_slotcount() < 2))
1840                 goto failure;
1841 
1842         /*
1843          * If this call is for key generation, check pMech for supported
1844          * FreeObject mechs
1845          */
1846         if (pMech != NULL) {
1847                 if (pMech->mechanism == CKM_RSA_PKCS_KEY_PAIR_GEN ||
1848                     pMech->mechanism == CKM_EC_KEY_PAIR_GEN ||
1849                     pMech->mechanism == CKM_DH_PKCS_KEY_PAIR_GEN ||
1850                     pMech->mechanism == CKM_DH_PKCS_DERIVE)
1851                         info->mech = pMech->mechanism;
1852                 else
1853                         goto failure;
1854 
1855         /*
1856          * If this call is for an object creation, look inside the template
1857          * for supported FreeObject mechs
1858          */
1859         } else if (tmpl_len > 0) {
1860                 if (!get_template_ulong(CKA_KEY_TYPE, tmpl, tmpl_len, &keytype))
1861                         goto failure;
1862 
1863                 switch (keytype) {
1864                 case CKK_RSA:
1865                         info->mech = CKM_RSA_PKCS_KEY_PAIR_GEN;
1866                         break;
1867                 case CKK_EC:
1868                         info->mech = CKM_EC_KEY_PAIR_GEN;
1869                         break;
1870                 case CKK_DH:
1871                         info->mech = CKM_DH_PKCS_KEY_PAIR_GEN;
1872                         break;
1873                 default:
1874                         goto failure;
1875                 }
1876         } else
1877                 goto failure;
1878 
1879         /* Get the slot that support this mech... */
1880         if (meta_mechManager_get_slots(info, B_FALSE, NULL) != CKR_OK)
1881                 goto failure;
1882 
1883         /*
1884          * If there is only one slot with the mech or the first slot in
1885          * the list is the keystore slot, we should bail.
1886          */
1887         if (info->num_supporting_slots < 2 &&
1888             info->supporting_slots[0]->slotnum == get_keystore_slotnum())
1889                 goto failure;
1890 
1891         if (object->isToken)
1892                 object->isFreeToken = FREE_ALLOWED_KEY;
1893         else
1894                 object->isFreeToken = FREE_DISABLED;
1895 
1896         object->isFreeObject = FREE_ALLOWED_KEY;
1897 
1898         return (B_TRUE);
1899 
1900 failure:
1901         object->isFreeToken = FREE_DISABLED;
1902         object->isFreeObject = FREE_DISABLED;
1903         return (B_FALSE);
1904 }
1905 
1906 /*
1907  * This function assumes meta_freeobject_check() has just been called and set
1908  * the isFreeObject and/or isFreeToken vars to FREE_ALLOWED_KEY.
1909  *
1910  * If the template value for CKA_PRIVATE, CKA_SENSITIVE and/or CKA_TOKEN are
1911  * true, then isFreeObject is fully enabled.  In addition isFreeToken is
1912  * enabled if is CKA_TOKEN true.
1913  *
1914  * If create is true, we are doing a C_CreateObject operation and don't
1915  * handle CKA_PRIVATE & CKA_SENSITIVE flags, we only care about CKA_TOKEN.
1916  */
1917 
1918 boolean_t
1919 meta_freeobject_set(meta_object_t *object, CK_ATTRIBUTE *tmpl,
1920     CK_ULONG tmpl_len, boolean_t create)
1921 {
1922 
1923         /* This check should never be true, if it is, it's a bug */
1924         if (object->isFreeObject < FREE_ALLOWED_KEY)
1925                 return (B_FALSE);
1926 
1927         if (!create) {
1928                 /* Turn off the Sensitive flag */
1929                 if (object->isSensitive) {
1930                         if (set_template_boolean(CKA_SENSITIVE, tmpl, tmpl_len,
1931                             B_TRUE, &falsevalue) == -1)
1932                                 goto failure;
1933 
1934                         object->isFreeObject = FREE_ENABLED;
1935                 }
1936 
1937                 /* Turn off the Private flag */
1938                 if (object->isPrivate) {
1939                         if (set_template_boolean(CKA_PRIVATE, tmpl, tmpl_len,
1940                             B_TRUE, &falsevalue) == -1)
1941                                 goto failure;
1942 
1943                         object->isFreeObject = FREE_ENABLED;
1944                 }
1945         }
1946 
1947         if (object->isToken) {
1948                 object->isToken = B_FALSE;
1949                 object->isFreeToken = FREE_ENABLED;
1950                 object->isFreeObject = FREE_ENABLED;
1951         } else
1952                 object->isFreeToken = FREE_DISABLED;
1953 
1954         /*
1955          *  If isFreeObject is not in the FREE_ENABLED state yet, it can be
1956          *  turned off because the object doesn't not need to be a FreeObject.
1957          */
1958         if (object->isFreeObject == FREE_ALLOWED_KEY)
1959                 object->isFreeObject = FREE_DISABLED;
1960 
1961         return (B_TRUE);
1962 
1963 failure:
1964         object->isFreeToken = FREE_DISABLED;
1965         object->isFreeObject = FREE_DISABLED;
1966         return (B_FALSE);
1967 }
1968 
1969 /*
1970  * This function sets the CKA_TOKEN flag on a given object template depending
1971  * if the slot being used is a keystore.
1972  *
1973  * If the object is a token, but the slot is not the system keystore or has
1974  * no keystore, then set the template to token = false; otherwise it's true.
1975  * In addition we know ahead of time what the value is, so if the value is
1976  * already correct, bypass the setting function
1977  */
1978 CK_RV
1979 meta_freetoken_set(CK_ULONG slot_num, CK_BBOOL *current_value,
1980     CK_ATTRIBUTE *tmpl, CK_ULONG tmpl_len)
1981 {
1982 
1983         if (slot_num == get_keystore_slotnum()) {
1984                 if (*current_value == TRUE)
1985                         return (CKR_OK);
1986 
1987                 if (set_template_boolean(CKA_TOKEN, tmpl, tmpl_len, B_TRUE,
1988                     &truevalue) == -1)
1989                         return (CKR_FUNCTION_FAILED);
1990 
1991         } else {
1992 
1993                 if (*current_value == FALSE)
1994                         return (CKR_OK);
1995 
1996                 if (set_template_boolean(CKA_TOKEN, tmpl, tmpl_len, B_TRUE,
1997                     &falsevalue) == -1)
1998                         return (CKR_FUNCTION_FAILED);
1999 
2000                 *current_value = FALSE;
2001         }
2002 
2003         return (CKR_OK);
2004 }
2005 
2006 /*
2007  * Cloning function for meta_freeobject_clone() to use.  This function
2008  * is streamlined because we know what the object is and this should
2009  * not be called as a generic cloner.
2010  */
2011 
2012 static CK_RV
2013 meta_freeobject_clone_maker(meta_session_t *session, meta_object_t *object,
2014     CK_ULONG slotnum)
2015 {
2016 
2017         slot_object_t *slot_object = NULL;
2018         slot_session_t *slot_session = NULL;
2019         CK_RV rv;
2020 
2021         rv = meta_slot_object_alloc(&slot_object);
2022         if (rv != CKR_OK)
2023                 goto cleanup;
2024 
2025         rv = meta_get_slot_session(slotnum, &slot_session,
2026             session->session_flags);
2027         if (rv != CKR_OK)
2028                 goto cleanup;
2029 
2030         rv = clone_by_create(object, slot_object, slot_session);
2031         if (rv == CKR_OK) {
2032                 object->clones[slotnum] = slot_object;
2033                 meta_slot_object_activate(slot_object, slot_session, B_TRUE);
2034         }
2035 
2036 cleanup:
2037         meta_release_slot_session(slot_session);
2038         return (rv);
2039 
2040 }
2041 
2042 /*
2043  * This function is called when a object is a FreeObject.
2044  *
2045  * What we are given is an object that has been generated on a provider
2046  * that is not its final usage place. That maybe because:
2047  * 1) it's a token and needs to be stored in keystore.
2048  * 2) it was to be a private/sensitive object that we modified so we could know
2049  *    the important attributes for cloning before we make it private/sensitive.
2050  */
2051 
2052 boolean_t
2053 meta_freeobject_clone(meta_session_t *session, meta_object_t *object)
2054 {
2055         CK_RV rv;
2056         CK_ULONG keystore_slotnum;
2057         CK_ATTRIBUTE attr[2];
2058         boolean_t failover = B_FALSE;
2059 
2060         if (object->attributes == NULL) {
2061                 rv = meta_object_copyin(object);
2062                 if (rv != CKR_OK)
2063                         return (rv);
2064         }
2065 
2066         if (object->isPrivate) {
2067                 CK_OBJECT_HANDLE new_clone;
2068                 CK_ULONG slotnum = object->master_clone_slotnum;
2069                 slot_session_t *slot_session;
2070 
2071                 attr[0].type = CKA_PRIVATE;
2072                 attr[0].pValue = &truevalue;
2073                 attr[0].ulValueLen = sizeof (truevalue);
2074 
2075                 /* Set the master attribute list */
2076                 rv = attribute_set_value(attr, object->attributes,
2077                     object->num_attributes);
2078                 if (rv > 0)
2079                         return (CKR_FUNCTION_FAILED);
2080 
2081                 /* Get a slot session */
2082                 rv = meta_get_slot_session(slotnum, &slot_session,
2083                     session->session_flags);
2084                 if (rv > 0)
2085                         return (rv);
2086 
2087                 /* Create the new CKA_PRIVATE one */
2088                 rv = FUNCLIST(slot_session->fw_st_id)->\
2089                     C_CopyObject(slot_session->hSession,
2090                     object->clones[slotnum]->hObject, attr, 1, &new_clone);
2091 
2092                 if (rv == CKR_USER_NOT_LOGGED_IN) {
2093                         /*
2094                          * If the CopyObject fails, we may be using a provider
2095                          * that has a keystore that is not the default
2096                          * keystore set in metaslot or has object management
2097                          * abilities. In which case we should write this
2098                          * object to metaslot's keystore and let the failover.
2099                          * rest of the function know we've changed providers.
2100                          */
2101                         failover = B_TRUE;
2102                         keystore_slotnum = get_keystore_slotnum();
2103                         if (object->clones[keystore_slotnum] == NULL) {
2104                                 rv = meta_freeobject_clone_maker(session,
2105                                     object, keystore_slotnum);
2106                                 if (rv != CKR_OK) {
2107                                         goto failure;
2108                                 }
2109                         }
2110                         object->master_clone_slotnum = keystore_slotnum;
2111 
2112                 } else if (rv != CKR_OK) {
2113                         meta_release_slot_session(slot_session);
2114                         goto failure;
2115                 }
2116                 /* Remove the old object */
2117                 rv = FUNCLIST(slot_session->fw_st_id)->   \
2118                     C_DestroyObject(slot_session->hSession,
2119                     object->clones[slotnum]->hObject);
2120                 if (rv != CKR_OK) {
2121                         meta_release_slot_session(slot_session);
2122                         goto failure;
2123                 }
2124 
2125                 if (!failover)
2126                         object->clones[slotnum]->hObject = new_clone;
2127                 else
2128                         object->clones[slotnum] = NULL;
2129 
2130                 meta_release_slot_session(slot_session);
2131 
2132         }
2133 
2134         if (object->isSensitive) {
2135                 slot_session_t *slot_session;
2136                 CK_ULONG slotnum = object->master_clone_slotnum;
2137 
2138                 attr[0].type = CKA_SENSITIVE;
2139                 attr[0].pValue = &truevalue;
2140                 attr[0].ulValueLen = sizeof (truevalue);
2141                 rv = attribute_set_value(attr, object->attributes,
2142                     object->num_attributes);
2143                 if (rv != CKR_OK)
2144                         goto failure;
2145 
2146                 rv = meta_get_slot_session(slotnum, &slot_session,
2147                     session->session_flags);
2148                 if (rv == CKR_OK) {
2149                         rv = FUNCLIST(slot_session->fw_st_id)->           \
2150                             C_SetAttributeValue(slot_session->hSession,
2151                             object->clones[slotnum]->hObject, attr, 1);
2152 
2153                         meta_release_slot_session(slot_session);
2154                 }
2155         }
2156 
2157         if (object->isFreeToken == FREE_ENABLED || failover) {
2158                 keystore_slotnum = get_keystore_slotnum();
2159                 if (object->clones[keystore_slotnum] == NULL) {
2160                         rv = meta_freeobject_clone_maker(session, object,
2161                             keystore_slotnum);
2162                         if (rv != CKR_OK)
2163                                 goto failure;
2164 
2165                         object->master_clone_slotnum = keystore_slotnum;
2166                 }
2167                 object->isFreeToken = FREE_ENABLED;
2168         }
2169 
2170         object->isFreeObject = FREE_ENABLED;
2171         return (CKR_OK);
2172 
2173 failure:
2174         object->isFreeToken = FREE_DISABLED;
2175         object->isFreeObject = FREE_DISABLED;
2176         return (rv);
2177 
2178 }