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