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 <errno.h> 31 #include <security/cryptoki.h> 32 #include <sys/crypto/ioctl.h> 33 #include "kernelGlobal.h" 34 #include "kernelSession.h" 35 #include "kernelSlot.h" 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 CK_RV rv = CKR_OK; 42 kernel_slot_t *pslot; 43 44 if (!kernel_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 (phSession == NULL) 55 return (CKR_ARGUMENTS_BAD); 56 57 if (slotID >= slot_count) { 58 return (CKR_SLOT_ID_INVALID); 59 } 60 61 /* 62 * Acquire the slot lock to protect sl_state and sl_sess_list. 63 * These two fields need to be protected atomically, even though 64 * "sl_sess_list" is updated in kernel_add_session(). 65 */ 66 pslot = slot_table[slotID]; 67 (void) pthread_mutex_lock(&pslot->sl_mutex); 68 69 /* If SO is logged in the slot, only the RW session is allowed. */ 70 if ((pslot->sl_state == CKU_SO) && !(flags & CKF_RW_SESSION)) { 71 (void) pthread_mutex_unlock(&pslot->sl_mutex); 72 return (CKR_SESSION_READ_WRITE_SO_EXISTS); 73 } 74 75 /* Create a new session */ 76 rv = kernel_add_session(slotID, flags, pApplication, Notify, 77 phSession); 78 (void) pthread_mutex_unlock(&pslot->sl_mutex); 79 return (rv); 80 } 81 82 CK_RV 83 C_CloseSession(CK_SESSION_HANDLE hSession) 84 { 85 CK_RV rv; 86 87 kernel_session_t *session_p; 88 boolean_t ses_lock_held = B_FALSE; 89 90 if (!kernel_initialized) 91 return (CKR_CRYPTOKI_NOT_INITIALIZED); 92 93 /* 94 * Obtain the session pointer. Also, increment the session 95 * reference count. 96 */ 97 rv = handle2session(hSession, &session_p); 98 if (rv != CKR_OK) 99 return (rv); 100 101 (void) pthread_mutex_lock(&session_p->session_mutex); 102 ses_lock_held = B_TRUE; 103 104 /* 105 * Set SESSION_IS_CLOSING flag so any access to this 106 * session will be rejected. 107 */ 108 session_p->ses_close_sync |= SESSION_IS_CLOSING; 109 110 /* 111 * Decrement the session reference count. 112 * We hold the session lock, and REFRELE() 113 * will release the session lock for us. 114 */ 115 REFRELE(session_p, ses_lock_held); 116 117 /* 118 * Delete a session by calling kernel_delete_session() with 119 * a session pointer and two boolean arguments. The 3rd argument 120 * boolean value FALSE indicates that the caller does not 121 * hold the slot lock. The 4th argument boolean value B_FALSE 122 * indicates that we want to delete all the objects completely. 123 * 124 * kernel_delete_session() will reset SESSION_IS_CLOSING 125 * flag after it is done. 126 */ 127 rv = kernel_delete_session(session_p->ses_slotid, session_p, B_FALSE, 128 B_FALSE); 129 return (rv); 130 } 131 132 133 CK_RV 134 C_CloseAllSessions(CK_SLOT_ID slotID) 135 { 136 CK_RV rv = CKR_OK; 137 138 if (!kernel_initialized) 139 return (CKR_CRYPTOKI_NOT_INITIALIZED); 140 141 /* Delete all the sessions and release the allocated resources */ 142 rv = kernel_delete_all_sessions(slotID, B_FALSE); 143 144 return (rv); 145 } 146 147 CK_RV 148 C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) 149 { 150 kernel_session_t *session_p; 151 CK_RV rv; 152 boolean_t ses_lock_held = B_FALSE; 153 kernel_slot_t *pslot; 154 155 if (!kernel_initialized) 156 return (CKR_CRYPTOKI_NOT_INITIALIZED); 157 158 if (pInfo == NULL) 159 return (CKR_ARGUMENTS_BAD); 160 161 /* 162 * Obtain the session pointer. Also, increment the session 163 * reference count. 164 */ 165 rv = handle2session(hSession, &session_p); 166 if (rv != CKR_OK) 167 return (rv); 168 169 /* Provide information for the specified session */ 170 pInfo->slotID = session_p->ses_slotid; 171 pInfo->flags = session_p->flags; 172 pInfo->ulDeviceError = 0; 173 174 pslot = slot_table[session_p->ses_slotid]; 175 (void) pthread_mutex_lock(&pslot->sl_mutex); 176 177 if (pslot->sl_state == CKU_PUBLIC) { 178 pInfo->state = (session_p->ses_RO) ? 179 CKS_RO_PUBLIC_SESSION : CKS_RW_PUBLIC_SESSION; 180 } else if (pslot->sl_state == CKU_USER) { 181 pInfo->state = (session_p->ses_RO) ? 182 CKS_RO_USER_FUNCTIONS : CKS_RW_USER_FUNCTIONS; 183 } else if (pslot->sl_state == CKU_SO) { 184 pInfo->state = CKS_RW_SO_FUNCTIONS; 185 } 186 187 (void) pthread_mutex_unlock(&pslot->sl_mutex); 188 189 /* 190 * Decrement the session reference count. 191 */ 192 REFRELE(session_p, ses_lock_held); 193 194 return (CKR_OK); 195 } 196 197 198 /*ARGSUSED*/ 199 CK_RV 200 C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 201 CK_ULONG_PTR pulOperationStateLen) 202 { 203 if (!kernel_initialized) 204 return (CKR_CRYPTOKI_NOT_INITIALIZED); 205 206 return (CKR_FUNCTION_NOT_SUPPORTED); 207 } 208 209 210 /*ARGSUSED*/ 211 CK_RV 212 C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 213 CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, 214 CK_OBJECT_HANDLE hAuthenticationKey) 215 { 216 if (!kernel_initialized) 217 return (CKR_CRYPTOKI_NOT_INITIALIZED); 218 219 return (CKR_FUNCTION_NOT_SUPPORTED); 220 } 221 222 223 CK_RV 224 C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, 225 CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) 226 { 227 CK_RV rv = CKR_OK; 228 kernel_session_t *session_p; 229 kernel_slot_t *pslot; 230 boolean_t ses_lock_held = B_FALSE; 231 crypto_login_t c_login; 232 int r; 233 234 if (!kernel_initialized) 235 return (CKR_CRYPTOKI_NOT_INITIALIZED); 236 237 if ((userType != CKU_SO) && (userType != CKU_USER)) { 238 return (CKR_USER_TYPE_INVALID); 239 } 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 /* Acquire the slot lock */ 250 pslot = slot_table[session_p->ses_slotid]; 251 (void) pthread_mutex_lock(&pslot->sl_mutex); 252 253 /* Check if the slot is logged in already */ 254 if ((pslot->sl_state == CKU_USER) || (pslot->sl_state == CKU_SO)) { 255 rv = CKR_USER_ALREADY_LOGGED_IN; 256 goto clean_exit; 257 } 258 259 /* To login as SO, every session in this slot needs to be R/W */ 260 if (userType == CKU_SO) { 261 kernel_session_t *sp; 262 boolean_t found; 263 264 found = B_FALSE; 265 sp = pslot->sl_sess_list; 266 while (sp) { 267 /* 268 * Need not to lock individual sessions before 269 * accessing their "ses_RO" and "next" fields, 270 * because they are always accessed under the 271 * slot's mutex protection. 272 */ 273 if (sp->ses_RO) { 274 found = B_TRUE; 275 break; 276 } 277 sp = sp->next; 278 } 279 280 if (found) { 281 rv = CKR_SESSION_READ_ONLY_EXISTS; 282 goto clean_exit; 283 } 284 } 285 286 /* Now make the ioctl call; no need to acquire the session lock. */ 287 c_login.co_session = session_p->k_session; 288 c_login.co_user_type = userType; 289 c_login.co_pin_len = ulPinLen; 290 c_login.co_pin = (char *)pPin; 291 292 while ((r = ioctl(kernel_fd, CRYPTO_LOGIN, &c_login)) < 0) { 293 if (errno != EINTR) 294 break; 295 } 296 if (r < 0) { 297 rv = CKR_FUNCTION_FAILED; 298 } else { 299 rv = crypto2pkcs11_error_number(c_login.co_return_value); 300 } 301 302 if (rv == CKR_OK) { 303 /* Set the slot's session state. */ 304 pslot->sl_state = userType; 305 } 306 307 clean_exit: 308 309 REFRELE(session_p, ses_lock_held); 310 (void) pthread_mutex_unlock(&pslot->sl_mutex); 311 return (rv); 312 } 313 314 315 CK_RV 316 C_Logout(CK_SESSION_HANDLE hSession) 317 { 318 CK_RV rv = CKR_OK; 319 kernel_session_t *session_p; 320 kernel_slot_t *pslot; 321 boolean_t ses_lock_held = B_FALSE; 322 crypto_logout_t c_logout; 323 int r; 324 325 if (!kernel_initialized) 326 return (CKR_CRYPTOKI_NOT_INITIALIZED); 327 328 /* 329 * Obtain the session pointer. Also, increment the session 330 * reference count. 331 */ 332 rv = handle2session(hSession, &session_p); 333 if (rv != CKR_OK) 334 return (rv); 335 336 /* Acquire the slot lock. */ 337 pslot = slot_table[session_p->ses_slotid]; 338 (void) pthread_mutex_lock(&pslot->sl_mutex); 339 340 /* Check if the user or SO was logged in */ 341 if (pslot->sl_state == CKU_PUBLIC) { 342 rv = CKR_USER_NOT_LOGGED_IN; 343 goto clean_exit; 344 } 345 346 /* Now make the ioctl call. No need to acquire the session lock. */ 347 c_logout.cl_session = session_p->k_session; 348 while ((r = ioctl(kernel_fd, CRYPTO_LOGOUT, &c_logout)) < 0) { 349 if (errno != EINTR) 350 break; 351 } 352 if (r < 0) { 353 rv = CKR_FUNCTION_FAILED; 354 } else { 355 rv = crypto2pkcs11_error_number(c_logout.cl_return_value); 356 } 357 358 if (rv != CKR_OK) { 359 goto clean_exit; 360 } 361 362 /* 363 * If this slot was logged in as USER previously, we need to clean up 364 * all private object wrappers in library for this slot. 365 */ 366 kernel_cleanup_pri_objects_in_slot(pslot, session_p); 367 368 if (rv == CKR_OK) { 369 /* Reset the slot's session state. */ 370 pslot->sl_state = CKU_PUBLIC; 371 } 372 373 clean_exit: 374 REFRELE(session_p, ses_lock_held); 375 (void) pthread_mutex_unlock(&pslot->sl_mutex); 376 return (rv); 377 } 378