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.
28 #include <security/cryptoki.h>
29 #include <sys/crypto/ioctl.h>
30 #include "kernelGlobal.h"
31 #include "kernelSession.h"
32 #include "kernelSlot.h"
33 #include "kernelEmulate.h"
36 C_OpenSession(CK_SLOT_ID slotID
, CK_FLAGS flags
, CK_VOID_PTR pApplication
,
37 CK_NOTIFY Notify
, CK_SESSION_HANDLE_PTR phSession
)
42 if (!kernel_initialized
)
43 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
46 * For legacy reasons, the CKF_SERIAL_SESSION bit must always
49 if (!(flags
& CKF_SERIAL_SESSION
))
50 return (CKR_SESSION_PARALLEL_NOT_SUPPORTED
);
52 if (phSession
== NULL
)
53 return (CKR_ARGUMENTS_BAD
);
55 if (slotID
>= slot_count
) {
56 return (CKR_SLOT_ID_INVALID
);
60 * Acquire the slot lock to protect sl_state and sl_sess_list.
61 * These two fields need to be protected atomically, even though
62 * "sl_sess_list" is updated in kernel_add_session().
64 pslot
= slot_table
[slotID
];
65 (void) pthread_mutex_lock(&pslot
->sl_mutex
);
67 /* If SO is logged in the slot, only the RW session is allowed. */
68 if ((pslot
->sl_state
== CKU_SO
) && !(flags
& CKF_RW_SESSION
)) {
69 (void) pthread_mutex_unlock(&pslot
->sl_mutex
);
70 return (CKR_SESSION_READ_WRITE_SO_EXISTS
);
73 /* Create a new session */
74 rv
= kernel_add_session(slotID
, flags
, pApplication
, Notify
,
76 (void) pthread_mutex_unlock(&pslot
->sl_mutex
);
81 C_CloseSession(CK_SESSION_HANDLE hSession
)
85 kernel_session_t
*session_p
;
86 boolean_t ses_lock_held
= B_FALSE
;
88 if (!kernel_initialized
)
89 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
92 * Obtain the session pointer. Also, increment the session
95 rv
= handle2session(hSession
, &session_p
);
99 (void) pthread_mutex_lock(&session_p
->session_mutex
);
100 ses_lock_held
= B_TRUE
;
103 * Set SESSION_IS_CLOSING flag so any access to this
104 * session will be rejected.
106 if (session_p
->ses_close_sync
& SESSION_IS_CLOSING
) {
107 REFRELE(session_p
, ses_lock_held
);
108 return (CKR_SESSION_CLOSED
);
110 session_p
->ses_close_sync
|= SESSION_IS_CLOSING
;
113 * Decrement the session reference count.
114 * We hold the session lock, and REFRELE()
115 * will release the session lock for us.
117 REFRELE(session_p
, ses_lock_held
);
120 * Delete a session by calling kernel_delete_session() with
121 * a session pointer and two boolean arguments. The 3rd argument
122 * boolean value FALSE indicates that the caller does not
123 * hold the slot lock. The 4th argument boolean value B_FALSE
124 * indicates that we want to delete all the objects completely.
126 * kernel_delete_session() will reset SESSION_IS_CLOSING
127 * flag after it is done.
129 kernel_delete_session(session_p
->ses_slotid
, session_p
, B_FALSE
,
136 C_CloseAllSessions(CK_SLOT_ID slotID
)
138 if (!kernel_initialized
)
139 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
141 /* Delete all the sessions and release the allocated resources */
142 kernel_delete_all_sessions(slotID
, B_FALSE
);
148 * Utility routine to get CK_STATE value for a session.
149 * The caller should not be holding the session lock.
152 get_ses_state(kernel_session_t
*session_p
)
155 kernel_slot_t
*pslot
;
157 pslot
= slot_table
[session_p
->ses_slotid
];
158 (void) pthread_mutex_lock(&pslot
->sl_mutex
);
160 if (pslot
->sl_state
== CKU_PUBLIC
) {
161 state
= (session_p
->ses_RO
) ?
162 CKS_RO_PUBLIC_SESSION
: CKS_RW_PUBLIC_SESSION
;
163 } else if (pslot
->sl_state
== CKU_USER
) {
164 state
= (session_p
->ses_RO
) ?
165 CKS_RO_USER_FUNCTIONS
: CKS_RW_USER_FUNCTIONS
;
166 } else if (pslot
->sl_state
== CKU_SO
) {
167 state
= CKS_RW_SO_FUNCTIONS
;
170 (void) pthread_mutex_unlock(&pslot
->sl_mutex
);
177 C_GetSessionInfo(CK_SESSION_HANDLE hSession
, CK_SESSION_INFO_PTR pInfo
)
179 kernel_session_t
*session_p
;
181 boolean_t ses_lock_held
= B_FALSE
;
183 if (!kernel_initialized
)
184 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
187 return (CKR_ARGUMENTS_BAD
);
190 * Obtain the session pointer. Also, increment the session
193 rv
= handle2session(hSession
, &session_p
);
197 /* Provide information for the specified session */
198 pInfo
->slotID
= session_p
->ses_slotid
;
199 pInfo
->flags
= session_p
->flags
;
200 pInfo
->ulDeviceError
= 0;
201 pInfo
->state
= get_ses_state(session_p
);
204 * Decrement the session reference count.
206 REFRELE(session_p
, ses_lock_held
);
212 * Save the state in pOperationState. The data format is:
213 * 1. Total length (including this field)
215 * 3. crypto_active_op_t structure
216 * 4. digest_buf_t's data buffer contents
219 kernel_get_operationstate(kernel_session_t
*session_p
, CK_STATE ses_state
,
220 CK_BYTE_PTR pOperationState
, CK_ULONG_PTR pulOperationStateLen
)
226 if (!(session_p
->digest
.flags
& CRYPTO_EMULATE
)) {
228 * Return CKR_OPERATION_NOT_INITIALIZED if the slot
229 * is capable of C_GetOperationState(). Return
230 * CKR_FUNCTION_NOT_SUPPORTED otherwise.
232 * We return these codes because some clients
233 * check the return code to determine if C_GetOperationState()
236 if (slot_table
[session_p
->ses_slotid
]->sl_flags
&
237 CRYPTO_LIMITED_HASH_SUPPORT
)
238 return (CKR_OPERATION_NOT_INITIALIZED
);
240 return (CKR_FUNCTION_NOT_SUPPORTED
);
244 * XXX Need to support this case in future.
245 * This is the case where we exceeded SLOT_HASH_MAX_INDATA_LEN and
246 * hence started using libmd. SLOT_HASH_MAX_INDATA_LEN is at least
247 * 64K for current crypto framework providers and web servers
248 * do not need to clone digests that big for SSL operations.
250 if (session_p
->digest
.flags
& CRYPTO_EMULATE_USING_SW
) {
251 return (CKR_STATE_UNSAVEABLE
);
254 /* Check to see if this is an unsupported operation. */
255 if (session_p
->encrypt
.flags
& CRYPTO_OPERATION_ACTIVE
||
256 session_p
->decrypt
.flags
& CRYPTO_OPERATION_ACTIVE
||
257 session_p
->sign
.flags
& CRYPTO_OPERATION_ACTIVE
||
258 session_p
->verify
.flags
& CRYPTO_OPERATION_ACTIVE
) {
259 return (CKR_STATE_UNSAVEABLE
);
262 /* Check to see if digest operation is active. */
263 if (!(session_p
->digest
.flags
& CRYPTO_OPERATION_ACTIVE
)) {
264 return (CKR_OPERATION_NOT_INITIALIZED
);
267 bufp
= session_p
->digest
.context
;
269 op_data_len
= sizeof (int);
270 op_data_len
+= sizeof (CK_STATE
);
271 op_data_len
+= sizeof (crypto_active_op_t
);
272 op_data_len
+= bufp
->indata_len
;
274 if (pOperationState
== NULL_PTR
) {
275 *pulOperationStateLen
= op_data_len
;
278 if (*pulOperationStateLen
< op_data_len
) {
279 *pulOperationStateLen
= op_data_len
;
280 return (CKR_BUFFER_TOO_SMALL
);
284 dst
= pOperationState
;
286 /* Save total length */
287 bcopy(&op_data_len
, dst
, sizeof (int));
290 /* Save session state */
291 bcopy(&ses_state
, dst
, sizeof (CK_STATE
));
292 dst
+= sizeof (CK_STATE
);
294 /* Save crypto_active_op_t */
295 bcopy(&session_p
->digest
, dst
, sizeof (crypto_active_op_t
));
296 dst
+= sizeof (crypto_active_op_t
);
298 /* Save the data buffer */
299 bcopy(bufp
->buf
, dst
, bufp
->indata_len
);
301 *pulOperationStateLen
= op_data_len
;
306 C_GetOperationState(CK_SESSION_HANDLE hSession
, CK_BYTE_PTR pOperationState
,
307 CK_ULONG_PTR pulOperationStateLen
)
311 kernel_session_t
*session_p
;
312 boolean_t ses_lock_held
= B_TRUE
;
314 if (!kernel_initialized
)
315 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
317 if (pulOperationStateLen
== NULL_PTR
)
318 return (CKR_ARGUMENTS_BAD
);
321 * Obtain the session pointer. Also, increment the session
324 rv
= handle2session(hSession
, &session_p
);
328 ses_state
= get_ses_state(session_p
);
330 (void) pthread_mutex_lock(&session_p
->session_mutex
);
331 rv
= kernel_get_operationstate(session_p
, ses_state
,
332 pOperationState
, pulOperationStateLen
);
334 REFRELE(session_p
, ses_lock_held
);
339 * Restore the state from pOperationState. The data format is:
340 * 1. Total length (including this field)
342 * 3. crypto_active_op_t structure
343 * 4. digest_buf_t's data buffer contents
346 kernel_set_operationstate(kernel_session_t
*session_p
, CK_STATE ses_state
,
347 CK_BYTE_PTR pOperationState
, CK_ULONG ulOperationStateLen
,
348 CK_OBJECT_HANDLE hEncryptionKey
, CK_OBJECT_HANDLE hAuthenticationKey
)
352 CK_STATE src_ses_state
;
353 int expected_len
, indata_len
;
355 crypto_active_op_t tmp_op
;
357 if ((hAuthenticationKey
!= 0) || (hEncryptionKey
!= 0))
358 return (CKR_KEY_NOT_NEEDED
);
360 src
= pOperationState
;
362 /* Get total length field */
363 bcopy(src
, &expected_len
, sizeof (int));
364 if (ulOperationStateLen
< expected_len
)
365 return (CKR_SAVED_STATE_INVALID
);
367 /* compute the data buffer length */
368 indata_len
= expected_len
- sizeof (int) -
369 sizeof (CK_STATE
) - sizeof (crypto_active_op_t
);
370 if (indata_len
> SLOT_HASH_MAX_INDATA_LEN(session_p
))
371 return (CKR_SAVED_STATE_INVALID
);
374 /* Get session state */
375 bcopy(src
, &src_ses_state
, sizeof (CK_STATE
));
376 if (ses_state
!= src_ses_state
)
377 return (CKR_SAVED_STATE_INVALID
);
378 src
+= sizeof (CK_STATE
);
381 * Restore crypto_active_op_t. We need to use a temporary
382 * buffer to avoid modifying the source session's buffer.
384 bcopy(src
, &tmp_op
, sizeof (crypto_active_op_t
));
385 if (tmp_op
.flags
& CRYPTO_EMULATE_USING_SW
)
386 return (CKR_SAVED_STATE_INVALID
);
387 session_p
->digest
.mech
= tmp_op
.mech
;
388 session_p
->digest
.flags
= tmp_op
.flags
;
389 src
+= sizeof (crypto_active_op_t
);
391 /* This routine reuses the session's existing buffer if possible */
392 rv
= emulate_buf_init(session_p
, indata_len
, OP_DIGEST
);
395 bufp
= session_p
->digest
.context
;
396 bufp
->indata_len
= indata_len
;
398 /* Restore the data buffer */
399 bcopy(src
, bufp
->buf
, bufp
->indata_len
);
406 C_SetOperationState(CK_SESSION_HANDLE hSession
, CK_BYTE_PTR pOperationState
,
407 CK_ULONG ulOperationStateLen
, CK_OBJECT_HANDLE hEncryptionKey
,
408 CK_OBJECT_HANDLE hAuthenticationKey
)
412 kernel_session_t
*session_p
;
413 boolean_t ses_lock_held
= B_TRUE
;
415 if (!kernel_initialized
)
416 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
418 if ((pOperationState
== NULL_PTR
) ||
419 (ulOperationStateLen
== 0))
420 return (CKR_ARGUMENTS_BAD
);
422 rv
= handle2session(hSession
, &session_p
);
426 ses_state
= get_ses_state(session_p
);
428 (void) pthread_mutex_lock(&session_p
->session_mutex
);
430 rv
= kernel_set_operationstate(session_p
, ses_state
,
431 pOperationState
, ulOperationStateLen
,
432 hEncryptionKey
, hAuthenticationKey
);
434 REFRELE(session_p
, ses_lock_held
);
440 C_Login(CK_SESSION_HANDLE hSession
, CK_USER_TYPE userType
,
441 CK_UTF8CHAR_PTR pPin
, CK_ULONG ulPinLen
)
444 kernel_session_t
*session_p
;
445 kernel_slot_t
*pslot
;
446 boolean_t ses_lock_held
= B_FALSE
;
447 crypto_login_t c_login
;
450 if (!kernel_initialized
)
451 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
453 if ((userType
!= CKU_SO
) && (userType
!= CKU_USER
)) {
454 return (CKR_USER_TYPE_INVALID
);
458 * Obtain the session pointer. Also, increment the session
461 rv
= handle2session(hSession
, &session_p
);
465 /* Acquire the slot lock */
466 pslot
= slot_table
[session_p
->ses_slotid
];
467 (void) pthread_mutex_lock(&pslot
->sl_mutex
);
469 /* Check if the slot is logged in already */
470 if ((pslot
->sl_state
== CKU_USER
) || (pslot
->sl_state
== CKU_SO
)) {
471 rv
= CKR_USER_ALREADY_LOGGED_IN
;
475 /* To login as SO, every session in this slot needs to be R/W */
476 if (userType
== CKU_SO
) {
477 kernel_session_t
*sp
;
481 sp
= pslot
->sl_sess_list
;
484 * Need not to lock individual sessions before
485 * accessing their "ses_RO" and "next" fields,
486 * because they are always accessed under the
487 * slot's mutex protection.
497 rv
= CKR_SESSION_READ_ONLY_EXISTS
;
502 /* Now make the ioctl call; no need to acquire the session lock. */
503 c_login
.co_session
= session_p
->k_session
;
504 c_login
.co_user_type
= userType
;
505 c_login
.co_pin_len
= ulPinLen
;
506 c_login
.co_pin
= (char *)pPin
;
508 while ((r
= ioctl(kernel_fd
, CRYPTO_LOGIN
, &c_login
)) < 0) {
513 rv
= CKR_FUNCTION_FAILED
;
515 rv
= crypto2pkcs11_error_number(c_login
.co_return_value
);
519 /* Set the slot's session state. */
520 pslot
->sl_state
= userType
;
525 REFRELE(session_p
, ses_lock_held
);
526 (void) pthread_mutex_unlock(&pslot
->sl_mutex
);
532 C_Logout(CK_SESSION_HANDLE hSession
)
535 kernel_session_t
*session_p
;
536 kernel_slot_t
*pslot
;
537 boolean_t ses_lock_held
= B_FALSE
;
538 crypto_logout_t c_logout
;
541 if (!kernel_initialized
)
542 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
545 * Obtain the session pointer. Also, increment the session
548 rv
= handle2session(hSession
, &session_p
);
552 /* Acquire the slot lock. */
553 pslot
= slot_table
[session_p
->ses_slotid
];
554 (void) pthread_mutex_lock(&pslot
->sl_mutex
);
556 /* Check if the user or SO was logged in */
557 if (pslot
->sl_state
== CKU_PUBLIC
) {
558 rv
= CKR_USER_NOT_LOGGED_IN
;
562 /* Now make the ioctl call. No need to acquire the session lock. */
563 c_logout
.cl_session
= session_p
->k_session
;
564 while ((r
= ioctl(kernel_fd
, CRYPTO_LOGOUT
, &c_logout
)) < 0) {
569 rv
= CKR_FUNCTION_FAILED
;
571 rv
= crypto2pkcs11_error_number(c_logout
.cl_return_value
);
579 * If this slot was logged in as USER previously, we need to clean up
580 * all private object wrappers in library for this slot.
582 kernel_cleanup_pri_objects_in_slot(pslot
, session_p
);
585 /* Reset the slot's session state. */
586 pslot
->sl_state
= CKU_PUBLIC
;
590 REFRELE(session_p
, ses_lock_held
);
591 (void) pthread_mutex_unlock(&pslot
->sl_mutex
);