xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_softtoken/common/softSession.c (revision 43d18f1c320355e93c47399bea0b2e022fe06364)
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 <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 	 * Set SESSION_IS_CLOSING flag so any access to this
97 	 * session will be rejected.
98 	 */
99 	if (session_p->ses_close_sync & SESSION_IS_CLOSING) {
100 		SES_REFRELE(session_p, lock_held);
101 		return (CKR_SESSION_CLOSED);
102 	}
103 	session_p->ses_close_sync |= SESSION_IS_CLOSING;
104 
105 	/*
106 	 * Decrement the session reference count.
107 	 * We hold the session lock, and SES_REFRELE()
108 	 * will release the session lock for us.
109 	 */
110 	SES_REFRELE(session_p, lock_held);
111 
112 	/*
113 	 * Delete a session by calling soft_delete_session() with
114 	 * a session pointer and a boolean arguments. Boolean
115 	 * value FALSE is used to indicate that the caller does not
116 	 * hold the lock on the global session list.
117 	 *
118 	 * soft_delete_session() will reset SESSION_IS_CLOSING
119 	 * flag after it is done.
120 	 */
121 	rv = soft_delete_session(session_p, B_FALSE);
122 
123 	if (soft_session_cnt == 0) {
124 		/* Clean up private token objects from the token object list */
125 		soft_delete_all_in_core_token_objects(PRIVATE_TOKEN);
126 		/*
127 		 * Invalidate public token object handles instead of
128 		 * deleting them.
129 		 */
130 		soft_validate_token_objects(B_FALSE);
131 		(void) pthread_mutex_lock(&soft_giant_mutex);
132 		soft_slot.authenticated = 0;
133 		soft_slot.userpin_change_needed = 0;
134 		(void) pthread_mutex_unlock(&soft_giant_mutex);
135 	}
136 
137 	return (rv);
138 }
139 
140 
141 CK_RV
142 C_CloseAllSessions(CK_SLOT_ID slotID)
143 {
144 
145 	CK_RV rv = CKR_OK;
146 
147 	if (!softtoken_initialized)
148 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
149 
150 	if (slotID != SOFTTOKEN_SLOTID)
151 		return (CKR_SLOT_ID_INVALID);
152 
153 	/* Acquire the global session list lock */
154 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
155 	/*
156 	 * Set all_sessions_closing flag so any access to any
157 	 * existing sessions will be rejected.
158 	 */
159 	all_sessions_closing = 1;
160 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
161 
162 	/* Delete all the sessions and release the allocated resources */
163 	rv = soft_delete_all_sessions();
164 
165 	/* Clean up private token objects from the token object list */
166 	soft_delete_all_in_core_token_objects(PRIVATE_TOKEN);
167 
168 	/* Invalidate public token object handles instead of deleting them */
169 	soft_validate_token_objects(B_FALSE);
170 
171 	(void) pthread_mutex_lock(&soft_giant_mutex);
172 	soft_slot.authenticated = 0;
173 	soft_slot.userpin_change_needed = 0;
174 	(void) pthread_mutex_unlock(&soft_giant_mutex);
175 
176 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
177 	/* Reset all_sessions_closing flag. */
178 	all_sessions_closing = 0;
179 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
180 
181 	return (rv);
182 }
183 
184 CK_RV
185 C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo)
186 {
187 
188 	soft_session_t *session_p;
189 	CK_RV rv;
190 	boolean_t lock_held = B_TRUE;
191 
192 	if (!softtoken_initialized)
193 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
194 
195 	/*
196 	 * Obtain the session pointer. Also, increment the session
197 	 * reference count.
198 	 */
199 	rv = handle2session(hSession, &session_p);
200 	if (rv != CKR_OK)
201 		return (rv);
202 
203 	if (pInfo == NULL) {
204 		lock_held = B_FALSE;
205 		rv = CKR_ARGUMENTS_BAD;
206 		goto clean_exit;
207 	}
208 
209 	(void) pthread_mutex_lock(&session_p->session_mutex);
210 
211 	/* Provide information for the specified session */
212 	pInfo->slotID = SOFTTOKEN_SLOTID;
213 	pInfo->state = session_p->state;
214 	pInfo->flags = session_p->flags;
215 	pInfo->ulDeviceError = 0;
216 
217 clean_exit:
218 	/*
219 	 * Decrement the session reference count.
220 	 * We hold the session lock, and SES_REFRELE()
221 	 * will release the session lock for us.
222 	 */
223 	SES_REFRELE(session_p, lock_held);
224 
225 	return (CKR_OK);
226 }
227 
228 
229 CK_RV
230 C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState,
231     CK_ULONG_PTR pulOperationStateLen)
232 {
233 	soft_session_t *session_p;
234 	CK_RV rv;
235 	boolean_t lock_held = B_FALSE;
236 
237 	if (!softtoken_initialized)
238 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
239 
240 	/*
241 	 * Obtain the session pointer. Also, increment the session
242 	 * reference count.
243 	 */
244 	rv = handle2session(hSession, &session_p);
245 	if (rv != CKR_OK)
246 		return (rv);
247 
248 	/*
249 	 * Only check if pulOperationStateLen is NULL_PTR.
250 	 * No need to check if pOperationState is NULL_PTR because
251 	 * application might just ask for the length of buffer to hold
252 	 * the OperationState.
253 	 */
254 	if (pulOperationStateLen == NULL_PTR) {
255 		rv = CKR_ARGUMENTS_BAD;
256 		goto clean_exit;
257 	}
258 
259 	rv = soft_get_operationstate(session_p, pOperationState,
260 	    pulOperationStateLen);
261 
262 clean_exit:
263 	SES_REFRELE(session_p, lock_held);
264 	return (rv);
265 
266 }
267 
268 
269 CK_RV
270 C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState,
271     CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey,
272     CK_OBJECT_HANDLE hAuthenticationKey)
273 {
274 	soft_session_t *session_p;
275 	CK_RV rv;
276 	boolean_t lock_held = B_FALSE;
277 
278 	if (!softtoken_initialized)
279 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
280 
281 	/*
282 	 * Obtain the session pointer. Also, increment the session
283 	 * reference count.
284 	 */
285 	rv = handle2session(hSession, &session_p);
286 	if (rv != CKR_OK)
287 		return (rv);
288 
289 	if ((pOperationState == NULL_PTR) ||
290 	    (ulOperationStateLen == 0)) {
291 		rv = CKR_ARGUMENTS_BAD;
292 		goto clean_exit;
293 	}
294 
295 	rv = soft_set_operationstate(session_p, pOperationState,
296 	    ulOperationStateLen, hEncryptionKey, hAuthenticationKey);
297 
298 clean_exit:
299 	SES_REFRELE(session_p, lock_held);
300 	return (rv);
301 }
302 
303 CK_RV
304 C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin,
305     CK_ULONG ulPinLen)
306 {
307 
308 	soft_session_t *session_p, *sp;
309 	CK_RV rv;
310 	boolean_t lock_held = B_FALSE;
311 
312 	if (!softtoken_initialized)
313 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
314 
315 	/*
316 	 * Obtain the session pointer. Also, increment the session
317 	 * reference count.
318 	 */
319 	rv = handle2session(hSession, &session_p);
320 	if (rv != CKR_OK)
321 		return (rv);
322 
323 	if (!soft_token_present) {
324 		SES_REFRELE(session_p, lock_held);
325 		return (CKR_DEVICE_REMOVED);
326 	}
327 
328 	if (userType != CKU_USER) {
329 		SES_REFRELE(session_p, lock_held);
330 		return (CKR_USER_TYPE_INVALID);
331 	}
332 
333 	if ((ulPinLen < MIN_PIN_LEN) || (ulPinLen > MAX_PIN_LEN)) {
334 		SES_REFRELE(session_p, lock_held);
335 		return (CKR_PIN_LEN_RANGE);
336 	}
337 
338 	if (pPin == NULL_PTR) {
339 		/*
340 		 * We don't support CKF_PROTECTED_AUTHENTICATION_PATH
341 		 */
342 		SES_REFRELE(session_p, lock_held);
343 		return (CKR_ARGUMENTS_BAD);
344 	}
345 
346 	(void) pthread_mutex_lock(&soft_giant_mutex);
347 	if (soft_slot.authenticated) {
348 		(void) pthread_mutex_unlock(&soft_giant_mutex);
349 		SES_REFRELE(session_p, lock_held);
350 		return (CKR_USER_ALREADY_LOGGED_IN);
351 	}
352 
353 	rv = soft_login(pPin, ulPinLen);
354 	if (rv == CKR_OK) {
355 		if (soft_slot.userpin_change_needed) {
356 			/*
357 			 * This is the special case when the PIN is never
358 			 * initialized in the keystore, which will always
359 			 * return CKR_OK with "userpin_change_needed" set.
360 			 */
361 			(void) pthread_mutex_unlock(&soft_giant_mutex);
362 			SES_REFRELE(session_p, lock_held);
363 			return (rv);
364 		}
365 
366 		soft_slot.authenticated = 1;
367 		(void) pthread_mutex_unlock(&soft_giant_mutex);
368 	} else {
369 		(void) pthread_mutex_unlock(&soft_giant_mutex);
370 		SES_REFRELE(session_p, lock_held);
371 		return (rv);
372 	}
373 
374 	/*
375 	 * Load all the private token objects from keystore.
376 	 */
377 	rv = soft_get_token_objects_from_keystore(PRI_TOKENOBJS);
378 	if (rv != CKR_OK) {
379 		SES_REFRELE(session_p, lock_held);
380 		return (rv);
381 	}
382 
383 	/* Acquire the global session list lock */
384 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
385 
386 	sp = soft_session_list;
387 
388 	while (sp) {
389 		(void) pthread_mutex_lock(&sp->session_mutex);
390 
391 		if (sp->flags & CKF_RW_SESSION) {
392 			sp->state = CKS_RW_USER_FUNCTIONS;
393 		} else {
394 			sp->state = CKS_RO_USER_FUNCTIONS;
395 		}
396 		(void) pthread_mutex_unlock(&sp->session_mutex);
397 		sp = sp->next;
398 	}
399 
400 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
401 
402 	SES_REFRELE(session_p, lock_held);
403 	return (rv);
404 
405 }
406 
407 CK_RV
408 C_Logout(CK_SESSION_HANDLE hSession)
409 {
410 
411 	soft_session_t *session_p, *sp;
412 	CK_RV rv;
413 	boolean_t lock_held = B_FALSE;
414 
415 	if (!softtoken_initialized)
416 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
417 
418 	/*
419 	 * Obtain the session pointer. Also, increment the session
420 	 * reference count.
421 	 */
422 	rv = handle2session(hSession, &session_p);
423 	if (rv != CKR_OK)
424 		return (rv);
425 
426 	(void) pthread_mutex_lock(&soft_giant_mutex);
427 	if (!soft_slot.authenticated) {
428 		if (!soft_slot.userpin_change_needed) {
429 			/*
430 			 * Only if the PIN has been initialized in the keystore.
431 			 */
432 			(void) pthread_mutex_unlock(&soft_giant_mutex);
433 			SES_REFRELE(session_p, lock_held);
434 			return (CKR_USER_NOT_LOGGED_IN);
435 		} else {
436 			soft_slot.userpin_change_needed = 0;
437 			(void) pthread_mutex_unlock(&soft_giant_mutex);
438 			SES_REFRELE(session_p, lock_held);
439 			return (CKR_OK);
440 		}
441 	}
442 
443 	soft_logout();
444 	soft_slot.authenticated = 0;
445 	(void) pthread_mutex_unlock(&soft_giant_mutex);
446 
447 	/* Acquire the global session list lock */
448 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
449 
450 	sp = soft_session_list;
451 
452 	while (sp) {
453 		(void) pthread_mutex_lock(&sp->session_mutex);
454 
455 		if (sp->flags & CKF_RW_SESSION) {
456 			sp->state = CKS_RW_PUBLIC_SESSION;
457 		} else {
458 			sp->state = CKS_RO_PUBLIC_SESSION;
459 		}
460 		(void) pthread_mutex_unlock(&sp->session_mutex);
461 		sp = sp->next;
462 	}
463 
464 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
465 
466 	SES_REFRELE(session_p, lock_held);
467 	return (rv);
468 
469 }
470