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 2007 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 <pthread.h> 29 #include <security/cryptoki.h> 30 #include "softGlobal.h" 31 #include "softSession.h" 32 #include "softObject.h" 33 #include "softKeystore.h" 34 #include "softKeystoreUtil.h" 35 36 37 CK_RV 38 C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, 39 CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession) 40 { 41 42 CK_RV rv = CKR_OK; 43 44 if (!softtoken_initialized) 45 return (CKR_CRYPTOKI_NOT_INITIALIZED); 46 47 /* 48 * For legacy reasons, the CKF_SERIAL_SESSION bit must always 49 * be set. 50 */ 51 if (!(flags & CKF_SERIAL_SESSION)) 52 return (CKR_SESSION_PARALLEL_NOT_SUPPORTED); 53 54 if (slotID != SOFTTOKEN_SLOTID) 55 return (CKR_SLOT_ID_INVALID); 56 57 if (phSession == NULL) 58 return (CKR_ARGUMENTS_BAD); 59 60 /* 61 * softtoken has no limit on the number of concurrent sessions 62 * that the token allows. No need to check to see if the 63 * token has too many sessions already open. 64 */ 65 66 /* Create a new session */ 67 rv = soft_add_session(flags, pApplication, Notify, phSession); 68 69 return (rv); 70 71 } 72 73 CK_RV 74 C_CloseSession(CK_SESSION_HANDLE hSession) 75 { 76 77 CK_RV rv; 78 79 soft_session_t *session_p; 80 boolean_t lock_held = B_TRUE; 81 82 if (!softtoken_initialized) 83 return (CKR_CRYPTOKI_NOT_INITIALIZED); 84 85 /* 86 * Obtain the session pointer. Also, increment the session 87 * reference count. 88 */ 89 rv = handle2session(hSession, &session_p); 90 if (rv != CKR_OK) 91 return (rv); 92 93 (void) pthread_mutex_lock(&session_p->session_mutex); 94 /* 95 * Set SESSION_IS_CLOSING flag so any access to this 96 * session will be rejected. 97 */ 98 if (session_p->ses_close_sync & SESSION_IS_CLOSING) { 99 SES_REFRELE(session_p, lock_held); 100 return (CKR_SESSION_CLOSED); 101 } 102 session_p->ses_close_sync |= SESSION_IS_CLOSING; 103 104 /* 105 * Decrement the session reference count. 106 * We hold the session lock, and SES_REFRELE() 107 * will release the session lock for us. 108 */ 109 SES_REFRELE(session_p, lock_held); 110 111 /* 112 * Delete a session by calling soft_delete_session() with 113 * a session pointer and a boolean arguments. Boolean 114 * value FALSE is used to indicate that the caller does not 115 * hold the lock on the global session list and also that 116 * this is not a forced session close but an explicit request. 117 * 118 * soft_delete_session() will reset SESSION_IS_CLOSING 119 * flag after it is done. 120 */ 121 rv = soft_delete_session(session_p, B_FALSE, B_FALSE); 122 123 if (soft_session_cnt == 0) { 124 /* Clean up private token objects from the token object list */ 125 soft_delete_all_in_core_token_objects(PRIVATE_TOKEN); 126 /* 127 * Invalidate public token object handles instead of 128 * deleting them. 129 */ 130 soft_validate_token_objects(B_FALSE); 131 (void) pthread_mutex_lock(&soft_giant_mutex); 132 soft_slot.authenticated = 0; 133 soft_slot.userpin_change_needed = 0; 134 (void) pthread_mutex_unlock(&soft_giant_mutex); 135 } 136 137 return (rv); 138 } 139 140 141 CK_RV 142 C_CloseAllSessions(CK_SLOT_ID slotID) 143 { 144 145 CK_RV rv = CKR_OK; 146 147 if (!softtoken_initialized) 148 return (CKR_CRYPTOKI_NOT_INITIALIZED); 149 150 if (slotID != SOFTTOKEN_SLOTID) 151 return (CKR_SLOT_ID_INVALID); 152 153 /* Acquire the global session list lock */ 154 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 155 /* 156 * Set all_sessions_closing flag so any access to any 157 * existing sessions will be rejected. 158 */ 159 all_sessions_closing = 1; 160 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 161 162 /* Delete all the sessions and release the allocated resources */ 163 rv = soft_delete_all_sessions(B_FALSE); 164 165 /* Clean up private token objects from the token object list */ 166 soft_delete_all_in_core_token_objects(PRIVATE_TOKEN); 167 168 /* Invalidate public token object handles instead of deleting them */ 169 soft_validate_token_objects(B_FALSE); 170 171 (void) pthread_mutex_lock(&soft_giant_mutex); 172 soft_slot.authenticated = 0; 173 soft_slot.userpin_change_needed = 0; 174 (void) pthread_mutex_unlock(&soft_giant_mutex); 175 176 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 177 /* Reset all_sessions_closing flag. */ 178 all_sessions_closing = 0; 179 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 180 181 return (rv); 182 } 183 184 CK_RV 185 C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) 186 { 187 188 soft_session_t *session_p; 189 CK_RV rv; 190 boolean_t lock_held = B_TRUE; 191 192 if (!softtoken_initialized) 193 return (CKR_CRYPTOKI_NOT_INITIALIZED); 194 195 /* 196 * Obtain the session pointer. Also, increment the session 197 * reference count. 198 */ 199 rv = handle2session(hSession, &session_p); 200 if (rv != CKR_OK) 201 return (rv); 202 203 if (pInfo == NULL) { 204 lock_held = B_FALSE; 205 rv = CKR_ARGUMENTS_BAD; 206 goto clean_exit; 207 } 208 209 (void) pthread_mutex_lock(&session_p->session_mutex); 210 211 /* Provide information for the specified session */ 212 pInfo->slotID = SOFTTOKEN_SLOTID; 213 pInfo->state = session_p->state; 214 pInfo->flags = session_p->flags; 215 pInfo->ulDeviceError = 0; 216 217 clean_exit: 218 /* 219 * Decrement the session reference count. 220 * We hold the session lock, and SES_REFRELE() 221 * will release the session lock for us. 222 */ 223 SES_REFRELE(session_p, lock_held); 224 225 return (rv); 226 } 227 228 229 CK_RV 230 C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 231 CK_ULONG_PTR pulOperationStateLen) 232 { 233 soft_session_t *session_p; 234 CK_RV rv; 235 boolean_t lock_held = B_FALSE; 236 237 if (!softtoken_initialized) 238 return (CKR_CRYPTOKI_NOT_INITIALIZED); 239 240 /* 241 * Obtain the session pointer. Also, increment the session 242 * reference count. 243 */ 244 rv = handle2session(hSession, &session_p); 245 if (rv != CKR_OK) 246 return (rv); 247 248 /* 249 * Only check if pulOperationStateLen is NULL_PTR. 250 * No need to check if pOperationState is NULL_PTR because 251 * application might just ask for the length of buffer to hold 252 * the OperationState. 253 */ 254 if (pulOperationStateLen == NULL_PTR) { 255 rv = CKR_ARGUMENTS_BAD; 256 goto clean_exit; 257 } 258 259 rv = soft_get_operationstate(session_p, pOperationState, 260 pulOperationStateLen); 261 262 clean_exit: 263 SES_REFRELE(session_p, lock_held); 264 return (rv); 265 266 } 267 268 269 CK_RV 270 C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 271 CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, 272 CK_OBJECT_HANDLE hAuthenticationKey) 273 { 274 soft_session_t *session_p; 275 CK_RV rv; 276 boolean_t lock_held = B_FALSE; 277 278 if (!softtoken_initialized) 279 return (CKR_CRYPTOKI_NOT_INITIALIZED); 280 281 /* 282 * Obtain the session pointer. Also, increment the session 283 * reference count. 284 */ 285 rv = handle2session(hSession, &session_p); 286 if (rv != CKR_OK) 287 return (rv); 288 289 if ((pOperationState == NULL_PTR) || 290 (ulOperationStateLen == 0)) { 291 rv = CKR_ARGUMENTS_BAD; 292 goto clean_exit; 293 } 294 295 rv = soft_set_operationstate(session_p, pOperationState, 296 ulOperationStateLen, hEncryptionKey, hAuthenticationKey); 297 298 clean_exit: 299 SES_REFRELE(session_p, lock_held); 300 return (rv); 301 } 302 303 CK_RV 304 C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, 305 CK_ULONG ulPinLen) 306 { 307 308 soft_session_t *session_p, *sp; 309 CK_RV rv; 310 boolean_t lock_held = B_FALSE; 311 312 if (!softtoken_initialized) 313 return (CKR_CRYPTOKI_NOT_INITIALIZED); 314 315 /* 316 * Obtain the session pointer. Also, increment the session 317 * reference count. 318 */ 319 rv = handle2session(hSession, &session_p); 320 if (rv != CKR_OK) 321 return (rv); 322 323 /* Check the load status of keystore */ 324 if (!soft_keystore_status(KEYSTORE_VERSION_OK)) { 325 SES_REFRELE(session_p, lock_held); 326 return (CKR_DEVICE_REMOVED); 327 } 328 329 if (userType != CKU_USER) { 330 SES_REFRELE(session_p, lock_held); 331 return (CKR_USER_TYPE_INVALID); 332 } 333 334 if ((ulPinLen < MIN_PIN_LEN) || (ulPinLen > MAX_PIN_LEN)) { 335 SES_REFRELE(session_p, lock_held); 336 return (CKR_PIN_LEN_RANGE); 337 } 338 339 if (pPin == NULL_PTR) { 340 /* 341 * We don't support CKF_PROTECTED_AUTHENTICATION_PATH 342 */ 343 SES_REFRELE(session_p, lock_held); 344 return (CKR_ARGUMENTS_BAD); 345 } 346 347 (void) pthread_mutex_lock(&soft_giant_mutex); 348 if (soft_slot.authenticated) { 349 (void) pthread_mutex_unlock(&soft_giant_mutex); 350 SES_REFRELE(session_p, lock_held); 351 return (CKR_USER_ALREADY_LOGGED_IN); 352 } 353 354 rv = soft_login(pPin, ulPinLen); 355 if (rv == CKR_OK) { 356 if (soft_slot.userpin_change_needed) { 357 /* 358 * This is the special case when the PIN is never 359 * initialized in the keystore, which will always 360 * return CKR_OK with "userpin_change_needed" set. 361 */ 362 (void) pthread_mutex_unlock(&soft_giant_mutex); 363 SES_REFRELE(session_p, lock_held); 364 return (rv); 365 } 366 367 soft_slot.authenticated = 1; 368 (void) pthread_mutex_unlock(&soft_giant_mutex); 369 } else { 370 (void) pthread_mutex_unlock(&soft_giant_mutex); 371 SES_REFRELE(session_p, lock_held); 372 return (rv); 373 } 374 375 /* 376 * Load all the private token objects from keystore. 377 */ 378 rv = soft_get_token_objects_from_keystore(PRI_TOKENOBJS); 379 if (rv != CKR_OK) { 380 SES_REFRELE(session_p, lock_held); 381 return (rv); 382 } 383 384 /* Acquire the global session list lock */ 385 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 386 387 sp = soft_session_list; 388 389 while (sp) { 390 (void) pthread_mutex_lock(&sp->session_mutex); 391 392 if (sp->flags & CKF_RW_SESSION) { 393 sp->state = CKS_RW_USER_FUNCTIONS; 394 } else { 395 sp->state = CKS_RO_USER_FUNCTIONS; 396 } 397 (void) pthread_mutex_unlock(&sp->session_mutex); 398 sp = sp->next; 399 } 400 401 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 402 403 SES_REFRELE(session_p, lock_held); 404 return (rv); 405 406 } 407 408 CK_RV 409 C_Logout(CK_SESSION_HANDLE hSession) 410 { 411 412 soft_session_t *session_p, *sp; 413 CK_RV rv; 414 boolean_t lock_held = B_FALSE; 415 416 if (!softtoken_initialized) 417 return (CKR_CRYPTOKI_NOT_INITIALIZED); 418 419 /* 420 * Obtain the session pointer. Also, increment the session 421 * reference count. 422 */ 423 rv = handle2session(hSession, &session_p); 424 if (rv != CKR_OK) 425 return (rv); 426 427 (void) pthread_mutex_lock(&soft_giant_mutex); 428 if (!soft_slot.authenticated) { 429 if (!soft_slot.userpin_change_needed) { 430 /* 431 * Only if the PIN has been initialized in the keystore. 432 */ 433 (void) pthread_mutex_unlock(&soft_giant_mutex); 434 SES_REFRELE(session_p, lock_held); 435 return (CKR_USER_NOT_LOGGED_IN); 436 } else { 437 soft_slot.userpin_change_needed = 0; 438 (void) pthread_mutex_unlock(&soft_giant_mutex); 439 SES_REFRELE(session_p, lock_held); 440 return (CKR_OK); 441 } 442 } 443 444 soft_logout(); 445 soft_slot.authenticated = 0; 446 (void) pthread_mutex_unlock(&soft_giant_mutex); 447 448 /* Acquire the global session list lock */ 449 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 450 451 sp = soft_session_list; 452 453 while (sp) { 454 (void) pthread_mutex_lock(&sp->session_mutex); 455 456 if (sp->flags & CKF_RW_SESSION) { 457 sp->state = CKS_RW_PUBLIC_SESSION; 458 } else { 459 sp->state = CKS_RO_PUBLIC_SESSION; 460 } 461 (void) pthread_mutex_unlock(&sp->session_mutex); 462 sp = sp->next; 463 } 464 465 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 466 467 SES_REFRELE(session_p, lock_held); 468 return (rv); 469 470 } 471