xref: /titanic_52/usr/src/lib/pkcs11/pkcs11_softtoken/common/softSession.c (revision 84ab085a13f931bc78e7415e7ce921dbaa14fcb3)
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