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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Session Management Functions 28 * (as defined in PKCS#11 spec spection 11.6) 29 */ 30 31 #include <string.h> 32 #include "metaGlobal.h" 33 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; 38 39 /* 40 * meta_OpenSession 41 * 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. 47 */ 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) 52 { 53 meta_session_t *new_session; 54 CK_RV rv; 55 56 if (!metaslot_enabled) { 57 return (CKR_SLOT_ID_INVALID); 58 } 59 60 if (phSession == NULL) { 61 return (CKR_ARGUMENTS_BAD); 62 } 63 64 /* Check for any unknown flags. */ 65 if (flags & ~(CKF_SERIAL_SESSION | CKF_RW_SESSION)) { 66 return (CKR_ARGUMENTS_BAD); 67 } 68 69 if (!(flags & CKF_SERIAL_SESSION)) { 70 return (CKR_SESSION_PARALLEL_NOT_SUPPORTED); 71 } 72 73 if (meta_slotManager_token_write_protected() && 74 (flags & CKF_RW_SESSION)) { 75 return (CKR_TOKEN_WRITE_PROTECTED); 76 } 77 78 rv = meta_session_alloc(&new_session); 79 if (rv != CKR_OK) 80 return (rv); 81 82 new_session->session_flags = flags; 83 84 rv = meta_session_activate(new_session); 85 if (rv != CKR_OK) { 86 meta_session_dealloc(new_session); 87 return (rv); 88 } 89 90 *phSession = (CK_SESSION_HANDLE) new_session; 91 92 num_meta_sessions++; 93 if (flags & CKF_RW_SESSION) { 94 num_rw_meta_sessions++; 95 } 96 97 return (CKR_OK); 98 } 99 100 101 /* 102 * meta_CloseSession 103 * 104 */ 105 CK_RV 106 meta_CloseSession(CK_SESSION_HANDLE hSession) 107 { 108 CK_RV rv; 109 meta_session_t *session; 110 CK_FLAGS flags; 111 112 rv = meta_handle2session(hSession, &session); 113 if (rv != CKR_OK) 114 return (rv); 115 116 /* save info about session flags before they are destroyed */ 117 flags = session->session_flags; 118 119 rv = meta_session_deactivate(session, B_FALSE); 120 121 if (rv == CKR_OK) 122 meta_session_dealloc(session); 123 124 num_meta_sessions--; 125 if (flags & CKF_RW_SESSION) { 126 num_rw_meta_sessions--; 127 } 128 129 return (rv); 130 } 131 132 133 /* 134 * meta_CloseAllSessions 135 * 136 * This is a simple loop that closes the sessionlist head (resulting in a 137 * new list head) until the list is empty. 138 * 139 */ 140 CK_RV 141 meta_CloseAllSessions(CK_SLOT_ID slotID) 142 { 143 CK_RV rv; 144 meta_session_t *session; 145 146 if (!metaslot_enabled) { 147 return (CKR_SLOT_ID_INVALID); 148 } 149 150 if (slotID != METASLOT_SLOTID) 151 return (CKR_SLOT_ID_INVALID); 152 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); 160 } 161 162 (void) meta_session_deactivate(session, B_TRUE); 163 meta_session_dealloc(session); 164 } 165 (void) pthread_rwlock_unlock(&meta_sessionlist_lock); 166 167 /* All open sessions should be closed, just reset the variables */ 168 num_meta_sessions = 0; 169 num_rw_meta_sessions = 0; 170 171 return (CKR_OK); 172 } 173 174 175 /* 176 * meta_GetSessionInfo 177 * 178 */ 179 CK_RV 180 meta_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) 181 { 182 CK_RV rv; 183 meta_session_t *session; 184 185 if (pInfo == NULL) 186 return (CKR_ARGUMENTS_BAD); 187 188 rv = meta_handle2session(hSession, &session); 189 if (rv != CKR_OK) 190 return (rv); 191 192 pInfo->slotID = METASLOT_SLOTID; 193 pInfo->flags = session->session_flags; 194 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; 200 } 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; 206 } 207 } 208 209 pInfo->ulDeviceError = 0; 210 211 REFRELEASE(session); 212 213 return (CKR_OK); 214 } 215 216 CK_RV 217 meta_getopstatelen(meta_session_t *session, CK_ULONG *out_length) 218 { 219 CK_RV rv = CKR_OK; 220 slot_session_t *slot_session; 221 CK_ULONG length; 222 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; 230 } 231 return (rv); 232 } 233 234 /* 235 * meta_GetOperationState 236 * 237 */ 238 CK_RV 239 meta_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 240 CK_ULONG_PTR pulOperationStateLen) 241 { 242 CK_RV rv; 243 meta_session_t *session; 244 slot_session_t *slot_session = NULL; 245 meta_opstate_t opstate; 246 247 if (pulOperationStateLen == NULL) 248 return (CKR_ARGUMENTS_BAD); 249 250 rv = meta_handle2session(hSession, &session); 251 if (rv != CKR_OK) 252 return (rv); 253 254 /* 255 * If no operation is active, then bail out. 256 */ 257 if (session->op1.type == 0) { 258 rv = CKR_OPERATION_NOT_INITIALIZED; 259 goto endgetopstate; 260 } 261 262 /* 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. 270 */ 271 if (pOperationState == NULL) { 272 rv = meta_getopstatelen(session, pulOperationStateLen); 273 REFRELEASE(session); 274 return (rv); 275 } 276 277 /* 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). 281 * 282 * The format of the Metaslot Opstate record: 283 * { 284 * struct metaopstate 285 * [ op1 state data ] 286 * } 287 */ 288 289 /* 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. 293 */ 294 if (*pulOperationStateLen < sizeof (meta_opstate_t)) { 295 rv = meta_getopstatelen(session, pulOperationStateLen); 296 /* 297 * Remap the error so the caller knows that they 298 * used an invalid buffer size in the first place. 299 */ 300 if (rv == CKR_OK) 301 rv = CKR_BUFFER_TOO_SMALL; 302 goto endgetopstate; 303 } 304 305 (void) memset(&opstate, 0, sizeof (meta_opstate_t)); 306 opstate.magic_marker = METASLOT_OPSTATE_MAGIC; 307 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)); 320 321 if (rv == CKR_BUFFER_TOO_SMALL) { 322 /* 323 * This should not happen, but if it does, 324 * recalculate the entire size needed 325 * and return the error. 326 */ 327 rv = meta_getopstatelen(session, pulOperationStateLen); 328 if (rv == CKR_OK) 329 rv = CKR_BUFFER_TOO_SMALL; 330 } 331 332 if (rv != CKR_OK) 333 goto endgetopstate; 334 } 335 336 endgetopstate: 337 if (rv == CKR_OK && pOperationState != NULL) { 338 (void) memcpy(pOperationState, (void *)&opstate, 339 sizeof (meta_opstate_t)); 340 341 *pulOperationStateLen = sizeof (meta_opstate_t) + 342 opstate.state[0].op_state_len; 343 } 344 345 REFRELEASE(session); 346 return (rv); 347 } 348 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) 355 { 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; 361 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); 367 } 368 } 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); 374 } 375 } 376 377 /* 378 * Check to see if the keys are needed to restore the 379 * state on the first operation. 380 */ 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); 385 /* 386 * If the operation did not need a key, try again. 387 */ 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); 392 /* 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. 400 */ 401 if (rv == CKR_KEY_NEEDED) { 402 rv = CKR_KEY_NOT_NEEDED; 403 } 404 } 405 406 return (rv); 407 } 408 409 /* 410 * meta_SetOperationState 411 * 412 */ 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) 417 { 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; 423 424 /* 425 * Make sure the opstate info buffer is big enough to be valid. 426 */ 427 if (ulOperationStateLen < sizeof (meta_opstate_t) || 428 pOperationState == NULL) 429 return (CKR_ARGUMENTS_BAD); 430 431 /* Copy the opstate info into the structure */ 432 (void) memcpy(&opstate, pOperationState, sizeof (meta_opstate_t)); 433 434 /* verify that a metaslot operation state was supplied */ 435 if (opstate.magic_marker != METASLOT_OPSTATE_MAGIC) 436 return (CKR_SAVED_STATE_INVALID); 437 438 /* 439 * Now, check the size again to make sure the "real" state 440 * data is present. Length of state provided must be exact. 441 */ 442 if (ulOperationStateLen != (sizeof (meta_opstate_t) + 443 opstate.state[0].op_state_len)) 444 return (CKR_SAVED_STATE_INVALID); 445 446 rv = meta_handle2session(hSession, &session); 447 if (rv != CKR_OK) 448 return (rv); 449 450 if (hEncryptionKey != CK_INVALID_HANDLE) { 451 rv = meta_handle2object(hEncryptionKey, &meta_enc_key); 452 if (rv != CKR_OK) 453 goto cleanup; 454 } 455 if (hAuthenticationKey != CK_INVALID_HANDLE) { 456 rv = meta_handle2object(hAuthenticationKey, &meta_auth_key); 457 if (rv != CKR_OK) 458 goto cleanup; 459 } 460 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); 465 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; 473 } 474 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; 479 480 rv = meta_set_opstate(slot_session, meta_enc_key, 481 meta_auth_key, &(opstate.state[0]), 482 pOperationState + sizeof (meta_opstate_t)); 483 484 if (rv != CKR_OK) { 485 meta_operation_cleanup(session, session->op1.type, 486 FALSE); 487 goto cleanup; 488 } 489 } 490 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); 498 } 499 500 /* 501 * meta_Login 502 * 503 * This allows the user to login to the object token. The metaslot itself 504 * does not have any kind of PIN. 505 * 506 */ 507 CK_RV 508 meta_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, 509 CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) 510 { 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; 516 517 rv = meta_handle2session(hSession, &session); 518 if (rv != CKR_OK) 519 return (rv); 520 521 if (metaslot_logged_in()) { 522 rv = CKR_USER_ALREADY_LOGGED_IN; 523 goto finish; 524 } 525 526 /* Note: CKU_SO is not supported. */ 527 if (userType != CKU_USER) { 528 rv = CKR_USER_TYPE_INVALID; 529 goto finish; 530 } 531 532 rv = meta_get_slot_session(get_keystore_slotnum(), &login_session, 533 session->session_flags); 534 if (rv != CKR_OK) 535 goto finish; 536 537 538 fw_st_id = login_session->fw_st_id; 539 rv = FUNCLIST(fw_st_id)->C_Login(login_session->hSession, userType, 540 pPin, ulPinLen); 541 542 if (rv != CKR_OK) { 543 goto finish; 544 } 545 546 /* 547 * Note: 548 * 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. 557 */ 558 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; 563 } 564 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); 568 } 569 finish: 570 if (login_session) 571 meta_release_slot_session(login_session); 572 573 REFRELEASE(session); 574 575 return (rv); 576 } 577 578 /* 579 * meta_Logout 580 * 581 */ 582 CK_RV 583 meta_Logout(CK_SESSION_HANDLE hSession) 584 { 585 CK_RV rv = CKR_OK; 586 meta_session_t *session; 587 slot_session_t *logout_session = NULL; 588 589 rv = meta_handle2session(hSession, &session); 590 if (rv != CKR_OK) 591 return (rv); 592 593 if (!metaslot_logged_in()) { 594 rv = CKR_USER_NOT_LOGGED_IN; 595 goto finish; 596 } 597 598 rv = meta_get_slot_session(get_keystore_slotnum(), &logout_session, 599 session->session_flags); 600 if (rv != CKR_OK) 601 goto finish; 602 603 rv = FUNCLIST(logout_session->fw_st_id)->C_Logout( 604 logout_session->hSession); 605 606 /* If the C_Logout fails, just ignore the error. */ 607 metaslot_set_logged_in_flag(B_FALSE); 608 609 finish: 610 if (logout_session) 611 meta_release_slot_session(logout_session); 612 613 REFRELEASE(session); 614 615 return (rv); 616 } 617