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