dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / pkcs11 / libpkcs11 / common / metaSession.c
blobc18f1731d1e925445e711533ba588a2b0b7dd5dd
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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)
31 #include <string.h>
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;
40 * meta_OpenSession
42 * NOTES:
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.
48 /* ARGSUSED */
49 CK_RV
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;
54 CK_RV rv;
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);
79 if (rv != CKR_OK)
80 return (rv);
82 new_session->session_flags = flags;
84 rv = meta_session_activate(new_session);
85 if (rv != CKR_OK) {
86 meta_session_dealloc(new_session);
87 return (rv);
90 *phSession = (CK_SESSION_HANDLE) new_session;
92 num_meta_sessions++;
93 if (flags & CKF_RW_SESSION) {
94 num_rw_meta_sessions++;
97 return (CKR_OK);
102 * meta_CloseSession
105 CK_RV
106 meta_CloseSession(CK_SESSION_HANDLE hSession)
108 CK_RV rv;
109 meta_session_t *session;
110 CK_FLAGS flags;
112 rv = meta_handle2session(hSession, &session);
113 if (rv != CKR_OK)
114 return (rv);
116 /* save info about session flags before they are destroyed */
117 flags = session->session_flags;
119 rv = meta_session_deactivate(session, B_FALSE);
121 if (rv == CKR_OK)
122 meta_session_dealloc(session);
124 num_meta_sessions--;
125 if (flags & CKF_RW_SESSION) {
126 num_rw_meta_sessions--;
129 return (rv);
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.
140 CK_RV
141 meta_CloseAllSessions(CK_SLOT_ID slotID)
143 CK_RV rv;
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);
156 if (rv != CKR_OK) {
157 /*NOTREACHED*/
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;
171 return (CKR_OK);
176 * meta_GetSessionInfo
179 CK_RV
180 meta_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo)
182 CK_RV rv;
183 meta_session_t *session;
185 if (pInfo == NULL)
186 return (CKR_ARGUMENTS_BAD);
188 rv = meta_handle2session(hSession, &session);
189 if (rv != CKR_OK)
190 return (rv);
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;
198 } else {
199 pInfo->state = CKS_RW_USER_FUNCTIONS;
201 } else {
202 if (IS_READ_ONLY_SESSION(session->session_flags)) {
203 pInfo->state = CKS_RO_PUBLIC_SESSION;
204 } else {
205 pInfo->state = CKS_RW_PUBLIC_SESSION;
209 pInfo->ulDeviceError = 0;
211 REFRELEASE(session);
213 return (CKR_OK);
216 CK_RV
217 meta_getopstatelen(meta_session_t *session, CK_ULONG *out_length)
219 CK_RV rv = CKR_OK;
220 slot_session_t *slot_session;
221 CK_ULONG length;
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);
228 if (rv == CKR_OK)
229 *out_length += length;
231 return (rv);
235 * meta_GetOperationState
238 CK_RV
239 meta_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState,
240 CK_ULONG_PTR pulOperationStateLen)
242 CK_RV rv;
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);
251 if (rv != CKR_OK)
252 return (rv);
255 * If no operation is active, then bail out.
257 if (session->op1.type == 0) {
258 rv = CKR_OPERATION_NOT_INITIALIZED;
259 goto endgetopstate;
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);
273 REFRELEASE(session);
274 return (rv);
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:
284 * struct metaopstate
285 * [ op1 state data ]
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.
300 if (rv == CKR_OK)
301 rv = CKR_BUFFER_TOO_SMALL;
302 goto endgetopstate;
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);
328 if (rv == CKR_OK)
329 rv = CKR_BUFFER_TOO_SMALL;
332 if (rv != CKR_OK)
333 goto endgetopstate;
336 endgetopstate:
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;
345 REFRELEASE(session);
346 return (rv);
349 static CK_RV
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,
354 CK_BYTE *databuf)
356 CK_RV rv;
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);
365 if (rv != CKR_OK) {
366 return (rv);
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);
372 if (rv != CKR_OK) {
373 return (rv);
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;
406 return (rv);
410 * meta_SetOperationState
413 CK_RV
414 meta_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState,
415 CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey,
416 CK_OBJECT_HANDLE hAuthenticationKey)
418 CK_RV rv = CKR_OK;
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);
447 if (rv != CKR_OK)
448 return (rv);
450 if (hEncryptionKey != CK_INVALID_HANDLE) {
451 rv = meta_handle2object(hEncryptionKey, &meta_enc_key);
452 if (rv != CKR_OK)
453 goto cleanup;
455 if (hAuthenticationKey != CK_INVALID_HANDLE) {
456 rv = meta_handle2object(hAuthenticationKey, &meta_auth_key);
457 if (rv != CKR_OK)
458 goto cleanup;
461 if (opstate.state[0].op_type != 0) {
462 if (session->op1.type != 0)
463 meta_operation_cleanup(session, session->op1.type,
464 B_FALSE);
466 if (session->op1.session != NULL) {
467 slot_session = session->op1.session;
468 } else {
469 rv = meta_get_slot_session(opstate.state[0].op_slotnum,
470 &slot_session, session->session_flags);
471 if (rv != CKR_OK)
472 goto cleanup;
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));
484 if (rv != CKR_OK) {
485 meta_operation_cleanup(session, session->op1.type,
486 FALSE);
487 goto cleanup;
491 cleanup:
492 if (meta_enc_key != NULL)
493 OBJRELEASE(meta_enc_key);
494 if (meta_auth_key != NULL)
495 OBJRELEASE(meta_auth_key);
496 REFRELEASE(session);
497 return (rv);
501 * meta_Login
503 * This allows the user to login to the object token. The metaslot itself
504 * does not have any kind of PIN.
507 CK_RV
508 meta_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
509 CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
511 CK_RV rv;
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);
518 if (rv != CKR_OK)
519 return (rv);
521 if (metaslot_logged_in()) {
522 rv = CKR_USER_ALREADY_LOGGED_IN;
523 goto finish;
526 /* Note: CKU_SO is not supported. */
527 if (userType != CKU_USER) {
528 rv = CKR_USER_TYPE_INVALID;
529 goto finish;
532 rv = meta_get_slot_session(get_keystore_slotnum(), &login_session,
533 session->session_flags);
534 if (rv != CKR_OK)
535 goto finish;
538 fw_st_id = login_session->fw_st_id;
539 rv = FUNCLIST(fw_st_id)->C_Login(login_session->hSession, userType,
540 pPin, ulPinLen);
542 if (rv != CKR_OK) {
543 goto finish;
547 * Note:
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);
561 if (rv != CKR_OK) {
562 goto finish;
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);
569 finish:
570 if (login_session)
571 meta_release_slot_session(login_session);
573 REFRELEASE(session);
575 return (rv);
579 * meta_Logout
582 CK_RV
583 meta_Logout(CK_SESSION_HANDLE hSession)
585 CK_RV rv = CKR_OK;
586 meta_session_t *session;
587 slot_session_t *logout_session = NULL;
589 rv = meta_handle2session(hSession, &session);
590 if (rv != CKR_OK)
591 return (rv);
593 if (!metaslot_logged_in()) {
594 rv = CKR_USER_NOT_LOGGED_IN;
595 goto finish;
598 rv = meta_get_slot_session(get_keystore_slotnum(), &logout_session,
599 session->session_flags);
600 if (rv != CKR_OK)
601 goto finish;
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);
610 finish:
611 if (logout_session)
612 meta_release_slot_session(logout_session);
614 REFRELEASE(session);
616 return (rv);