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.
27 * Session Management Functions
28 * (as defined in PKCS#11 spec spection 11.6)
32 #include "metaGlobal.h"
34 extern meta_session_t
*meta_sessionlist_head
;
35 extern pthread_rwlock_t meta_sessionlist_lock
;
36 extern CK_ULONG num_meta_sessions
;
37 extern CK_ULONG num_rw_meta_sessions
;
43 * 1) The pApplication and Notify args are not used, as the metaslot does not
44 * support application callbacks.
45 * 2) the slotID argument is not checked or used because this function
46 * is only called from the framework.
50 meta_OpenSession(CK_SLOT_ID slotID
, CK_FLAGS flags
, CK_VOID_PTR pApplication
,
51 CK_NOTIFY Notify
, CK_SESSION_HANDLE_PTR phSession
)
53 meta_session_t
*new_session
;
56 if (!metaslot_enabled
) {
57 return (CKR_SLOT_ID_INVALID
);
60 if (phSession
== NULL
) {
61 return (CKR_ARGUMENTS_BAD
);
64 /* Check for any unknown flags. */
65 if (flags
& ~(CKF_SERIAL_SESSION
| CKF_RW_SESSION
)) {
66 return (CKR_ARGUMENTS_BAD
);
69 if (!(flags
& CKF_SERIAL_SESSION
)) {
70 return (CKR_SESSION_PARALLEL_NOT_SUPPORTED
);
73 if (meta_slotManager_token_write_protected() &&
74 (flags
& CKF_RW_SESSION
)) {
75 return (CKR_TOKEN_WRITE_PROTECTED
);
78 rv
= meta_session_alloc(&new_session
);
82 new_session
->session_flags
= flags
;
84 rv
= meta_session_activate(new_session
);
86 meta_session_dealloc(new_session
);
90 *phSession
= (CK_SESSION_HANDLE
) new_session
;
93 if (flags
& CKF_RW_SESSION
) {
94 num_rw_meta_sessions
++;
106 meta_CloseSession(CK_SESSION_HANDLE hSession
)
109 meta_session_t
*session
;
112 rv
= meta_handle2session(hSession
, &session
);
116 /* save info about session flags before they are destroyed */
117 flags
= session
->session_flags
;
119 rv
= meta_session_deactivate(session
, B_FALSE
);
122 meta_session_dealloc(session
);
125 if (flags
& CKF_RW_SESSION
) {
126 num_rw_meta_sessions
--;
134 * meta_CloseAllSessions
136 * This is a simple loop that closes the sessionlist head (resulting in a
137 * new list head) until the list is empty.
141 meta_CloseAllSessions(CK_SLOT_ID slotID
)
144 meta_session_t
*session
;
146 if (!metaslot_enabled
) {
147 return (CKR_SLOT_ID_INVALID
);
150 if (slotID
!= METASLOT_SLOTID
)
151 return (CKR_SLOT_ID_INVALID
);
153 (void) pthread_rwlock_wrlock(&meta_sessionlist_lock
);
154 while ((session
= meta_sessionlist_head
) != NULL
) {
155 rv
= meta_handle2session((CK_SESSION_HANDLE
)session
, &session
);
158 (void) pthread_rwlock_unlock(&meta_sessionlist_lock
);
159 return (CKR_FUNCTION_FAILED
);
162 (void) meta_session_deactivate(session
, B_TRUE
);
163 meta_session_dealloc(session
);
165 (void) pthread_rwlock_unlock(&meta_sessionlist_lock
);
167 /* All open sessions should be closed, just reset the variables */
168 num_meta_sessions
= 0;
169 num_rw_meta_sessions
= 0;
176 * meta_GetSessionInfo
180 meta_GetSessionInfo(CK_SESSION_HANDLE hSession
, CK_SESSION_INFO_PTR pInfo
)
183 meta_session_t
*session
;
186 return (CKR_ARGUMENTS_BAD
);
188 rv
= meta_handle2session(hSession
, &session
);
192 pInfo
->slotID
= METASLOT_SLOTID
;
193 pInfo
->flags
= session
->session_flags
;
195 if (metaslot_logged_in()) {
196 if (IS_READ_ONLY_SESSION(session
->session_flags
)) {
197 pInfo
->state
= CKS_RO_USER_FUNCTIONS
;
199 pInfo
->state
= CKS_RW_USER_FUNCTIONS
;
202 if (IS_READ_ONLY_SESSION(session
->session_flags
)) {
203 pInfo
->state
= CKS_RO_PUBLIC_SESSION
;
205 pInfo
->state
= CKS_RW_PUBLIC_SESSION
;
209 pInfo
->ulDeviceError
= 0;
217 meta_getopstatelen(meta_session_t
*session
, CK_ULONG
*out_length
)
220 slot_session_t
*slot_session
;
223 *out_length
= sizeof (meta_opstate_t
);
224 if (session
->op1
.type
!= 0) {
225 slot_session
= session
->op1
.session
;
226 rv
= FUNCLIST(slot_session
->fw_st_id
)->C_GetOperationState(
227 slot_session
->hSession
, NULL
, &length
);
229 *out_length
+= length
;
235 * meta_GetOperationState
239 meta_GetOperationState(CK_SESSION_HANDLE hSession
, CK_BYTE_PTR pOperationState
,
240 CK_ULONG_PTR pulOperationStateLen
)
243 meta_session_t
*session
;
244 slot_session_t
*slot_session
= NULL
;
245 meta_opstate_t opstate
;
247 if (pulOperationStateLen
== NULL
)
248 return (CKR_ARGUMENTS_BAD
);
250 rv
= meta_handle2session(hSession
, &session
);
255 * If no operation is active, then bail out.
257 if (session
->op1
.type
== 0) {
258 rv
= CKR_OPERATION_NOT_INITIALIZED
;
263 * If the caller did not give an OpState buffer,
264 * shortcut and just return the size needed to hold
265 * a metaslot OpState record later.
266 * The actual size of the returned state will be the
267 * sizeof(meta_opstate_t) + SIZE (op1 state),
268 * so we have to get the size of
269 * the operation states now.
271 if (pOperationState
== NULL
) {
272 rv
= meta_getopstatelen(session
, pulOperationStateLen
);
278 * To be here, the caller must have supplied an
279 * already initialized meta_opstate_t pointer.
280 * Use it to get the real state info from the operation(s).
282 * The format of the Metaslot Opstate record:
290 * If the buffer is not even big enough for the metaslot
291 * opstate data, return error and set the returned
292 * state length to indicate the minimum needed.
294 if (*pulOperationStateLen
< sizeof (meta_opstate_t
)) {
295 rv
= meta_getopstatelen(session
, pulOperationStateLen
);
297 * Remap the error so the caller knows that they
298 * used an invalid buffer size in the first place.
301 rv
= CKR_BUFFER_TOO_SMALL
;
305 (void) memset(&opstate
, 0, sizeof (meta_opstate_t
));
306 opstate
.magic_marker
= METASLOT_OPSTATE_MAGIC
;
308 if (session
->op1
.type
!= 0) {
309 slot_session
= session
->op1
.session
;
310 opstate
.state
[0].op_type
= session
->op1
.type
;
311 opstate
.state
[0].op_slotnum
= slot_session
->slotnum
;
312 opstate
.state
[0].op_state_len
= *pulOperationStateLen
-
313 sizeof (meta_opstate_t
);
314 opstate
.state
[0].op_init_app
= session
->init
.app
;
315 opstate
.state
[0].op_init_done
= session
->init
.done
;
316 rv
= FUNCLIST(slot_session
->fw_st_id
)->C_GetOperationState(
317 slot_session
->hSession
,
318 pOperationState
+ sizeof (meta_opstate_t
),
319 &(opstate
.state
[0].op_state_len
));
321 if (rv
== CKR_BUFFER_TOO_SMALL
) {
323 * This should not happen, but if it does,
324 * recalculate the entire size needed
325 * and return the error.
327 rv
= meta_getopstatelen(session
, pulOperationStateLen
);
329 rv
= CKR_BUFFER_TOO_SMALL
;
337 if (rv
== CKR_OK
&& pOperationState
!= NULL
) {
338 (void) memcpy(pOperationState
, (void *)&opstate
,
339 sizeof (meta_opstate_t
));
341 *pulOperationStateLen
= sizeof (meta_opstate_t
) +
342 opstate
.state
[0].op_state_len
;
350 meta_set_opstate(slot_session_t
*slot_session
,
351 meta_object_t
*meta_enc_key
,
352 meta_object_t
*meta_auth_key
,
353 struct opstate_data
*state
,
357 static CK_ULONG encrypt_optypes
= (CKF_ENCRYPT
| CKF_DECRYPT
);
358 static CK_ULONG sign_optypes
= (CKF_SIGN
| CKF_VERIFY
|
359 CKF_SIGN_RECOVER
| CKF_VERIFY_RECOVER
);
360 slot_object_t
*enc_key_obj
= NULL
, *auth_key_obj
= NULL
;
362 if (state
->op_type
& encrypt_optypes
) {
363 rv
= meta_object_get_clone(meta_enc_key
, slot_session
->slotnum
,
364 slot_session
, &enc_key_obj
);
369 if (state
->op_type
& sign_optypes
) {
370 rv
= meta_object_get_clone(meta_auth_key
, slot_session
->slotnum
,
371 slot_session
, &auth_key_obj
);
378 * Check to see if the keys are needed to restore the
379 * state on the first operation.
381 rv
= FUNCLIST(slot_session
->fw_st_id
)->C_SetOperationState(
382 slot_session
->hSession
, databuf
, state
->op_state_len
,
383 enc_key_obj
? enc_key_obj
->hObject
: CK_INVALID_HANDLE
,
384 auth_key_obj
? auth_key_obj
->hObject
: CK_INVALID_HANDLE
);
386 * If the operation did not need a key, try again.
388 if (rv
== CKR_KEY_NOT_NEEDED
) {
389 rv
= FUNCLIST(slot_session
->fw_st_id
)->C_SetOperationState(
390 slot_session
->hSession
, databuf
, state
->op_state_len
,
391 CK_INVALID_HANDLE
, CK_INVALID_HANDLE
);
393 * Strange case... If the first try returned
394 * KEY_NOT_NEEDED, and this one returns KEY_NEEDED,
395 * we want to remap the return so the caller sees
396 * the original "CKR_KEY_NOT_NEEDED" return value.
397 * This ensures that a correct caller will retry
398 * without the unnecessary key argument and this
399 * 2nd attempt will not happen again.
401 if (rv
== CKR_KEY_NEEDED
) {
402 rv
= CKR_KEY_NOT_NEEDED
;
410 * meta_SetOperationState
414 meta_SetOperationState(CK_SESSION_HANDLE hSession
, CK_BYTE_PTR pOperationState
,
415 CK_ULONG ulOperationStateLen
, CK_OBJECT_HANDLE hEncryptionKey
,
416 CK_OBJECT_HANDLE hAuthenticationKey
)
419 meta_session_t
*session
;
420 slot_session_t
*slot_session
= NULL
;
421 meta_opstate_t opstate
;
422 meta_object_t
*meta_enc_key
= NULL
, *meta_auth_key
= NULL
;
425 * Make sure the opstate info buffer is big enough to be valid.
427 if (ulOperationStateLen
< sizeof (meta_opstate_t
) ||
428 pOperationState
== NULL
)
429 return (CKR_ARGUMENTS_BAD
);
431 /* Copy the opstate info into the structure */
432 (void) memcpy(&opstate
, pOperationState
, sizeof (meta_opstate_t
));
434 /* verify that a metaslot operation state was supplied */
435 if (opstate
.magic_marker
!= METASLOT_OPSTATE_MAGIC
)
436 return (CKR_SAVED_STATE_INVALID
);
439 * Now, check the size again to make sure the "real" state
440 * data is present. Length of state provided must be exact.
442 if (ulOperationStateLen
!= (sizeof (meta_opstate_t
) +
443 opstate
.state
[0].op_state_len
))
444 return (CKR_SAVED_STATE_INVALID
);
446 rv
= meta_handle2session(hSession
, &session
);
450 if (hEncryptionKey
!= CK_INVALID_HANDLE
) {
451 rv
= meta_handle2object(hEncryptionKey
, &meta_enc_key
);
455 if (hAuthenticationKey
!= CK_INVALID_HANDLE
) {
456 rv
= meta_handle2object(hAuthenticationKey
, &meta_auth_key
);
461 if (opstate
.state
[0].op_type
!= 0) {
462 if (session
->op1
.type
!= 0)
463 meta_operation_cleanup(session
, session
->op1
.type
,
466 if (session
->op1
.session
!= NULL
) {
467 slot_session
= session
->op1
.session
;
469 rv
= meta_get_slot_session(opstate
.state
[0].op_slotnum
,
470 &slot_session
, session
->session_flags
);
475 session
->op1
.type
= opstate
.state
[0].op_type
;
476 session
->op1
.session
= slot_session
;
477 session
->init
.app
= opstate
.state
[0].op_init_app
;
478 session
->init
.done
= opstate
.state
[0].op_init_done
;
480 rv
= meta_set_opstate(slot_session
, meta_enc_key
,
481 meta_auth_key
, &(opstate
.state
[0]),
482 pOperationState
+ sizeof (meta_opstate_t
));
485 meta_operation_cleanup(session
, session
->op1
.type
,
492 if (meta_enc_key
!= NULL
)
493 OBJRELEASE(meta_enc_key
);
494 if (meta_auth_key
!= NULL
)
495 OBJRELEASE(meta_auth_key
);
503 * This allows the user to login to the object token. The metaslot itself
504 * does not have any kind of PIN.
508 meta_Login(CK_SESSION_HANDLE hSession
, CK_USER_TYPE userType
,
509 CK_UTF8CHAR_PTR pPin
, CK_ULONG ulPinLen
)
512 meta_session_t
*session
;
513 slot_session_t
*login_session
= NULL
;
514 CK_TOKEN_INFO token_info
;
515 CK_SLOT_ID true_id
, fw_st_id
;
517 rv
= meta_handle2session(hSession
, &session
);
521 if (metaslot_logged_in()) {
522 rv
= CKR_USER_ALREADY_LOGGED_IN
;
526 /* Note: CKU_SO is not supported. */
527 if (userType
!= CKU_USER
) {
528 rv
= CKR_USER_TYPE_INVALID
;
532 rv
= meta_get_slot_session(get_keystore_slotnum(), &login_session
,
533 session
->session_flags
);
538 fw_st_id
= login_session
->fw_st_id
;
539 rv
= FUNCLIST(fw_st_id
)->C_Login(login_session
->hSession
, userType
,
549 * For some slots (eg: the pkcs11_softtoken.so), C_Login()
550 * returning OK don't mean that the login is truely
551 * successful. For pkcs11_softtoken.so, the CKF_USER_PIN_TO_BE_CHANGED
552 * is set to indicate that the pin needs to be changed, and
553 * the login is not really successful. We will check
554 * that flag for this special condition. Checking for
555 * this flag shouldn't be harmful for other slots that doesn't
556 * behave like pkcs11_softtoken.so.
559 true_id
= TRUEID(fw_st_id
);
560 rv
= FUNCLIST(fw_st_id
)->C_GetTokenInfo(true_id
, &token_info
);
565 metaslot_set_logged_in_flag(B_TRUE
);
566 if (token_info
.flags
& CKF_USER_PIN_TO_BE_CHANGED
) {
567 metaslot_set_logged_in_flag(B_FALSE
);
571 meta_release_slot_session(login_session
);
583 meta_Logout(CK_SESSION_HANDLE hSession
)
586 meta_session_t
*session
;
587 slot_session_t
*logout_session
= NULL
;
589 rv
= meta_handle2session(hSession
, &session
);
593 if (!metaslot_logged_in()) {
594 rv
= CKR_USER_NOT_LOGGED_IN
;
598 rv
= meta_get_slot_session(get_keystore_slotnum(), &logout_session
,
599 session
->session_flags
);
603 rv
= FUNCLIST(logout_session
->fw_st_id
)->C_Logout(
604 logout_session
->hSession
);
606 /* If the C_Logout fails, just ignore the error. */
607 metaslot_set_logged_in_flag(B_FALSE
);
608 (void) meta_token_object_deactivate(PRIVATE_TOKEN
);
612 meta_release_slot_session(logout_session
);