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 2004 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 * Se SESSION_IS_CLOSING flag so any access to this 97 * session will be rejected. 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. 113 * 114 * soft_delete_session() will reset SESSION_IS_CLOSING 115 * flag after it is done. 116 */ 117 rv = soft_delete_session(session_p, B_FALSE); 118 119 if (soft_session_cnt == 0) { 120 /* Clean up private token objects from the token object list */ 121 soft_delete_all_in_core_token_objects(PRIVATE_TOKEN); 122 /* 123 * Invalidate public token object handles instead of 124 * deleting them. 125 */ 126 soft_validate_token_objects(B_FALSE); 127 (void) pthread_mutex_lock(&soft_giant_mutex); 128 soft_slot.authenticated = 0; 129 soft_slot.userpin_change_needed = 0; 130 (void) pthread_mutex_unlock(&soft_giant_mutex); 131 } 132 133 return (rv); 134 } 135 136 137 CK_RV 138 C_CloseAllSessions(CK_SLOT_ID slotID) 139 { 140 141 CK_RV rv = CKR_OK; 142 143 if (!softtoken_initialized) 144 return (CKR_CRYPTOKI_NOT_INITIALIZED); 145 146 if (slotID != SOFTTOKEN_SLOTID) 147 return (CKR_SLOT_ID_INVALID); 148 149 /* Acquire the global session list lock */ 150 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 151 /* 152 * Set all_sessions_closing flag so any access to any 153 * existing sessions will be rejected. 154 */ 155 all_sessions_closing = 1; 156 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 157 158 /* Delete all the sessions and release the allocated resources */ 159 rv = soft_delete_all_sessions(); 160 161 /* Clean up private token objects from the token object list */ 162 soft_delete_all_in_core_token_objects(PRIVATE_TOKEN); 163 164 /* Invalidate public token object handles instead of deleting them */ 165 soft_validate_token_objects(B_FALSE); 166 167 (void) pthread_mutex_lock(&soft_giant_mutex); 168 soft_slot.authenticated = 0; 169 soft_slot.userpin_change_needed = 0; 170 (void) pthread_mutex_unlock(&soft_giant_mutex); 171 172 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 173 /* Reset all_sessions_closing flag. */ 174 all_sessions_closing = 0; 175 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 176 177 return (rv); 178 } 179 180 CK_RV 181 C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) 182 { 183 184 soft_session_t *session_p; 185 CK_RV rv; 186 boolean_t lock_held = B_TRUE; 187 188 if (!softtoken_initialized) 189 return (CKR_CRYPTOKI_NOT_INITIALIZED); 190 191 /* 192 * Obtain the session pointer. Also, increment the session 193 * reference count. 194 */ 195 rv = handle2session(hSession, &session_p); 196 if (rv != CKR_OK) 197 return (rv); 198 199 if (pInfo == NULL) { 200 lock_held = B_FALSE; 201 rv = CKR_ARGUMENTS_BAD; 202 goto clean_exit; 203 } 204 205 (void) pthread_mutex_lock(&session_p->session_mutex); 206 207 /* Provide information for the specified session */ 208 pInfo->slotID = SOFTTOKEN_SLOTID; 209 pInfo->state = session_p->state; 210 pInfo->flags = session_p->flags; 211 pInfo->ulDeviceError = 0; 212 213 clean_exit: 214 /* 215 * Decrement the session reference count. 216 * We hold the session lock, and SES_REFRELE() 217 * will release the session lock for us. 218 */ 219 SES_REFRELE(session_p, lock_held); 220 221 return (CKR_OK); 222 } 223 224 225 CK_RV 226 C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 227 CK_ULONG_PTR pulOperationStateLen) 228 { 229 soft_session_t *session_p; 230 CK_RV rv; 231 boolean_t lock_held = B_FALSE; 232 233 if (!softtoken_initialized) 234 return (CKR_CRYPTOKI_NOT_INITIALIZED); 235 236 /* 237 * Obtain the session pointer. Also, increment the session 238 * reference count. 239 */ 240 rv = handle2session(hSession, &session_p); 241 if (rv != CKR_OK) 242 return (rv); 243 244 /* 245 * Only check if pulOperationStateLen is NULL_PTR. 246 * No need to check if pOperationState is NULL_PTR because 247 * application might just ask for the length of buffer to hold 248 * the OperationState. 249 */ 250 if (pulOperationStateLen == NULL_PTR) { 251 rv = CKR_ARGUMENTS_BAD; 252 goto clean_exit; 253 } 254 255 rv = soft_get_operationstate(session_p, pOperationState, 256 pulOperationStateLen); 257 258 clean_exit: 259 SES_REFRELE(session_p, lock_held); 260 return (rv); 261 262 } 263 264 265 CK_RV 266 C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 267 CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, 268 CK_OBJECT_HANDLE hAuthenticationKey) 269 { 270 soft_session_t *session_p; 271 CK_RV rv; 272 boolean_t lock_held = B_FALSE; 273 274 if (!softtoken_initialized) 275 return (CKR_CRYPTOKI_NOT_INITIALIZED); 276 277 /* 278 * Obtain the session pointer. Also, increment the session 279 * reference count. 280 */ 281 rv = handle2session(hSession, &session_p); 282 if (rv != CKR_OK) 283 return (rv); 284 285 if ((pOperationState == NULL_PTR) || 286 (ulOperationStateLen == 0)) { 287 rv = CKR_ARGUMENTS_BAD; 288 goto clean_exit; 289 } 290 291 rv = soft_set_operationstate(session_p, pOperationState, 292 ulOperationStateLen, hEncryptionKey, hAuthenticationKey); 293 294 clean_exit: 295 SES_REFRELE(session_p, lock_held); 296 return (rv); 297 } 298 299 CK_RV 300 C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, 301 CK_ULONG ulPinLen) 302 { 303 304 soft_session_t *session_p, *sp; 305 CK_RV rv; 306 boolean_t lock_held = B_FALSE; 307 308 if (!softtoken_initialized) 309 return (CKR_CRYPTOKI_NOT_INITIALIZED); 310 311 /* 312 * Obtain the session pointer. Also, increment the session 313 * reference count. 314 */ 315 rv = handle2session(hSession, &session_p); 316 if (rv != CKR_OK) 317 return (rv); 318 319 if (!soft_token_present) { 320 SES_REFRELE(session_p, lock_held); 321 return (CKR_DEVICE_REMOVED); 322 } 323 324 if (userType != CKU_USER) { 325 SES_REFRELE(session_p, lock_held); 326 return (CKR_USER_TYPE_INVALID); 327 } 328 329 if ((ulPinLen < MIN_PIN_LEN) || (ulPinLen > MAX_PIN_LEN)) { 330 SES_REFRELE(session_p, lock_held); 331 return (CKR_PIN_LEN_RANGE); 332 } 333 334 if (pPin == NULL_PTR) { 335 /* 336 * We don't support CKF_PROTECTED_AUTHENTICATION_PATH 337 */ 338 SES_REFRELE(session_p, lock_held); 339 return (CKR_ARGUMENTS_BAD); 340 } 341 342 (void) pthread_mutex_lock(&soft_giant_mutex); 343 if (soft_slot.authenticated) { 344 (void) pthread_mutex_unlock(&soft_giant_mutex); 345 SES_REFRELE(session_p, lock_held); 346 return (CKR_USER_ALREADY_LOGGED_IN); 347 } 348 349 rv = soft_login(pPin, ulPinLen); 350 if (rv == CKR_OK) { 351 if (soft_slot.userpin_change_needed) { 352 /* 353 * This is the special case when the PIN is never 354 * initialized in the keystore, which will always 355 * return CKR_OK with "userpin_change_needed" set. 356 */ 357 (void) pthread_mutex_unlock(&soft_giant_mutex); 358 SES_REFRELE(session_p, lock_held); 359 return (rv); 360 } 361 362 soft_slot.authenticated = 1; 363 (void) pthread_mutex_unlock(&soft_giant_mutex); 364 } else { 365 (void) pthread_mutex_unlock(&soft_giant_mutex); 366 SES_REFRELE(session_p, lock_held); 367 return (rv); 368 } 369 370 /* 371 * Load all the private token objects from keystore. 372 */ 373 rv = soft_get_token_objects_from_keystore(PRI_TOKENOBJS); 374 if (rv != CKR_OK) { 375 SES_REFRELE(session_p, lock_held); 376 return (rv); 377 } 378 379 /* Acquire the global session list lock */ 380 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 381 382 sp = soft_session_list; 383 384 while (sp) { 385 (void) pthread_mutex_lock(&sp->session_mutex); 386 387 if (sp->flags & CKF_RW_SESSION) { 388 sp->state = CKS_RW_USER_FUNCTIONS; 389 } else { 390 sp->state = CKS_RO_USER_FUNCTIONS; 391 } 392 (void) pthread_mutex_unlock(&sp->session_mutex); 393 sp = sp->next; 394 } 395 396 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 397 398 SES_REFRELE(session_p, lock_held); 399 return (rv); 400 401 } 402 403 CK_RV 404 C_Logout(CK_SESSION_HANDLE hSession) 405 { 406 407 soft_session_t *session_p, *sp; 408 CK_RV rv; 409 boolean_t lock_held = B_FALSE; 410 411 if (!softtoken_initialized) 412 return (CKR_CRYPTOKI_NOT_INITIALIZED); 413 414 /* 415 * Obtain the session pointer. Also, increment the session 416 * reference count. 417 */ 418 rv = handle2session(hSession, &session_p); 419 if (rv != CKR_OK) 420 return (rv); 421 422 (void) pthread_mutex_lock(&soft_giant_mutex); 423 if (!soft_slot.authenticated) { 424 if (!soft_slot.userpin_change_needed) { 425 /* 426 * Only if the PIN has been initialized in the keystore. 427 */ 428 (void) pthread_mutex_unlock(&soft_giant_mutex); 429 SES_REFRELE(session_p, lock_held); 430 return (CKR_USER_NOT_LOGGED_IN); 431 } else { 432 soft_slot.userpin_change_needed = 0; 433 (void) pthread_mutex_unlock(&soft_giant_mutex); 434 SES_REFRELE(session_p, lock_held); 435 return (CKR_OK); 436 } 437 } 438 439 soft_logout(); 440 soft_slot.authenticated = 0; 441 (void) pthread_mutex_unlock(&soft_giant_mutex); 442 443 /* Acquire the global session list lock */ 444 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 445 446 sp = soft_session_list; 447 448 while (sp) { 449 (void) pthread_mutex_lock(&sp->session_mutex); 450 451 if (sp->flags & CKF_RW_SESSION) { 452 sp->state = CKS_RW_PUBLIC_SESSION; 453 } else { 454 sp->state = CKS_RO_PUBLIC_SESSION; 455 } 456 (void) pthread_mutex_unlock(&sp->session_mutex); 457 sp = sp->next; 458 } 459 460 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 461 462 SES_REFRELE(session_p, lock_held); 463 return (rv); 464 465 } 466