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