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