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