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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <pthread.h>
26 #include <security/cryptoki.h>
27 #include "softGlobal.h"
28 #include "softSession.h"
29 #include "softObject.h"
30 #include "softKeystore.h"
31 #include "softKeystoreUtil.h"
32 
33 
34 CK_RV
C_OpenSession(CK_SLOT_ID slotID,CK_FLAGS flags,CK_VOID_PTR pApplication,CK_NOTIFY Notify,CK_SESSION_HANDLE_PTR phSession)35 C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication,
36     CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession)
37 {
38 
39 	CK_RV rv = CKR_OK;
40 
41 	if (!softtoken_initialized)
42 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
43 
44 	/*
45 	 * For legacy reasons, the CKF_SERIAL_SESSION bit must always
46 	 * be set.
47 	 */
48 	if (!(flags & CKF_SERIAL_SESSION))
49 		return (CKR_SESSION_PARALLEL_NOT_SUPPORTED);
50 
51 	if (slotID != SOFTTOKEN_SLOTID)
52 		return (CKR_SLOT_ID_INVALID);
53 
54 	if (phSession == NULL)
55 		return (CKR_ARGUMENTS_BAD);
56 
57 	/*
58 	 * softtoken has no limit on the number of concurrent sessions
59 	 * that the token allows. No need to check to see if the
60 	 * token has too many sessions already open.
61 	 */
62 
63 	/* Create a new session */
64 	rv = soft_add_session(flags, pApplication, Notify, phSession);
65 
66 	return (rv);
67 
68 }
69 
70 CK_RV
C_CloseSession(CK_SESSION_HANDLE hSession)71 C_CloseSession(CK_SESSION_HANDLE hSession)
72 {
73 
74 	CK_RV rv;
75 
76 	soft_session_t *session_p;
77 	boolean_t lock_held = B_TRUE;
78 
79 	if (!softtoken_initialized)
80 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
81 
82 	/*
83 	 * Obtain the session pointer. Also, increment the session
84 	 * reference count.
85 	 */
86 	rv = handle2session(hSession, &session_p);
87 	if (rv != CKR_OK)
88 		return (rv);
89 
90 	(void) pthread_mutex_lock(&session_p->session_mutex);
91 	/*
92 	 * Set SESSION_IS_CLOSING flag so any access to this
93 	 * session will be rejected.
94 	 */
95 	if (session_p->ses_close_sync & SESSION_IS_CLOSING) {
96 		SES_REFRELE(session_p, lock_held);
97 		return (CKR_SESSION_CLOSED);
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 and also that
113 	 * this is not a forced session close but an explicit request.
114 	 *
115 	 * soft_delete_session() will reset SESSION_IS_CLOSING
116 	 * flag after it is done.
117 	 */
118 	rv = soft_delete_session(session_p, B_FALSE, B_FALSE);
119 
120 	if (soft_session_cnt == 0) {
121 		/* Clean up private token objects from the token object list */
122 		soft_delete_all_in_core_token_objects(PRIVATE_TOKEN);
123 		/*
124 		 * Invalidate public token object handles instead of
125 		 * deleting them.
126 		 */
127 		soft_validate_token_objects(B_FALSE);
128 		(void) pthread_mutex_lock(&soft_giant_mutex);
129 		soft_slot.authenticated = 0;
130 		soft_slot.userpin_change_needed = 0;
131 		(void) pthread_mutex_unlock(&soft_giant_mutex);
132 	}
133 
134 	return (rv);
135 }
136 
137 
138 CK_RV
C_CloseAllSessions(CK_SLOT_ID slotID)139 C_CloseAllSessions(CK_SLOT_ID slotID)
140 {
141 
142 	CK_RV rv = CKR_OK;
143 
144 	if (!softtoken_initialized)
145 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
146 
147 	if (slotID != SOFTTOKEN_SLOTID)
148 		return (CKR_SLOT_ID_INVALID);
149 
150 	/* Acquire the global session list lock */
151 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
152 	/*
153 	 * Set all_sessions_closing flag so any access to any
154 	 * existing sessions will be rejected.
155 	 */
156 	all_sessions_closing = 1;
157 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
158 
159 	/* Delete all the sessions and release the allocated resources */
160 	rv = soft_delete_all_sessions(B_FALSE);
161 
162 	/* Clean up private token objects from the token object list */
163 	soft_delete_all_in_core_token_objects(PRIVATE_TOKEN);
164 
165 	/* Invalidate public token object handles instead of deleting them */
166 	soft_validate_token_objects(B_FALSE);
167 
168 	(void) pthread_mutex_lock(&soft_giant_mutex);
169 	soft_slot.authenticated = 0;
170 	soft_slot.userpin_change_needed = 0;
171 	(void) pthread_mutex_unlock(&soft_giant_mutex);
172 
173 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
174 	/* Reset all_sessions_closing flag. */
175 	all_sessions_closing = 0;
176 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
177 
178 	return (rv);
179 }
180 
181 CK_RV
C_GetSessionInfo(CK_SESSION_HANDLE hSession,CK_SESSION_INFO_PTR pInfo)182 C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo)
183 {
184 
185 	soft_session_t *session_p;
186 	CK_RV rv;
187 	boolean_t lock_held = B_TRUE;
188 
189 	if (!softtoken_initialized)
190 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
191 
192 	/*
193 	 * Obtain the session pointer. Also, increment the session
194 	 * reference count.
195 	 */
196 	rv = handle2session(hSession, &session_p);
197 	if (rv != CKR_OK)
198 		return (rv);
199 
200 	if (pInfo == NULL) {
201 		lock_held = B_FALSE;
202 		rv = CKR_ARGUMENTS_BAD;
203 		goto clean_exit;
204 	}
205 
206 	(void) pthread_mutex_lock(&session_p->session_mutex);
207 
208 	/* Provide information for the specified session */
209 	pInfo->slotID = SOFTTOKEN_SLOTID;
210 	pInfo->state = session_p->state;
211 	pInfo->flags = session_p->flags;
212 	pInfo->ulDeviceError = 0;
213 
214 clean_exit:
215 	/*
216 	 * Decrement the session reference count.
217 	 * We hold the session lock, and SES_REFRELE()
218 	 * will release the session lock for us.
219 	 */
220 	SES_REFRELE(session_p, lock_held);
221 
222 	return (rv);
223 }
224 
225 
226 CK_RV
C_GetOperationState(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pOperationState,CK_ULONG_PTR pulOperationStateLen)227 C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState,
228     CK_ULONG_PTR pulOperationStateLen)
229 {
230 	soft_session_t *session_p;
231 	CK_RV rv;
232 	boolean_t lock_held = B_FALSE;
233 
234 	if (!softtoken_initialized)
235 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
236 
237 	/*
238 	 * Obtain the session pointer. Also, increment the session
239 	 * reference count.
240 	 */
241 	rv = handle2session(hSession, &session_p);
242 	if (rv != CKR_OK)
243 		return (rv);
244 
245 	/*
246 	 * Only check if pulOperationStateLen is NULL_PTR.
247 	 * No need to check if pOperationState is NULL_PTR because
248 	 * application might just ask for the length of buffer to hold
249 	 * the OperationState.
250 	 */
251 	if (pulOperationStateLen == NULL_PTR) {
252 		rv = CKR_ARGUMENTS_BAD;
253 		goto clean_exit;
254 	}
255 
256 	rv = soft_get_operationstate(session_p, pOperationState,
257 	    pulOperationStateLen);
258 
259 clean_exit:
260 	SES_REFRELE(session_p, lock_held);
261 	return (rv);
262 
263 }
264 
265 
266 CK_RV
C_SetOperationState(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pOperationState,CK_ULONG ulOperationStateLen,CK_OBJECT_HANDLE hEncryptionKey,CK_OBJECT_HANDLE hAuthenticationKey)267 C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState,
268     CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey,
269     CK_OBJECT_HANDLE hAuthenticationKey)
270 {
271 	soft_session_t *session_p;
272 	CK_RV rv;
273 	boolean_t lock_held = B_FALSE;
274 
275 	if (!softtoken_initialized)
276 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
277 
278 	/*
279 	 * Obtain the session pointer. Also, increment the session
280 	 * reference count.
281 	 */
282 	rv = handle2session(hSession, &session_p);
283 	if (rv != CKR_OK)
284 		return (rv);
285 
286 	if ((pOperationState == NULL_PTR) ||
287 	    (ulOperationStateLen == 0)) {
288 		rv = CKR_ARGUMENTS_BAD;
289 		goto clean_exit;
290 	}
291 
292 	rv = soft_set_operationstate(session_p, pOperationState,
293 	    ulOperationStateLen, hEncryptionKey, hAuthenticationKey);
294 
295 clean_exit:
296 	SES_REFRELE(session_p, lock_held);
297 	return (rv);
298 }
299 
300 CK_RV
C_Login(CK_SESSION_HANDLE hSession,CK_USER_TYPE userType,CK_UTF8CHAR_PTR pPin,CK_ULONG ulPinLen)301 C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin,
302     CK_ULONG ulPinLen)
303 {
304 
305 	soft_session_t *session_p, *sp;
306 	CK_RV rv;
307 	boolean_t lock_held = B_FALSE;
308 
309 	if (!softtoken_initialized)
310 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
311 
312 	/*
313 	 * Obtain the session pointer. Also, increment the session
314 	 * reference count.
315 	 */
316 	rv = handle2session(hSession, &session_p);
317 	if (rv != CKR_OK)
318 		return (rv);
319 
320 	/* Check the load status of keystore */
321 	if (!soft_keystore_status(KEYSTORE_LOAD)) {
322 		SES_REFRELE(session_p, lock_held);
323 		return (CKR_DEVICE_REMOVED);
324 	}
325 
326 	if (userType != CKU_USER) {
327 		SES_REFRELE(session_p, lock_held);
328 		return (CKR_USER_TYPE_INVALID);
329 	}
330 
331 	if ((ulPinLen < MIN_PIN_LEN) || (ulPinLen > MAX_PIN_LEN)) {
332 		SES_REFRELE(session_p, lock_held);
333 		return (CKR_PIN_LEN_RANGE);
334 	}
335 
336 	if (pPin == NULL_PTR) {
337 		/*
338 		 * We don't support CKF_PROTECTED_AUTHENTICATION_PATH
339 		 */
340 		SES_REFRELE(session_p, lock_held);
341 		return (CKR_ARGUMENTS_BAD);
342 	}
343 
344 	(void) pthread_mutex_lock(&soft_giant_mutex);
345 	if (soft_slot.authenticated) {
346 		(void) pthread_mutex_unlock(&soft_giant_mutex);
347 		SES_REFRELE(session_p, lock_held);
348 		return (CKR_USER_ALREADY_LOGGED_IN);
349 	}
350 
351 	rv = soft_login(pPin, ulPinLen);
352 	if (rv == CKR_OK) {
353 		if (soft_slot.userpin_change_needed) {
354 			/*
355 			 * This is the special case when the PIN is never
356 			 * initialized in the keystore, which will always
357 			 * return CKR_OK with "userpin_change_needed" set.
358 			 */
359 			(void) pthread_mutex_unlock(&soft_giant_mutex);
360 			SES_REFRELE(session_p, lock_held);
361 			return (rv);
362 		}
363 
364 		soft_slot.authenticated = 1;
365 		(void) pthread_mutex_unlock(&soft_giant_mutex);
366 	} else {
367 		(void) pthread_mutex_unlock(&soft_giant_mutex);
368 		SES_REFRELE(session_p, lock_held);
369 		return (rv);
370 	}
371 
372 	/*
373 	 * Load all the private token objects from keystore.
374 	 */
375 	rv = soft_get_token_objects_from_keystore(PRI_TOKENOBJS);
376 	if (rv != CKR_OK) {
377 		SES_REFRELE(session_p, lock_held);
378 		return (rv);
379 	}
380 
381 	/* Acquire the global session list lock */
382 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
383 
384 	sp = soft_session_list;
385 
386 	while (sp) {
387 		(void) pthread_mutex_lock(&sp->session_mutex);
388 
389 		if (sp->flags & CKF_RW_SESSION) {
390 			sp->state = CKS_RW_USER_FUNCTIONS;
391 		} else {
392 			sp->state = CKS_RO_USER_FUNCTIONS;
393 		}
394 		(void) pthread_mutex_unlock(&sp->session_mutex);
395 		sp = sp->next;
396 	}
397 
398 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
399 
400 	SES_REFRELE(session_p, lock_held);
401 	return (rv);
402 
403 }
404 
405 CK_RV
C_Logout(CK_SESSION_HANDLE hSession)406 C_Logout(CK_SESSION_HANDLE hSession)
407 {
408 
409 	soft_session_t *session_p, *sp;
410 	CK_RV rv;
411 	boolean_t lock_held = B_FALSE;
412 
413 	if (!softtoken_initialized)
414 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
415 
416 	/*
417 	 * Obtain the session pointer. Also, increment the session
418 	 * reference count.
419 	 */
420 	rv = handle2session(hSession, &session_p);
421 	if (rv != CKR_OK)
422 		return (rv);
423 
424 	(void) pthread_mutex_lock(&soft_giant_mutex);
425 	if (!soft_slot.authenticated) {
426 		if (!soft_slot.userpin_change_needed) {
427 			/*
428 			 * Only if the PIN has been initialized in the keystore.
429 			 */
430 			(void) pthread_mutex_unlock(&soft_giant_mutex);
431 			SES_REFRELE(session_p, lock_held);
432 			return (CKR_USER_NOT_LOGGED_IN);
433 		} else {
434 			soft_slot.userpin_change_needed = 0;
435 			(void) pthread_mutex_unlock(&soft_giant_mutex);
436 			SES_REFRELE(session_p, lock_held);
437 			return (CKR_OK);
438 		}
439 	}
440 
441 	soft_logout();
442 	soft_slot.authenticated = 0;
443 	(void) pthread_mutex_unlock(&soft_giant_mutex);
444 
445 	/* Acquire the global session list lock */
446 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
447 
448 	sp = soft_session_list;
449 
450 	while (sp) {
451 		(void) pthread_mutex_lock(&sp->session_mutex);
452 
453 		if (sp->flags & CKF_RW_SESSION) {
454 			sp->state = CKS_RW_PUBLIC_SESSION;
455 		} else {
456 			sp->state = CKS_RO_PUBLIC_SESSION;
457 		}
458 		(void) pthread_mutex_unlock(&sp->session_mutex);
459 		sp = sp->next;
460 	}
461 
462 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
463 
464 	SES_REFRELE(session_p, lock_held);
465 	return (rv);
466 
467 }
468