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. 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); 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(); 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 (CKR_OK); 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 if (!soft_token_present) { 324 SES_REFRELE(session_p, lock_held); 325 return (CKR_DEVICE_REMOVED); 326 } 327 328 if (userType != CKU_USER) { 329 SES_REFRELE(session_p, lock_held); 330 return (CKR_USER_TYPE_INVALID); 331 } 332 333 if ((ulPinLen < MIN_PIN_LEN) || (ulPinLen > MAX_PIN_LEN)) { 334 SES_REFRELE(session_p, lock_held); 335 return (CKR_PIN_LEN_RANGE); 336 } 337 338 if (pPin == NULL_PTR) { 339 /* 340 * We don't support CKF_PROTECTED_AUTHENTICATION_PATH 341 */ 342 SES_REFRELE(session_p, lock_held); 343 return (CKR_ARGUMENTS_BAD); 344 } 345 346 (void) pthread_mutex_lock(&soft_giant_mutex); 347 if (soft_slot.authenticated) { 348 (void) pthread_mutex_unlock(&soft_giant_mutex); 349 SES_REFRELE(session_p, lock_held); 350 return (CKR_USER_ALREADY_LOGGED_IN); 351 } 352 353 rv = soft_login(pPin, ulPinLen); 354 if (rv == CKR_OK) { 355 if (soft_slot.userpin_change_needed) { 356 /* 357 * This is the special case when the PIN is never 358 * initialized in the keystore, which will always 359 * return CKR_OK with "userpin_change_needed" set. 360 */ 361 (void) pthread_mutex_unlock(&soft_giant_mutex); 362 SES_REFRELE(session_p, lock_held); 363 return (rv); 364 } 365 366 soft_slot.authenticated = 1; 367 (void) pthread_mutex_unlock(&soft_giant_mutex); 368 } else { 369 (void) pthread_mutex_unlock(&soft_giant_mutex); 370 SES_REFRELE(session_p, lock_held); 371 return (rv); 372 } 373 374 /* 375 * Load all the private token objects from keystore. 376 */ 377 rv = soft_get_token_objects_from_keystore(PRI_TOKENOBJS); 378 if (rv != CKR_OK) { 379 SES_REFRELE(session_p, lock_held); 380 return (rv); 381 } 382 383 /* Acquire the global session list lock */ 384 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 385 386 sp = soft_session_list; 387 388 while (sp) { 389 (void) pthread_mutex_lock(&sp->session_mutex); 390 391 if (sp->flags & CKF_RW_SESSION) { 392 sp->state = CKS_RW_USER_FUNCTIONS; 393 } else { 394 sp->state = CKS_RO_USER_FUNCTIONS; 395 } 396 (void) pthread_mutex_unlock(&sp->session_mutex); 397 sp = sp->next; 398 } 399 400 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 401 402 SES_REFRELE(session_p, lock_held); 403 return (rv); 404 405 } 406 407 CK_RV 408 C_Logout(CK_SESSION_HANDLE hSession) 409 { 410 411 soft_session_t *session_p, *sp; 412 CK_RV rv; 413 boolean_t lock_held = B_FALSE; 414 415 if (!softtoken_initialized) 416 return (CKR_CRYPTOKI_NOT_INITIALIZED); 417 418 /* 419 * Obtain the session pointer. Also, increment the session 420 * reference count. 421 */ 422 rv = handle2session(hSession, &session_p); 423 if (rv != CKR_OK) 424 return (rv); 425 426 (void) pthread_mutex_lock(&soft_giant_mutex); 427 if (!soft_slot.authenticated) { 428 if (!soft_slot.userpin_change_needed) { 429 /* 430 * Only if the PIN has been initialized in the keystore. 431 */ 432 (void) pthread_mutex_unlock(&soft_giant_mutex); 433 SES_REFRELE(session_p, lock_held); 434 return (CKR_USER_NOT_LOGGED_IN); 435 } else { 436 soft_slot.userpin_change_needed = 0; 437 (void) pthread_mutex_unlock(&soft_giant_mutex); 438 SES_REFRELE(session_p, lock_held); 439 return (CKR_OK); 440 } 441 } 442 443 soft_logout(); 444 soft_slot.authenticated = 0; 445 (void) pthread_mutex_unlock(&soft_giant_mutex); 446 447 /* Acquire the global session list lock */ 448 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 449 450 sp = soft_session_list; 451 452 while (sp) { 453 (void) pthread_mutex_lock(&sp->session_mutex); 454 455 if (sp->flags & CKF_RW_SESSION) { 456 sp->state = CKS_RW_PUBLIC_SESSION; 457 } else { 458 sp->state = CKS_RO_PUBLIC_SESSION; 459 } 460 (void) pthread_mutex_unlock(&sp->session_mutex); 461 sp = sp->next; 462 } 463 464 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 465 466 SES_REFRELE(session_p, lock_held); 467 return (rv); 468 469 } 470