xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_softtoken/common/softSession.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <pthread.h>
29 #include <security/cryptoki.h>
30 #include "softGlobal.h"
31 #include "softSession.h"
32 #include "softObject.h"
33 #include "softKeystore.h"
34 #include "softKeystoreUtil.h"
35 
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 
42 	CK_RV rv = CKR_OK;
43 
44 	if (!softtoken_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 (slotID != SOFTTOKEN_SLOTID)
55 		return (CKR_SLOT_ID_INVALID);
56 
57 	if (phSession == NULL)
58 		return (CKR_ARGUMENTS_BAD);
59 
60 	/*
61 	 * softtoken has no limit on the number of concurrent sessions
62 	 * that the token allows. No need to check to see if the
63 	 * token has too many sessions already open.
64 	 */
65 
66 	/* Create a new session */
67 	rv = soft_add_session(flags, pApplication, Notify, phSession);
68 
69 	return (rv);
70 
71 }
72 
73 CK_RV
74 C_CloseSession(CK_SESSION_HANDLE hSession)
75 {
76 
77 	CK_RV rv;
78 
79 	soft_session_t *session_p;
80 	boolean_t lock_held = B_TRUE;
81 
82 	if (!softtoken_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 	/*
95 	 * Set SESSION_IS_CLOSING flag so any access to this
96 	 * session will be rejected.
97 	 */
98 	if (session_p->ses_close_sync & SESSION_IS_CLOSING) {
99 		SES_REFRELE(session_p, lock_held);
100 		return (CKR_SESSION_CLOSED);
101 	}
102 	session_p->ses_close_sync |= SESSION_IS_CLOSING;
103 
104 	/*
105 	 * Decrement the session reference count.
106 	 * We hold the session lock, and SES_REFRELE()
107 	 * will release the session lock for us.
108 	 */
109 	SES_REFRELE(session_p, lock_held);
110 
111 	/*
112 	 * Delete a session by calling soft_delete_session() with
113 	 * a session pointer and a boolean arguments. Boolean
114 	 * value FALSE is used to indicate that the caller does not
115 	 * hold the lock on the global session list and also that
116 	 * this is not a forced session close but an explicit request.
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, 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(B_FALSE);
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 (rv);
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 	/* Check the load status of keystore */
324 	if (!soft_keystore_status(KEYSTORE_VERSION_OK)) {
325 		SES_REFRELE(session_p, lock_held);
326 		return (CKR_DEVICE_REMOVED);
327 	}
328 
329 	if (userType != CKU_USER) {
330 		SES_REFRELE(session_p, lock_held);
331 		return (CKR_USER_TYPE_INVALID);
332 	}
333 
334 	if ((ulPinLen < MIN_PIN_LEN) || (ulPinLen > MAX_PIN_LEN)) {
335 		SES_REFRELE(session_p, lock_held);
336 		return (CKR_PIN_LEN_RANGE);
337 	}
338 
339 	if (pPin == NULL_PTR) {
340 		/*
341 		 * We don't support CKF_PROTECTED_AUTHENTICATION_PATH
342 		 */
343 		SES_REFRELE(session_p, lock_held);
344 		return (CKR_ARGUMENTS_BAD);
345 	}
346 
347 	(void) pthread_mutex_lock(&soft_giant_mutex);
348 	if (soft_slot.authenticated) {
349 		(void) pthread_mutex_unlock(&soft_giant_mutex);
350 		SES_REFRELE(session_p, lock_held);
351 		return (CKR_USER_ALREADY_LOGGED_IN);
352 	}
353 
354 	rv = soft_login(pPin, ulPinLen);
355 	if (rv == CKR_OK) {
356 		if (soft_slot.userpin_change_needed) {
357 			/*
358 			 * This is the special case when the PIN is never
359 			 * initialized in the keystore, which will always
360 			 * return CKR_OK with "userpin_change_needed" set.
361 			 */
362 			(void) pthread_mutex_unlock(&soft_giant_mutex);
363 			SES_REFRELE(session_p, lock_held);
364 			return (rv);
365 		}
366 
367 		soft_slot.authenticated = 1;
368 		(void) pthread_mutex_unlock(&soft_giant_mutex);
369 	} else {
370 		(void) pthread_mutex_unlock(&soft_giant_mutex);
371 		SES_REFRELE(session_p, lock_held);
372 		return (rv);
373 	}
374 
375 	/*
376 	 * Load all the private token objects from keystore.
377 	 */
378 	rv = soft_get_token_objects_from_keystore(PRI_TOKENOBJS);
379 	if (rv != CKR_OK) {
380 		SES_REFRELE(session_p, lock_held);
381 		return (rv);
382 	}
383 
384 	/* Acquire the global session list lock */
385 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
386 
387 	sp = soft_session_list;
388 
389 	while (sp) {
390 		(void) pthread_mutex_lock(&sp->session_mutex);
391 
392 		if (sp->flags & CKF_RW_SESSION) {
393 			sp->state = CKS_RW_USER_FUNCTIONS;
394 		} else {
395 			sp->state = CKS_RO_USER_FUNCTIONS;
396 		}
397 		(void) pthread_mutex_unlock(&sp->session_mutex);
398 		sp = sp->next;
399 	}
400 
401 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
402 
403 	SES_REFRELE(session_p, lock_held);
404 	return (rv);
405 
406 }
407 
408 CK_RV
409 C_Logout(CK_SESSION_HANDLE hSession)
410 {
411 
412 	soft_session_t *session_p, *sp;
413 	CK_RV rv;
414 	boolean_t lock_held = B_FALSE;
415 
416 	if (!softtoken_initialized)
417 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
418 
419 	/*
420 	 * Obtain the session pointer. Also, increment the session
421 	 * reference count.
422 	 */
423 	rv = handle2session(hSession, &session_p);
424 	if (rv != CKR_OK)
425 		return (rv);
426 
427 	(void) pthread_mutex_lock(&soft_giant_mutex);
428 	if (!soft_slot.authenticated) {
429 		if (!soft_slot.userpin_change_needed) {
430 			/*
431 			 * Only if the PIN has been initialized in the keystore.
432 			 */
433 			(void) pthread_mutex_unlock(&soft_giant_mutex);
434 			SES_REFRELE(session_p, lock_held);
435 			return (CKR_USER_NOT_LOGGED_IN);
436 		} else {
437 			soft_slot.userpin_change_needed = 0;
438 			(void) pthread_mutex_unlock(&soft_giant_mutex);
439 			SES_REFRELE(session_p, lock_held);
440 			return (CKR_OK);
441 		}
442 	}
443 
444 	soft_logout();
445 	soft_slot.authenticated = 0;
446 	(void) pthread_mutex_unlock(&soft_giant_mutex);
447 
448 	/* Acquire the global session list lock */
449 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
450 
451 	sp = soft_session_list;
452 
453 	while (sp) {
454 		(void) pthread_mutex_lock(&sp->session_mutex);
455 
456 		if (sp->flags & CKF_RW_SESSION) {
457 			sp->state = CKS_RW_PUBLIC_SESSION;
458 		} else {
459 			sp->state = CKS_RO_PUBLIC_SESSION;
460 		}
461 		(void) pthread_mutex_unlock(&sp->session_mutex);
462 		sp = sp->next;
463 	}
464 
465 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
466 
467 	SES_REFRELE(session_p, lock_held);
468 	return (rv);
469 
470 }
471