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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Session Management Functions 30 * (as defined in PKCS#11 spec spection 11.6) 31 */ 32 33 #include <string.h> 34 #include "metaGlobal.h" 35 36 extern meta_session_t *meta_sessionlist_head; 37 extern pthread_rwlock_t meta_sessionlist_lock; 38 extern CK_ULONG num_meta_sessions; 39 extern CK_ULONG num_rw_meta_sessions; 40 41 /* 42 * meta_OpenSession 43 * 44 * NOTES: 45 * 1) The pApplication and Notify args are not used, as the metaslot does not 46 * support application callbacks. 47 * 2) the slotID argument is not checked or used because this function 48 * is only called from the framework. 49 */ 50 /* ARGSUSED */ 51 CK_RV 52 meta_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, 53 CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession) 54 { 55 meta_session_t *new_session; 56 CK_RV rv; 57 58 if (!metaslot_enabled) { 59 return (CKR_SLOT_ID_INVALID); 60 } 61 62 if (phSession == NULL) { 63 return (CKR_ARGUMENTS_BAD); 64 } 65 66 /* Check for any unknown flags. */ 67 if (flags & ~(CKF_SERIAL_SESSION | CKF_RW_SESSION)) { 68 return (CKR_ARGUMENTS_BAD); 69 } 70 71 if (!(flags & CKF_SERIAL_SESSION)) { 72 return (CKR_SESSION_PARALLEL_NOT_SUPPORTED); 73 } 74 75 if (meta_slotManager_token_write_protected() && 76 (flags & CKF_RW_SESSION)) { 77 return (CKR_TOKEN_WRITE_PROTECTED); 78 } 79 80 rv = meta_session_alloc(&new_session); 81 if (rv != CKR_OK) 82 return (rv); 83 84 new_session->session_flags = flags; 85 86 rv = meta_session_activate(new_session); 87 if (rv != CKR_OK) { 88 meta_session_dealloc(new_session); 89 return (rv); 90 } 91 92 *phSession = (CK_SESSION_HANDLE) new_session; 93 94 num_meta_sessions++; 95 if (flags & CKF_RW_SESSION) { 96 num_rw_meta_sessions++; 97 } 98 99 return (CKR_OK); 100 } 101 102 103 /* 104 * meta_CloseSession 105 * 106 */ 107 CK_RV 108 meta_CloseSession(CK_SESSION_HANDLE hSession) 109 { 110 CK_RV rv; 111 meta_session_t *session; 112 CK_FLAGS flags; 113 114 rv = meta_handle2session(hSession, &session); 115 if (rv != CKR_OK) 116 return (rv); 117 118 /* save info about session flags before they are destroyed */ 119 flags = session->session_flags; 120 121 rv = meta_session_deactivate(session, B_FALSE); 122 123 if (rv == CKR_OK) 124 meta_session_dealloc(session); 125 126 num_meta_sessions--; 127 if (flags & CKF_RW_SESSION) { 128 num_rw_meta_sessions--; 129 } 130 131 return (rv); 132 } 133 134 135 /* 136 * meta_CloseAllSessions 137 * 138 * This is a simple loop that closes the sessionlist head (resulting in a 139 * new list head) until the list is empty. 140 * 141 */ 142 CK_RV 143 meta_CloseAllSessions(CK_SLOT_ID slotID) 144 { 145 CK_RV rv; 146 meta_session_t *session; 147 148 if (!metaslot_enabled) { 149 return (CKR_SLOT_ID_INVALID); 150 } 151 152 if (slotID != METASLOT_SLOTID) 153 return (CKR_SLOT_ID_INVALID); 154 155 (void) pthread_rwlock_wrlock(&meta_sessionlist_lock); 156 while ((session = meta_sessionlist_head) != NULL) { 157 rv = meta_handle2session((CK_SESSION_HANDLE)session, &session); 158 if (rv != CKR_OK) { 159 /*NOTREACHED*/ 160 (void) pthread_rwlock_unlock(&meta_sessionlist_lock); 161 return (CKR_FUNCTION_FAILED); 162 } 163 164 (void) meta_session_deactivate(session, B_TRUE); 165 meta_session_dealloc(session); 166 } 167 (void) pthread_rwlock_unlock(&meta_sessionlist_lock); 168 169 /* All open sessions should be closed, just reset the variables */ 170 num_meta_sessions = 0; 171 num_rw_meta_sessions = 0; 172 173 return (CKR_OK); 174 } 175 176 177 /* 178 * meta_GetSessionInfo 179 * 180 */ 181 CK_RV 182 meta_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) 183 { 184 CK_RV rv; 185 meta_session_t *session; 186 187 if (pInfo == NULL) 188 return (CKR_ARGUMENTS_BAD); 189 190 rv = meta_handle2session(hSession, &session); 191 if (rv != CKR_OK) 192 return (rv); 193 194 pInfo->slotID = METASLOT_SLOTID; 195 pInfo->flags = session->session_flags; 196 197 if (metaslot_logged_in()) { 198 if (IS_READ_ONLY_SESSION(session->session_flags)) { 199 pInfo->state = CKS_RO_USER_FUNCTIONS; 200 } else { 201 pInfo->state = CKS_RW_USER_FUNCTIONS; 202 } 203 } else { 204 if (IS_READ_ONLY_SESSION(session->session_flags)) { 205 pInfo->state = CKS_RO_PUBLIC_SESSION; 206 } else { 207 pInfo->state = CKS_RW_PUBLIC_SESSION; 208 } 209 } 210 211 pInfo->ulDeviceError = 0; 212 213 REFRELEASE(session); 214 215 return (CKR_OK); 216 } 217 218 CK_RV 219 meta_getopstatelen(meta_session_t *session, CK_ULONG *out_length) 220 { 221 CK_RV rv = CKR_OK; 222 slot_session_t *slot_session; 223 CK_ULONG length; 224 225 *out_length = sizeof (meta_opstate_t); 226 if (session->op1.type != 0) { 227 slot_session = session->op1.session; 228 rv = FUNCLIST(slot_session->fw_st_id)->C_GetOperationState( 229 slot_session->hSession, NULL, &length); 230 if (rv == CKR_OK) 231 *out_length += length; 232 } 233 return (rv); 234 } 235 236 /* 237 * meta_GetOperationState 238 * 239 */ 240 CK_RV 241 meta_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 242 CK_ULONG_PTR pulOperationStateLen) 243 { 244 CK_RV rv; 245 meta_session_t *session; 246 slot_session_t *slot_session = NULL; 247 meta_opstate_t opstate; 248 249 if (pulOperationStateLen == NULL) 250 return (CKR_ARGUMENTS_BAD); 251 252 rv = meta_handle2session(hSession, &session); 253 if (rv != CKR_OK) 254 return (rv); 255 256 /* 257 * If no operation is active, then bail out. 258 */ 259 if (session->op1.type == 0) { 260 rv = CKR_OPERATION_NOT_INITIALIZED; 261 goto endgetopstate; 262 } 263 264 /* 265 * If the caller did not give an OpState buffer, 266 * shortcut and just return the size needed to hold 267 * a metaslot OpState record later. 268 * The actual size of the returned state will be the 269 * sizeof(meta_opstate_t) + SIZE (op1 state), 270 * so we have to get the size of 271 * the operation states now. 272 */ 273 if (pOperationState == NULL) { 274 rv = meta_getopstatelen(session, pulOperationStateLen); 275 REFRELEASE(session); 276 return (rv); 277 } 278 279 /* 280 * To be here, the caller must have supplied an 281 * already initialized meta_opstate_t pointer. 282 * Use it to get the real state info from the operation(s). 283 * 284 * The format of the Metaslot Opstate record: 285 * { 286 * struct metaopstate 287 * [ op1 state data ] 288 * } 289 */ 290 291 /* 292 * If the buffer is not even big enough for the metaslot 293 * opstate data, return error and set the returned 294 * state length to indicate the minimum needed. 295 */ 296 if (*pulOperationStateLen < sizeof (meta_opstate_t)) { 297 rv = meta_getopstatelen(session, pulOperationStateLen); 298 /* 299 * Remap the error so the caller knows that they 300 * used an invalid buffer size in the first place. 301 */ 302 if (rv == CKR_OK) 303 rv = CKR_BUFFER_TOO_SMALL; 304 goto endgetopstate; 305 } 306 307 (void) memset(&opstate, 0, sizeof (meta_opstate_t)); 308 opstate.magic_marker = METASLOT_OPSTATE_MAGIC; 309 310 if (session->op1.type != 0) { 311 slot_session = session->op1.session; 312 opstate.state[0].op_type = session->op1.type; 313 opstate.state[0].op_slotnum = slot_session->slotnum; 314 opstate.state[0].op_state_len = *pulOperationStateLen - 315 sizeof (meta_opstate_t); 316 opstate.state[0].op_init_app = session->init.app; 317 opstate.state[0].op_init_done = session->init.done; 318 rv = FUNCLIST(slot_session->fw_st_id)->C_GetOperationState( 319 slot_session->hSession, 320 pOperationState + sizeof (meta_opstate_t), 321 &(opstate.state[0].op_state_len)); 322 323 if (rv == CKR_BUFFER_TOO_SMALL) { 324 /* 325 * This should not happen, but if it does, 326 * recalculate the entire size needed 327 * and return the error. 328 */ 329 rv = meta_getopstatelen(session, pulOperationStateLen); 330 if (rv == CKR_OK) 331 rv = CKR_BUFFER_TOO_SMALL; 332 } 333 334 if (rv != CKR_OK) 335 goto endgetopstate; 336 } 337 338 endgetopstate: 339 if (rv == CKR_OK && pOperationState != NULL) { 340 (void) memcpy(pOperationState, (void *)&opstate, 341 sizeof (meta_opstate_t)); 342 343 *pulOperationStateLen = sizeof (meta_opstate_t) + 344 opstate.state[0].op_state_len; 345 } 346 347 REFRELEASE(session); 348 return (rv); 349 } 350 351 static CK_RV 352 meta_set_opstate(slot_session_t *slot_session, 353 meta_object_t *meta_enc_key, 354 meta_object_t *meta_auth_key, 355 struct opstate_data *state, 356 CK_BYTE *databuf) 357 { 358 CK_RV rv; 359 static CK_ULONG encrypt_optypes = (CKF_ENCRYPT | CKF_DECRYPT); 360 static CK_ULONG sign_optypes = (CKF_SIGN | CKF_VERIFY | 361 CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER); 362 slot_object_t *enc_key_obj = NULL, *auth_key_obj = NULL; 363 364 if (state->op_type & encrypt_optypes) { 365 rv = meta_object_get_clone(meta_enc_key, slot_session->slotnum, 366 slot_session, &enc_key_obj); 367 if (rv != CKR_OK) { 368 return (rv); 369 } 370 } 371 if (state->op_type & sign_optypes) { 372 rv = meta_object_get_clone(meta_auth_key, slot_session->slotnum, 373 slot_session, &auth_key_obj); 374 if (rv != CKR_OK) { 375 return (rv); 376 } 377 } 378 379 /* 380 * Check to see if the keys are needed to restore the 381 * state on the first operation. 382 */ 383 rv = FUNCLIST(slot_session->fw_st_id)->C_SetOperationState( 384 slot_session->hSession, databuf, state->op_state_len, 385 enc_key_obj ? enc_key_obj->hObject : CK_INVALID_HANDLE, 386 auth_key_obj ? auth_key_obj->hObject : CK_INVALID_HANDLE); 387 /* 388 * If the operation did not need a key, try again. 389 */ 390 if (rv == CKR_KEY_NOT_NEEDED) { 391 rv = FUNCLIST(slot_session->fw_st_id)->C_SetOperationState( 392 slot_session->hSession, databuf, state->op_state_len, 393 CK_INVALID_HANDLE, CK_INVALID_HANDLE); 394 /* 395 * Strange case... If the first try returned 396 * KEY_NOT_NEEDED, and this one returns KEY_NEEDED, 397 * we want to remap the return so the caller sees 398 * the original "CKR_KEY_NOT_NEEDED" return value. 399 * This ensures that a correct caller will retry 400 * without the unnecessary key argument and this 401 * 2nd attempt will not happen again. 402 */ 403 if (rv == CKR_KEY_NEEDED) { 404 rv = CKR_KEY_NOT_NEEDED; 405 } 406 } 407 408 return (rv); 409 } 410 411 /* 412 * meta_SetOperationState 413 * 414 */ 415 CK_RV 416 meta_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 417 CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, 418 CK_OBJECT_HANDLE hAuthenticationKey) 419 { 420 CK_RV rv = CKR_OK; 421 meta_session_t *session; 422 slot_session_t *slot_session = NULL; 423 meta_opstate_t opstate; 424 meta_object_t *meta_enc_key = NULL, *meta_auth_key = NULL; 425 426 /* 427 * Make sure the opstate info buffer is big enough to be valid. 428 */ 429 if (ulOperationStateLen < sizeof (meta_opstate_t) || 430 pOperationState == NULL) 431 return (CKR_ARGUMENTS_BAD); 432 433 /* Copy the opstate info into the structure */ 434 (void) memcpy(&opstate, pOperationState, sizeof (meta_opstate_t)); 435 436 /* verify that a metaslot operation state was supplied */ 437 if (opstate.magic_marker != METASLOT_OPSTATE_MAGIC) 438 return (CKR_SAVED_STATE_INVALID); 439 440 /* 441 * Now, check the size again to make sure the "real" state 442 * data is present. Length of state provided must be exact. 443 */ 444 if (ulOperationStateLen != (sizeof (meta_opstate_t) + 445 opstate.state[0].op_state_len)) 446 return (CKR_SAVED_STATE_INVALID); 447 448 rv = meta_handle2session(hSession, &session); 449 if (rv != CKR_OK) 450 return (rv); 451 452 if (hEncryptionKey != CK_INVALID_HANDLE) { 453 rv = meta_handle2object(hEncryptionKey, &meta_enc_key); 454 if (rv != CKR_OK) 455 goto cleanup; 456 } 457 if (hAuthenticationKey != CK_INVALID_HANDLE) { 458 rv = meta_handle2object(hAuthenticationKey, &meta_auth_key); 459 if (rv != CKR_OK) 460 goto cleanup; 461 } 462 463 if (opstate.state[0].op_type != 0) { 464 if (session->op1.type != 0) 465 meta_operation_cleanup(session, session->op1.type, 466 B_FALSE); 467 468 rv = meta_get_slot_session(opstate.state[0].op_slotnum, 469 &slot_session, session->session_flags); 470 if (rv != CKR_OK) 471 goto cleanup; 472 473 session->op1.type = opstate.state[0].op_type; 474 session->op1.session = slot_session; 475 session->init.app = opstate.state[0].op_init_app; 476 session->init.done = opstate.state[0].op_init_done; 477 478 rv = meta_set_opstate(slot_session, meta_enc_key, 479 meta_auth_key, &(opstate.state[0]), 480 pOperationState + sizeof (meta_opstate_t)); 481 482 if (rv != CKR_OK) { 483 meta_operation_cleanup(session, session->op1.type, 484 FALSE); 485 goto cleanup; 486 } 487 } 488 489 cleanup: 490 if (meta_enc_key != NULL) 491 OBJRELEASE(meta_enc_key); 492 if (meta_auth_key != NULL) 493 OBJRELEASE(meta_auth_key); 494 REFRELEASE(session); 495 return (rv); 496 } 497 498 /* 499 * meta_Login 500 * 501 * This allows the user to login to the object token. The metaslot itself 502 * does not have any kind of PIN. 503 * 504 */ 505 CK_RV 506 meta_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, 507 CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) 508 { 509 CK_RV rv; 510 meta_session_t *session; 511 slot_session_t *login_session = NULL; 512 CK_TOKEN_INFO token_info; 513 CK_SLOT_ID true_id, fw_st_id; 514 515 rv = meta_handle2session(hSession, &session); 516 if (rv != CKR_OK) 517 return (rv); 518 519 if (metaslot_logged_in()) { 520 rv = CKR_USER_ALREADY_LOGGED_IN; 521 goto finish; 522 } 523 524 /* Note: CKU_SO is not supported. */ 525 if (userType != CKU_USER) { 526 rv = CKR_USER_TYPE_INVALID; 527 goto finish; 528 } 529 530 rv = meta_get_slot_session(get_keystore_slotnum(), &login_session, 531 session->session_flags); 532 if (rv != CKR_OK) 533 goto finish; 534 535 536 fw_st_id = login_session->fw_st_id; 537 rv = FUNCLIST(fw_st_id)->C_Login(login_session->hSession, userType, 538 pPin, ulPinLen); 539 540 if (rv != CKR_OK) { 541 goto finish; 542 } 543 544 /* 545 * Note: 546 * 547 * For some slots (eg: the pkcs11_softtoken.so), C_Login() 548 * returning OK don't mean that the login is truely 549 * successful. For pkcs11_softtoken.so, the CKF_USER_PIN_TO_BE_CHANGED 550 * is set to indicate that the pin needs to be changed, and 551 * the login is not really successful. We will check 552 * that flag for this special condition. Checking for 553 * this flag shouldn't be harmful for other slots that doesn't 554 * behave like pkcs11_softtoken.so. 555 */ 556 557 true_id = TRUEID(fw_st_id); 558 rv = FUNCLIST(fw_st_id)->C_GetTokenInfo(true_id, &token_info); 559 if (rv != CKR_OK) { 560 goto finish; 561 } 562 563 metaslot_set_logged_in_flag(B_TRUE); 564 if (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED) { 565 metaslot_set_logged_in_flag(B_FALSE); 566 } 567 finish: 568 if (login_session) 569 meta_release_slot_session(login_session); 570 571 REFRELEASE(session); 572 573 return (rv); 574 } 575 576 /* 577 * meta_Logout 578 * 579 */ 580 CK_RV 581 meta_Logout(CK_SESSION_HANDLE hSession) 582 { 583 CK_RV rv = CKR_OK; 584 meta_session_t *session; 585 slot_session_t *logout_session = NULL; 586 587 rv = meta_handle2session(hSession, &session); 588 if (rv != CKR_OK) 589 return (rv); 590 591 if (!metaslot_logged_in()) { 592 rv = CKR_USER_NOT_LOGGED_IN; 593 goto finish; 594 } 595 596 rv = meta_get_slot_session(get_keystore_slotnum(), &logout_session, 597 session->session_flags); 598 if (rv != CKR_OK) 599 goto finish; 600 601 rv = FUNCLIST(logout_session->fw_st_id)->C_Logout( 602 logout_session->hSession); 603 604 /* If the C_Logout fails, just ignore the error. */ 605 metaslot_set_logged_in_flag(B_FALSE); 606 607 finish: 608 if (logout_session) 609 meta_release_slot_session(logout_session); 610 611 REFRELEASE(session); 612 613 return (rv); 614 } 615