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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <fcntl.h> 30 #include <pthread.h> 31 #include <strings.h> 32 #include <unistd.h> /* for pid */ 33 #include <errno.h> 34 #include <security/cryptoki.h> 35 #include "kernelGlobal.h" 36 #include "kernelSession.h" 37 #include "kernelSlot.h" 38 39 #pragma fini(kernel_fini) 40 41 static struct CK_FUNCTION_LIST functionList = { 42 { 2, 20 }, /* version */ 43 C_Initialize, 44 C_Finalize, 45 C_GetInfo, 46 C_GetFunctionList, 47 C_GetSlotList, 48 C_GetSlotInfo, 49 C_GetTokenInfo, 50 C_GetMechanismList, 51 C_GetMechanismInfo, 52 C_InitToken, 53 C_InitPIN, 54 C_SetPIN, 55 C_OpenSession, 56 C_CloseSession, 57 C_CloseAllSessions, 58 C_GetSessionInfo, 59 C_GetOperationState, 60 C_SetOperationState, 61 C_Login, 62 C_Logout, 63 C_CreateObject, 64 C_CopyObject, 65 C_DestroyObject, 66 C_GetObjectSize, 67 C_GetAttributeValue, 68 C_SetAttributeValue, 69 C_FindObjectsInit, 70 C_FindObjects, 71 C_FindObjectsFinal, 72 C_EncryptInit, 73 C_Encrypt, 74 C_EncryptUpdate, 75 C_EncryptFinal, 76 C_DecryptInit, 77 C_Decrypt, 78 C_DecryptUpdate, 79 C_DecryptFinal, 80 C_DigestInit, 81 C_Digest, 82 C_DigestUpdate, 83 C_DigestKey, 84 C_DigestFinal, 85 C_SignInit, 86 C_Sign, 87 C_SignUpdate, 88 C_SignFinal, 89 C_SignRecoverInit, 90 C_SignRecover, 91 C_VerifyInit, 92 C_Verify, 93 C_VerifyUpdate, 94 C_VerifyFinal, 95 C_VerifyRecoverInit, 96 C_VerifyRecover, 97 C_DigestEncryptUpdate, 98 C_DecryptDigestUpdate, 99 C_SignEncryptUpdate, 100 C_DecryptVerifyUpdate, 101 C_GenerateKey, 102 C_GenerateKeyPair, 103 C_WrapKey, 104 C_UnwrapKey, 105 C_DeriveKey, 106 C_SeedRandom, 107 C_GenerateRandom, 108 C_GetFunctionStatus, 109 C_CancelFunction, 110 C_WaitForSlotEvent 111 }; 112 113 boolean_t kernel_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 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 133 int initialize_pid; 134 boolean_t supplied_ok; 135 CK_RV rv = CKR_OK; 136 137 /* 138 * Grab lock to insure that only one thread enters this 139 * function at a time. 140 */ 141 (void) pthread_mutex_lock(&globalmutex); 142 initialize_pid = getpid(); 143 144 if (kernel_initialized) { 145 if (initialize_pid == kernel_pid) { 146 /* 147 * This process has called C_Initialize already 148 */ 149 (void) pthread_mutex_unlock(&globalmutex); 150 return (CKR_CRYPTOKI_ALREADY_INITIALIZED); 151 } else { 152 /* 153 * A fork has happened and the child is 154 * reinitializing. Do a cleanup_library to close 155 * out any state from the parent, and then 156 * continue on. 157 */ 158 cleanup_library(); 159 } 160 } 161 162 if (pInitArgs != NULL) { 163 CK_C_INITIALIZE_ARGS *initargs1 = 164 (CK_C_INITIALIZE_ARGS *) pInitArgs; 165 166 /* pReserved must be NULL */ 167 if (initargs1->pReserved != NULL) { 168 (void) pthread_mutex_unlock(&globalmutex); 169 return (CKR_ARGUMENTS_BAD); 170 } 171 172 /* 173 * ALL supplied function pointers need to have the value 174 * either NULL or non-NULL. 175 */ 176 supplied_ok = (initargs1->CreateMutex == NULL && 177 initargs1->DestroyMutex == NULL && 178 initargs1->LockMutex == NULL && 179 initargs1->UnlockMutex == NULL) || 180 (initargs1->CreateMutex != NULL && 181 initargs1->DestroyMutex != NULL && 182 initargs1->LockMutex != NULL && 183 initargs1->UnlockMutex != NULL); 184 185 if (!supplied_ok) { 186 (void) pthread_mutex_unlock(&globalmutex); 187 return (CKR_ARGUMENTS_BAD); 188 } 189 190 /* 191 * When the CKF_OS_LOCKING_OK flag isn't set and mutex 192 * function pointers are supplied by an application, 193 * return an error. We must be able to use our own locks. 194 */ 195 if (!(initargs1->flags & CKF_OS_LOCKING_OK) && 196 (initargs1->CreateMutex != NULL)) { 197 (void) pthread_mutex_unlock(&globalmutex); 198 return (CKR_CANT_LOCK); 199 } 200 } 201 202 while ((kernel_fd = open(CRYPTO_DEVICE, O_RDWR)) < 0) { 203 if (errno != EINTR) 204 break; 205 } 206 if (kernel_fd < 0) { 207 (void) pthread_mutex_unlock(&globalmutex); 208 return (CKR_FUNCTION_FAILED); 209 } 210 211 /* Mark kernel_fd "close on exec" */ 212 (void) fcntl(kernel_fd, F_SETFD, FD_CLOEXEC); 213 214 /* Initialize the slot table */ 215 rv = kernel_slottable_init(); 216 if (rv != CKR_OK) { 217 (void) close(kernel_fd); 218 (void) pthread_mutex_unlock(&globalmutex); 219 return (rv); 220 } 221 222 /* Initialize the object_to_be_freed list */ 223 (void) pthread_mutex_init(&obj_delay_freed.obj_to_be_free_mutex, NULL); 224 obj_delay_freed.count = 0; 225 obj_delay_freed.first = NULL; 226 obj_delay_freed.last = NULL; 227 228 /* Initialize the session_to_be_freed list */ 229 (void) pthread_mutex_init(&ses_delay_freed.ses_to_be_free_mutex, NULL); 230 ses_delay_freed.count = 0; 231 ses_delay_freed.first = NULL; 232 ses_delay_freed.last = NULL; 233 234 kernel_initialized = B_TRUE; 235 kernel_pid = initialize_pid; 236 237 (void) pthread_mutex_unlock(&globalmutex); 238 239 return (CKR_OK); 240 241 } 242 243 244 /* 245 * C_Finalize is a wrapper around finalize_common. The 246 * globalmutex should be locked by C_Finalize(). 247 */ 248 CK_RV 249 C_Finalize(CK_VOID_PTR pReserved) 250 { 251 int i; 252 253 (void) pthread_mutex_lock(&globalmutex); 254 255 if (!kernel_initialized) { 256 (void) pthread_mutex_unlock(&globalmutex); 257 return (CKR_CRYPTOKI_NOT_INITIALIZED); 258 } 259 260 /* Check to see if pReseved is NULL */ 261 if (pReserved != NULL) { 262 (void) pthread_mutex_unlock(&globalmutex); 263 return (CKR_ARGUMENTS_BAD); 264 } 265 266 /* 267 * Delete all the sessions for each slot and release the allocated 268 * resources 269 */ 270 for (i = 0; i < slot_count; i++) { 271 kernel_delete_all_sessions(i, B_FALSE); 272 } 273 274 finalize_common(); 275 276 (void) pthread_mutex_unlock(&globalmutex); 277 278 return (CKR_OK); 279 } 280 281 /* 282 * finalize_common() does the work for C_Finalize. globalmutex 283 * must be held before calling this function. 284 */ 285 static void 286 finalize_common() { 287 288 int i; 289 kernel_object_t *delay_free_obj, *tmpo; 290 kernel_session_t *delay_free_ses, *tmps; 291 292 /* 293 * Free the resources allocated for the slot table and reset 294 * slot_count to 0. 295 */ 296 if (slot_count > 0) { 297 for (i = 0; i < slot_count; i++) { 298 (void) pthread_mutex_destroy(&slot_table[i]->sl_mutex); 299 (void) free(slot_table[i]); 300 } 301 (void) free(slot_table); 302 slot_count = 0; 303 } 304 305 /* Close CRYPTO_DEVICE */ 306 if (kernel_fd >= 0) { 307 (void) close(kernel_fd); 308 } 309 310 kernel_fd = -1; 311 kernel_initialized = B_FALSE; 312 kernel_pid = 0; 313 314 /* 315 * free all entries in the delay_freed list 316 */ 317 delay_free_obj = obj_delay_freed.first; 318 while (delay_free_obj != NULL) { 319 tmpo = delay_free_obj->next; 320 free(delay_free_obj); 321 delay_free_obj = tmpo; 322 } 323 (void) pthread_mutex_destroy(&obj_delay_freed.obj_to_be_free_mutex); 324 325 delay_free_ses = ses_delay_freed.first; 326 while (delay_free_ses != NULL) { 327 tmps = delay_free_ses->next; 328 free(delay_free_ses); 329 delay_free_ses = tmps; 330 } 331 (void) pthread_mutex_destroy(&ses_delay_freed.ses_to_be_free_mutex); 332 } 333 334 /* 335 * This function cleans up all the resources in the library (user space only) 336 */ 337 static void 338 cleanup_library() 339 { 340 int i; 341 342 /* 343 * Delete all the sessions for each slot and release the allocated 344 * resources from the library. The boolean argument TRUE indicates 345 * that we only wants to clean up the resource in the library only. 346 * We don't want to clean up the corresponding kernel part of 347 * resources, because they are used by the parent process still. 348 */ 349 350 for (i = 0; i < slot_count; i++) { 351 kernel_delete_all_sessions(i, B_TRUE); 352 } 353 354 finalize_common(); 355 } 356 357 /* 358 * kernel_fini() function required to make sure complete cleanup 359 * is done if pkcs11_kernel is ever unloaded without 360 * a C_Finalize() call. 361 */ 362 static void 363 kernel_fini() 364 { 365 366 (void) pthread_mutex_lock(&globalmutex); 367 368 /* if we're not initilized, do not attempt to finalize */ 369 if (!kernel_initialized) { 370 (void) pthread_mutex_unlock(&globalmutex); 371 return; 372 } 373 374 cleanup_library(); 375 376 (void) pthread_mutex_unlock(&globalmutex); 377 } 378 379 CK_RV 380 C_GetInfo(CK_INFO_PTR pInfo) 381 { 382 if (!kernel_initialized) 383 return (CKR_CRYPTOKI_NOT_INITIALIZED); 384 385 if (pInfo == NULL) { 386 return (CKR_ARGUMENTS_BAD); 387 } 388 389 /* Check if the cryptoki was initialized */ 390 391 pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR; 392 pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR; 393 (void) strncpy((char *)pInfo->manufacturerID, 394 MANUFACTURER_ID, 32); 395 pInfo->flags = 0; 396 (void) strncpy((char *)pInfo->libraryDescription, 397 LIBRARY_DESCRIPTION, 32); 398 pInfo->libraryVersion.major = LIBRARY_VERSION_MAJOR; 399 pInfo->libraryVersion.minor = LIBRARY_VERSION_MINOR; 400 401 return (CKR_OK); 402 } 403 404 CK_RV 405 C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) 406 { 407 if (ppFunctionList == NULL) { 408 return (CKR_ARGUMENTS_BAD); 409 } 410 411 *ppFunctionList = &functionList; 412 413 return (CKR_OK); 414 } 415 416 /* 417 * PKCS#11 states that C_GetFunctionStatus should always return 418 * CKR_FUNCTION_NOT_PARALLEL 419 */ 420 /*ARGSUSED*/ 421 CK_RV 422 C_GetFunctionStatus(CK_SESSION_HANDLE hSession) 423 { 424 return (CKR_FUNCTION_NOT_PARALLEL); 425 } 426 427 /* 428 * PKCS#11 states that C_CancelFunction should always return 429 * CKR_FUNCTION_NOT_PARALLEL 430 */ 431 /*ARGSUSED*/ 432 CK_RV 433 C_CancelFunction(CK_SESSION_HANDLE hSession) 434 { 435 return (CKR_FUNCTION_NOT_PARALLEL); 436 } 437