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 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 22 */ 23 24#include <fcntl.h> 25#include <pthread.h> 26#include <strings.h> 27#include <unistd.h> /* for pid */ 28#include <errno.h> 29#include <security/cryptoki.h> 30 31#include "kmsKeystoreUtil.h" 32#include "kmsGlobal.h" 33#include "kmsSession.h" 34#include "kmsSlot.h" 35 36/* 37 * PKCS#11 KMS Crypto provider module. 38 * 39 * This module provides access to a Key Management System (v 2.0) 40 * through the Solaris Cryptographic Framework interfaces (PKCS#11). 41 * 42 * PREREQUISITES 43 * ============= 44 * 1. You must have access to a KMS on the network and you must 45 * know the IP address and name of the "Agent" assigned to 46 * you and the passphrase needed to access the Agent information. 47 * 48 * 2. The token configuration must be completed prior 49 * to using this provider using the kmscfg(1m) utility. 50 * 51 * This provider provides support for 3 AES mechanisms: 52 * CKM_AES_KEY_GEN (for 256 bit keys only) 53 * CKM_AES_CBC (encrypt/decrypt) 54 * CKM_AES_CBC_PAD (encrypt/decrypt) 55 * 56 * DETAILS 57 * ======= 58 * Each user has their own local configuration for the KMS. 59 * The local configuration information is typically located 60 * in a private token directory - /var/tmp/kms/$USERNAME 61 * The location may be overridden using an environment variable 62 * $KMSTOKEN_DIR. The user's private token namespace is configured 63 * using kmscfg(1M) which establishes the directory and populates 64 * it with a simple configuration file that this module later uses 65 * to access the KMS. 66 * 67 * INITIALIZING 68 * ============ 69 * Once the token configuration is established, C_InitToken 70 * is used to initialize the first contact with the KMS. This 71 * will cause the provider to contact the KMS and download 72 * the profile configuration data, a server certificate, and a 73 * private entity key and certificate (in a PKCS#12 file). 74 * Once the above data is collected it is stored under $KMSTOKEN_DIR. 75 * The user may then proceed with normal PKCS#11 activity. 76 * 77 * LOGIN 78 * ===== 79 * The concept of a "Login" is established when the user provides 80 * a PIN that will successfully unwrap the private data in the 81 * PKCS#12 file downloaded earlier when C_InitToken was called. 82 * If the PKCS#12 file is successfully opened, then the user 83 * is considered "logged in" and may use the private key and 84 * certificate to initiate secure communications with the KMS. 85 * 86 * CHANGE PIN 87 * ========== 88 * The C_SetPIN interface may be used to change the passphrase 89 * on the PKCS#12 file and thus effectively change the passphrase 90 * for the token itself (even though the wrapped private key and 91 * certificate do not change). 92 * 93 * KEY STORAGE 94 * =========== 95 * Keys generated in the KMS are always kept securely in the KMS. 96 * The local token area contains only a list of CKA_LABEL values 97 * for all successfully created keys, no sensitive key data 98 * is stored on the client system. When a key is "destroyed", the 99 * local references to that key's label is removed and it is no 100 * longer visible to the token provider. 101 * 102 * NOTE: The KMS itself does not have an interface for destroying 103 * keys, it only allows for the keys to be disassociated from 104 * a particular "DataUnit". Key labels should not be re-used. 105 */ 106#pragma init(kms_init) 107#pragma fini(kms_fini) 108 109static struct CK_FUNCTION_LIST functionList = { 110 { 2, 20 }, /* version */ 111 C_Initialize, 112 C_Finalize, 113 C_GetInfo, 114 C_GetFunctionList, 115 C_GetSlotList, 116 C_GetSlotInfo, 117 C_GetTokenInfo, 118 C_GetMechanismList, 119 C_GetMechanismInfo, 120 C_InitToken, 121 C_InitPIN, 122 C_SetPIN, 123 C_OpenSession, 124 C_CloseSession, 125 C_CloseAllSessions, 126 C_GetSessionInfo, 127 C_GetOperationState, 128 C_SetOperationState, 129 C_Login, 130 C_Logout, 131 C_CreateObject, 132 C_CopyObject, 133 C_DestroyObject, 134 C_GetObjectSize, 135 C_GetAttributeValue, 136 C_SetAttributeValue, 137 C_FindObjectsInit, 138 C_FindObjects, 139 C_FindObjectsFinal, 140 C_EncryptInit, 141 C_Encrypt, 142 C_EncryptUpdate, 143 C_EncryptFinal, 144 C_DecryptInit, 145 C_Decrypt, 146 C_DecryptUpdate, 147 C_DecryptFinal, 148 C_DigestInit, 149 C_Digest, 150 C_DigestUpdate, 151 C_DigestKey, 152 C_DigestFinal, 153 C_SignInit, 154 C_Sign, 155 C_SignUpdate, 156 C_SignFinal, 157 C_SignRecoverInit, 158 C_SignRecover, 159 C_VerifyInit, 160 C_Verify, 161 C_VerifyUpdate, 162 C_VerifyFinal, 163 C_VerifyRecoverInit, 164 C_VerifyRecover, 165 C_DigestEncryptUpdate, 166 C_DecryptDigestUpdate, 167 C_SignEncryptUpdate, 168 C_DecryptVerifyUpdate, 169 C_GenerateKey, 170 C_GenerateKeyPair, 171 C_WrapKey, 172 C_UnwrapKey, 173 C_DeriveKey, 174 C_SeedRandom, 175 C_GenerateRandom, 176 C_GetFunctionStatus, 177 C_CancelFunction, 178 C_WaitForSlotEvent 179}; 180 181boolean_t kms_initialized = B_FALSE; 182static pid_t kms_pid = 0; 183 184 185/* protects kms_initialized and entrance to C_Initialize/Finalize */ 186static pthread_mutex_t globalmutex = PTHREAD_MUTEX_INITIALIZER; 187 188ses_to_be_freed_list_t ses_delay_freed; 189object_to_be_freed_list_t obj_delay_freed; 190kms_elem_t **kms_mechhash; /* Hash table for kCF mech numbers */ 191 192static void kms_finalize_common(); 193static void kms_cleanup_library(); 194static void kms_init(); 195static void kms_fini(); 196static void kms_fork_prepare(); 197static void kms_fork_after(); 198 199CK_RV 200C_Initialize(CK_VOID_PTR pInitArgs) 201{ 202 int initialize_pid; 203 boolean_t supplied_ok; 204 CK_RV rv = CKR_OK; 205 206 /* 207 * Grab lock to insure that only one thread enters this 208 * function at a time. 209 */ 210 (void) pthread_mutex_lock(&globalmutex); 211 initialize_pid = getpid(); 212 213 if (kms_initialized) { 214 if (initialize_pid == kms_pid) { 215 /* 216 * This process has called C_Initialize already 217 */ 218 (void) pthread_mutex_unlock(&globalmutex); 219 return (CKR_CRYPTOKI_ALREADY_INITIALIZED); 220 } else { 221 /* 222 * A fork has happened and the child is 223 * reinitializing. Do a kms_cleanup_library to close 224 * out any state from the parent, and then 225 * continue on. 226 */ 227 kms_cleanup_library(); 228 } 229 } 230 231 if (pInitArgs != NULL) { 232 CK_C_INITIALIZE_ARGS *initargs1 = 233 (CK_C_INITIALIZE_ARGS *) pInitArgs; 234 235 /* pReserved must be NULL */ 236 if (initargs1->pReserved != NULL) { 237 (void) pthread_mutex_unlock(&globalmutex); 238 return (CKR_ARGUMENTS_BAD); 239 } 240 241 /* 242 * ALL supplied function pointers need to have the value 243 * either NULL or non-NULL. 244 */ 245 supplied_ok = (initargs1->CreateMutex == NULL && 246 initargs1->DestroyMutex == NULL && 247 initargs1->LockMutex == NULL && 248 initargs1->UnlockMutex == NULL) || 249 (initargs1->CreateMutex != NULL && 250 initargs1->DestroyMutex != NULL && 251 initargs1->LockMutex != NULL && 252 initargs1->UnlockMutex != NULL); 253 254 if (!supplied_ok) { 255 (void) pthread_mutex_unlock(&globalmutex); 256 return (CKR_ARGUMENTS_BAD); 257 } 258 259 /* 260 * When the CKF_OS_LOCKING_OK flag isn't set and mutex 261 * function pointers are supplied by an application, 262 * return an error. We must be able to use our own locks. 263 */ 264 if (!(initargs1->flags & CKF_OS_LOCKING_OK) && 265 (initargs1->CreateMutex != NULL)) { 266 (void) pthread_mutex_unlock(&globalmutex); 267 return (CKR_CANT_LOCK); 268 } 269 } 270 271 /* Create the hash table */ 272 kms_mechhash = calloc(KMECH_HASHTABLE_SIZE, sizeof (void *)); 273 if (kms_mechhash == NULL) { 274 (void) pthread_mutex_unlock(&globalmutex); 275 return (CKR_HOST_MEMORY); 276 } 277 278 /* Initialize the slot table */ 279 rv = kms_slottable_init(); 280 if (rv != CKR_OK) { 281 free(kms_mechhash); 282 goto end; 283 } 284 285 /* Initialize the object_to_be_freed list */ 286 (void) pthread_mutex_init(&obj_delay_freed.obj_to_be_free_mutex, NULL); 287 obj_delay_freed.count = 0; 288 obj_delay_freed.first = NULL; 289 obj_delay_freed.last = NULL; 290 291 /* Initialize the session_to_be_freed list */ 292 (void) pthread_mutex_init(&ses_delay_freed.ses_to_be_free_mutex, NULL); 293 ses_delay_freed.count = 0; 294 ses_delay_freed.first = NULL; 295 ses_delay_freed.last = NULL; 296 297 rv = KMS_Initialize(); 298 if (rv != CKR_OK) { 299 free(kms_mechhash); 300 goto end; 301 } 302 303 kms_initialized = B_TRUE; 304 kms_pid = initialize_pid; 305 306end: 307 (void) pthread_mutex_unlock(&globalmutex); 308 309 return (CKR_OK); 310} 311 312/* 313 * C_Finalize is a wrapper around kms_finalize_common. The 314 * globalmutex should be locked by C_Finalize(). 315 */ 316CK_RV 317C_Finalize(CK_VOID_PTR pReserved) 318{ 319 (void) pthread_mutex_lock(&globalmutex); 320 321 if (!kms_initialized) { 322 (void) pthread_mutex_unlock(&globalmutex); 323 return (CKR_CRYPTOKI_NOT_INITIALIZED); 324 } 325 326 /* Check to see if pReseved is NULL */ 327 if (pReserved != NULL) { 328 (void) pthread_mutex_unlock(&globalmutex); 329 return (CKR_ARGUMENTS_BAD); 330 } 331 332 /* 333 * Delete all the sessions for each slot and release the allocated 334 * resources 335 */ 336 kms_delete_all_sessions(B_FALSE); 337 338 kms_finalize_common(); 339 340 (void) pthread_mutex_unlock(&globalmutex); 341 342 return (CKR_OK); 343} 344 345/* 346 * kms_finalize_common() does the work for C_Finalize. globalmutex 347 * must be held before calling this function. 348 */ 349static void 350kms_finalize_common() { 351 352 int i; 353 kms_elem_t *elem, *next; 354 kms_object_t *delay_free_obj, *tmpo; 355 kms_session_t *delay_free_ses, *tmps; 356 357 cleanup_slottable(); 358 /* Walk the hash table and free all entries */ 359 for (i = 0; i < KMECH_HASHTABLE_SIZE; i++) { 360 elem = kms_mechhash[i]; 361 while (elem != NULL) { 362 next = elem->knext; 363 free(elem); 364 elem = next; 365 } 366 } 367 368 free(kms_mechhash); 369 370 kms_mechhash = NULL; 371 kms_initialized = B_FALSE; 372 kms_pid = 0; 373 374 /* 375 * free all entries in the delay_freed list 376 */ 377 delay_free_obj = obj_delay_freed.first; 378 while (delay_free_obj != NULL) { 379 tmpo = delay_free_obj->next; 380 free(delay_free_obj); 381 delay_free_obj = tmpo; 382 } 383 obj_delay_freed.count = 0; 384 obj_delay_freed.first = NULL; 385 obj_delay_freed.last = NULL; 386 (void) pthread_mutex_destroy(&obj_delay_freed.obj_to_be_free_mutex); 387 388 delay_free_ses = ses_delay_freed.first; 389 while (delay_free_ses != NULL) { 390 tmps = delay_free_ses->next; 391 free(delay_free_ses); 392 delay_free_ses = tmps; 393 } 394 ses_delay_freed.count = 0; 395 ses_delay_freed.first = NULL; 396 ses_delay_freed.last = NULL; 397 (void) pthread_mutex_destroy(&ses_delay_freed.ses_to_be_free_mutex); 398} 399 400/* 401 * This function cleans up all the resources in the library (user space only) 402 */ 403static void 404kms_cleanup_library() 405{ 406 kms_slot_t *pslot = get_slotinfo(); 407 408 if (pslot) 409 kms_cleanup_pri_objects_in_slot(pslot, NULL); 410 411 /* 412 * Delete all the sessions for each slot and release the allocated 413 * resources from the library. The boolean argument TRUE indicates 414 * that we only wants to clean up the resource in the library only. 415 * We don't want to clean up the corresponding kernel part of 416 * resources, because they are used by the parent process still. 417 */ 418 kms_delete_all_sessions(B_TRUE); 419 420 kms_finalize_common(); 421} 422 423static void 424kms_init() 425{ 426 (void) pthread_atfork(kms_fork_prepare, kms_fork_after, 427 kms_fork_after); 428} 429 430/* 431 * kms_fini() function required to make sure complete cleanup 432 * is done if pkcs11_kms is ever unloaded without 433 * a C_Finalize() call. 434 */ 435static void 436kms_fini() 437{ 438 (void) pthread_mutex_lock(&globalmutex); 439 440 (void) KMS_Finalize(); 441 442 /* if we're not initilized, do not attempt to finalize */ 443 if (!kms_initialized) { 444 (void) pthread_mutex_unlock(&globalmutex); 445 return; 446 } 447 448 kms_cleanup_library(); 449 450 (void) pthread_mutex_unlock(&globalmutex); 451} 452 453CK_RV 454C_GetInfo(CK_INFO_PTR pInfo) 455{ 456 if (!kms_initialized) 457 return (CKR_CRYPTOKI_NOT_INITIALIZED); 458 459 if (pInfo == NULL) { 460 return (CKR_ARGUMENTS_BAD); 461 } 462 463 /* Check if the cryptoki was initialized */ 464 pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR; 465 pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR; 466 (void) strncpy((char *)pInfo->manufacturerID, 467 MANUFACTURER_ID, 32); 468 pInfo->flags = 0; 469 (void) strncpy((char *)pInfo->libraryDescription, 470 LIBRARY_DESCRIPTION, 32); 471 pInfo->libraryVersion.major = LIBRARY_VERSION_MAJOR; 472 pInfo->libraryVersion.minor = LIBRARY_VERSION_MINOR; 473 474 return (CKR_OK); 475} 476 477CK_RV 478C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) 479{ 480 if (ppFunctionList == NULL) { 481 return (CKR_ARGUMENTS_BAD); 482 } 483 484 *ppFunctionList = &functionList; 485 486 return (CKR_OK); 487} 488 489/* 490 * PKCS#11 states that C_GetFunctionStatus should always return 491 * CKR_FUNCTION_NOT_PARALLEL 492 */ 493/*ARGSUSED*/ 494CK_RV 495C_GetFunctionStatus(CK_SESSION_HANDLE hSession) 496{ 497 return (CKR_FUNCTION_NOT_PARALLEL); 498} 499 500/* 501 * Take out all mutexes before fork. 502 * Order: 503 * 1. globalmutex 504 * 2. all slots mutexes (and all their sessions) via 505 * kms_acquire_all_slots_mutexes() 506 * 3. obj_delay_freed.obj_to_be_free_mutex; 507 * 4. ses_delay_freed.ses_to_be_free_mutex 508 */ 509void 510kms_fork_prepare() 511{ 512 (void) pthread_mutex_lock(&globalmutex); 513 if (kms_initialized) { 514 kms_acquire_all_slots_mutexes(); 515 (void) pthread_mutex_lock( 516 &obj_delay_freed.obj_to_be_free_mutex); 517 (void) pthread_mutex_lock( 518 &ses_delay_freed.ses_to_be_free_mutex); 519 } 520} 521 522/* 523 * Release in opposite order to kms_fork_prepare(). 524 * Function is used for parent and child. 525 */ 526void 527kms_fork_after() 528{ 529 if (kms_initialized) { 530 (void) pthread_mutex_unlock( 531 &ses_delay_freed.ses_to_be_free_mutex); 532 (void) pthread_mutex_unlock( 533 &obj_delay_freed.obj_to_be_free_mutex); 534 kms_release_all_slots_mutexes(); 535 } 536 (void) pthread_mutex_unlock(&globalmutex); 537} 538 539/* 540 * PKCS#11 states that C_CancelFunction should always return 541 * CKR_FUNCTION_NOT_PARALLEL 542 */ 543/*ARGSUSED*/ 544CK_RV 545C_CancelFunction(CK_SESSION_HANDLE hSession) 546{ 547 return (CKR_FUNCTION_NOT_PARALLEL); 548} 549