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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <fcntl.h> 29 #include <pthread.h> 30 #include <strings.h> 31 #include <unistd.h> /* for pid */ 32 #include <errno.h> 33 #include <security/cryptoki.h> 34 #include "kernelGlobal.h" 35 #include "kernelSession.h" 36 #include "kernelSlot.h" 37 38 #pragma fini(kernel_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 kernel_initialized = B_FALSE; 113 static boolean_t kernel_atfork_initialized = B_FALSE; 114 static pid_t kernel_pid = 0; 115 116 int kernel_fd = -1; 117 118 119 /* protects kernel_initialized and entrance to C_Initialize/Finalize */ 120 static pthread_mutex_t globalmutex = PTHREAD_MUTEX_INITIALIZER; 121 122 ses_to_be_freed_list_t ses_delay_freed; 123 object_to_be_freed_list_t obj_delay_freed; 124 kmh_elem_t **kernel_mechhash; /* Hash table for kCF mech numbers */ 125 126 static void finalize_common(); 127 static void cleanup_library(); 128 static void kernel_fini(); 129 static void kernel_fork_prepare(); 130 static void kernel_fork_parent(); 131 static void kernel_fork_child(); 132 133 CK_RV 134 C_Initialize(CK_VOID_PTR pInitArgs) 135 { 136 int initialize_pid; 137 boolean_t supplied_ok; 138 CK_RV rv = CKR_OK; 139 140 /* 141 * Grab lock to insure that only one thread enters this 142 * function at a time. 143 */ 144 (void) pthread_mutex_lock(&globalmutex); 145 initialize_pid = getpid(); 146 147 if (kernel_initialized) { 148 if (initialize_pid == kernel_pid) { 149 /* 150 * This process has called C_Initialize already 151 */ 152 (void) pthread_mutex_unlock(&globalmutex); 153 return (CKR_CRYPTOKI_ALREADY_INITIALIZED); 154 } else { 155 /* 156 * A fork has happened and the child is 157 * reinitializing. Do a cleanup_library to close 158 * out any state from the parent, and then 159 * continue on. 160 */ 161 cleanup_library(); 162 } 163 } 164 165 if (pInitArgs != NULL) { 166 CK_C_INITIALIZE_ARGS *initargs1 = 167 (CK_C_INITIALIZE_ARGS *) pInitArgs; 168 169 /* pReserved must be NULL */ 170 if (initargs1->pReserved != NULL) { 171 (void) pthread_mutex_unlock(&globalmutex); 172 return (CKR_ARGUMENTS_BAD); 173 } 174 175 /* 176 * ALL supplied function pointers need to have the value 177 * either NULL or non-NULL. 178 */ 179 supplied_ok = (initargs1->CreateMutex == NULL && 180 initargs1->DestroyMutex == NULL && 181 initargs1->LockMutex == NULL && 182 initargs1->UnlockMutex == NULL) || 183 (initargs1->CreateMutex != NULL && 184 initargs1->DestroyMutex != NULL && 185 initargs1->LockMutex != NULL && 186 initargs1->UnlockMutex != NULL); 187 188 if (!supplied_ok) { 189 (void) pthread_mutex_unlock(&globalmutex); 190 return (CKR_ARGUMENTS_BAD); 191 } 192 193 /* 194 * When the CKF_OS_LOCKING_OK flag isn't set and mutex 195 * function pointers are supplied by an application, 196 * return an error. We must be able to use our own locks. 197 */ 198 if (!(initargs1->flags & CKF_OS_LOCKING_OK) && 199 (initargs1->CreateMutex != NULL)) { 200 (void) pthread_mutex_unlock(&globalmutex); 201 return (CKR_CANT_LOCK); 202 } 203 } 204 205 while ((kernel_fd = open(CRYPTO_DEVICE, O_RDWR)) < 0) { 206 if (errno != EINTR) 207 break; 208 } 209 if (kernel_fd < 0) { 210 (void) pthread_mutex_unlock(&globalmutex); 211 return (CKR_FUNCTION_FAILED); 212 } 213 214 /* Mark kernel_fd "close on exec" */ 215 (void) fcntl(kernel_fd, F_SETFD, FD_CLOEXEC); 216 217 /* Create the hash table */ 218 kernel_mechhash = calloc(KMECH_HASHTABLE_SIZE, sizeof (void *)); 219 if (kernel_mechhash == NULL) { 220 (void) close(kernel_fd); 221 (void) pthread_mutex_unlock(&globalmutex); 222 return (CKR_HOST_MEMORY); 223 } 224 225 /* Initialize the slot table */ 226 rv = kernel_slottable_init(); 227 if (rv != CKR_OK) { 228 free(kernel_mechhash); 229 (void) close(kernel_fd); 230 (void) pthread_mutex_unlock(&globalmutex); 231 return (rv); 232 } 233 234 /* Initialize the object_to_be_freed list */ 235 (void) pthread_mutex_init(&obj_delay_freed.obj_to_be_free_mutex, NULL); 236 obj_delay_freed.count = 0; 237 obj_delay_freed.first = NULL; 238 obj_delay_freed.last = NULL; 239 240 /* Initialize the session_to_be_freed list */ 241 (void) pthread_mutex_init(&ses_delay_freed.ses_to_be_free_mutex, NULL); 242 ses_delay_freed.count = 0; 243 ses_delay_freed.first = NULL; 244 ses_delay_freed.last = NULL; 245 246 kernel_initialized = B_TRUE; 247 kernel_pid = initialize_pid; 248 249 /* Children inherit parent's atfork handlers */ 250 if (!kernel_atfork_initialized) { 251 (void) pthread_atfork(kernel_fork_prepare, kernel_fork_parent, 252 kernel_fork_child); 253 kernel_atfork_initialized = B_TRUE; 254 } 255 256 (void) pthread_mutex_unlock(&globalmutex); 257 258 return (CKR_OK); 259 260 } 261 262 263 /* 264 * C_Finalize is a wrapper around finalize_common. The 265 * globalmutex should be locked by C_Finalize(). 266 */ 267 CK_RV 268 C_Finalize(CK_VOID_PTR pReserved) 269 { 270 int i; 271 272 (void) pthread_mutex_lock(&globalmutex); 273 274 if (!kernel_initialized) { 275 (void) pthread_mutex_unlock(&globalmutex); 276 return (CKR_CRYPTOKI_NOT_INITIALIZED); 277 } 278 279 /* Check to see if pReseved is NULL */ 280 if (pReserved != NULL) { 281 (void) pthread_mutex_unlock(&globalmutex); 282 return (CKR_ARGUMENTS_BAD); 283 } 284 285 /* 286 * Delete all the sessions for each slot and release the allocated 287 * resources 288 */ 289 for (i = 0; i < slot_count; i++) { 290 kernel_delete_all_sessions(i, B_FALSE); 291 } 292 293 finalize_common(); 294 295 (void) pthread_mutex_unlock(&globalmutex); 296 297 return (CKR_OK); 298 } 299 300 /* 301 * finalize_common() does the work for C_Finalize. globalmutex 302 * must be held before calling this function. 303 */ 304 static void 305 finalize_common() { 306 307 int i; 308 kmh_elem_t *elem, *next; 309 kernel_object_t *delay_free_obj, *tmpo; 310 kernel_session_t *delay_free_ses, *tmps; 311 312 /* 313 * Free the resources allocated for the slot table and reset 314 * slot_count to 0. 315 */ 316 if (slot_count > 0) { 317 for (i = 0; i < slot_count; i++) { 318 (void) pthread_mutex_destroy(&slot_table[i]->sl_mutex); 319 (void) free(slot_table[i]); 320 } 321 (void) free(slot_table); 322 slot_count = 0; 323 } 324 325 /* Close CRYPTO_DEVICE */ 326 if (kernel_fd >= 0) { 327 (void) close(kernel_fd); 328 } 329 330 /* Walk the hash table and free all entries */ 331 for (i = 0; i < KMECH_HASHTABLE_SIZE; i++) { 332 elem = kernel_mechhash[i]; 333 while (elem != NULL) { 334 next = elem->knext; 335 free(elem); 336 elem = next; 337 } 338 } 339 340 free(kernel_mechhash); 341 342 kernel_fd = -1; 343 kernel_initialized = B_FALSE; 344 kernel_pid = 0; 345 346 /* 347 * free all entries in the delay_freed list 348 */ 349 delay_free_obj = obj_delay_freed.first; 350 while (delay_free_obj != NULL) { 351 tmpo = delay_free_obj->next; 352 free(delay_free_obj); 353 delay_free_obj = tmpo; 354 } 355 (void) pthread_mutex_destroy(&obj_delay_freed.obj_to_be_free_mutex); 356 357 delay_free_ses = ses_delay_freed.first; 358 while (delay_free_ses != NULL) { 359 tmps = delay_free_ses->next; 360 free(delay_free_ses); 361 delay_free_ses = tmps; 362 } 363 (void) pthread_mutex_destroy(&ses_delay_freed.ses_to_be_free_mutex); 364 } 365 366 /* 367 * This function cleans up all the resources in the library (user space only) 368 */ 369 static void 370 cleanup_library() 371 { 372 int i; 373 374 /* 375 * Delete all the sessions for each slot and release the allocated 376 * resources from the library. The boolean argument TRUE indicates 377 * that we only wants to clean up the resource in the library only. 378 * We don't want to clean up the corresponding kernel part of 379 * resources, because they are used by the parent process still. 380 */ 381 382 for (i = 0; i < slot_count; i++) { 383 kernel_delete_all_sessions(i, B_TRUE); 384 } 385 386 finalize_common(); 387 } 388 389 /* 390 * kernel_fini() function required to make sure complete cleanup 391 * is done if pkcs11_kernel is ever unloaded without 392 * a C_Finalize() call. 393 */ 394 static void 395 kernel_fini() 396 { 397 398 (void) pthread_mutex_lock(&globalmutex); 399 400 /* if we're not initilized, do not attempt to finalize */ 401 if (!kernel_initialized) { 402 (void) pthread_mutex_unlock(&globalmutex); 403 return; 404 } 405 406 cleanup_library(); 407 408 (void) pthread_mutex_unlock(&globalmutex); 409 } 410 411 CK_RV 412 C_GetInfo(CK_INFO_PTR pInfo) 413 { 414 if (!kernel_initialized) 415 return (CKR_CRYPTOKI_NOT_INITIALIZED); 416 417 if (pInfo == NULL) { 418 return (CKR_ARGUMENTS_BAD); 419 } 420 421 /* Check if the cryptoki was initialized */ 422 423 pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR; 424 pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR; 425 (void) strncpy((char *)pInfo->manufacturerID, 426 MANUFACTURER_ID, 32); 427 pInfo->flags = 0; 428 (void) strncpy((char *)pInfo->libraryDescription, 429 LIBRARY_DESCRIPTION, 32); 430 pInfo->libraryVersion.major = LIBRARY_VERSION_MAJOR; 431 pInfo->libraryVersion.minor = LIBRARY_VERSION_MINOR; 432 433 return (CKR_OK); 434 } 435 436 CK_RV 437 C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) 438 { 439 if (ppFunctionList == NULL) { 440 return (CKR_ARGUMENTS_BAD); 441 } 442 443 *ppFunctionList = &functionList; 444 445 return (CKR_OK); 446 } 447 448 /* 449 * PKCS#11 states that C_GetFunctionStatus should always return 450 * CKR_FUNCTION_NOT_PARALLEL 451 */ 452 /*ARGSUSED*/ 453 CK_RV 454 C_GetFunctionStatus(CK_SESSION_HANDLE hSession) 455 { 456 return (CKR_FUNCTION_NOT_PARALLEL); 457 } 458 459 /* 460 * Take out all mutexes before fork. 461 * Order: 462 * 1. globalmutex 463 * 2. all slots mutexes (and all their sessions) via 464 * kernel_acquire_all_slots_mutexes() 465 * 3. obj_delay_freed.obj_to_be_free_mutex; 466 * 4. ses_delay_freed.ses_to_be_free_mutex 467 */ 468 void 469 kernel_fork_prepare() 470 { 471 (void) pthread_mutex_lock(&globalmutex); 472 kernel_acquire_all_slots_mutexes(); 473 (void) pthread_mutex_lock( 474 &obj_delay_freed.obj_to_be_free_mutex); 475 (void) pthread_mutex_lock( 476 &ses_delay_freed.ses_to_be_free_mutex); 477 } 478 479 /* Release in opposite order to kernel_fork_prepare(). */ 480 void 481 kernel_fork_parent() 482 { 483 (void) pthread_mutex_unlock( 484 &ses_delay_freed.ses_to_be_free_mutex); 485 (void) pthread_mutex_unlock( 486 &obj_delay_freed.obj_to_be_free_mutex); 487 kernel_release_all_slots_mutexes(); 488 (void) pthread_mutex_unlock(&globalmutex); 489 } 490 491 /* Release in opposite order to kernel_fork_prepare(). */ 492 void 493 kernel_fork_child() 494 { 495 (void) pthread_mutex_unlock( 496 &ses_delay_freed.ses_to_be_free_mutex); 497 (void) pthread_mutex_unlock( 498 &obj_delay_freed.obj_to_be_free_mutex); 499 kernel_release_all_slots_mutexes(); 500 (void) pthread_mutex_unlock(&globalmutex); 501 } 502 503 /* 504 * PKCS#11 states that C_CancelFunction should always return 505 * CKR_FUNCTION_NOT_PARALLEL 506 */ 507 /*ARGSUSED*/ 508 CK_RV 509 C_CancelFunction(CK_SESSION_HANDLE hSession) 510 { 511 return (CKR_FUNCTION_NOT_PARALLEL); 512 } 513