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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Session Management Functions 31 * (as defined in PKCS#11 spec spection 11.6) 32 */ 33 34 #include <string.h> 35 #include "metaGlobal.h" 36 37 extern meta_session_t *meta_sessionlist_head; 38 extern pthread_rwlock_t meta_sessionlist_lock; 39 extern CK_ULONG num_meta_sessions; 40 extern CK_ULONG num_rw_meta_sessions; 41 42 /* 43 * meta_OpenSession 44 * 45 * NOTES: 46 * 1) The pApplication and Notify args are not used, as the metaslot does not 47 * support application callbacks. 48 * 2) the slotID argument is not checked or used because this function 49 * is only called from the framework. 50 */ 51 /* ARGSUSED */ 52 CK_RV 53 meta_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, 54 CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession) 55 { 56 meta_session_t *new_session; 57 CK_RV rv; 58 59 if (!metaslot_enabled) { 60 return (CKR_SLOT_ID_INVALID); 61 } 62 63 if (phSession == NULL) { 64 return (CKR_ARGUMENTS_BAD); 65 } 66 67 /* Check for any unknown flags. */ 68 if (flags & ~(CKF_SERIAL_SESSION | CKF_RW_SESSION)) { 69 return (CKR_ARGUMENTS_BAD); 70 } 71 72 if (!(flags & CKF_SERIAL_SESSION)) { 73 return (CKR_SESSION_PARALLEL_NOT_SUPPORTED); 74 } 75 76 if (meta_slotManager_token_write_protected() && 77 (flags & CKF_RW_SESSION)) { 78 return (CKR_TOKEN_WRITE_PROTECTED); 79 } 80 81 rv = meta_session_alloc(&new_session); 82 if (rv != CKR_OK) 83 return (rv); 84 85 new_session->session_flags = flags; 86 87 rv = meta_session_activate(new_session); 88 if (rv != CKR_OK) { 89 meta_session_dealloc(new_session); 90 return (rv); 91 } 92 93 *phSession = (CK_SESSION_HANDLE) new_session; 94 95 num_meta_sessions++; 96 if (flags & CKF_RW_SESSION) { 97 num_rw_meta_sessions++; 98 } 99 100 return (CKR_OK); 101 } 102 103 104 /* 105 * meta_CloseSession 106 * 107 */ 108 CK_RV 109 meta_CloseSession(CK_SESSION_HANDLE hSession) 110 { 111 CK_RV rv; 112 meta_session_t *session; 113 CK_FLAGS flags; 114 115 rv = meta_handle2session(hSession, &session); 116 if (rv != CKR_OK) 117 return (rv); 118 119 /* save info about session flags before they are destroyed */ 120 flags = session->session_flags; 121 122 rv = meta_session_deactivate(session, B_FALSE); 123 124 if (rv == CKR_OK) 125 meta_session_dealloc(session); 126 127 num_meta_sessions--; 128 if (flags & CKF_RW_SESSION) { 129 num_rw_meta_sessions--; 130 } 131 132 return (rv); 133 } 134 135 136 /* 137 * meta_CloseAllSessions 138 * 139 * This is a simple loop that closes the sessionlist head (resulting in a 140 * new list head) until the list is empty. 141 * 142 */ 143 CK_RV 144 meta_CloseAllSessions(CK_SLOT_ID slotID) 145 { 146 CK_RV rv; 147 meta_session_t *session; 148 149 if (!metaslot_enabled) { 150 return (CKR_SLOT_ID_INVALID); 151 } 152 153 if (slotID != METASLOT_SLOTID) 154 return (CKR_SLOT_ID_INVALID); 155 156 (void) pthread_rwlock_wrlock(&meta_sessionlist_lock); 157 while ((session = meta_sessionlist_head) != NULL) { 158 rv = meta_handle2session((CK_SESSION_HANDLE)session, &session); 159 if (rv != CKR_OK) { 160 /*NOTREACHED*/ 161 (void) pthread_rwlock_unlock(&meta_sessionlist_lock); 162 return (CKR_FUNCTION_FAILED); 163 } 164 165 (void) meta_session_deactivate(session, B_TRUE); 166 meta_session_dealloc(session); 167 } 168 (void) pthread_rwlock_unlock(&meta_sessionlist_lock); 169 170 /* All open sessions should be closed, just reset the variables */ 171 num_meta_sessions = 0; 172 num_rw_meta_sessions = 0; 173 174 return (CKR_OK); 175 } 176 177 178 /* 179 * meta_GetSessionInfo 180 * 181 */ 182 CK_RV 183 meta_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) 184 { 185 CK_RV rv; 186 meta_session_t *session; 187 188 if (pInfo == NULL) 189 return (CKR_ARGUMENTS_BAD); 190 191 rv = meta_handle2session(hSession, &session); 192 if (rv != CKR_OK) 193 return (rv); 194 195 pInfo->slotID = METASLOT_SLOTID; 196 pInfo->flags = session->session_flags; 197 198 if (metaslot_logged_in()) { 199 if (IS_READ_ONLY_SESSION(session->session_flags)) { 200 pInfo->state = CKS_RO_USER_FUNCTIONS; 201 } else { 202 pInfo->state = CKS_RW_USER_FUNCTIONS; 203 } 204 } else { 205 if (IS_READ_ONLY_SESSION(session->session_flags)) { 206 pInfo->state = CKS_RO_PUBLIC_SESSION; 207 } else { 208 pInfo->state = CKS_RW_PUBLIC_SESSION; 209 } 210 } 211 212 pInfo->ulDeviceError = 0; 213 214 REFRELEASE(session); 215 216 return (CKR_OK); 217 } 218 219 CK_RV 220 meta_getopstatelen(meta_session_t *session, CK_ULONG *out_length) 221 { 222 CK_RV rv = CKR_OK; 223 slot_session_t *slot_session; 224 CK_ULONG length; 225 226 *out_length = sizeof (meta_opstate_t); 227 if (session->op1.type != OP_UNUSED) { 228 slot_session = session->op1.session; 229 rv = FUNCLIST(slot_session->fw_st_id)->C_GetOperationState( 230 slot_session->hSession, NULL, &length); 231 if (rv == CKR_OK) 232 *out_length += length; 233 } 234 return (rv); 235 } 236 237 /* 238 * meta_GetOperationState 239 * 240 */ 241 CK_RV 242 meta_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 243 CK_ULONG_PTR pulOperationStateLen) 244 { 245 CK_RV rv; 246 meta_session_t *session; 247 slot_session_t *slot_session = NULL; 248 meta_opstate_t opstate; 249 250 if (pulOperationStateLen == NULL) 251 return (CKR_ARGUMENTS_BAD); 252 253 rv = meta_handle2session(hSession, &session); 254 if (rv != CKR_OK) 255 return (rv); 256 257 /* 258 * If no operation is active, then bail out. 259 */ 260 if (session->op1.type == OP_UNUSED) { 261 rv = CKR_OPERATION_NOT_INITIALIZED; 262 goto endgetopstate; 263 } 264 265 /* 266 * If the caller did not give an OpState buffer, 267 * shortcut and just return the size needed to hold 268 * a metaslot OpState record later. 269 * The actual size of the returned state will be the 270 * sizeof(meta_opstate_t) + SIZE (op1 state), 271 * so we have to get the size of 272 * the operation states now. 273 */ 274 if (pOperationState == NULL) { 275 rv = meta_getopstatelen(session, pulOperationStateLen); 276 REFRELEASE(session); 277 return (rv); 278 } 279 280 /* 281 * To be here, the caller must have supplied an 282 * already initialized meta_opstate_t pointer. 283 * Use it to get the real state info from the operation(s). 284 * 285 * The format of the Metaslot Opstate record: 286 * { 287 * struct metaopstate 288 * [ op1 state data ] 289 * } 290 */ 291 292 /* 293 * If the buffer is not even big enough for the metaslot 294 * opstate data, return error and set the returned 295 * state length to indicate the minimum needed. 296 */ 297 if (*pulOperationStateLen < sizeof (meta_opstate_t)) { 298 rv = meta_getopstatelen(session, pulOperationStateLen); 299 /* 300 * Remap the error so the caller knows that they 301 * used an invalid buffer size in the first place. 302 */ 303 if (rv == CKR_OK) 304 rv = CKR_BUFFER_TOO_SMALL; 305 goto endgetopstate; 306 } 307 308 (void) memset(&opstate, 0, sizeof (meta_opstate_t)); 309 opstate.magic_marker = METASLOT_OPSTATE_MAGIC; 310 311 if (session->op1.type != OP_UNUSED) { 312 slot_session = session->op1.session; 313 opstate.state[0].op_type = session->op1.type; 314 opstate.state[0].op_slotnum = slot_session->slotnum; 315 opstate.state[0].op_state_len = *pulOperationStateLen - 316 sizeof (meta_opstate_t); 317 rv = FUNCLIST(slot_session->fw_st_id)->C_GetOperationState( 318 slot_session->hSession, 319 pOperationState + sizeof (meta_opstate_t), 320 &(opstate.state[0].op_state_len)); 321 322 if (rv == CKR_BUFFER_TOO_SMALL) { 323 /* 324 * This should not happen, but if it does, 325 * recalculate the entire size needed 326 * and return the error. 327 */ 328 rv = meta_getopstatelen(session, pulOperationStateLen); 329 if (rv == CKR_OK) 330 rv = CKR_BUFFER_TOO_SMALL; 331 } 332 333 if (rv != CKR_OK) 334 goto endgetopstate; 335 } 336 337 endgetopstate: 338 if (rv == CKR_OK && pOperationState != NULL) { 339 (void) memcpy(pOperationState, (void *)&opstate, 340 sizeof (meta_opstate_t)); 341 342 *pulOperationStateLen = sizeof (meta_opstate_t) + 343 opstate.state[0].op_state_len; 344 } 345 346 REFRELEASE(session); 347 return (rv); 348 } 349 350 static CK_RV 351 meta_set_opstate(slot_session_t *slot_session, 352 meta_object_t *meta_enc_key, 353 meta_object_t *meta_auth_key, 354 struct opstate_data *state, 355 CK_BYTE *databuf) 356 { 357 CK_RV rv; 358 static CK_ULONG encrypt_optypes = (OP_ENCRYPT | OP_DECRYPT); 359 static CK_ULONG sign_optypes = (OP_SIGN | OP_VERIFY | 360 OP_SIGNRECOVER | OP_VERIFYRECOVER); 361 slot_object_t *enc_key_obj = NULL, *auth_key_obj = NULL; 362 363 if (state->op_type & encrypt_optypes) { 364 rv = meta_object_get_clone(meta_enc_key, 365 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, 373 slot_session->slotnum, 374 slot_session, &auth_key_obj); 375 if (rv != CKR_OK) { 376 return (rv); 377 } 378 } 379 380 /* 381 * Check to see if the keys are needed to restore the 382 * state on the first operation. 383 */ 384 rv = FUNCLIST(slot_session->fw_st_id)->C_SetOperationState( 385 slot_session->hSession, databuf, state->op_state_len, 386 enc_key_obj ? enc_key_obj->hObject : CK_INVALID_HANDLE, 387 auth_key_obj ? auth_key_obj->hObject : CK_INVALID_HANDLE); 388 /* 389 * If the operation did not need a key, try again. 390 */ 391 if (rv == CKR_KEY_NOT_NEEDED) { 392 rv = FUNCLIST(slot_session->fw_st_id)->C_SetOperationState( 393 slot_session->hSession, databuf, state->op_state_len, 394 CK_INVALID_HANDLE, CK_INVALID_HANDLE); 395 /* 396 * Strange case... If the first try returned 397 * KEY_NOT_NEEDED, and this one returns KEY_NEEDED, 398 * we want to remap the return so the caller sees 399 * the original "CKR_KEY_NOT_NEEDED" return value. 400 * This ensures that a correct caller will retry 401 * without the unnecessary key argument and this 402 * 2nd attempt will not happen again. 403 */ 404 if (rv == CKR_KEY_NEEDED) { 405 rv = CKR_KEY_NOT_NEEDED; 406 } 407 } 408 409 return (rv); 410 } 411 412 /* 413 * meta_SetOperationState 414 * 415 */ 416 CK_RV 417 meta_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 418 CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, 419 CK_OBJECT_HANDLE hAuthenticationKey) 420 { 421 CK_RV rv = CKR_OK; 422 meta_session_t *session; 423 slot_session_t *slot_session = NULL; 424 meta_opstate_t opstate; 425 meta_object_t *meta_enc_key = NULL, *meta_auth_key = NULL; 426 427 /* 428 * Make sure the opstate info buffer is big enough to be valid. 429 */ 430 if (ulOperationStateLen < sizeof (meta_opstate_t) || 431 pOperationState == NULL) 432 return (CKR_ARGUMENTS_BAD); 433 434 /* Copy the opstate info into the structure */ 435 (void) memcpy(&opstate, pOperationState, sizeof (meta_opstate_t)); 436 437 /* verify that a metaslot operation state was supplied */ 438 if (opstate.magic_marker != METASLOT_OPSTATE_MAGIC) 439 return (CKR_SAVED_STATE_INVALID); 440 441 /* 442 * Now, check the size again to make sure the "real" state 443 * data is present. Length of state provided must be exact. 444 */ 445 if (ulOperationStateLen != (sizeof (meta_opstate_t) + 446 opstate.state[0].op_state_len)) 447 return (CKR_SAVED_STATE_INVALID); 448 449 rv = meta_handle2session(hSession, &session); 450 if (rv != CKR_OK) 451 return (rv); 452 453 if (hEncryptionKey != CK_INVALID_HANDLE) { 454 rv = meta_handle2object(hEncryptionKey, &meta_enc_key); 455 if (rv != CKR_OK) 456 goto cleanup; 457 } 458 if (hAuthenticationKey != CK_INVALID_HANDLE) { 459 rv = meta_handle2object(hAuthenticationKey, &meta_auth_key); 460 if (rv != CKR_OK) 461 goto cleanup; 462 } 463 464 if (opstate.state[0].op_type != OP_UNUSED) { 465 if (session->op1.type != OP_UNUSED) 466 meta_operation_cleanup(session, session->op1.type, 467 B_FALSE); 468 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 session->op1.type = opstate.state[0].op_type; 475 session->op1.session = slot_session; 476 477 rv = meta_set_opstate(slot_session, 478 meta_enc_key, meta_auth_key, 479 &(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