xref: /onnv-gate/usr/src/lib/pkcs11/pkcs11_kms/common/kmsSession.c (revision 12720:3db6e0082404)
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