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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 *
21 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
22 */
23
24 #include <pthread.h>
25 #include <errno.h>
26 #include <security/cryptoki.h>
27 #include "kmsGlobal.h"
28 #include "kmsSession.h"
29 #include "kmsSlot.h"
30 #include "kmsKeystoreUtil.h"
31
32 CK_RV
C_OpenSession(CK_SLOT_ID slotID,CK_FLAGS flags,CK_VOID_PTR pApplication,CK_NOTIFY Notify,CK_SESSION_HANDLE_PTR phSession)33 C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication,
34 CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession)
35 {
36 CK_RV rv = CKR_OK;
37 kms_slot_t *pslot;
38
39 if (!kms_initialized)
40 return (CKR_CRYPTOKI_NOT_INITIALIZED);
41
42 if (!(flags & CKF_SERIAL_SESSION))
43 return (CKR_SESSION_PARALLEL_NOT_SUPPORTED);
44
45 if (phSession == NULL)
46 return (CKR_ARGUMENTS_BAD);
47
48 if (slotID != KMS_TOKEN_SLOTID) {
49 return (CKR_SLOT_ID_INVALID);
50 }
51
52 /*
53 * Acquire the slot lock to protect sl_state and sl_sess_list.
54 * These two fields need to be protected atomically, even though
55 * "sl_sess_list" is updated in kms_add_session().
56 */
57 pslot = get_slotinfo();
58 (void) pthread_mutex_lock(&pslot->sl_mutex);
59
60 /* If SO is logged in the slot, only the RW session is allowed. */
61 if ((pslot->sl_state == CKU_SO) && !(flags & CKF_RW_SESSION)) {
62 (void) pthread_mutex_unlock(&pslot->sl_mutex);
63 return (CKR_SESSION_READ_WRITE_SO_EXISTS);
64 }
65
66 /* Create a new session */
67 rv = kms_add_session(slotID, flags, pApplication, Notify,
68 phSession);
69
70 (void) pthread_mutex_unlock(&pslot->sl_mutex);
71 return (rv);
72 }
73
74 CK_RV
C_CloseSession(CK_SESSION_HANDLE hSession)75 C_CloseSession(CK_SESSION_HANDLE hSession)
76 {
77 CK_RV rv;
78
79 kms_session_t *session_p;
80 boolean_t ses_lock_held = B_FALSE;
81
82 if (!kms_initialized)
83 return (CKR_CRYPTOKI_NOT_INITIALIZED);
84
85 /*
86 * Obtain the session pointer. Also, increment the session
87 * reference count.
88 */
89 rv = handle2session(hSession, &session_p);
90 if (rv != CKR_OK)
91 return (rv);
92
93 (void) pthread_mutex_lock(&session_p->session_mutex);
94 ses_lock_held = B_TRUE;
95
96 /*
97 * Set SESSION_IS_CLOSING flag so any access to this
98 * session will be rejected.
99 */
100 if (session_p->ses_close_sync & SESSION_IS_CLOSING) {
101 REFRELE(session_p, ses_lock_held);
102 return (CKR_SESSION_CLOSED);
103 }
104 session_p->ses_close_sync |= SESSION_IS_CLOSING;
105
106 /*
107 * Decrement the session reference count.
108 * We hold the session lock, and REFRELE()
109 * will release the session lock for us.
110 */
111 REFRELE(session_p, ses_lock_held);
112
113 /*
114 * Delete a session by calling kms_delete_session() with
115 * a session pointer and two boolean arguments. The 3rd argument
116 * boolean value FALSE indicates that the caller does not
117 * hold the slot lock. The 4th argument boolean value B_FALSE
118 * indicates that we want to delete all the objects completely.
119 *
120 * kms_delete_session() will reset SESSION_IS_CLOSING
121 * flag after it is done.
122 */
123 kms_delete_session(session_p, B_FALSE, B_FALSE);
124 return (rv);
125 }
126
127 /*ARGSUSED*/
128 CK_RV
C_CloseAllSessions(CK_SLOT_ID slotID)129 C_CloseAllSessions(CK_SLOT_ID slotID)
130 {
131 if (!kms_initialized)
132 return (CKR_CRYPTOKI_NOT_INITIALIZED);
133
134 /* Delete all the sessions and release the allocated resources */
135 kms_delete_all_sessions(B_FALSE);
136
137 return (CKR_OK);
138 }
139
140 /*
141 * Utility routine to get CK_STATE value for a session.
142 * The caller should not be holding the session lock.
143 */
144 static CK_STATE
get_ses_state(kms_session_t * session_p)145 get_ses_state(kms_session_t *session_p)
146 {
147 CK_STATE state;
148 kms_slot_t *pslot;
149
150 pslot = get_slotinfo();
151 (void) pthread_mutex_lock(&pslot->sl_mutex);
152
153 if (pslot->sl_state == CKU_PUBLIC) {
154 state = (session_p->ses_RO) ?
155 CKS_RO_PUBLIC_SESSION : CKS_RW_PUBLIC_SESSION;
156 } else if (pslot->sl_state == CKU_USER) {
157 state = (session_p->ses_RO) ?
158 CKS_RO_USER_FUNCTIONS : CKS_RW_USER_FUNCTIONS;
159 } else if (pslot->sl_state == CKU_SO) {
160 state = CKS_RW_SO_FUNCTIONS;
161 }
162
163 (void) pthread_mutex_unlock(&pslot->sl_mutex);
164
165 return (state);
166 }
167
168 CK_RV
C_GetSessionInfo(CK_SESSION_HANDLE hSession,CK_SESSION_INFO_PTR pInfo)169 C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo)
170 {
171 kms_session_t *session_p;
172 CK_RV rv;
173 boolean_t ses_lock_held = B_FALSE;
174
175 if (!kms_initialized)
176 return (CKR_CRYPTOKI_NOT_INITIALIZED);
177
178 if (pInfo == NULL)
179 return (CKR_ARGUMENTS_BAD);
180
181 /*
182 * Obtain the session pointer. Also, increment the session
183 * reference count.
184 */
185 rv = handle2session(hSession, &session_p);
186 if (rv != CKR_OK)
187 return (rv);
188
189 /* Provide information for the specified session */
190 pInfo->slotID = session_p->ses_slotid;
191 pInfo->flags = session_p->flags;
192 pInfo->ulDeviceError = 0;
193 pInfo->state = get_ses_state(session_p);
194
195 /*
196 * Decrement the session reference count.
197 */
198 REFRELE(session_p, ses_lock_held);
199
200 return (rv);
201 }
202
203 /*ARGSUSED*/
204 CK_RV
C_GetOperationState(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pOperationState,CK_ULONG_PTR pulOperationStateLen)205 C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState,
206 CK_ULONG_PTR pulOperationStateLen)
207 {
208 if (!kms_initialized)
209 return (CKR_CRYPTOKI_NOT_INITIALIZED);
210
211 return (CKR_FUNCTION_NOT_SUPPORTED);
212 }
213
214 /*ARGSUSED*/
215 CK_RV
C_SetOperationState(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pOperationState,CK_ULONG ulOperationStateLen,CK_OBJECT_HANDLE hEncryptionKey,CK_OBJECT_HANDLE hAuthenticationKey)216 C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState,
217 CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey,
218 CK_OBJECT_HANDLE hAuthenticationKey)
219 {
220 if (!kms_initialized)
221 return (CKR_CRYPTOKI_NOT_INITIALIZED);
222
223 return (CKR_FUNCTION_NOT_SUPPORTED);
224 }
225
226 CK_RV
C_Login(CK_SESSION_HANDLE hSession,CK_USER_TYPE userType,CK_UTF8CHAR_PTR pPin,CK_ULONG ulPinLen)227 C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
228 CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
229 {
230 CK_RV rv = CKR_OK;
231 kms_session_t *session_p;
232 kms_slot_t *pslot;
233 boolean_t ses_lock_held = B_FALSE;
234
235 if (!kms_initialized)
236 return (CKR_CRYPTOKI_NOT_INITIALIZED);
237
238 if ((userType != CKU_SO) && (userType != CKU_USER)) {
239 return (CKR_USER_TYPE_INVALID);
240 }
241
242 /*
243 * Obtain the session pointer. Also, increment the session
244 * reference count.
245 */
246 rv = handle2session(hSession, &session_p);
247 if (rv != CKR_OK)
248 return (rv);
249
250 /* Acquire the slot lock */
251 pslot = get_slotinfo();
252 (void) pthread_mutex_lock(&pslot->sl_mutex);
253
254 /* Check if the slot is logged in already */
255 if ((pslot->sl_state == CKU_USER) || (pslot->sl_state == CKU_SO)) {
256 rv = CKR_USER_ALREADY_LOGGED_IN;
257 goto clean_exit;
258 }
259
260 /* To login as SO, every session in this slot needs to be R/W */
261 if (userType == CKU_SO) {
262 kms_session_t *sp;
263 boolean_t found;
264
265 found = B_FALSE;
266 sp = pslot->sl_sess_list;
267 while (sp) {
268 /*
269 * Need not to lock individual sessions before
270 * accessing their "ses_RO" and "next" fields,
271 * because they are always accessed under the
272 * slot's mutex protection.
273 */
274 if (sp->ses_RO) {
275 found = B_TRUE;
276 break;
277 }
278 sp = sp->next;
279 }
280
281 if (found) {
282 rv = CKR_SESSION_READ_ONLY_EXISTS;
283 goto clean_exit;
284 }
285 }
286
287 /*
288 * Login to KMS by attempting to load the profile using
289 * the given password.
290 */
291 rv = KMS_LoadProfile(
292 &session_p->kmsProfile,
293 &session_p->configInfo,
294 (const char *)pPin,
295 (size_t)ulPinLen);
296
297 if (rv == CKR_OK) {
298 /* Set the slot's session state. */
299 pslot->sl_state = userType;
300 }
301
302 clean_exit:
303
304 REFRELE(session_p, ses_lock_held);
305 (void) pthread_mutex_unlock(&pslot->sl_mutex);
306 return (rv);
307 }
308
309 CK_RV
C_Logout(CK_SESSION_HANDLE hSession)310 C_Logout(CK_SESSION_HANDLE hSession)
311 {
312 CK_RV rv = CKR_OK;
313 kms_session_t *session_p;
314 kms_slot_t *pslot;
315 boolean_t ses_lock_held = B_FALSE;
316
317 if (!kms_initialized)
318 return (CKR_CRYPTOKI_NOT_INITIALIZED);
319
320 /*
321 * Obtain the session pointer. Also, increment the session
322 * reference count.
323 */
324 rv = handle2session(hSession, &session_p);
325 if (rv != CKR_OK)
326 return (rv);
327
328 /* Acquire the slot lock. */
329 pslot = get_slotinfo();
330 (void) pthread_mutex_lock(&pslot->sl_mutex);
331
332 /* Check if the user or SO was logged in */
333 if (pslot->sl_state == CKU_PUBLIC) {
334 rv = CKR_USER_NOT_LOGGED_IN;
335 goto clean_exit;
336 }
337
338 KMS_UnloadProfile(&session_p->kmsProfile);
339
340 /*
341 * If this slot was logged in as USER previously, we need to clean up
342 * all private object wrappers in library for this slot.
343 */
344 kms_cleanup_pri_objects_in_slot(pslot, session_p);
345
346 if (rv == CKR_OK) {
347 /* Reset the slot's session state. */
348 pslot->sl_state = CKU_PUBLIC;
349 }
350
351 clean_exit:
352 REFRELE(session_p, ses_lock_held);
353 (void) pthread_mutex_unlock(&pslot->sl_mutex);
354 return (rv);
355 }
356