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 /* 23 * Copyright 2007 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 #include <pthread.h> 30 #include <errno.h> 31 #include <sys/crypto/ioctl.h> 32 #include <security/cryptoki.h> 33 #include "kernelGlobal.h" 34 #include "kernelSession.h" 35 #include "kernelEmulate.h" 36 37 static CK_RV 38 common_digest_init(CK_SESSION_HANDLE hSession, 39 CK_MECHANISM_PTR pMechanism, boolean_t is_external_caller) 40 { 41 CK_RV rv; 42 kernel_session_t *session_p; 43 boolean_t ses_lock_held = B_TRUE; 44 crypto_digest_init_t digest_init; 45 crypto_mech_type_t k_mech_type; 46 int r; 47 48 if (!kernel_initialized) 49 return (CKR_CRYPTOKI_NOT_INITIALIZED); 50 51 if (pMechanism == NULL) 52 return (CKR_ARGUMENTS_BAD); 53 54 /* 55 * Get the kernel's internal mechanism number. 56 */ 57 rv = kernel_mech(pMechanism->mechanism, &k_mech_type); 58 if (rv != CKR_OK) 59 return (rv); 60 61 /* 62 * Obtain the session pointer. Also, increment the session 63 * reference count. 64 */ 65 rv = handle2session(hSession, &session_p); 66 if (rv != CKR_OK) 67 return (rv); 68 69 /* Acquire the session lock */ 70 (void) pthread_mutex_lock(&session_p->session_mutex); 71 72 /* 73 * This active flag will remain ON until application calls either 74 * C_Digest or C_DigestFinal to actually obtain the value of 75 * the message digest. 76 */ 77 session_p->digest.flags |= CRYPTO_OPERATION_ACTIVE; 78 79 if (SLOT_HAS_LIMITED_HASH(session_p) && is_external_caller) { 80 session_p->digest.mech.mechanism = pMechanism->mechanism; 81 session_p->digest.mech.pParameter = NULL; 82 session_p->digest.mech.ulParameterLen = 0; 83 session_p->digest.flags |= CRYPTO_EMULATE; 84 rv = emulate_buf_init(session_p, EDIGEST_LENGTH, OP_DIGEST); 85 REFRELE(session_p, ses_lock_held); 86 return (rv); 87 } 88 89 digest_init.di_session = session_p->k_session; 90 (void) pthread_mutex_unlock(&session_p->session_mutex); 91 digest_init.di_mech.cm_type = k_mech_type; 92 digest_init.di_mech.cm_param = pMechanism->pParameter; 93 94 /* 95 * If pParameter is NULL, set cm_param_len to be 0, so that ioctl call 96 * will have a clean input data. 97 */ 98 if (pMechanism->pParameter != NULL) 99 digest_init.di_mech.cm_param_len = pMechanism->ulParameterLen; 100 else 101 digest_init.di_mech.cm_param_len = 0; 102 103 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_INIT, &digest_init)) < 0) { 104 if (errno != EINTR) 105 break; 106 } 107 if (r < 0) { 108 rv = CKR_FUNCTION_FAILED; 109 } else { 110 rv = crypto2pkcs11_error_number(digest_init.di_return_value); 111 } 112 113 if (rv != CKR_OK) { 114 (void) pthread_mutex_lock(&session_p->session_mutex); 115 session_p->digest.flags &= ~CRYPTO_OPERATION_ACTIVE; 116 /* 117 * Decrement the session reference count. 118 * We hold the session lock, and REFRELE() 119 * will release the session lock for us. 120 */ 121 REFRELE(session_p, ses_lock_held); 122 return (rv); 123 } 124 125 /* 126 * Decrement the session reference count. 127 * We do not hold the session lock. 128 */ 129 ses_lock_held = B_FALSE; 130 REFRELE(session_p, ses_lock_held); 131 return (rv); 132 } 133 134 CK_RV 135 C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) 136 { 137 return (common_digest_init(hSession, pMechanism, B_TRUE)); 138 } 139 140 CK_RV 141 C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, 142 CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) 143 { 144 CK_RV rv; 145 kernel_session_t *session_p; 146 boolean_t ses_lock_held = B_TRUE; 147 crypto_digest_t digest; 148 int r; 149 150 if (!kernel_initialized) 151 return (CKR_CRYPTOKI_NOT_INITIALIZED); 152 153 /* 154 * Obtain the session pointer. Also, increment the session 155 * reference count. 156 */ 157 rv = handle2session(hSession, &session_p); 158 if (rv != CKR_OK) 159 return (rv); 160 161 if (pData == NULL || pulDigestLen == NULL) { 162 rv = CKR_ARGUMENTS_BAD; 163 goto clean_exit; 164 } 165 166 /* Acquire the session lock */ 167 (void) pthread_mutex_lock(&session_p->session_mutex); 168 169 /* Application must call C_DigestInit before calling C_Digest */ 170 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 171 /* 172 * Decrement the session reference count. 173 * We hold the session lock, and REFRELE() 174 * will release the session lock for us. 175 */ 176 REFRELE(session_p, ses_lock_held); 177 return (CKR_OPERATION_NOT_INITIALIZED); 178 } 179 180 /* 181 * C_Digest must be called without intervening C_DigestUpdate 182 * calls. 183 */ 184 if (session_p->digest.flags & CRYPTO_OPERATION_UPDATE) { 185 /* 186 * C_Digest can not be used to terminate a multi-part 187 * operation, so we'll leave the active digest operation 188 * flag on and let the application continue with the 189 * digest update operation. 190 * 191 * Decrement the session reference count. 192 * We hold the session lock, and REFRELE() 193 * will release the session lock for us. 194 */ 195 REFRELE(session_p, ses_lock_held); 196 return (CKR_FUNCTION_FAILED); 197 } 198 199 if (session_p->digest.flags & CRYPTO_EMULATE) { 200 crypto_active_op_t *opp; 201 CK_MECHANISM_PTR pMechanism; 202 203 opp = &(session_p->digest); 204 if (opp->context == NULL) 205 return (CKR_ARGUMENTS_BAD); 206 pMechanism = &(opp->mech); 207 208 if ((ulDataLen < SLOT_THRESHOLD(session_p)) || 209 (ulDataLen > SLOT_MAX_INDATA_LEN(session_p))) { 210 session_p->digest.flags |= CRYPTO_EMULATE_USING_SW; 211 (void) pthread_mutex_unlock(&session_p->session_mutex); 212 213 rv = do_soft_digest(get_spp(opp), pMechanism, 214 pData, ulDataLen, pDigest, pulDigestLen, 215 OP_INIT | OP_SINGLE); 216 goto done; 217 } else if (!(session_p->digest.flags & 218 CRYPTO_EMULATE_INIT_DONE)) { 219 session_p->digest.flags |= CRYPTO_EMULATE_INIT_DONE; 220 (void) pthread_mutex_unlock(&session_p->session_mutex); 221 rv = common_digest_init(hSession, pMechanism, B_FALSE); 222 if (rv != CKR_OK) 223 goto clean_exit; 224 (void) pthread_mutex_lock(&session_p->session_mutex); 225 } 226 } 227 228 digest.cd_session = session_p->k_session; 229 (void) pthread_mutex_unlock(&session_p->session_mutex); 230 digest.cd_datalen = ulDataLen; 231 digest.cd_databuf = (char *)pData; 232 digest.cd_digestbuf = (char *)pDigest; 233 digest.cd_digestlen = *pulDigestLen; 234 235 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST, &digest)) < 0) { 236 if (errno != EINTR) 237 break; 238 } 239 if (r < 0) { 240 rv = CKR_FUNCTION_FAILED; 241 } else { 242 rv = crypto2pkcs11_error_number(digest.cd_return_value); 243 } 244 245 if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL)) 246 *pulDigestLen = digest.cd_digestlen; 247 248 done: 249 if ((rv == CKR_BUFFER_TOO_SMALL) || 250 (rv == CKR_OK && pDigest == NULL)) { 251 /* 252 * We will not terminate the active digest operation flag, 253 * when the application-supplied buffer is too small, or 254 * the application asks for the length of buffer to hold 255 * the message digest. 256 * 257 * Decrement the session reference count. 258 * We do not hold the session lock. 259 */ 260 ses_lock_held = B_FALSE; 261 REFRELE(session_p, ses_lock_held); 262 return (rv); 263 } 264 265 clean_exit: 266 /* 267 * Terminates the active digest operation. 268 * Application needs to call C_DigestInit again for next 269 * digest operation. 270 */ 271 (void) pthread_mutex_lock(&session_p->session_mutex); 272 273 REINIT_OPBUF(&session_p->digest); 274 session_p->digest.flags = 0; 275 276 /* 277 * Decrement the session reference count. 278 * We hold the session lock, and REFRELE() 279 * will release the session lock for us. 280 */ 281 REFRELE(session_p, ses_lock_held); 282 283 return (rv); 284 } 285 286 CK_RV 287 C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, 288 CK_ULONG ulPartLen) 289 { 290 291 CK_RV rv; 292 kernel_session_t *session_p; 293 boolean_t ses_lock_held = B_TRUE; 294 crypto_digest_update_t digest_update; 295 int r; 296 297 if (!kernel_initialized) 298 return (CKR_CRYPTOKI_NOT_INITIALIZED); 299 300 /* 301 * Obtain the session pointer. Also, increment the session 302 * reference count. 303 */ 304 rv = handle2session(hSession, &session_p); 305 if (rv != CKR_OK) 306 return (rv); 307 308 if (pPart == NULL) { 309 rv = CKR_ARGUMENTS_BAD; 310 goto clean_exit; 311 } 312 313 /* Acquire the session lock */ 314 (void) pthread_mutex_lock(&session_p->session_mutex); 315 316 /* 317 * Application must call C_DigestInit before calling 318 * C_DigestUpdate. 319 */ 320 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 321 /* 322 * Decrement the session reference count. 323 * We hold the session lock, and REFRELE() 324 * will release the session lock for us. 325 */ 326 REFRELE(session_p, ses_lock_held); 327 return (CKR_OPERATION_NOT_INITIALIZED); 328 } 329 330 /* Set update flag to protect C_Digest */ 331 session_p->digest.flags |= CRYPTO_OPERATION_UPDATE; 332 333 if (session_p->digest.flags & CRYPTO_EMULATE) { 334 (void) pthread_mutex_unlock(&session_p->session_mutex); 335 rv = emulate_update(session_p, pPart, ulPartLen, OP_DIGEST); 336 goto done; 337 } 338 339 digest_update.du_session = session_p->k_session; 340 (void) pthread_mutex_unlock(&session_p->session_mutex); 341 digest_update.du_datalen = ulPartLen; 342 digest_update.du_databuf = (char *)pPart; 343 344 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE, 345 &digest_update)) < 0) { 346 if (errno != EINTR) 347 break; 348 } 349 if (r < 0) { 350 rv = CKR_FUNCTION_FAILED; 351 } else { 352 rv = crypto2pkcs11_error_number(digest_update.du_return_value); 353 } 354 355 done: 356 if (rv == CKR_OK) { 357 /* 358 * Decrement the session reference count. 359 * We do not hold the session lock. 360 */ 361 ses_lock_held = B_FALSE; 362 REFRELE(session_p, ses_lock_held); 363 return (CKR_OK); 364 } 365 366 clean_exit: 367 /* 368 * After an error occurred, terminate the current digest 369 * operation by resetting the active and update flags. 370 */ 371 (void) pthread_mutex_lock(&session_p->session_mutex); 372 REINIT_OPBUF(&session_p->digest); 373 session_p->digest.flags = 0; 374 375 /* 376 * Decrement the session reference count. 377 * We hold the session lock, and REFRELE() 378 * will release the session lock for us. 379 */ 380 REFRELE(session_p, ses_lock_held); 381 382 return (rv); 383 } 384 385 386 CK_RV 387 C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) 388 { 389 390 CK_RV rv; 391 kernel_session_t *session_p; 392 kernel_object_t *key_p; 393 boolean_t ses_lock_held = B_TRUE; 394 CK_BYTE_PTR pPart; 395 CK_ULONG ulPartLen; 396 crypto_digest_key_t digest_key; 397 crypto_digest_update_t digest_update; 398 int r; 399 400 if (!kernel_initialized) 401 return (CKR_CRYPTOKI_NOT_INITIALIZED); 402 403 /* 404 * Obtain the session pointer. Also, increment the session 405 * reference count. 406 */ 407 rv = handle2session(hSession, &session_p); 408 if (rv != CKR_OK) 409 return (rv); 410 411 /* Obtain the object pointer. */ 412 HANDLE2OBJECT(hKey, key_p, rv); 413 if (rv != CKR_OK) { 414 (void) pthread_mutex_lock(&session_p->session_mutex); 415 REINIT_OPBUF(&session_p->digest); 416 session_p->digest.flags = 0; 417 REFRELE(session_p, ses_lock_held); 418 return (rv); 419 } 420 421 /* Check the key type */ 422 if (key_p->is_lib_obj && (key_p->class != CKO_SECRET_KEY)) { 423 rv = CKR_KEY_INDIGESTIBLE; 424 goto clean_exit; 425 } 426 427 /* 428 * Application must call C_DigestInit before calling 429 * C_DigestKey. 430 */ 431 (void) pthread_mutex_lock(&session_p->session_mutex); 432 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 433 /* 434 * Decrement the session reference count. 435 * We hold the session lock, and REFRELE() 436 * will release the session lock for us. 437 */ 438 OBJ_REFRELE(key_p); 439 REFRELE(session_p, ses_lock_held); 440 return (CKR_OPERATION_NOT_INITIALIZED); 441 } 442 session_p->digest.flags |= CRYPTO_OPERATION_UPDATE; 443 444 /* 445 * If the key object is from the HW provider, call CRYPTO_DIGEST_KEY 446 * ioctl. Otherwise, call CRYPTO_DIGEST_UPDATE ioctl and pass the key 447 * by value. 448 */ 449 if (key_p->is_lib_obj) { 450 digest_update.du_session = session_p->k_session; 451 } else { 452 digest_key.dk_session = session_p->k_session; 453 } 454 (void) pthread_mutex_unlock(&session_p->session_mutex); 455 456 if (!key_p->is_lib_obj) { 457 if (session_p->digest.flags & CRYPTO_EMULATE) { 458 rv = CKR_FUNCTION_NOT_SUPPORTED; 459 goto clean_exit; 460 } 461 digest_key.dk_key.ck_format = CRYPTO_KEY_REFERENCE; 462 digest_key.dk_key.ck_obj_id = key_p->k_handle; 463 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_KEY, 464 &digest_key)) < 0) { 465 if (errno != EINTR) 466 break; 467 } 468 if (r < 0) { 469 rv = CKR_FUNCTION_FAILED; 470 } else { 471 rv = crypto2pkcs11_error_number( 472 digest_key.dk_return_value); 473 } 474 } else { 475 ulPartLen = OBJ_SEC_VALUE_LEN(key_p); 476 if (ulPartLen == 0) { 477 rv = CKR_KEY_SIZE_RANGE; 478 goto clean_exit; 479 } 480 481 pPart = (CK_BYTE_PTR) OBJ_SEC_VALUE(key_p); 482 if (pPart == NULL) { 483 rv = CKR_KEY_HANDLE_INVALID; 484 goto clean_exit; 485 } 486 487 (void) pthread_mutex_lock(&session_p->session_mutex); 488 if (session_p->digest.flags & CRYPTO_EMULATE) { 489 (void) pthread_mutex_unlock(&session_p->session_mutex); 490 rv = emulate_update(session_p, pPart, 491 ulPartLen, OP_DIGEST); 492 goto done; 493 } 494 (void) pthread_mutex_unlock(&session_p->session_mutex); 495 496 digest_update.du_datalen = ulPartLen; 497 digest_update.du_databuf = (char *)pPart; 498 499 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE, 500 &digest_update)) < 0) { 501 if (errno != EINTR) 502 break; 503 } 504 if (r < 0) { 505 rv = CKR_FUNCTION_FAILED; 506 } else { 507 rv = crypto2pkcs11_error_number( 508 digest_update.du_return_value); 509 } 510 } 511 512 done: 513 if (rv == CKR_OK) { 514 /* 515 * Decrement the session reference count. 516 * We do not hold the session lock. 517 */ 518 OBJ_REFRELE(key_p); 519 ses_lock_held = B_FALSE; 520 REFRELE(session_p, ses_lock_held); 521 return (CKR_OK); 522 } 523 524 clean_exit: 525 OBJ_REFRELE(key_p); 526 /* 527 * After an error occurred, terminate the current digest 528 * operation by resetting the active and update flags. 529 */ 530 (void) pthread_mutex_lock(&session_p->session_mutex); 531 REINIT_OPBUF(&session_p->digest); 532 session_p->digest.flags = 0; 533 534 /* 535 * Decrement the session reference count. 536 * We hold the session lock, and REFRELE() 537 * will release the session lock for us. 538 */ 539 REFRELE(session_p, ses_lock_held); 540 return (rv); 541 } 542 543 544 CK_RV 545 C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, 546 CK_ULONG_PTR pulDigestLen) 547 { 548 549 CK_RV rv; 550 kernel_session_t *session_p; 551 boolean_t ses_lock_held = B_TRUE; 552 crypto_digest_final_t digest_final; 553 int r; 554 555 if (!kernel_initialized) 556 return (CKR_CRYPTOKI_NOT_INITIALIZED); 557 558 /* 559 * Obtain the session pointer. Also, increment the session 560 * reference count. 561 */ 562 rv = handle2session(hSession, &session_p); 563 if (rv != CKR_OK) 564 return (rv); 565 566 if (pulDigestLen == NULL) { 567 rv = CKR_ARGUMENTS_BAD; 568 goto clean_exit; 569 } 570 571 /* Acquire the session lock */ 572 (void) pthread_mutex_lock(&session_p->session_mutex); 573 574 /* 575 * Application must call C_DigestInit before calling 576 * C_DigestFinal. 577 */ 578 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 579 /* 580 * Decrement the session reference count. 581 * We hold the session lock, and REFRELE() 582 * will release the session lock for us. 583 */ 584 REFRELE(session_p, ses_lock_held); 585 return (CKR_OPERATION_NOT_INITIALIZED); 586 } 587 588 /* The order of checks is important here */ 589 if (session_p->digest.flags & CRYPTO_EMULATE_USING_SW) { 590 if (session_p->digest.flags & CRYPTO_EMULATE_UPDATE_DONE) { 591 (void) pthread_mutex_unlock(&session_p->session_mutex); 592 rv = do_soft_digest(get_spp(&session_p->digest), 593 NULL, NULL, NULL, pDigest, pulDigestLen, OP_FINAL); 594 } else { 595 /* 596 * We end up here if an earlier C_DigestFinal() call 597 * took the C_Digest() path and it had returned 598 * CKR_BUFFER_TOO_SMALL. 599 */ 600 digest_buf_t *bufp = session_p->digest.context; 601 (void) pthread_mutex_unlock(&session_p->session_mutex); 602 if (bufp == NULL || bufp->buf == NULL) { 603 rv = CKR_ARGUMENTS_BAD; 604 goto clean_exit; 605 } 606 rv = do_soft_digest(get_spp(&session_p->digest), 607 NULL, bufp->buf, bufp->indata_len, 608 pDigest, pulDigestLen, OP_SINGLE); 609 } 610 goto done; 611 } else if (session_p->digest.flags & CRYPTO_EMULATE) { 612 digest_buf_t *bufp = session_p->digest.context; 613 614 /* 615 * We are emulating a single-part operation now. 616 * So, clear the flag. 617 */ 618 session_p->digest.flags &= ~CRYPTO_OPERATION_UPDATE; 619 if (bufp == NULL || bufp->buf == NULL) { 620 rv = CKR_ARGUMENTS_BAD; 621 goto clean_exit; 622 } 623 REFRELE(session_p, ses_lock_held); 624 rv = C_Digest(hSession, bufp->buf, bufp->indata_len, 625 pDigest, pulDigestLen); 626 return (rv); 627 } 628 629 digest_final.df_session = session_p->k_session; 630 (void) pthread_mutex_unlock(&session_p->session_mutex); 631 digest_final.df_digestlen = *pulDigestLen; 632 digest_final.df_digestbuf = (char *)pDigest; 633 634 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_FINAL, &digest_final)) < 0) { 635 if (errno != EINTR) 636 break; 637 } 638 if (r < 0) { 639 rv = CKR_FUNCTION_FAILED; 640 } else { 641 rv = crypto2pkcs11_error_number(digest_final.df_return_value); 642 } 643 644 if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL)) 645 *pulDigestLen = digest_final.df_digestlen; 646 647 done: 648 if ((rv == CKR_BUFFER_TOO_SMALL) || 649 (rv == CKR_OK && pDigest == NULL)) { 650 /* 651 * We will not terminate the active digest operation flag, 652 * when the application-supplied buffer is too small, or 653 * the application asks for the length of buffer to hold 654 * the message digest. 655 * 656 * Decrement the session reference count. 657 * We do not hold the session lock. 658 */ 659 ses_lock_held = B_FALSE; 660 REFRELE(session_p, ses_lock_held); 661 return (rv); 662 } 663 664 clean_exit: 665 /* Terminates the active digest operation */ 666 (void) pthread_mutex_lock(&session_p->session_mutex); 667 REINIT_OPBUF(&session_p->digest); 668 session_p->digest.flags = 0; 669 670 /* 671 * Decrement the session reference count. 672 * We hold the session lock, and REFRELE() 673 * will release the session lock for us. 674 */ 675 REFRELE(session_p, ses_lock_held); 676 677 return (rv); 678 } 679