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 int soft_urandom_fd = -1; 124 int soft_urandom_seed_fd = -1; 125 int soft_random_fd = -1; 126 127 slot_t soft_slot; 128 obj_to_be_freed_list_t obj_delay_freed; 129 ses_to_be_freed_list_t ses_delay_freed; 130 131 /* protects softtoken_initialized and access to C_Initialize/C_Finalize */ 132 pthread_mutex_t soft_giant_mutex = PTHREAD_MUTEX_INITIALIZER; 133 134 static CK_RV finalize_common(boolean_t force, CK_VOID_PTR pReserved); 135 static void softtoken_fini(); 136 static void softtoken_fork_prepare(); 137 static void softtoken_fork_parent(); 138 static void softtoken_fork_child(); 139 140 CK_RV 141 C_Initialize(CK_VOID_PTR pInitArgs) 142 { 143 144 int initialize_pid; 145 boolean_t supplied_ok; 146 CK_RV rv; 147 148 /* 149 * Get lock to insure only one thread enters this 150 * function at a time. 151 */ 152 (void) pthread_mutex_lock(&soft_giant_mutex); 153 154 initialize_pid = getpid(); 155 156 if (softtoken_initialized) { 157 if (initialize_pid == softtoken_pid) { 158 /* 159 * This process has called C_Initialize already 160 */ 161 (void) pthread_mutex_unlock(&soft_giant_mutex); 162 return (CKR_CRYPTOKI_ALREADY_INITIALIZED); 163 } else { 164 /* 165 * A fork has happened and the child is 166 * reinitializing. Do a finalize_common to close 167 * out any state from the parent, and then 168 * continue on. 169 */ 170 (void) finalize_common(B_TRUE, NULL); 171 } 172 } 173 174 if (pInitArgs != NULL) { 175 CK_C_INITIALIZE_ARGS *initargs1 = 176 (CK_C_INITIALIZE_ARGS *) pInitArgs; 177 178 /* pReserved must be NULL */ 179 if (initargs1->pReserved != NULL) { 180 (void) pthread_mutex_unlock(&soft_giant_mutex); 181 return (CKR_ARGUMENTS_BAD); 182 } 183 184 /* 185 * ALL supplied function pointers need to have the value 186 * either NULL or non-NULL. 187 */ 188 supplied_ok = (initargs1->CreateMutex == NULL && 189 initargs1->DestroyMutex == NULL && 190 initargs1->LockMutex == NULL && 191 initargs1->UnlockMutex == NULL) || 192 (initargs1->CreateMutex != NULL && 193 initargs1->DestroyMutex != NULL && 194 initargs1->LockMutex != NULL && 195 initargs1->UnlockMutex != NULL); 196 197 if (!supplied_ok) { 198 (void) pthread_mutex_unlock(&soft_giant_mutex); 199 return (CKR_ARGUMENTS_BAD); 200 } 201 202 /* 203 * When the CKF_OS_LOCKING_OK flag isn't set and mutex 204 * function pointers are supplied by an application, 205 * return an error. We must be able to use our own primitives. 206 */ 207 if (!(initargs1->flags & CKF_OS_LOCKING_OK) && 208 (initargs1->CreateMutex != NULL)) { 209 (void) pthread_mutex_unlock(&soft_giant_mutex); 210 return (CKR_CANT_LOCK); 211 } 212 } 213 214 /* Initialize the session list lock */ 215 if (pthread_mutex_init(&soft_sessionlist_mutex, NULL) != 0) { 216 (void) pthread_mutex_unlock(&soft_giant_mutex); 217 return (CKR_CANT_LOCK); 218 } 219 220 softtoken_initialized = B_TRUE; 221 softtoken_pid = initialize_pid; 222 223 /* 224 * token object related initialization 225 */ 226 soft_slot.authenticated = 0; 227 soft_slot.userpin_change_needed = 0; 228 soft_slot.token_object_list = NULL; 229 soft_slot.keystore_load_status = KEYSTORE_UNINITIALIZED; 230 231 if ((rv = soft_init_token_session()) != CKR_OK) { 232 (void) pthread_mutex_unlock(&soft_giant_mutex); 233 return (rv); 234 } 235 236 /* Initialize the slot lock */ 237 if (pthread_mutex_init(&soft_slot.slot_mutex, NULL) != 0) { 238 (void) soft_destroy_token_session(); 239 (void) pthread_mutex_unlock(&soft_giant_mutex); 240 return (CKR_CANT_LOCK); 241 } 242 243 /* Initialize the keystore lock */ 244 if (pthread_mutex_init(&soft_slot.keystore_mutex, NULL) != 0) { 245 (void) pthread_mutex_unlock(&soft_giant_mutex); 246 return (CKR_CANT_LOCK); 247 } 248 249 /* Children inherit parent's atfork handlers */ 250 if (!softtoken_atfork_initialized) { 251 (void) pthread_atfork(softtoken_fork_prepare, 252 softtoken_fork_parent, softtoken_fork_child); 253 softtoken_atfork_initialized = B_TRUE; 254 } 255 256 (void) pthread_mutex_unlock(&soft_giant_mutex); 257 258 /* Initialize the object_to_be_freed list */ 259 (void) pthread_mutex_init(&obj_delay_freed.obj_to_be_free_mutex, NULL); 260 obj_delay_freed.count = 0; 261 obj_delay_freed.first = NULL; 262 obj_delay_freed.last = NULL; 263 264 (void) pthread_mutex_init(&ses_delay_freed.ses_to_be_free_mutex, NULL); 265 ses_delay_freed.count = 0; 266 ses_delay_freed.first = NULL; 267 ses_delay_freed.last = NULL; 268 return (CKR_OK); 269 270 } 271 272 /* 273 * C_Finalize is a wrapper around finalize_common. The 274 * soft_giant_mutex should be locked by C_Finalize(). 275 */ 276 CK_RV 277 C_Finalize(CK_VOID_PTR pReserved) 278 { 279 280 CK_RV rv; 281 282 (void) pthread_mutex_lock(&soft_giant_mutex); 283 284 rv = finalize_common(B_FALSE, pReserved); 285 286 (void) pthread_mutex_unlock(&soft_giant_mutex); 287 288 return (rv); 289 290 } 291 292 /* 293 * finalize_common() does the work for C_Finalize. soft_giant_mutex 294 * must be held before calling this function. 295 */ 296 static CK_RV 297 finalize_common(boolean_t force, CK_VOID_PTR pReserved) { 298 299 CK_RV rv = CKR_OK; 300 struct object *delay_free_obj, *tmpo; 301 struct session *delay_free_ses, *tmps; 302 303 if (!softtoken_initialized) { 304 return (CKR_CRYPTOKI_NOT_INITIALIZED); 305 } 306 307 /* Check to see if pReseved is NULL */ 308 if (pReserved != NULL) { 309 return (CKR_ARGUMENTS_BAD); 310 } 311 312 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 313 /* 314 * Set all_sessions_closing flag so any access to any 315 * existing sessions will be rejected. 316 */ 317 all_sessions_closing = 1; 318 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 319 320 /* Delete all the sessions and release the allocated resources */ 321 rv = soft_delete_all_sessions(force); 322 323 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 324 /* Reset all_sessions_closing flag. */ 325 all_sessions_closing = 0; 326 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 327 328 softtoken_initialized = B_FALSE; 329 softtoken_pid = 0; 330 331 if (soft_urandom_fd > 0) { 332 (void) close(soft_urandom_fd); 333 soft_urandom_fd = -1; 334 } 335 336 if (soft_urandom_seed_fd > 0) { 337 (void) close(soft_urandom_seed_fd); 338 soft_urandom_seed_fd = -1; 339 } 340 341 if (soft_random_fd > 0) { 342 (void) close(soft_random_fd); 343 soft_random_fd = -1; 344 } 345 346 /* Destroy the session list lock here */ 347 (void) pthread_mutex_destroy(&soft_sessionlist_mutex); 348 349 /* 350 * Destroy token object related stuffs 351 * 1. Clean up the token object list 352 * 2. Destroy slot mutex 353 * 3. Destroy mutex in token_session 354 */ 355 soft_delete_all_in_core_token_objects(ALL_TOKEN); 356 (void) pthread_mutex_destroy(&soft_slot.slot_mutex); 357 (void) pthread_mutex_destroy(&soft_slot.keystore_mutex); 358 (void) soft_destroy_token_session(); 359 360 /* 361 * free all entries in the delay_freed list 362 */ 363 delay_free_obj = obj_delay_freed.first; 364 while (delay_free_obj != NULL) { 365 tmpo = delay_free_obj->next; 366 free(delay_free_obj); 367 delay_free_obj = tmpo; 368 } 369 370 soft_slot.keystore_load_status = KEYSTORE_UNINITIALIZED; 371 (void) pthread_mutex_destroy(&obj_delay_freed.obj_to_be_free_mutex); 372 373 delay_free_ses = ses_delay_freed.first; 374 while (delay_free_ses != NULL) { 375 tmps = delay_free_ses->next; 376 free(delay_free_ses); 377 delay_free_ses = tmps; 378 } 379 (void) pthread_mutex_destroy(&ses_delay_freed.ses_to_be_free_mutex); 380 381 return (rv); 382 } 383 384 /* 385 * softtoken_fini() function required to make sure complete cleanup 386 * is done if softtoken is ever unloaded without a C_Finalize() call. 387 */ 388 static void 389 softtoken_fini() 390 { 391 (void) pthread_mutex_lock(&soft_giant_mutex); 392 393 /* if we're not initilized, do not attempt to finalize */ 394 if (!softtoken_initialized) { 395 (void) pthread_mutex_unlock(&soft_giant_mutex); 396 return; 397 } 398 399 (void) finalize_common(B_TRUE, NULL_PTR); 400 401 (void) pthread_mutex_unlock(&soft_giant_mutex); 402 } 403 404 CK_RV 405 C_GetInfo(CK_INFO_PTR pInfo) 406 { 407 if (!softtoken_initialized) 408 return (CKR_CRYPTOKI_NOT_INITIALIZED); 409 410 if (pInfo == NULL) { 411 return (CKR_ARGUMENTS_BAD); 412 } 413 414 /* Provide general information in the provided buffer */ 415 pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR; 416 pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR; 417 (void) strncpy((char *)pInfo->manufacturerID, 418 SOFT_MANUFACTURER_ID, 32); 419 pInfo->flags = 0; 420 (void) strncpy((char *)pInfo->libraryDescription, 421 LIBRARY_DESCRIPTION, 32); 422 pInfo->libraryVersion.major = LIBRARY_VERSION_MAJOR; 423 pInfo->libraryVersion.major = LIBRARY_VERSION_MINOR; 424 425 return (CKR_OK); 426 } 427 428 CK_RV 429 C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) 430 { 431 if (ppFunctionList == NULL) { 432 return (CKR_ARGUMENTS_BAD); 433 } 434 435 *ppFunctionList = &functionList; 436 437 return (CKR_OK); 438 } 439 440 /* 441 * PKCS#11 states that C_GetFunctionStatus should always return 442 * CKR_FUNCTION_NOT_PARALLEL 443 */ 444 /*ARGSUSED*/ 445 CK_RV 446 C_GetFunctionStatus(CK_SESSION_HANDLE hSession) 447 { 448 return (CKR_FUNCTION_NOT_PARALLEL); 449 } 450 451 /* 452 * PKCS#11 states that C_CancelFunction should always return 453 * CKR_FUNCTION_NOT_PARALLEL 454 */ 455 /*ARGSUSED*/ 456 CK_RV 457 C_CancelFunction(CK_SESSION_HANDLE hSession) 458 { 459 return (CKR_FUNCTION_NOT_PARALLEL); 460 } 461 462 /* 463 * Take out all mutexes before fork. 464 * Order: 465 * 1. soft_giant_mutex 466 * 2. soft_sessionlist_mutex 467 * 3. soft_slot.slot_mutex 468 * 4. soft_slot.keystore_mutex 469 * 5. all soft_session_list mutexs via soft_acquire_all_session_mutexes() 470 * 6. obj_delay_freed.obj_to_be_free_mutex; 471 * 7. ses_delay_freed.ses_to_be_free_mutex 472 */ 473 void 474 softtoken_fork_prepare() 475 { 476 (void) pthread_mutex_lock(&soft_giant_mutex); 477 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 478 (void) pthread_mutex_lock(&soft_slot.slot_mutex); 479 (void) pthread_mutex_lock(&soft_slot.keystore_mutex); 480 soft_acquire_all_session_mutexes(); 481 (void) pthread_mutex_lock(&obj_delay_freed.obj_to_be_free_mutex); 482 (void) pthread_mutex_lock(&ses_delay_freed.ses_to_be_free_mutex); 483 } 484 485 /* Release in opposite order to softtoken_fork_prepare(). */ 486 void 487 softtoken_fork_parent() 488 { 489 (void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex); 490 (void) pthread_mutex_unlock(&obj_delay_freed.obj_to_be_free_mutex); 491 soft_release_all_session_mutexes(); 492 (void) pthread_mutex_unlock(&soft_slot.keystore_mutex); 493 (void) pthread_mutex_unlock(&soft_slot.slot_mutex); 494 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 495 (void) pthread_mutex_unlock(&soft_giant_mutex); 496 } 497 498 /* Release in opposite order to softtoken_fork_prepare(). */ 499 void 500 softtoken_fork_child() 501 { 502 (void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex); 503 (void) pthread_mutex_unlock(&obj_delay_freed.obj_to_be_free_mutex); 504 soft_release_all_session_mutexes(); 505 (void) pthread_mutex_unlock(&soft_slot.keystore_mutex); 506 (void) pthread_mutex_unlock(&soft_slot.slot_mutex); 507 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 508 (void) pthread_mutex_unlock(&soft_giant_mutex); 509 } 510