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