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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
33 #include <security/cryptoki.h>
34 #include "softGlobal.h"
35 #include "softSession.h"
36 #include "softObject.h"
38 #include "softKeystore.h"
39 #include "softKeystoreUtil.h"
42 CK_ULONG soft_session_cnt
= 0; /* the number of opened sessions */
43 CK_ULONG soft_session_rw_cnt
= 0; /* the number of opened R/W sessions */
45 #define DIGEST_MECH_OK(_m_) ((_m_) == CKM_MD5 || (_m_) == CKM_SHA_1)
48 * Delete all the sessions. First, obtain the global session
49 * list lock. Then start to delete one session at a time.
50 * Release the global session list lock before returning to
54 soft_delete_all_sessions(boolean_t force
)
59 soft_session_t
*session_p
;
60 soft_session_t
*session_p1
;
62 /* Acquire the global session list lock */
63 (void) pthread_mutex_lock(&soft_sessionlist_mutex
);
65 session_p
= soft_session_list
;
67 /* Delete all the sessions in the session list */
69 session_p1
= session_p
->next
;
72 * Delete a session by calling soft_delete_session()
73 * with a session pointer and a boolean arguments.
74 * Boolean value TRUE is used to indicate that the
75 * caller holds the lock on the global session list.
78 rv1
= soft_delete_session(session_p
, force
, B_TRUE
);
80 /* Record the very first error code */
85 session_p
= session_p1
;
89 soft_session_list
= NULL
;
91 /* Release the global session list lock */
92 (void) pthread_mutex_unlock(&soft_sessionlist_mutex
);
100 * Create a new session struct, and add it to the session linked list.
102 * This function will acquire the global session list lock, and release
103 * it after adding the session to the session linked list.
106 soft_add_session(CK_FLAGS flags
, CK_VOID_PTR pApplication
,
107 CK_NOTIFY notify
, CK_ULONG
*sessionhandle_p
)
110 soft_session_t
*new_sp
= NULL
;
112 /* Allocate a new session struct */
113 new_sp
= calloc(1, sizeof (soft_session_t
));
114 if (new_sp
== NULL
) {
115 return (CKR_HOST_MEMORY
);
118 new_sp
->magic_marker
= SOFTTOKEN_SESSION_MAGIC
;
119 new_sp
->pApplication
= pApplication
;
120 new_sp
->Notify
= notify
;
121 new_sp
->flags
= flags
;
122 new_sp
->state
= CKS_RO_PUBLIC_SESSION
;
123 new_sp
->object_list
= NULL
;
124 new_sp
->ses_refcnt
= 0;
125 new_sp
->ses_close_sync
= 0;
127 (void) pthread_mutex_lock(&soft_giant_mutex
);
128 if (soft_slot
.authenticated
) {
129 (void) pthread_mutex_unlock(&soft_giant_mutex
);
130 if (flags
& CKF_RW_SESSION
) {
131 new_sp
->state
= CKS_RW_USER_FUNCTIONS
;
133 new_sp
->state
= CKS_RO_USER_FUNCTIONS
;
136 (void) pthread_mutex_unlock(&soft_giant_mutex
);
137 if (flags
& CKF_RW_SESSION
) {
138 new_sp
->state
= CKS_RW_PUBLIC_SESSION
;
140 new_sp
->state
= CKS_RO_PUBLIC_SESSION
;
144 /* Initialize the lock for the newly created session */
145 if (pthread_mutex_init(&new_sp
->session_mutex
, NULL
) != 0) {
147 return (CKR_CANT_LOCK
);
150 (void) pthread_cond_init(&new_sp
->ses_free_cond
, NULL
);
152 /* Acquire the global session list lock */
153 (void) pthread_mutex_lock(&soft_sessionlist_mutex
);
155 /* Insert the new session in front of session list */
156 if (soft_session_list
== NULL
) {
157 soft_session_list
= new_sp
;
161 soft_session_list
->prev
= new_sp
;
162 new_sp
->next
= soft_session_list
;
164 soft_session_list
= new_sp
;
167 /* Type casting the address of a session struct to a session handle */
168 *sessionhandle_p
= (CK_ULONG
)new_sp
;
170 if (flags
& CKF_RW_SESSION
)
171 ++soft_session_rw_cnt
;
173 if (soft_session_cnt
== 1)
175 * This is the first session to be opened, so we can set
176 * validate the public token objects in token list now.
178 soft_validate_token_objects(B_TRUE
);
180 /* Release the global session list lock */
181 (void) pthread_mutex_unlock(&soft_sessionlist_mutex
);
188 * This function adds the to-be-freed session to a linked list.
189 * When the number of sessions queued in the linked list reaches the
190 * maximum threshold MAX_SES_TO_BE_FREED, it will free the first
191 * session (FIFO) in the list.
194 session_delay_free(soft_session_t
*sp
)
198 (void) pthread_mutex_lock(&ses_delay_freed
.ses_to_be_free_mutex
);
200 /* Add the newly deleted session at the end of the list */
202 if (ses_delay_freed
.first
== NULL
) {
203 ses_delay_freed
.last
= sp
;
204 ses_delay_freed
.first
= sp
;
206 ses_delay_freed
.last
->next
= sp
;
207 ses_delay_freed
.last
= sp
;
210 if (++ses_delay_freed
.count
>= MAX_SES_TO_BE_FREED
) {
212 * Free the first session in the list only if
213 * the total count reaches maximum threshold.
215 ses_delay_freed
.count
--;
216 tmp
= ses_delay_freed
.first
->next
;
217 free(ses_delay_freed
.first
);
218 ses_delay_freed
.first
= tmp
;
220 (void) pthread_mutex_unlock(&ses_delay_freed
.ses_to_be_free_mutex
);
225 * - Remove the session from the session linked list.
226 * Holding the lock on the global session list is needed to do this.
227 * - Release all the objects created by the session.
229 * The boolean argument lock_held is used to indicate that whether
230 * the caller of this function holds the lock on the global session
232 * - When called by soft_delete_all_sessions(), which is called by
233 * C_Finalize() or C_CloseAllSessions() -- the lock_held = TRUE.
234 * - When called by C_CloseSession() -- the lock_held = FALSE.
236 * When the caller does not hold the lock on the global session
237 * list, this function will acquire that lock in order to proceed,
238 * and also release that lock before returning to caller.
241 soft_delete_session(soft_session_t
*session_p
,
242 boolean_t force
, boolean_t lock_held
)
246 * Check to see if the caller holds the lock on the global
247 * session list. If not, we need to acquire that lock in
251 /* Acquire the global session list lock */
252 (void) pthread_mutex_lock(&soft_sessionlist_mutex
);
256 * Remove the session from the session linked list first.
258 if (soft_session_list
== session_p
) {
259 /* Session is the first one in the list */
260 if (session_p
->next
) {
261 soft_session_list
= session_p
->next
;
262 session_p
->next
->prev
= NULL
;
264 /* Session is the only one in the list */
265 soft_session_list
= NULL
;
268 /* Session is not the first one in the list */
269 if (session_p
->next
) {
270 /* Session is in the middle of the list */
271 session_p
->prev
->next
= session_p
->next
;
272 session_p
->next
->prev
= session_p
->prev
;
274 /* Session is the last one in the list */
275 session_p
->prev
->next
= NULL
;
280 if (session_p
->flags
& CKF_RW_SESSION
)
281 --soft_session_rw_cnt
;
285 * If the global session list lock is obtained by
286 * this function, then release that lock after
287 * removing the session from session linked list.
288 * We want the releasing of the objects of the
289 * session, and freeing of the session itself to
290 * be done without holding the global session list
293 (void) pthread_mutex_unlock(&soft_sessionlist_mutex
);
297 /* Acquire the individual session lock */
298 (void) pthread_mutex_lock(&session_p
->session_mutex
);
300 * Make sure another thread hasn't freed the session.
302 if (session_p
->magic_marker
!= SOFTTOKEN_SESSION_MAGIC
) {
303 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
308 * The deletion of a session must be blocked when the session
309 * reference count is not zero. This means if any session related
310 * operation starts prior to the session close operation gets in,
311 * the session closing thread must wait for the non-closing
312 * operation to be completed before it can proceed the close
315 * Unless we are being forced to shut everything down, this only
316 * happens if the libraries _fini() is running not of someone
317 * explicitly called C_Finalize().
320 session_p
->ses_refcnt
= 0;
322 while (session_p
->ses_refcnt
!= 0) {
324 * We set the SESSION_REFCNT_WAITING flag before we put
325 * this closing thread in a wait state, so other non-closing
326 * operation thread will signal to wake it up only when
327 * the session reference count becomes zero and this flag
330 session_p
->ses_close_sync
|= SESSION_REFCNT_WAITING
;
331 (void) pthread_cond_wait(&session_p
->ses_free_cond
,
332 &session_p
->session_mutex
);
335 session_p
->ses_close_sync
&= ~SESSION_REFCNT_WAITING
;
338 * Remove all the objects created in this session.
340 soft_delete_all_objects_in_session(session_p
, force
);
343 * Mark session as no longer valid. This can only be done after all
344 * objects created by this session are free'd since the marker is
345 * still needed in the process of removing objects from the session.
347 session_p
->magic_marker
= 0;
349 (void) pthread_cond_destroy(&session_p
->ses_free_cond
);
351 /* In case application did not call Final */
352 if (session_p
->digest
.context
!= NULL
)
353 free(session_p
->digest
.context
);
355 if (session_p
->encrypt
.context
!= NULL
)
357 * 1st B_TRUE: encrypt
358 * 2nd B_TRUE: caller is holding session_mutex.
360 soft_crypt_cleanup(session_p
, B_TRUE
, B_TRUE
);
362 if (session_p
->decrypt
.context
!= NULL
)
364 * 1st B_FALSE: decrypt
365 * 2nd B_TRUE: caller is holding session_mutex.
367 soft_crypt_cleanup(session_p
, B_FALSE
, B_TRUE
);
369 if (session_p
->sign
.context
!= NULL
)
370 free(session_p
->sign
.context
);
372 if (session_p
->verify
.context
!= NULL
)
373 free(session_p
->verify
.context
);
375 if (session_p
->find_objects
.context
!= NULL
) {
376 find_context_t
*fcontext
;
377 fcontext
= (find_context_t
*)session_p
->find_objects
.context
;
378 free(fcontext
->objs_found
);
382 /* Reset SESSION_IS_CLOSIN flag. */
383 session_p
->ses_close_sync
&= ~SESSION_IS_CLOSING
;
385 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
386 /* Destroy the individual session lock */
387 (void) pthread_mutex_destroy(&session_p
->session_mutex
);
389 /* Delay freeing the session */
390 session_delay_free(session_p
);
397 * This function is used to type cast a session handle to a pointer to
398 * the session struct. Also, it does the following things:
399 * 1) Check to see if the session struct is tagged with a session
400 * magic number. This is to detect when an application passes
401 * a bogus session pointer.
402 * 2) Acquire the lock on the designated session.
403 * 3) Check to see if the session is in the closing state that another
404 * thread is performing.
405 * 4) Increment the session reference count by one. This is to prevent
406 * this session from being closed by other thread.
407 * 5) Release the lock held on the designated session.
410 handle2session(CK_SESSION_HANDLE hSession
, soft_session_t
**session_p
)
413 soft_session_t
*sp
= (soft_session_t
*)(hSession
);
416 * No need to hold soft_sessionlist_mutex as we are
417 * just reading the value and 32-bit reads are atomic.
419 if (all_sessions_closing
) {
420 return (CKR_SESSION_CLOSED
);
424 (sp
->magic_marker
!= SOFTTOKEN_SESSION_MAGIC
)) {
425 return (CKR_SESSION_HANDLE_INVALID
);
427 (void) pthread_mutex_lock(&sp
->session_mutex
);
429 if (sp
->ses_close_sync
& SESSION_IS_CLOSING
) {
430 (void) pthread_mutex_unlock(&sp
->session_mutex
);
431 return (CKR_SESSION_CLOSED
);
434 /* Increment session ref count. */
437 (void) pthread_mutex_unlock(&sp
->session_mutex
);
445 * The format to be saved in the pOperationState will be:
446 * 1. internal_op_state_t
447 * 2. crypto_active_op_t
448 * 3. actual context of the active operation
451 soft_get_operationstate(soft_session_t
*session_p
, CK_BYTE_PTR pOperationState
,
452 CK_ULONG_PTR pulOperationStateLen
)
455 internal_op_state_t
*p_op_state
;
456 CK_ULONG op_data_len
= 0;
459 if (pulOperationStateLen
== NULL
)
460 return (CKR_ARGUMENTS_BAD
);
462 (void) pthread_mutex_lock(&session_p
->session_mutex
);
464 /* Check to see if encrypt operation is active. */
465 if (session_p
->encrypt
.flags
& CRYPTO_OPERATION_ACTIVE
) {
466 rv
= CKR_STATE_UNSAVEABLE
;
470 /* Check to see if decrypt operation is active. */
471 if (session_p
->decrypt
.flags
& CRYPTO_OPERATION_ACTIVE
) {
472 rv
= CKR_STATE_UNSAVEABLE
;
476 /* Check to see if sign operation is active. */
477 if (session_p
->sign
.flags
& CRYPTO_OPERATION_ACTIVE
) {
478 rv
= CKR_STATE_UNSAVEABLE
;
482 /* Check to see if verify operation is active. */
483 if (session_p
->verify
.flags
& CRYPTO_OPERATION_ACTIVE
) {
484 rv
= CKR_STATE_UNSAVEABLE
;
488 /* Check to see if digest operation is active. */
489 if (session_p
->digest
.flags
& CRYPTO_OPERATION_ACTIVE
) {
490 op_data_len
= sizeof (internal_op_state_t
) +
491 sizeof (crypto_active_op_t
);
493 switch (session_p
->digest
.mech
.mechanism
) {
495 op_data_len
+= sizeof (MD5_CTX
);
498 op_data_len
+= sizeof (SHA1_CTX
);
501 rv
= CKR_STATE_UNSAVEABLE
;
505 if (pOperationState
== NULL_PTR
) {
506 *pulOperationStateLen
= op_data_len
;
509 if (*pulOperationStateLen
< op_data_len
) {
510 *pulOperationStateLen
= op_data_len
;
511 rv
= CKR_BUFFER_TOO_SMALL
;
516 /* Save internal_op_state_t */
517 /* LINTED E_BAD_PTR_CAST_ALIGN */
518 p_op_state
= (internal_op_state_t
*)pOperationState
;
519 p_op_state
->op_len
= op_data_len
;
520 p_op_state
->op_active
= DIGEST_OP
;
521 p_op_state
->op_session_state
= session_p
->state
;
523 /* Save crypto_active_op_t */
524 (void) memcpy((CK_BYTE
*)pOperationState
+
525 sizeof (internal_op_state_t
),
527 sizeof (crypto_active_op_t
));
529 switch (session_p
->digest
.mech
.mechanism
) {
531 /* Save MD5_CTX for the active digest operation */
532 (void) memcpy((CK_BYTE
*)pOperationState
+
533 sizeof (internal_op_state_t
) +
534 sizeof (crypto_active_op_t
),
535 session_p
->digest
.context
,
540 /* Save SHA1_CTX for the active digest operation */
541 (void) memcpy((CK_BYTE
*)pOperationState
+
542 sizeof (internal_op_state_t
) +
543 sizeof (crypto_active_op_t
),
544 session_p
->digest
.context
,
549 rv
= CKR_STATE_UNSAVEABLE
;
552 rv
= CKR_OPERATION_NOT_INITIALIZED
;
556 *pulOperationStateLen
= op_data_len
;
559 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
565 static CK_BYTE_PTR
alloc_digest(CK_ULONG mech
)
571 ret_val
= (CK_BYTE_PTR
) malloc(sizeof (MD5_CTX
));
574 ret_val
= (CK_BYTE_PTR
) malloc(sizeof (SHA1_CTX
));
576 default: ret_val
= NULL
;
583 * The format to be restored from the pOperationState will be:
584 * 1. internal_op_state_t
585 * 2. crypto_active_op_t
586 * 3. actual context of the saved operation
589 soft_set_operationstate(soft_session_t
*session_p
, CK_BYTE_PTR pOperationState
,
590 CK_ULONG ulOperationStateLen
, CK_OBJECT_HANDLE hEncryptionKey
,
591 CK_OBJECT_HANDLE hAuthenticationKey
)
595 internal_op_state_t
*p_op_state
;
596 crypto_active_op_t
*p_active_op
;
599 void *free_it
= NULL
;
601 /* LINTED E_BAD_PTR_CAST_ALIGN */
602 p_op_state
= (internal_op_state_t
*)pOperationState
;
604 if (p_op_state
->op_len
!= ulOperationStateLen
) {
606 * The supplied data length does not match with
607 * the saved data length.
609 return (CKR_SAVED_STATE_INVALID
);
612 if (p_op_state
->op_active
!= DIGEST_OP
)
613 return (CKR_SAVED_STATE_INVALID
);
615 if ((hAuthenticationKey
!= 0) || (hEncryptionKey
!= 0)) {
616 return (CKR_KEY_NOT_NEEDED
);
619 offset
= sizeof (internal_op_state_t
);
620 /* LINTED E_BAD_PTR_CAST_ALIGN */
621 p_active_op
= (crypto_active_op_t
*)(pOperationState
+ offset
);
622 offset
+= sizeof (crypto_active_op_t
);
623 mech
= p_active_op
->mech
.mechanism
;
625 if (!DIGEST_MECH_OK(mech
)) {
626 return (CKR_SAVED_STATE_INVALID
);
630 * We may reuse digest.context in case the digest mechanisms (the one,
631 * which belongs to session and the operation, which we are restoring)
632 * are the same. If digest mechanisms are different, we have to release
633 * the digest context, which belongs to session and allocate a new one.
635 (void) pthread_mutex_lock(&session_p
->session_mutex
);
637 if (session_p
->state
!= p_op_state
->op_session_state
) {
639 * The supplied session state does not match with
640 * the saved session state.
642 rv
= CKR_SAVED_STATE_INVALID
;
646 if (session_p
->digest
.context
&&
647 (session_p
->digest
.mech
.mechanism
!= mech
)) {
648 free_it
= session_p
->digest
.context
;
649 session_p
->digest
.context
= NULL
;
652 if (session_p
->digest
.context
== NULL
) {
653 session_p
->digest
.context
= alloc_digest(mech
);
655 if (session_p
->digest
.context
== NULL
) {
657 * put back original context into session in case
658 * allocation of new context has failed.
660 session_p
->digest
.context
= free_it
;
662 rv
= CKR_HOST_MEMORY
;
667 /* Restore crypto_active_op_t */
668 session_p
->digest
.mech
.mechanism
= mech
;
669 session_p
->digest
.flags
= p_active_op
->flags
;
673 /* Restore MD5_CTX from the saved digest operation */
674 (void) memcpy((CK_BYTE
*)session_p
->digest
.context
,
675 (CK_BYTE
*)pOperationState
+ offset
,
679 /* Restore SHA1_CTX from the saved digest operation */
680 (void) memcpy((CK_BYTE
*)session_p
->digest
.context
,
681 (CK_BYTE
*)pOperationState
+ offset
,
686 rv
= CKR_SAVED_STATE_INVALID
;
690 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
700 soft_login(CK_UTF8CHAR_PTR pPin
, CK_ULONG ulPinLen
)
704 * Authenticate the input PIN.
706 return (soft_verify_pin(pPin
, ulPinLen
));
715 * Delete all the private token objects from the "token_object_list".
717 soft_delete_all_in_core_token_objects(PRIVATE_TOKEN
);
723 soft_acquire_all_session_mutexes(soft_session_t
*session_p
)
725 /* Iterate through sessions acquiring all mutexes */
727 soft_object_t
*object_p
;
729 (void) pthread_mutex_lock(&session_p
->session_mutex
);
730 object_p
= session_p
->object_list
;
732 /* Lock also all objects related to session */
734 (void) pthread_mutex_lock(&object_p
->object_mutex
);
735 object_p
= object_p
->next
;
737 session_p
= session_p
->next
;
742 soft_release_all_session_mutexes(soft_session_t
*session_p
)
744 /* Iterate through sessions releasing all mutexes */
747 * N.B. Ideally, should go in opposite order to guarantee
748 * lock-order requirements but there is no tail pointer.
750 soft_object_t
*object_p
= session_p
->object_list
;
752 /* Unlock also all objects related to session */
754 (void) pthread_mutex_unlock(&object_p
->object_mutex
);
755 object_p
= object_p
->next
;
757 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
758 session_p
= session_p
->next
;