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 <pthread.h> 30 #include <security/cryptoki.h> 31 #include "softGlobal.h" 32 #include "softSession.h" 33 #include "softObject.h" 34 #include "softKeystore.h" 35 #include "softKeystoreUtil.h" 36 37 38 CK_RV 39 C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, 40 CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession) 41 { 42 43 CK_RV rv = CKR_OK; 44 45 if (!softtoken_initialized) 46 return (CKR_CRYPTOKI_NOT_INITIALIZED); 47 48 /* 49 * For legacy reasons, the CKF_SERIAL_SESSION bit must always 50 * be set. 51 */ 52 if (!(flags & CKF_SERIAL_SESSION)) 53 return (CKR_SESSION_PARALLEL_NOT_SUPPORTED); 54 55 if (slotID != SOFTTOKEN_SLOTID) 56 return (CKR_SLOT_ID_INVALID); 57 58 if (phSession == NULL) 59 return (CKR_ARGUMENTS_BAD); 60 61 /* 62 * softtoken has no limit on the number of concurrent sessions 63 * that the token allows. No need to check to see if the 64 * token has too many sessions already open. 65 */ 66 67 /* Create a new session */ 68 rv = soft_add_session(flags, pApplication, Notify, phSession); 69 70 return (rv); 71 72 } 73 74 CK_RV 75 C_CloseSession(CK_SESSION_HANDLE hSession) 76 { 77 78 CK_RV rv; 79 80 soft_session_t *session_p; 81 boolean_t lock_held = B_TRUE; 82 83 if (!softtoken_initialized) 84 return (CKR_CRYPTOKI_NOT_INITIALIZED); 85 86 /* 87 * Obtain the session pointer. Also, increment the session 88 * reference count. 89 */ 90 rv = handle2session(hSession, &session_p); 91 if (rv != CKR_OK) 92 return (rv); 93 94 (void) pthread_mutex_lock(&session_p->session_mutex); 95 /* 96 * Set SESSION_IS_CLOSING flag so any access to this 97 * session will be rejected. 98 */ 99 if (session_p->ses_close_sync & SESSION_IS_CLOSING) { 100 SES_REFRELE(session_p, lock_held); 101 return (CKR_SESSION_CLOSED); 102 } 103 session_p->ses_close_sync |= SESSION_IS_CLOSING; 104 105 /* 106 * Decrement the session reference count. 107 * We hold the session lock, and SES_REFRELE() 108 * will release the session lock for us. 109 */ 110 SES_REFRELE(session_p, lock_held); 111 112 /* 113 * Delete a session by calling soft_delete_session() with 114 * a session pointer and a boolean arguments. Boolean 115 * value FALSE is used to indicate that the caller does not 116 * hold the lock on the global session list and also that 117 * this is not a forced session close but an explicit request. 118 * 119 * soft_delete_session() will reset SESSION_IS_CLOSING 120 * flag after it is done. 121 */ 122 rv = soft_delete_session(session_p, B_FALSE, B_FALSE); 123 124 if (soft_session_cnt == 0) { 125 /* Clean up private token objects from the token object list */ 126 soft_delete_all_in_core_token_objects(PRIVATE_TOKEN); 127 /* 128 * Invalidate public token object handles instead of 129 * deleting them. 130 */ 131 soft_validate_token_objects(B_FALSE); 132 (void) pthread_mutex_lock(&soft_giant_mutex); 133 soft_slot.authenticated = 0; 134 soft_slot.userpin_change_needed = 0; 135 (void) pthread_mutex_unlock(&soft_giant_mutex); 136 } 137 138 return (rv); 139 } 140 141 142 CK_RV 143 C_CloseAllSessions(CK_SLOT_ID slotID) 144 { 145 146 CK_RV rv = CKR_OK; 147 148 if (!softtoken_initialized) 149 return (CKR_CRYPTOKI_NOT_INITIALIZED); 150 151 if (slotID != SOFTTOKEN_SLOTID) 152 return (CKR_SLOT_ID_INVALID); 153 154 /* Acquire the global session list lock */ 155 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 156 /* 157 * Set all_sessions_closing flag so any access to any 158 * existing sessions will be rejected. 159 */ 160 all_sessions_closing = 1; 161 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 162 163 /* Delete all the sessions and release the allocated resources */ 164 rv = soft_delete_all_sessions(B_FALSE); 165 166 /* Clean up private token objects from the token object list */ 167 soft_delete_all_in_core_token_objects(PRIVATE_TOKEN); 168 169 /* Invalidate public token object handles instead of deleting them */ 170 soft_validate_token_objects(B_FALSE); 171 172 (void) pthread_mutex_lock(&soft_giant_mutex); 173 soft_slot.authenticated = 0; 174 soft_slot.userpin_change_needed = 0; 175 (void) pthread_mutex_unlock(&soft_giant_mutex); 176 177 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 178 /* Reset all_sessions_closing flag. */ 179 all_sessions_closing = 0; 180 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 181 182 return (rv); 183 } 184 185 CK_RV 186 C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) 187 { 188 189 soft_session_t *session_p; 190 CK_RV rv; 191 boolean_t lock_held = B_TRUE; 192 193 if (!softtoken_initialized) 194 return (CKR_CRYPTOKI_NOT_INITIALIZED); 195 196 /* 197 * Obtain the session pointer. Also, increment the session 198 * reference count. 199 */ 200 rv = handle2session(hSession, &session_p); 201 if (rv != CKR_OK) 202 return (rv); 203 204 if (pInfo == NULL) { 205 lock_held = B_FALSE; 206 rv = CKR_ARGUMENTS_BAD; 207 goto clean_exit; 208 } 209 210 (void) pthread_mutex_lock(&session_p->session_mutex); 211 212 /* Provide information for the specified session */ 213 pInfo->slotID = SOFTTOKEN_SLOTID; 214 pInfo->state = session_p->state; 215 pInfo->flags = session_p->flags; 216 pInfo->ulDeviceError = 0; 217 218 clean_exit: 219 /* 220 * Decrement the session reference count. 221 * We hold the session lock, and SES_REFRELE() 222 * will release the session lock for us. 223 */ 224 SES_REFRELE(session_p, lock_held); 225 226 return (CKR_OK); 227 } 228 229 230 CK_RV 231 C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 232 CK_ULONG_PTR pulOperationStateLen) 233 { 234 soft_session_t *session_p; 235 CK_RV rv; 236 boolean_t lock_held = B_FALSE; 237 238 if (!softtoken_initialized) 239 return (CKR_CRYPTOKI_NOT_INITIALIZED); 240 241 /* 242 * Obtain the session pointer. Also, increment the session 243 * reference count. 244 */ 245 rv = handle2session(hSession, &session_p); 246 if (rv != CKR_OK) 247 return (rv); 248 249 /* 250 * Only check if pulOperationStateLen is NULL_PTR. 251 * No need to check if pOperationState is NULL_PTR because 252 * application might just ask for the length of buffer to hold 253 * the OperationState. 254 */ 255 if (pulOperationStateLen == NULL_PTR) { 256 rv = CKR_ARGUMENTS_BAD; 257 goto clean_exit; 258 } 259 260 rv = soft_get_operationstate(session_p, pOperationState, 261 pulOperationStateLen); 262 263 clean_exit: 264 SES_REFRELE(session_p, lock_held); 265 return (rv); 266 267 } 268 269 270 CK_RV 271 C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 272 CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, 273 CK_OBJECT_HANDLE hAuthenticationKey) 274 { 275 soft_session_t *session_p; 276 CK_RV rv; 277 boolean_t lock_held = B_FALSE; 278 279 if (!softtoken_initialized) 280 return (CKR_CRYPTOKI_NOT_INITIALIZED); 281 282 /* 283 * Obtain the session pointer. Also, increment the session 284 * reference count. 285 */ 286 rv = handle2session(hSession, &session_p); 287 if (rv != CKR_OK) 288 return (rv); 289 290 if ((pOperationState == NULL_PTR) || 291 (ulOperationStateLen == 0)) { 292 rv = CKR_ARGUMENTS_BAD; 293 goto clean_exit; 294 } 295 296 rv = soft_set_operationstate(session_p, pOperationState, 297 ulOperationStateLen, hEncryptionKey, hAuthenticationKey); 298 299 clean_exit: 300 SES_REFRELE(session_p, lock_held); 301 return (rv); 302 } 303 304 CK_RV 305 C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, 306 CK_ULONG ulPinLen) 307 { 308 309 soft_session_t *session_p, *sp; 310 CK_RV rv; 311 boolean_t lock_held = B_FALSE; 312 313 if (!softtoken_initialized) 314 return (CKR_CRYPTOKI_NOT_INITIALIZED); 315 316 /* 317 * Obtain the session pointer. Also, increment the session 318 * reference count. 319 */ 320 rv = handle2session(hSession, &session_p); 321 if (rv != CKR_OK) 322 return (rv); 323 324 if (!soft_token_present) { 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