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