1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <strings.h>
  27 #include <errno.h>
  28 #include <cryptoutil.h>
  29 #include <unistd.h> /* for pid_t */
  30 #include <pthread.h>
  31 #include <security/cryptoki.h>
  32 #include "softGlobal.h"
  33 #include "softSession.h"
  34 #include "softObject.h"
  35 #include "softKeystore.h"
  36 #include "softKeystoreUtil.h"
  37 
  38 #pragma init(softtoken_init)
  39 #pragma fini(softtoken_fini)
  40 
  41 extern soft_session_t token_session; /* for fork handler */
  42 
  43 static struct CK_FUNCTION_LIST functionList = {
  44         { 2, 20 },      /* version */
  45         C_Initialize,
  46         C_Finalize,
  47         C_GetInfo,
  48         C_GetFunctionList,
  49         C_GetSlotList,
  50         C_GetSlotInfo,
  51         C_GetTokenInfo,
  52         C_GetMechanismList,
  53         C_GetMechanismInfo,
  54         C_InitToken,
  55         C_InitPIN,
  56         C_SetPIN,
  57         C_OpenSession,
  58         C_CloseSession,
  59         C_CloseAllSessions,
  60         C_GetSessionInfo,
  61         C_GetOperationState,
  62         C_SetOperationState,
  63         C_Login,
  64         C_Logout,
  65         C_CreateObject,
  66         C_CopyObject,
  67         C_DestroyObject,
  68         C_GetObjectSize,
  69         C_GetAttributeValue,
  70         C_SetAttributeValue,
  71         C_FindObjectsInit,
  72         C_FindObjects,
  73         C_FindObjectsFinal,
  74         C_EncryptInit,
  75         C_Encrypt,
  76         C_EncryptUpdate,
  77         C_EncryptFinal,
  78         C_DecryptInit,
  79         C_Decrypt,
  80         C_DecryptUpdate,
  81         C_DecryptFinal,
  82         C_DigestInit,
  83         C_Digest,
  84         C_DigestUpdate,
  85         C_DigestKey,
  86         C_DigestFinal,
  87         C_SignInit,
  88         C_Sign,
  89         C_SignUpdate,
  90         C_SignFinal,
  91         C_SignRecoverInit,
  92         C_SignRecover,
  93         C_VerifyInit,
  94         C_Verify,
  95         C_VerifyUpdate,
  96         C_VerifyFinal,
  97         C_VerifyRecoverInit,
  98         C_VerifyRecover,
  99         C_DigestEncryptUpdate,
 100         C_DecryptDigestUpdate,
 101         C_SignEncryptUpdate,
 102         C_DecryptVerifyUpdate,
 103         C_GenerateKey,
 104         C_GenerateKeyPair,
 105         C_WrapKey,
 106         C_UnwrapKey,
 107         C_DeriveKey,
 108         C_SeedRandom,
 109         C_GenerateRandom,
 110         C_GetFunctionStatus,
 111         C_CancelFunction,
 112         C_WaitForSlotEvent
 113 };
 114 
 115 boolean_t softtoken_initialized = B_FALSE;
 116 
 117 static pid_t softtoken_pid = 0;
 118 
 119 /* This mutex protects soft_session_list, all_sessions_closing */
 120 pthread_mutex_t soft_sessionlist_mutex;
 121 soft_session_t *soft_session_list = NULL;
 122 
 123 int all_sessions_closing = 0;
 124 
 125 slot_t soft_slot;
 126 obj_to_be_freed_list_t obj_delay_freed;
 127 ses_to_be_freed_list_t ses_delay_freed;
 128 
 129 /* protects softtoken_initialized and access to C_Initialize/C_Finalize */
 130 pthread_mutex_t soft_giant_mutex = PTHREAD_MUTEX_INITIALIZER;
 131 
 132 static CK_RV finalize_common(boolean_t force, CK_VOID_PTR pReserved);
 133 static void softtoken_init();
 134 static void softtoken_fini();
 135 static void softtoken_fork_prepare();
 136 static void softtoken_fork_after();
 137 
 138 CK_RV
 139 C_Initialize(CK_VOID_PTR pInitArgs)
 140 {
 141 
 142         int initialize_pid;
 143         boolean_t supplied_ok;
 144         CK_RV rv;
 145 
 146         /*
 147          * Get lock to insure only one thread enters this
 148          * function at a time.
 149          */
 150         (void) pthread_mutex_lock(&soft_giant_mutex);
 151 
 152         initialize_pid = getpid();
 153 
 154         if (softtoken_initialized) {
 155                 if (initialize_pid == softtoken_pid) {
 156                         /*
 157                          * This process has called C_Initialize already
 158                          */
 159                         (void) pthread_mutex_unlock(&soft_giant_mutex);
 160                         return (CKR_CRYPTOKI_ALREADY_INITIALIZED);
 161                 } else {
 162                         /*
 163                          * A fork has happened and the child is
 164                          * reinitializing.  Do a finalize_common to close
 165                          * out any state from the parent, and then
 166                          * continue on.
 167                          */
 168                         (void) finalize_common(B_TRUE, NULL);
 169                 }
 170         }
 171 
 172         if (pInitArgs != NULL) {
 173                 CK_C_INITIALIZE_ARGS *initargs1 =
 174                     (CK_C_INITIALIZE_ARGS *) pInitArgs;
 175 
 176                 /* pReserved must be NULL */
 177                 if (initargs1->pReserved != NULL) {
 178                         (void) pthread_mutex_unlock(&soft_giant_mutex);
 179                         return (CKR_ARGUMENTS_BAD);
 180                 }
 181 
 182                 /*
 183                  * ALL supplied function pointers need to have the value
 184                  * either NULL or non-NULL.
 185                  */
 186                 supplied_ok = (initargs1->CreateMutex == NULL &&
 187                     initargs1->DestroyMutex == NULL &&
 188                     initargs1->LockMutex == NULL &&
 189                     initargs1->UnlockMutex == NULL) ||
 190                     (initargs1->CreateMutex != NULL &&
 191                     initargs1->DestroyMutex != NULL &&
 192                     initargs1->LockMutex != NULL &&
 193                     initargs1->UnlockMutex != NULL);
 194 
 195                 if (!supplied_ok) {
 196                         (void) pthread_mutex_unlock(&soft_giant_mutex);
 197                         return (CKR_ARGUMENTS_BAD);
 198                 }
 199 
 200                 /*
 201                  * When the CKF_OS_LOCKING_OK flag isn't set and mutex
 202                  * function pointers are supplied by an application,
 203                  * return an error.  We must be able to use our own primitives.
 204                  */
 205                 if (!(initargs1->flags & CKF_OS_LOCKING_OK) &&
 206                     (initargs1->CreateMutex != NULL)) {
 207                         (void) pthread_mutex_unlock(&soft_giant_mutex);
 208                         return (CKR_CANT_LOCK);
 209                 }
 210         }
 211 
 212         /* Initialize the session list lock */
 213         if (pthread_mutex_init(&soft_sessionlist_mutex, NULL) != 0) {
 214                 (void) pthread_mutex_unlock(&soft_giant_mutex);
 215                 return (CKR_CANT_LOCK);
 216         }
 217 
 218         /*
 219          * token object related initialization
 220          */
 221         soft_slot.authenticated = 0;
 222         soft_slot.userpin_change_needed = 0;
 223         soft_slot.token_object_list = NULL;
 224         soft_slot.keystore_load_status = KEYSTORE_UNINITIALIZED;
 225 
 226         if ((rv = soft_init_token_session()) != CKR_OK) {
 227                 (void) pthread_mutex_destroy(&soft_sessionlist_mutex);
 228                 (void) pthread_mutex_unlock(&soft_giant_mutex);
 229                 return (rv);
 230         }
 231 
 232         /* Initialize the slot lock */
 233         if (pthread_mutex_init(&soft_slot.slot_mutex, NULL) != 0) {
 234                 (void) pthread_mutex_destroy(&soft_sessionlist_mutex);
 235                 (void) soft_destroy_token_session();
 236                 (void) pthread_mutex_unlock(&soft_giant_mutex);
 237                 return (CKR_CANT_LOCK);
 238         }
 239 
 240         /* Initialize the keystore lock */
 241         if (pthread_mutex_init(&soft_slot.keystore_mutex, NULL) != 0) {
 242                 (void) pthread_mutex_destroy(&soft_slot.slot_mutex);
 243                 (void) pthread_mutex_destroy(&soft_sessionlist_mutex);
 244                 (void) soft_destroy_token_session();
 245                 (void) pthread_mutex_unlock(&soft_giant_mutex);
 246                 return (CKR_CANT_LOCK);
 247         }
 248 
 249         /* Initialize the object_to_be_freed list */
 250         if (pthread_mutex_init(&obj_delay_freed.obj_to_be_free_mutex, NULL)
 251             != 0) {
 252                 (void) pthread_mutex_destroy(&soft_slot.keystore_mutex);
 253                 (void) pthread_mutex_destroy(&soft_slot.slot_mutex);
 254                 (void) pthread_mutex_destroy(&soft_sessionlist_mutex);
 255                 (void) soft_destroy_token_session();
 256                 (void) pthread_mutex_unlock(&soft_giant_mutex);
 257                 return (CKR_CANT_LOCK);
 258         }
 259         obj_delay_freed.count = 0;
 260         obj_delay_freed.first = NULL;
 261         obj_delay_freed.last = NULL;
 262 
 263         if (pthread_mutex_init(&ses_delay_freed.ses_to_be_free_mutex, NULL)
 264             != 0) {
 265                 (void) pthread_mutex_destroy(
 266                     &obj_delay_freed.obj_to_be_free_mutex);
 267                 (void) pthread_mutex_destroy(&soft_slot.keystore_mutex);
 268                 (void) pthread_mutex_destroy(&soft_slot.slot_mutex);
 269                 (void) pthread_mutex_destroy(&soft_sessionlist_mutex);
 270                 (void) soft_destroy_token_session();
 271                 (void) pthread_mutex_unlock(&soft_giant_mutex);
 272                 return (CKR_CANT_LOCK);
 273         }
 274         ses_delay_freed.count = 0;
 275         ses_delay_freed.first = NULL;
 276         ses_delay_freed.last = NULL;
 277 
 278         if (rv != CKR_OK) {
 279                 (void) pthread_mutex_destroy(
 280                     &ses_delay_freed.ses_to_be_free_mutex);
 281                 (void) pthread_mutex_destroy(
 282                     &obj_delay_freed.obj_to_be_free_mutex);
 283                 (void) pthread_mutex_destroy(&soft_slot.keystore_mutex);
 284                 (void) pthread_mutex_destroy(&soft_slot.slot_mutex);
 285                 (void) pthread_mutex_destroy(&soft_sessionlist_mutex);
 286                 (void) soft_destroy_token_session();
 287                 (void) pthread_mutex_unlock(&soft_giant_mutex);
 288                 return (CKR_FUNCTION_FAILED);
 289         }
 290 
 291         softtoken_pid = initialize_pid;
 292         softtoken_initialized = B_TRUE;
 293         (void) pthread_mutex_unlock(&soft_giant_mutex);
 294 
 295         return (CKR_OK);
 296 }
 297 
 298 /*
 299  * C_Finalize is a wrapper around finalize_common. The
 300  * soft_giant_mutex should be locked by C_Finalize().
 301  */
 302 CK_RV
 303 C_Finalize(CK_VOID_PTR pReserved)
 304 {
 305 
 306         CK_RV rv;
 307 
 308         (void) pthread_mutex_lock(&soft_giant_mutex);
 309 
 310         rv = finalize_common(B_FALSE, pReserved);
 311 
 312         (void) pthread_mutex_unlock(&soft_giant_mutex);
 313 
 314         return (rv);
 315 
 316 }
 317 
 318 /*
 319  * finalize_common() does the work for C_Finalize.  soft_giant_mutex
 320  * must be held before calling this function.
 321  */
 322 static CK_RV
 323 finalize_common(boolean_t force, CK_VOID_PTR pReserved) {
 324 
 325         CK_RV rv = CKR_OK;
 326         struct object *delay_free_obj, *tmpo;
 327         struct session *delay_free_ses, *tmps;
 328 
 329         if (!softtoken_initialized) {
 330                 return (CKR_CRYPTOKI_NOT_INITIALIZED);
 331         }
 332 
 333         /* Check to see if pReseved is NULL */
 334         if (pReserved != NULL) {
 335                 return (CKR_ARGUMENTS_BAD);
 336         }
 337 
 338         (void) pthread_mutex_lock(&soft_sessionlist_mutex);
 339         /*
 340          * Set all_sessions_closing flag so any access to any
 341          * existing sessions will be rejected.
 342          */
 343         all_sessions_closing = 1;
 344         (void) pthread_mutex_unlock(&soft_sessionlist_mutex);
 345 
 346         /* Delete all the sessions and release the allocated resources */
 347         rv = soft_delete_all_sessions(force);
 348 
 349         (void) pthread_mutex_lock(&soft_sessionlist_mutex);
 350         /* Reset all_sessions_closing flag. */
 351         all_sessions_closing = 0;
 352         (void) pthread_mutex_unlock(&soft_sessionlist_mutex);
 353 
 354         softtoken_initialized = B_FALSE;
 355         softtoken_pid = 0;
 356 
 357         pkcs11_close_urandom();
 358         pkcs11_close_urandom_seed();
 359         pkcs11_close_random();
 360 
 361         /* Destroy the session list lock here */
 362         (void) pthread_mutex_destroy(&soft_sessionlist_mutex);
 363 
 364         /*
 365          * Destroy token object related stuffs
 366          * 1. Clean up the token object list
 367          * 2. Destroy slot mutex
 368          * 3. Destroy mutex in token_session
 369          */
 370         soft_delete_all_in_core_token_objects(ALL_TOKEN);
 371         (void) pthread_mutex_destroy(&soft_slot.slot_mutex);
 372         (void) pthread_mutex_destroy(&soft_slot.keystore_mutex);
 373         (void) soft_destroy_token_session();
 374 
 375         /*
 376          * free all entries in the delay_freed list
 377          */
 378         delay_free_obj = obj_delay_freed.first;
 379         while (delay_free_obj != NULL) {
 380                 tmpo = delay_free_obj->next;
 381                 free(delay_free_obj);
 382                 delay_free_obj = tmpo;
 383         }
 384 
 385         soft_slot.keystore_load_status = KEYSTORE_UNINITIALIZED;
 386         (void) pthread_mutex_destroy(&obj_delay_freed.obj_to_be_free_mutex);
 387 
 388         delay_free_ses = ses_delay_freed.first;
 389         while (delay_free_ses != NULL) {
 390                 tmps = delay_free_ses->next;
 391                 free(delay_free_ses);
 392                 delay_free_ses = tmps;
 393         }
 394         (void) pthread_mutex_destroy(&ses_delay_freed.ses_to_be_free_mutex);
 395 
 396         return (rv);
 397 }
 398 
 399 static void
 400 softtoken_init()
 401 {
 402         /* Children inherit parent's atfork handlers */
 403         (void) pthread_atfork(softtoken_fork_prepare,
 404             softtoken_fork_after, softtoken_fork_after);
 405 }
 406 
 407 /*
 408  * softtoken_fini() function required to make sure complete cleanup
 409  * is done if softtoken is ever unloaded without a C_Finalize() call.
 410  */
 411 static void
 412 softtoken_fini()
 413 {
 414         (void) pthread_mutex_lock(&soft_giant_mutex);
 415 
 416         /* if we're not initilized, do not attempt to finalize */
 417         if (!softtoken_initialized) {
 418                 (void) pthread_mutex_unlock(&soft_giant_mutex);
 419                 return;
 420         }
 421 
 422         (void) finalize_common(B_TRUE, NULL_PTR);
 423 
 424         (void) pthread_mutex_unlock(&soft_giant_mutex);
 425 }
 426 
 427 CK_RV
 428 C_GetInfo(CK_INFO_PTR pInfo)
 429 {
 430         if (!softtoken_initialized)
 431                 return (CKR_CRYPTOKI_NOT_INITIALIZED);
 432 
 433         if (pInfo == NULL) {
 434                 return (CKR_ARGUMENTS_BAD);
 435         }
 436 
 437         /* Provide general information in the provided buffer */
 438         pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR;
 439         pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR;
 440         (void) strncpy((char *)pInfo->manufacturerID,
 441             SOFT_MANUFACTURER_ID, 32);
 442         pInfo->flags = 0;
 443         (void) strncpy((char *)pInfo->libraryDescription,
 444             LIBRARY_DESCRIPTION, 32);
 445         pInfo->libraryVersion.major = LIBRARY_VERSION_MAJOR;
 446         pInfo->libraryVersion.minor = LIBRARY_VERSION_MINOR;
 447 
 448         return (CKR_OK);
 449 }
 450 
 451 CK_RV
 452 C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
 453 {
 454         if (ppFunctionList == NULL) {
 455                 return (CKR_ARGUMENTS_BAD);
 456         }
 457 
 458         *ppFunctionList = &functionList;
 459 
 460         return (CKR_OK);
 461 }
 462 
 463 /*
 464  * PKCS#11 states that C_GetFunctionStatus should always return
 465  * CKR_FUNCTION_NOT_PARALLEL
 466  */
 467 /*ARGSUSED*/
 468 CK_RV
 469 C_GetFunctionStatus(CK_SESSION_HANDLE hSession)
 470 {
 471         return (CKR_FUNCTION_NOT_PARALLEL);
 472 }
 473 
 474 /*
 475  * PKCS#11 states that C_CancelFunction should always return
 476  * CKR_FUNCTION_NOT_PARALLEL
 477  */
 478 /*ARGSUSED*/
 479 CK_RV
 480 C_CancelFunction(CK_SESSION_HANDLE hSession)
 481 {
 482         return (CKR_FUNCTION_NOT_PARALLEL);
 483 }
 484 
 485 /*
 486  * Take out all mutexes before fork.
 487  *
 488  * Order:
 489  * 1. soft_giant_mutex
 490  * 2. soft_sessionlist_mutex
 491  * 3. soft_slot.slot_mutex
 492  * 4. soft_slot.keystore_mutex
 493  * 5. token_session mutexes via soft_acquire_all_session_mutexes()
 494  * 6. all soft_session_list mutexes via soft_acquire_all_session_mutexes()
 495  * 7. obj_delay_freed.obj_to_be_free_mutex;
 496  * 8. ses_delay_freed.ses_to_be_free_mutex
 497  */
 498 void
 499 softtoken_fork_prepare()
 500 {
 501         (void) pthread_mutex_lock(&soft_giant_mutex);
 502         if (softtoken_initialized) {
 503                 (void) pthread_mutex_lock(&soft_sessionlist_mutex);
 504                 (void) pthread_mutex_lock(&soft_slot.slot_mutex);
 505                 (void) pthread_mutex_lock(&soft_slot.keystore_mutex);
 506                 soft_acquire_all_session_mutexes(&token_session);
 507                 soft_acquire_all_session_mutexes(soft_session_list);
 508                 (void) pthread_mutex_lock(
 509                     &obj_delay_freed.obj_to_be_free_mutex);
 510                 (void) pthread_mutex_lock(
 511                     &ses_delay_freed.ses_to_be_free_mutex);
 512         }
 513 }
 514 
 515 /*
 516  * Release in opposite order to softtoken_fork_prepare().
 517  * Function is used for parent and child.
 518  */
 519 void
 520 softtoken_fork_after()
 521 {
 522         if (softtoken_initialized) {
 523                 (void) pthread_mutex_unlock(
 524                     &ses_delay_freed.ses_to_be_free_mutex);
 525                 (void) pthread_mutex_unlock(
 526                     &obj_delay_freed.obj_to_be_free_mutex);
 527                 soft_release_all_session_mutexes(soft_session_list);
 528                 soft_release_all_session_mutexes(&token_session);
 529                 (void) pthread_mutex_unlock(&soft_slot.keystore_mutex);
 530                 (void) pthread_mutex_unlock(&soft_slot.slot_mutex);
 531                 (void) pthread_mutex_unlock(&soft_sessionlist_mutex);
 532         }
 533         (void) pthread_mutex_unlock(&soft_giant_mutex);
 534 }