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 <fcntl.h> 27 #include <pthread.h> 28 #include <strings.h> 29 #include <unistd.h> /* for pid */ 30 #include <errno.h> 31 #include <security/cryptoki.h> 32 #include "kernelGlobal.h" 33 #include "kernelSession.h" 34 #include "kernelSlot.h" 35 36 #pragma init(kernel_init) 37 #pragma fini(kernel_fini) 38 39 static struct CK_FUNCTION_LIST functionList = { 40 { 2, 20 }, /* version */ 41 C_Initialize, 42 C_Finalize, 43 C_GetInfo, 44 C_GetFunctionList, 45 C_GetSlotList, 46 C_GetSlotInfo, 47 C_GetTokenInfo, 48 C_GetMechanismList, 49 C_GetMechanismInfo, 50 C_InitToken, 51 C_InitPIN, 52 C_SetPIN, 53 C_OpenSession, 54 C_CloseSession, 55 C_CloseAllSessions, 56 C_GetSessionInfo, 57 C_GetOperationState, 58 C_SetOperationState, 59 C_Login, 60 C_Logout, 61 C_CreateObject, 62 C_CopyObject, 63 C_DestroyObject, 64 C_GetObjectSize, 65 C_GetAttributeValue, 66 C_SetAttributeValue, 67 C_FindObjectsInit, 68 C_FindObjects, 69 C_FindObjectsFinal, 70 C_EncryptInit, 71 C_Encrypt, 72 C_EncryptUpdate, 73 C_EncryptFinal, 74 C_DecryptInit, 75 C_Decrypt, 76 C_DecryptUpdate, 77 C_DecryptFinal, 78 C_DigestInit, 79 C_Digest, 80 C_DigestUpdate, 81 C_DigestKey, 82 C_DigestFinal, 83 C_SignInit, 84 C_Sign, 85 C_SignUpdate, 86 C_SignFinal, 87 C_SignRecoverInit, 88 C_SignRecover, 89 C_VerifyInit, 90 C_Verify, 91 C_VerifyUpdate, 92 C_VerifyFinal, 93 C_VerifyRecoverInit, 94 C_VerifyRecover, 95 C_DigestEncryptUpdate, 96 C_DecryptDigestUpdate, 97 C_SignEncryptUpdate, 98 C_DecryptVerifyUpdate, 99 C_GenerateKey, 100 C_GenerateKeyPair, 101 C_WrapKey, 102 C_UnwrapKey, 103 C_DeriveKey, 104 C_SeedRandom, 105 C_GenerateRandom, 106 C_GetFunctionStatus, 107 C_CancelFunction, 108 C_WaitForSlotEvent 109 }; 110 111 boolean_t kernel_initialized = B_FALSE; 112 static pid_t kernel_pid = 0; 113 114 extern pthread_mutex_t mechhash_mutex; 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_init(); 129 static void kernel_fini(); 130 static void kernel_fork_prepare(); 131 static void kernel_fork_after(); 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 (void) pthread_mutex_unlock(&globalmutex); 250 251 return (CKR_OK); 252 253 } 254 255 256 /* 257 * C_Finalize is a wrapper around finalize_common. The 258 * globalmutex should be locked by C_Finalize(). 259 */ 260 CK_RV 261 C_Finalize(CK_VOID_PTR pReserved) 262 { 263 int i; 264 265 (void) pthread_mutex_lock(&globalmutex); 266 267 if (!kernel_initialized) { 268 (void) pthread_mutex_unlock(&globalmutex); 269 return (CKR_CRYPTOKI_NOT_INITIALIZED); 270 } 271 272 /* Check to see if pReseved is NULL */ 273 if (pReserved != NULL) { 274 (void) pthread_mutex_unlock(&globalmutex); 275 return (CKR_ARGUMENTS_BAD); 276 } 277 278 /* 279 * Delete all the sessions for each slot and release the allocated 280 * resources 281 */ 282 for (i = 0; i < slot_count; i++) { 283 kernel_delete_all_sessions(i, B_FALSE); 284 } 285 286 finalize_common(); 287 288 (void) pthread_mutex_unlock(&globalmutex); 289 290 return (CKR_OK); 291 } 292 293 /* 294 * finalize_common() does the work for C_Finalize. globalmutex 295 * must be held before calling this function. 296 */ 297 static void 298 finalize_common() { 299 300 int i; 301 kmh_elem_t *elem, *next; 302 kernel_object_t *delay_free_obj, *tmpo; 303 kernel_session_t *delay_free_ses, *tmps; 304 305 /* 306 * Free the resources allocated for the slot table and reset 307 * slot_count to 0. 308 */ 309 if (slot_count > 0) { 310 for (i = 0; i < slot_count; i++) { 311 (void) pthread_mutex_destroy(&slot_table[i]->sl_mutex); 312 (void) free(slot_table[i]); 313 } 314 (void) free(slot_table); 315 slot_count = 0; 316 } 317 318 /* Close CRYPTO_DEVICE */ 319 if (kernel_fd >= 0) { 320 (void) close(kernel_fd); 321 } 322 323 /* Walk the hash table and free all entries */ 324 for (i = 0; i < KMECH_HASHTABLE_SIZE; i++) { 325 elem = kernel_mechhash[i]; 326 while (elem != NULL) { 327 next = elem->knext; 328 free(elem); 329 elem = next; 330 } 331 } 332 333 free(kernel_mechhash); 334 335 kernel_fd = -1; 336 kernel_initialized = B_FALSE; 337 kernel_pid = 0; 338 339 /* 340 * free all entries in the delay_freed list 341 */ 342 delay_free_obj = obj_delay_freed.first; 343 while (delay_free_obj != NULL) { 344 tmpo = delay_free_obj->next; 345 free(delay_free_obj); 346 delay_free_obj = tmpo; 347 } 348 (void) pthread_mutex_destroy(&obj_delay_freed.obj_to_be_free_mutex); 349 350 delay_free_ses = ses_delay_freed.first; 351 while (delay_free_ses != NULL) { 352 tmps = delay_free_ses->next; 353 free(delay_free_ses); 354 delay_free_ses = tmps; 355 } 356 (void) pthread_mutex_destroy(&ses_delay_freed.ses_to_be_free_mutex); 357 } 358 359 /* 360 * This function cleans up all the resources in the library (user space only) 361 */ 362 static void 363 cleanup_library() 364 { 365 int i; 366 367 /* 368 * Delete all the sessions for each slot and release the allocated 369 * resources from the library. The boolean argument TRUE indicates 370 * that we only wants to clean up the resource in the library only. 371 * We don't want to clean up the corresponding kernel part of 372 * resources, because they are used by the parent process still. 373 */ 374 375 for (i = 0; i < slot_count; i++) { 376 kernel_delete_all_sessions(i, B_TRUE); 377 } 378 379 finalize_common(); 380 } 381 382 static void 383 kernel_init() 384 { 385 (void) pthread_atfork(kernel_fork_prepare, kernel_fork_after, 386 kernel_fork_after); 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 if (kernel_initialized) { 473 kernel_acquire_all_slots_mutexes(); 474 (void) pthread_mutex_lock( 475 &obj_delay_freed.obj_to_be_free_mutex); 476 (void) pthread_mutex_lock( 477 &ses_delay_freed.ses_to_be_free_mutex); 478 (void) pthread_mutex_lock(&mechhash_mutex); 479 } 480 } 481 482 /* 483 * Release in opposite order to kernel_fork_prepare(). 484 * Function is used for parent and child. 485 */ 486 void 487 kernel_fork_after() 488 { 489 if (kernel_initialized) { 490 (void) pthread_mutex_unlock(&mechhash_mutex); 491 (void) pthread_mutex_unlock( 492 &ses_delay_freed.ses_to_be_free_mutex); 493 (void) pthread_mutex_unlock( 494 &obj_delay_freed.obj_to_be_free_mutex); 495 kernel_release_all_slots_mutexes(); 496 } 497 (void) pthread_mutex_unlock(&globalmutex); 498 } 499 500 /* 501 * PKCS#11 states that C_CancelFunction should always return 502 * CKR_FUNCTION_NOT_PARALLEL 503 */ 504 /*ARGSUSED*/ 505 CK_RV 506 C_CancelFunction(CK_SESSION_HANDLE hSession) 507 { 508 return (CKR_FUNCTION_NOT_PARALLEL); 509 } 510