1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  * Copyright (c) 2018, Joyent, Inc.
  25  */
  26 
  27 #include <stdio.h>
  28 #include <stdlib.h>
  29 #include <strings.h>
  30 #include <errno.h>
  31 #include <security/cryptoki.h>
  32 #include <cryptoutil.h>
  33 #include "kernelGlobal.h"
  34 #include "kernelObject.h"
  35 #include "kernelSession.h"
  36 #include "kernelSlot.h"
  37 
  38 /*
  39  * Add an object to the session's object list.
  40  *
  41  * This function will acquire the lock on the session, and release
  42  * that lock after adding the object to the session's object list.
  43  */
  44 void
  45 kernel_add_object_to_session(kernel_object_t *objp, kernel_session_t *sp)
  46 {
  47         /* Acquire the session lock. */
  48         (void) pthread_mutex_lock(&sp->session_mutex);
  49 
  50         /* Insert the new object in front of session's object list. */
  51         if (sp->object_list == NULL) {
  52                 sp->object_list = objp;
  53                 objp->next = NULL;
  54                 objp->prev = NULL;
  55         } else {
  56                 sp->object_list->prev = objp;
  57                 objp->next = sp->object_list;
  58                 objp->prev = NULL;
  59                 sp->object_list = objp;
  60         }
  61 
  62         /* Release the session lock. */
  63         (void) pthread_mutex_unlock(&sp->session_mutex);
  64 }
  65 
  66 /*
  67  * Clean up and release the storage allocated to the object.
  68  *
  69  * The function is called either with the object lock being held
  70  * (by caller kernel_delete_object()), or there is no object lock
  71  * yet (by kernel_build_XXX_object() during creating an object).
  72  */
  73 void
  74 kernel_cleanup_object(kernel_object_t *objp)
  75 {
  76         /*
  77          * Free the storage allocated to a secret key object.
  78          */
  79         if (objp->class == CKO_SECRET_KEY) {
  80                 if (OBJ_SEC(objp) != NULL && OBJ_SEC_VALUE(objp) != NULL) {
  81                         freezero(OBJ_SEC_VALUE(objp), OBJ_SEC_VALUE_LEN(objp));
  82                         OBJ_SEC_VALUE(objp) = NULL;
  83                         OBJ_SEC_VALUE_LEN(objp) = 0;
  84                 }
  85                 free(OBJ_SEC(objp));
  86                 OBJ_SEC(objp) = NULL;
  87         } else {
  88                 kernel_cleanup_object_bigint_attrs(objp);
  89         }
  90 
  91         /*
  92          * Free the storage allocated to the extra attribute list.
  93          */
  94         kernel_cleanup_extra_attr(objp);
  95 }
  96 
  97 /*
  98  * Create a new object. Copy the attributes that can be modified
  99  * (in the boolean attribute mask field and extra attribute list)
 100  * from the old object to the new object.
 101  *
 102  * The caller of this function holds the lock on the old object.
 103  */
 104 CK_RV
 105 kernel_copy_object(kernel_object_t *old_object, kernel_object_t **new_object,
 106     boolean_t copy_everything, kernel_session_t *sp)
 107 {
 108         CK_RV rv = CKR_OK;
 109         kernel_object_t *new_objp = NULL;
 110         CK_ATTRIBUTE_INFO_PTR attrp;
 111 
 112         /* Allocate new object. */
 113         new_objp = calloc(1, sizeof (kernel_object_t));
 114         if (new_objp == NULL)
 115                 return (CKR_HOST_MEMORY);
 116 
 117         new_objp->class = old_object->class;
 118         new_objp->bool_attr_mask = old_object->bool_attr_mask;
 119 
 120         attrp = old_object->extra_attrlistp;
 121         while (attrp) {
 122                 /*
 123                  * Copy the attribute_info struct from the old
 124                  * object to a new attribute_info struct, and add
 125                  * that new struct to the extra attribute list
 126                  * of the new object.
 127                  */
 128                 rv = kernel_copy_extra_attr(attrp, new_objp);
 129                 if (rv != CKR_OK) {
 130                         kernel_cleanup_extra_attr(new_objp);
 131                         free(new_objp);
 132                         return (rv);
 133                 }
 134                 attrp = attrp->next;
 135         }
 136 
 137         *new_object = new_objp;
 138 
 139         if (!copy_everything) {
 140                 /* done with copying all information that can be modified */
 141                 return (CKR_OK);
 142         }
 143 
 144         /*
 145          * Copy the rest of the object.
 146          * Certain fields that are not appropriate for coping will be
 147          * initialized.
 148          */
 149         new_objp->key_type = old_object->key_type;
 150         new_objp->magic_marker = old_object->magic_marker;
 151         new_objp->mechanism = old_object->mechanism;
 152         new_objp->session_handle = (CK_SESSION_HANDLE)sp;
 153         (void) pthread_mutex_init(&(new_objp->object_mutex), NULL);
 154         /* copy key related information */
 155         switch (new_objp->class) {
 156                 case CKO_PUBLIC_KEY:
 157                         rv = kernel_copy_public_key_attr(OBJ_PUB(old_object),
 158                             &(OBJ_PUB(new_objp)), new_objp->key_type);
 159                         break;
 160                 case CKO_PRIVATE_KEY:
 161                         rv = kernel_copy_private_key_attr(OBJ_PRI(old_object),
 162                             &(OBJ_PRI(new_objp)), new_objp->key_type);
 163                         break;
 164                 case CKO_SECRET_KEY:
 165                         rv = kernel_copy_secret_key_attr(OBJ_SEC(old_object),
 166                             &(OBJ_SEC(new_objp)));
 167                         break;
 168                 default:
 169                         /* should never be this case */
 170                         break;
 171         }
 172         if (rv != CKR_OK) {
 173                 /*
 174                  * don't need to cleanup the memory from failure of copying
 175                  * any key related stuff.  Each individual function for
 176                  * copying key attr will free the memory if it fails
 177                  */
 178                 kernel_cleanup_extra_attr(new_objp);
 179                 free(new_objp);
 180         }
 181         return (rv);
 182 }
 183 
 184 /*
 185  * Copy the attributes (in the boolean attribute mask field and
 186  * extra attribute list) from the new object back to the original
 187  * object. Also, clean up and release all the storage in the extra
 188  * attribute list of the original object.
 189  *
 190  * The caller of this function holds the lock on the old object.
 191  */
 192 void
 193 kernel_merge_object(kernel_object_t *old_object, kernel_object_t *new_object)
 194 {
 195 
 196         old_object->bool_attr_mask = new_object->bool_attr_mask;
 197         kernel_cleanup_extra_attr(old_object);
 198         old_object->extra_attrlistp = new_object->extra_attrlistp;
 199 
 200 }
 201 
 202 /*
 203  * Create a new object struct.  If it is a session object, add the object to
 204  * the session's object list.  If it is a token object, add it to the slot's
 205  * token object list.  The caller does not hold the slot lock.
 206  */
 207 CK_RV
 208 kernel_add_object(CK_ATTRIBUTE_PTR pTemplate,  CK_ULONG ulCount,
 209         CK_ULONG *objecthandle_p, kernel_session_t *sp)
 210 {
 211         CK_RV rv = CKR_OK;
 212         kernel_object_t *new_objp = NULL;
 213         kernel_slot_t   *pslot;
 214         crypto_object_create_t  objc;
 215         CK_BBOOL is_pri_obj;
 216         CK_BBOOL is_token_obj = B_FALSE;
 217         int r;
 218 
 219         new_objp = calloc(1, sizeof (kernel_object_t));
 220         if (new_objp == NULL) {
 221                 rv = CKR_HOST_MEMORY;
 222                 goto fail_cleanup;
 223         }
 224 
 225         new_objp->extra_attrlistp = NULL;
 226         new_objp->is_lib_obj = B_TRUE;
 227 
 228         /*
 229          * If the HW provider supports object creation, create the object
 230          * in the HW provider by calling the CRYPTO_OBJECT_CREATE ioctl.
 231          * Otherwise, create the object in the library.
 232          */
 233         pslot = slot_table[sp->ses_slotid];
 234         if (pslot->sl_func_list.fl_object_create) {
 235                 new_objp->is_lib_obj = B_FALSE;
 236                 objc.oc_session = sp->k_session;
 237                 objc.oc_count = ulCount;
 238                 rv = process_object_attributes(pTemplate, ulCount,
 239                     &objc.oc_attributes, &is_token_obj);
 240                 if (rv != CKR_OK) {
 241                         goto fail_cleanup;
 242                 }
 243 
 244                 /* Cannot create a token object with a READ-ONLY session */
 245                 if (is_token_obj && sp->ses_RO) {
 246                         free_object_attributes(objc.oc_attributes, ulCount);
 247                         rv = CKR_SESSION_READ_ONLY;
 248                         goto fail_cleanup;
 249                 }
 250 
 251                 while ((r = ioctl(kernel_fd, CRYPTO_OBJECT_CREATE,
 252                     &objc)) < 0) {
 253                         if (errno != EINTR)
 254                                 break;
 255                 }
 256                 if (r < 0) {
 257                         rv = CKR_FUNCTION_FAILED;
 258                 } else {
 259                         rv = crypto2pkcs11_error_number(objc.oc_return_value);
 260                 }
 261 
 262                 free_object_attributes(objc.oc_attributes, ulCount);
 263 
 264                 if (rv != CKR_OK) {
 265                         goto fail_cleanup;
 266                 }
 267 
 268                 /* Get the CKA_PRIVATE value of this object. */
 269                 new_objp->k_handle = objc.oc_handle;
 270                 rv = get_cka_private_value(sp, new_objp->k_handle,
 271                     &is_pri_obj);
 272                 if (rv != CKR_OK) {
 273                         goto fail_cleanup;
 274                 }
 275 
 276                 /* Set the PRIVATE_BOOL_ON and TOKEN_BOOL_ON attributes */
 277                 if (is_pri_obj)
 278                         new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
 279                 else
 280                         new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
 281 
 282                 if (is_token_obj)
 283                         new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
 284                 else
 285                         new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
 286 
 287         } else {
 288                 /*
 289                  * Create the object in the library.
 290                  * Validate attribute template and fill in the attributes
 291                  * in the kernel_object_t.
 292                  */
 293                 rv = kernel_build_object(pTemplate, ulCount, new_objp, sp,
 294                     KERNEL_CREATE_OBJ);
 295                 if (rv != CKR_OK) {
 296                         goto fail_cleanup;
 297                 }
 298         }
 299 
 300         /* Initialize the rest of stuffs in kernel_object_t. */
 301         (void) pthread_mutex_init(&new_objp->object_mutex, NULL);
 302         new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
 303         new_objp->session_handle = (CK_SESSION_HANDLE)sp;
 304 
 305         if (is_token_obj) {
 306                 /* Add the new object to the slot's token object list. */
 307                 pslot = slot_table[sp->ses_slotid];
 308                 kernel_add_token_object_to_slot(new_objp, pslot);
 309         } else {
 310                 /* Add the new object to the session's object list. */
 311                 kernel_add_object_to_session(new_objp, sp);
 312         }
 313 
 314         /* Type casting the address of an object struct to an object handle. */
 315         *objecthandle_p = (CK_ULONG)new_objp;
 316 
 317         return (CKR_OK);
 318 
 319 fail_cleanup:
 320         if (new_objp) {
 321                 /*
 322                  * If the object is created in the HW provider, the storage
 323                  * allocated for the ioctl call is always cleaned up after
 324                  * the call.  If the object is created in the library,
 325                  * the storage allocated inside of this object should
 326                  * have been cleaned up in the kernel_build_object()
 327                  * after an error occurred. Therefore, we can safely
 328                  * free the object.
 329                  */
 330                 free(new_objp);
 331         }
 332 
 333         return (rv);
 334 }
 335 
 336 /*
 337  * Remove an object from the session's object list.
 338  *
 339  * The caller of this function holds the session lock.
 340  */
 341 CK_RV
 342 kernel_remove_object_from_session(kernel_object_t *objp, kernel_session_t *sp)
 343 {
 344         kernel_object_t *tmp_objp;
 345         boolean_t found = B_FALSE;
 346 
 347         /*
 348          * Remove the object from the session's object list.
 349          */
 350         if ((sp == NULL) ||
 351             (sp->magic_marker != KERNELTOKEN_SESSION_MAGIC)) {
 352                 return (CKR_SESSION_HANDLE_INVALID);
 353         }
 354 
 355         if ((sp->object_list == NULL) || (objp == NULL) ||
 356             (objp->magic_marker != KERNELTOKEN_OBJECT_MAGIC)) {
 357                 return (CKR_OBJECT_HANDLE_INVALID);
 358         }
 359 
 360         tmp_objp = sp->object_list;
 361         while (tmp_objp) {
 362                 if (tmp_objp == objp) {
 363                         found = B_TRUE;
 364                         break;
 365                 }
 366                 tmp_objp = tmp_objp->next;
 367         }
 368         if (!found)
 369                 return (CKR_OBJECT_HANDLE_INVALID);
 370 
 371         if (sp->object_list == objp) {
 372                 /* Object is the first one in the list. */
 373                 if (objp->next) {
 374                         sp->object_list = objp->next;
 375                         objp->next->prev = NULL;
 376                 } else {
 377                         /* Object is the only one in the list. */
 378                         sp->object_list = NULL;
 379                 }
 380         } else {
 381                 /* Object is not the first one in the list. */
 382                 if (objp->next) {
 383                         /* Object is in the middle of the list. */
 384                         objp->prev->next = objp->next;
 385                         objp->next->prev = objp->prev;
 386                 } else {
 387                         /* Object is the last one in the list. */
 388                         objp->prev->next = NULL;
 389                 }
 390         }
 391         return (CKR_OK);
 392 }
 393 
 394 static void
 395 kernel_delete_object_cleanup(kernel_object_t *objp, boolean_t wrapper_only)
 396 {
 397         /* Acquire the lock on the object. */
 398         (void) pthread_mutex_lock(&objp->object_mutex);
 399 
 400         /*
 401          * Make sure another thread hasn't freed the object.
 402          */
 403         if (objp->magic_marker != KERNELTOKEN_OBJECT_MAGIC) {
 404                 (void) pthread_mutex_unlock(&objp->object_mutex);
 405                 return;
 406         }
 407 
 408         /*
 409          * The deletion of an object must be blocked when the object
 410          * reference count is not zero. This means if any object related
 411          * operation starts prior to the delete object operation gets in,
 412          * the object deleting thread must wait for the non-deleting
 413          * operation to be completed before it can proceed the delete
 414          * operation.
 415          *
 416          * Unless we are being forced to shut everything down, this only
 417          * happens if the library's _fini() is running not if someone
 418          * explicitly called C_Finalize().
 419          */
 420         if (wrapper_only) {
 421                 objp->obj_refcnt = 0;
 422         }
 423 
 424         while (objp->obj_refcnt != 0) {
 425                 /*
 426                  * We set the OBJECT_REFCNT_WAITING flag before we put
 427                  * this deleting thread in a wait state, so other non-deleting
 428                  * operation thread will signal to wake it up only when
 429                  * the object reference count becomes zero and this flag
 430                  * is set.
 431                  */
 432                 objp->obj_delete_sync |= OBJECT_REFCNT_WAITING;
 433                 (void) pthread_cond_wait(&objp->obj_free_cond,
 434                     &objp->object_mutex);
 435         }
 436 
 437         objp->obj_delete_sync &= ~OBJECT_REFCNT_WAITING;
 438 
 439         /* Mark object as no longer valid. */
 440         objp->magic_marker = 0;
 441 
 442         (void) pthread_cond_destroy(&objp->obj_free_cond);
 443 }
 444 
 445 /*
 446  * Delete a session object:
 447  * - Remove the object from the session's object list.
 448  * - Release the storage allocated to the object.
 449  *
 450  * The boolean argument ses_lock_held is used to indicate that whether
 451  * the caller holds the session lock or not.
 452  * - When called by kernel_delete_all_objects_in_session() or
 453  *   kernel_delete_pri_objects_in_slot() -- ses_lock_held = TRUE.
 454  *
 455  * The boolean argument wrapper_only is used to indicate that whether
 456  * the caller only wants to clean up the object wrapper from the library and
 457  * needs not to make an ioctl call.
 458  * - This argument only applies to the object created in the provider level.
 459  * - When called by kernel_cleanup_pri_objects_in_slot(), wrapper_only is TRUE.
 460  * - When called by C_DestroyObject(), wrapper_only is FALSE.
 461  * - When called by kernel_delete_all_objects_in_session(), the value of
 462  *   wrapper_only depends on its caller.
 463  */
 464 CK_RV
 465 kernel_delete_session_object(kernel_session_t *sp, kernel_object_t *objp,
 466     boolean_t ses_lock_held, boolean_t wrapper_only)
 467 {
 468         CK_RV rv = CKR_OK;
 469         crypto_object_destroy_t obj_destroy;
 470 
 471         /*
 472          * Check to see if the caller holds the lock on the session.
 473          * If not, we need to acquire that lock in order to proceed.
 474          */
 475         if (!ses_lock_held) {
 476                 /* Acquire the session lock. */
 477                 (void) pthread_mutex_lock(&sp->session_mutex);
 478         }
 479 
 480         /* Remove the object from the session's object list first. */
 481         rv = kernel_remove_object_from_session(objp, sp);
 482         if (!ses_lock_held) {
 483                 /*
 484                  * If the session lock is obtained by this function,
 485                  * then release that lock after removing the object
 486                  * from session's object list.
 487                  * We want the releasing of the object storage to
 488                  * be done without holding the session lock.
 489                  */
 490                 (void) pthread_mutex_unlock(&sp->session_mutex);
 491         }
 492 
 493         if (rv != CKR_OK)
 494                 return (rv);
 495 
 496         kernel_delete_object_cleanup(objp, wrapper_only);
 497 
 498         /* Destroy the object. */
 499         if (objp->is_lib_obj) {
 500                 /*
 501                  * If this object is created in the library, cleanup the
 502                  * contents of this object such as free all the storage
 503                  * allocated for this object.
 504                  */
 505                 kernel_cleanup_object(objp);
 506         } else {
 507                 /*
 508                  * This object is created in the HW provider. If wrapper_only
 509                  * is FALSE, make an ioctl call to destroy it in kernel.
 510                  */
 511                 if (!wrapper_only) {
 512                         obj_destroy.od_session = sp->k_session;
 513                         obj_destroy.od_handle = objp->k_handle;
 514 
 515                         while (ioctl(kernel_fd, CRYPTO_OBJECT_DESTROY,
 516                             &obj_destroy) < 0) {
 517                                 if (errno != EINTR)
 518                                         break;
 519                         }
 520 
 521                         /*
 522                          * Ignore ioctl return codes for a session object.
 523                          * If the kernel can not delete a session object, it
 524                          * is likely caused by the HW provider. There's not
 525                          * much that can be done.  The library will still
 526                          * cleanup the object wrapper in the library. The HW
 527                          * provider will destroy all session objects when
 528                          * the application exits.
 529                          */
 530                 }
 531         }
 532 
 533         /* Reset OBJECT_IS_DELETING flag. */
 534         objp->obj_delete_sync &= ~OBJECT_IS_DELETING;
 535 
 536         (void) pthread_mutex_unlock(&objp->object_mutex);
 537         /* Destroy the object lock */
 538         (void) pthread_mutex_destroy(&objp->object_mutex);
 539         /* Free the object itself */
 540         kernel_object_delay_free(objp);
 541 
 542         return (CKR_OK);
 543 }
 544 
 545 /*
 546  * Delete all the objects in a session. The caller holds the lock
 547  * on the session.   If the wrapper_only argument is TRUE, the caller only
 548  * want to clean up object wrappers in the library.
 549  */
 550 void
 551 kernel_delete_all_objects_in_session(kernel_session_t *sp,
 552     boolean_t wrapper_only)
 553 {
 554         kernel_object_t *objp = sp->object_list;
 555         kernel_object_t *objp1;
 556 
 557         /* Delete all the objects in the session. */
 558         while (objp) {
 559                 objp1 = objp->next;
 560 
 561                 /*
 562                  * Delete an session object by calling
 563                  * kernel_delete_session_object():
 564                  * - The 3rd TRUE boolean argument indicates that the caller
 565                  *   holds the session lock.
 566                  * - The 4th boolean argument indicates whether we only want
 567                  *   clean up object wrappers in the library.
 568                  */
 569                 (void) kernel_delete_session_object(sp, objp, B_TRUE,
 570                     wrapper_only);
 571 
 572                 objp = objp1;
 573         }
 574 }
 575 
 576 static CK_RV
 577 add_to_search_result(kernel_object_t *obj, find_context_t *fcontext,
 578     CK_ULONG *num_result_alloc)
 579 {
 580         /*
 581          * allocate space for storing results if the currently
 582          * allocated space is not enough
 583          */
 584         if (*num_result_alloc <= fcontext->num_results) {
 585                 fcontext->objs_found = realloc(fcontext->objs_found,
 586                     sizeof (kernel_object_t *) * (*num_result_alloc + BUFSIZ));
 587                 if (fcontext->objs_found == NULL) {
 588                         return (CKR_HOST_MEMORY);
 589                 }
 590                 *num_result_alloc += BUFSIZ;
 591         }
 592 
 593         (fcontext->objs_found)[(fcontext->num_results)++] = obj;
 594         return (CKR_OK);
 595 }
 596 
 597 static CK_RV
 598 search_for_objects(kernel_session_t *sp, CK_ATTRIBUTE_PTR pTemplate,
 599     CK_ULONG ulCount, find_context_t *fcontext)
 600 {
 601         kernel_session_t *session_p;
 602         kernel_object_t *obj;
 603         CK_OBJECT_CLASS pclasses[6]; /* classes attrs possibly exist */
 604         CK_ULONG num_pclasses;  /* number of possible classes */
 605         CK_ULONG num_result_alloc = 0; /* spaces allocated for results */
 606         CK_RV rv = CKR_OK;
 607         kernel_slot_t   *pslot;
 608 
 609         if (ulCount > 0) {
 610                 /* there are some search requirement */
 611                 kernel_process_find_attr(pclasses, &num_pclasses,
 612                     pTemplate, ulCount);
 613         }
 614 
 615         /* Acquire the slot lock */
 616         pslot = slot_table[sp->ses_slotid];
 617         (void) pthread_mutex_lock(&pslot->sl_mutex);
 618 
 619         /*
 620          * Go through all objects in each session.
 621          * Acquire individual session lock for the session
 622          * we are searching.
 623          */
 624         session_p = pslot->sl_sess_list;
 625         while (session_p) {
 626                 (void) pthread_mutex_lock(&session_p->session_mutex);
 627                 obj = session_p->object_list;
 628                 while (obj) {
 629                         (void) pthread_mutex_lock(&obj->object_mutex);
 630                         if (ulCount > 0) {
 631                                 if (kernel_find_match_attrs(obj, pclasses,
 632                                     num_pclasses, pTemplate, ulCount)) {
 633                                         rv = add_to_search_result(
 634                                             obj, fcontext, &num_result_alloc);
 635                                 }
 636                         } else {
 637                                 /* no search criteria, just record the object */
 638                                 rv = add_to_search_result(obj, fcontext,
 639                                     &num_result_alloc);
 640                         }
 641                         (void) pthread_mutex_unlock(&obj->object_mutex);
 642                         if (rv != CKR_OK) {
 643                                 (void) pthread_mutex_unlock(
 644                                     &session_p->session_mutex);
 645                                 goto cleanup;
 646                         }
 647                         obj = obj->next;
 648                 }
 649                 (void) pthread_mutex_unlock(&session_p->session_mutex);
 650                 session_p = session_p->next;
 651         }
 652 
 653 cleanup:
 654         /* Release the slot lock */
 655         (void) pthread_mutex_unlock(&pslot->sl_mutex);
 656         return (rv);
 657 }
 658 
 659 /*
 660  * Initialize the context for C_FindObjects() calls
 661  */
 662 CK_RV
 663 kernel_find_objects_init(kernel_session_t *sp, CK_ATTRIBUTE_PTR pTemplate,
 664     CK_ULONG ulCount)
 665 {
 666         CK_RV rv = CKR_OK;
 667         CK_OBJECT_CLASS class; /* for kernel_validate_attr(). Value unused */
 668         find_context_t *fcontext;
 669 
 670         if (ulCount) {
 671                 rv = kernel_validate_attr(pTemplate, ulCount, &class);
 672                 /* Make sure all attributes in template are valid */
 673                 if (rv != CKR_OK) {
 674                         return (rv);
 675                 }
 676         }
 677 
 678         /* prepare the find context */
 679         fcontext = calloc(1, sizeof (find_context_t));
 680         if (fcontext == NULL) {
 681                 return (CKR_HOST_MEMORY);
 682         }
 683 
 684         rv = search_for_objects(sp, pTemplate, ulCount, fcontext);
 685         if (rv != CKR_OK) {
 686                 free(fcontext);
 687                 return (rv);
 688         }
 689 
 690         /* store the find_context in the session */
 691         sp->find_objects.context = (CK_VOID_PTR)fcontext;
 692 
 693         return (rv);
 694 }
 695 
 696 void
 697 kernel_find_objects_final(kernel_session_t *sp)
 698 {
 699         find_context_t *fcontext;
 700 
 701         fcontext = sp->find_objects.context;
 702         sp->find_objects.context = NULL;
 703         sp->find_objects.flags = 0;
 704         if (fcontext->objs_found != NULL) {
 705                 free(fcontext->objs_found);
 706         }
 707 
 708         free(fcontext);
 709 }
 710 
 711 void
 712 kernel_find_objects(kernel_session_t *sp, CK_OBJECT_HANDLE *obj_found,
 713     CK_ULONG max_obj_requested, CK_ULONG *found_obj_count)
 714 {
 715         find_context_t *fcontext;
 716         CK_ULONG num_obj_found = 0;
 717         CK_ULONG i;
 718         kernel_object_t *obj;
 719 
 720         fcontext = sp->find_objects.context;
 721 
 722         for (i = fcontext->next_result_index;
 723             ((num_obj_found < max_obj_requested) &&
 724             (i < fcontext->num_results));
 725             i++) {
 726                 obj = fcontext->objs_found[i];
 727                 if (obj != NULL) {
 728                         (void) pthread_mutex_lock(&obj->object_mutex);
 729                         /* a sanity check to make sure the obj is still valid */
 730                         if (obj->magic_marker == KERNELTOKEN_OBJECT_MAGIC) {
 731                                 obj_found[num_obj_found] =
 732                                     (CK_OBJECT_HANDLE)obj;
 733                                 num_obj_found++;
 734                         }
 735                         (void) pthread_mutex_unlock(&obj->object_mutex);
 736                 }
 737         }
 738         fcontext->next_result_index = i;
 739         *found_obj_count = num_obj_found;
 740 }
 741 
 742 /*
 743  * Add an token object to the token object list in slot.
 744  *
 745  * This function will acquire the lock on the slot, and release
 746  * that lock after adding the object to the slot's token object list.
 747  */
 748 void
 749 kernel_add_token_object_to_slot(kernel_object_t *objp, kernel_slot_t *pslot)
 750 {
 751         /* Acquire the slot lock. */
 752         (void) pthread_mutex_lock(&pslot->sl_mutex);
 753 
 754         /* Insert the new object in front of slot's token object list. */
 755         if (pslot->sl_tobj_list == NULL) {
 756                 pslot->sl_tobj_list = objp;
 757                 objp->next = NULL;
 758                 objp->prev = NULL;
 759         } else {
 760                 pslot->sl_tobj_list->prev = objp;
 761                 objp->next = pslot->sl_tobj_list;
 762                 objp->prev = NULL;
 763                 pslot->sl_tobj_list = objp;
 764         }
 765 
 766         /* Release the slot lock. */
 767         (void) pthread_mutex_unlock(&pslot->sl_mutex);
 768 }
 769 
 770 /*
 771  * Remove an token object from the slot's token object list.
 772  * This routine is called by kernel_delete_token_object().
 773  * The caller of this function hold the slot lock.
 774  */
 775 void
 776 kernel_remove_token_object_from_slot(kernel_slot_t *pslot,
 777     kernel_object_t *objp)
 778 {
 779 
 780         if (pslot->sl_tobj_list == objp) {
 781                 /* Object is the first one in the list */
 782                 if (objp->next) {
 783                         pslot->sl_tobj_list = objp->next;
 784                         objp->next->prev = NULL;
 785                 } else {
 786                         /* Object is the only one in the list. */
 787                         pslot->sl_tobj_list = NULL;
 788                 }
 789         } else {
 790                 /* Object is not the first one in the list. */
 791                 if (objp->next) {
 792                         /* Object is in the middle of the list. */
 793                         objp->prev->next = objp->next;
 794                         objp->next->prev = objp->prev;
 795                 } else {
 796                         /* Object is the last one in the list. */
 797                         objp->prev->next = NULL;
 798                 }
 799         }
 800 }
 801 
 802 /*
 803  * Delete a token object:
 804  * - Remove the object from the slot's token object list.
 805  * - Release the storage allocated to the object.
 806  *
 807  * The boolean argument slot_lock_held is used to indicate that whether
 808  * the caller holds the slot lock or not. When the caller does not hold
 809  * the slot lock, this function will acquire that lock in order to proceed,
 810  * and also release that lock before returning to caller.
 811  *
 812  * The boolean argument wrapper_only is used to indicate that whether
 813  * the caller only wants to the object wrapper from library.
 814  */
 815 CK_RV
 816 kernel_delete_token_object(kernel_slot_t *pslot, kernel_session_t *sp,
 817     kernel_object_t *objp, boolean_t slot_lock_held, boolean_t wrapper_only)
 818 {
 819         CK_RV rv;
 820         crypto_object_destroy_t obj_destroy;
 821         int r;
 822 
 823         /*
 824          * Check to see if the caller holds the lock on the slot.
 825          * If not, we need to acquire that lock in order to proceed.
 826          */
 827         if (!slot_lock_held) {
 828                 (void) pthread_mutex_lock(&pslot->sl_mutex);
 829         }
 830 
 831         /* Remove the object from the slot's token object list first. */
 832         kernel_remove_token_object_from_slot(pslot, objp);
 833 
 834         /* Release the slot lock if the call doesn't hold the lock. */
 835         if (!slot_lock_held) {
 836                 (void) pthread_mutex_unlock(&pslot->sl_mutex);
 837         }
 838 
 839         kernel_delete_object_cleanup(objp, wrapper_only);
 840 
 841         if (!wrapper_only) {
 842                 obj_destroy.od_session = sp->k_session;
 843                 obj_destroy.od_handle = objp->k_handle;
 844 
 845                 while ((r = ioctl(kernel_fd, CRYPTO_OBJECT_DESTROY,
 846                     &obj_destroy)) < 0) {
 847                         if (errno != EINTR)
 848                                 break;
 849                 }
 850                 if (r < 0) {
 851                         rv = CKR_FUNCTION_FAILED;
 852                 } else {
 853                         rv = crypto2pkcs11_error_number(
 854                             obj_destroy.od_return_value);
 855                 }
 856 
 857                 /*
 858                  * Could not destroy an object from kernel. Write a warning
 859                  * in syslog, but we still clean up the object wrapper in
 860                  * the library.
 861                  */
 862                 if (rv != CKR_OK) {
 863                         cryptoerror(LOG_ERR, "pkcs11_kernel: Could not "
 864                             "destroy an object in kernel.");
 865                 }
 866         }
 867 
 868         (void) pthread_mutex_unlock(&objp->object_mutex);
 869         /* Destroy the object lock */
 870         (void) pthread_mutex_destroy(&objp->object_mutex);
 871         /* Free the object itself */
 872         kernel_object_delay_free(objp);
 873 
 874         return (CKR_OK);
 875 }
 876 
 877 /*
 878  * Clean up private object wrappers in this slot. The caller holds the slot
 879  * lock.
 880  */
 881 void
 882 kernel_cleanup_pri_objects_in_slot(kernel_slot_t *pslot,
 883     kernel_session_t *cur_sp)
 884 {
 885         kernel_session_t *session_p;
 886         kernel_object_t *objp;
 887         kernel_object_t *objp1;
 888 
 889         /*
 890          * Delete every private token object from the slot' token object list
 891          */
 892         objp = pslot->sl_tobj_list;
 893         while (objp) {
 894                 objp1 = objp->next;
 895                 /*
 896                  * The first TRUE boolean argument indicates that the caller
 897                  * hold the slot lock.  The second TRUE boolean argument
 898                  * indicates that the caller just wants to clean up the object
 899                  * wrapper from the library only.
 900                  */
 901                 if (objp->bool_attr_mask & PRIVATE_BOOL_ON) {
 902                         (void) kernel_delete_token_object(pslot, cur_sp, objp,
 903                             B_TRUE, B_TRUE);
 904                 }
 905                 objp = objp1;
 906         }
 907 
 908         /*
 909          * Walk through all the sessions in this slot and delete every
 910          * private object.
 911          */
 912         session_p = pslot->sl_sess_list;
 913         while (session_p) {
 914 
 915                 /* Delete all the objects in the session. */
 916                 objp = session_p->object_list;
 917                 while (objp) {
 918                         objp1 = objp->next;
 919                         /*
 920                          * The FALSE boolean argument indicates that the
 921                          * caller does not hold the session lock.  The TRUE
 922                          * boolean argument indicates that the caller just
 923                          * want to clean upt the object wrapper from the
 924                          * library only.
 925                          */
 926                         if (objp->bool_attr_mask & PRIVATE_BOOL_ON) {
 927                                 (void) kernel_delete_session_object(session_p,
 928                                     objp, B_FALSE, B_TRUE);
 929                         }
 930 
 931                         objp = objp1;
 932                 }
 933 
 934                 session_p = session_p->next;
 935         }
 936 }
 937 
 938 /*
 939  * Get the object size in bytes for the objects created in the library.
 940  */
 941 CK_RV
 942 kernel_get_object_size(kernel_object_t *obj, CK_ULONG_PTR pulSize)
 943 {
 944         CK_RV rv = CKR_OK;
 945         CK_ULONG obj_size;
 946         biginteger_t *big;
 947 
 948         obj_size = sizeof (kernel_object_t);
 949 
 950         switch (obj->class) {
 951         case CKO_PUBLIC_KEY:
 952                 if (obj->key_type == CKK_RSA) {
 953                         big = OBJ_PUB_RSA_PUBEXPO(obj);
 954                         obj_size += big->big_value_len;
 955                         big = OBJ_PUB_RSA_MOD(obj);
 956                         obj_size += big->big_value_len;
 957 
 958                 } else if (obj->key_type == CKK_DSA) {
 959                         big = OBJ_PUB_DSA_PRIME(obj);
 960                         obj_size += big->big_value_len;
 961                         big = OBJ_PUB_DSA_SUBPRIME(obj);
 962                         obj_size += big->big_value_len;
 963                         big = OBJ_PUB_DSA_BASE(obj);
 964                         obj_size += big->big_value_len;
 965                         big = OBJ_PUB_DSA_VALUE(obj);
 966                         obj_size += big->big_value_len;
 967 
 968                 } else if (obj->key_type == CKK_EC) {
 969                         big = OBJ_PUB_EC_POINT(obj);
 970                         obj_size += big->big_value_len;
 971 
 972                 } else {
 973                         rv = CKR_OBJECT_HANDLE_INVALID;
 974                 }
 975                 break;
 976 
 977         case CKO_PRIVATE_KEY:
 978                 if (obj->key_type == CKK_RSA) {
 979                         big = OBJ_PRI_RSA_MOD(obj);
 980                         obj_size += big->big_value_len;
 981 
 982                         big = OBJ_PRI_RSA_PUBEXPO(obj); /* optional */
 983                         if (big != NULL) {
 984                                 obj_size += big->big_value_len;
 985                         }
 986 
 987                         big = OBJ_PRI_RSA_PRIEXPO(obj);
 988                         obj_size += big->big_value_len;
 989 
 990                         big = OBJ_PRI_RSA_PRIME1(obj); /* optional */
 991                         if (big != NULL) {
 992                                 obj_size += big->big_value_len;
 993                         }
 994 
 995                         big = OBJ_PRI_RSA_PRIME2(obj); /* optional */
 996                         if (big != NULL) {
 997                                 obj_size += big->big_value_len;
 998                         }
 999 
1000                         big = OBJ_PRI_RSA_EXPO1(obj); /* optional */
1001                         if (big != NULL) {
1002                                 obj_size += big->big_value_len;
1003                         }
1004 
1005                         big = OBJ_PRI_RSA_EXPO2(obj); /* optional */
1006                         if (big != NULL) {
1007                                 obj_size += big->big_value_len;
1008                         }
1009 
1010                         big = OBJ_PRI_RSA_COEF(obj); /* optional */
1011                         if (big != NULL) {
1012                                 obj_size += big->big_value_len;
1013                         }
1014 
1015                 } else if (obj->key_type == CKK_DSA) {
1016                         big = OBJ_PRI_DSA_PRIME(obj);
1017                         obj_size += big->big_value_len;
1018                         big = OBJ_PRI_DSA_SUBPRIME(obj);
1019                         obj_size += big->big_value_len;
1020                         big = OBJ_PRI_DSA_BASE(obj);
1021                         obj_size += big->big_value_len;
1022                         big = OBJ_PRI_DSA_VALUE(obj);
1023                         obj_size += big->big_value_len;
1024 
1025                 } else if (obj->key_type == CKK_EC) {
1026                         big = OBJ_PRI_EC_VALUE(obj);
1027                         obj_size += big->big_value_len;
1028 
1029                 } else {
1030                         rv = CKR_OBJECT_HANDLE_INVALID;
1031                 }
1032                 break;
1033 
1034         case CKO_SECRET_KEY:
1035                 obj_size += OBJ_SEC_VALUE_LEN(obj);
1036                 break;
1037 
1038         default:
1039                 rv = CKR_OBJECT_HANDLE_INVALID;
1040         }
1041 
1042         if (rv == CKR_OK) {
1043                 *pulSize = obj_size;
1044         }
1045 
1046         return (rv);
1047 }
1048 
1049 /*
1050  * This function adds the to-be-freed session object to a linked list.
1051  * When the number of objects queued in the linked list reaches the
1052  * maximum threshold MAX_OBJ_TO_BE_FREED, it will free the first
1053  * object (FIFO) in the list.
1054  */
1055 void
1056 kernel_object_delay_free(kernel_object_t *objp)
1057 {
1058         kernel_object_t *tmp;
1059 
1060         (void) pthread_mutex_lock(&obj_delay_freed.obj_to_be_free_mutex);
1061 
1062         /* Add the newly deleted object at the end of the list */
1063         objp->next = NULL;
1064         if (obj_delay_freed.first == NULL) {
1065                 obj_delay_freed.last = objp;
1066                 obj_delay_freed.first = objp;
1067         } else {
1068                 obj_delay_freed.last->next = objp;
1069                 obj_delay_freed.last = objp;
1070         }
1071 
1072         if (++obj_delay_freed.count >= MAX_OBJ_TO_BE_FREED) {
1073                 /*
1074                  * Free the first object in the list only if
1075                  * the total count reaches maximum threshold.
1076                  */
1077                 obj_delay_freed.count--;
1078                 tmp = obj_delay_freed.first->next;
1079                 free(obj_delay_freed.first);
1080                 obj_delay_freed.first = tmp;
1081         }
1082         (void) pthread_mutex_unlock(&obj_delay_freed.obj_to_be_free_mutex);
1083 }