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 #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 36 37 CK_RV 38 C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) 39 { 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 digest_init.di_session = session_p->k_session; 79 (void) pthread_mutex_unlock(&session_p->session_mutex); 80 digest_init.di_mech.cm_type = k_mech_type; 81 digest_init.di_mech.cm_param = pMechanism->pParameter; 82 83 /* 84 * If pParameter is NULL, set cm_param_len to be 0, so that ioctl call 85 * will have a clean input data. 86 */ 87 if (pMechanism->pParameter != NULL) 88 digest_init.di_mech.cm_param_len = pMechanism->ulParameterLen; 89 else 90 digest_init.di_mech.cm_param_len = 0; 91 92 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_INIT, &digest_init)) < 0) { 93 if (errno != EINTR) 94 break; 95 } 96 if (r < 0) { 97 rv = CKR_FUNCTION_FAILED; 98 } else { 99 rv = crypto2pkcs11_error_number(digest_init.di_return_value); 100 } 101 102 if (rv != CKR_OK) { 103 (void) pthread_mutex_lock(&session_p->session_mutex); 104 session_p->digest.flags &= ~CRYPTO_OPERATION_ACTIVE; 105 /* 106 * Decrement the session reference count. 107 * We hold the session lock, and REFRELE() 108 * will release the session lock for us. 109 */ 110 REFRELE(session_p, ses_lock_held); 111 return (rv); 112 } 113 114 /* 115 * Decrement the session reference count. 116 * We do not hold the session lock. 117 */ 118 ses_lock_held = B_FALSE; 119 REFRELE(session_p, ses_lock_held); 120 return (rv); 121 } 122 123 124 CK_RV 125 C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, 126 CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) 127 { 128 129 CK_RV rv; 130 kernel_session_t *session_p; 131 boolean_t ses_lock_held = B_TRUE; 132 crypto_digest_t digest; 133 int r; 134 135 if (!kernel_initialized) 136 return (CKR_CRYPTOKI_NOT_INITIALIZED); 137 138 /* 139 * Obtain the session pointer. Also, increment the session 140 * reference count. 141 */ 142 rv = handle2session(hSession, &session_p); 143 if (rv != CKR_OK) 144 return (rv); 145 146 if (pData == NULL || pulDigestLen == NULL) { 147 rv = CKR_ARGUMENTS_BAD; 148 goto clean_exit; 149 } 150 151 /* Acquire the session lock */ 152 (void) pthread_mutex_lock(&session_p->session_mutex); 153 154 /* Application must call C_DigestInit before calling C_Digest */ 155 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 156 /* 157 * Decrement the session reference count. 158 * We hold the session lock, and REFRELE() 159 * will release the session lock for us. 160 */ 161 REFRELE(session_p, ses_lock_held); 162 return (CKR_OPERATION_NOT_INITIALIZED); 163 } 164 165 /* 166 * C_Digest must be called without intervening C_DigestUpdate 167 * calls. 168 */ 169 if (session_p->digest.flags & CRYPTO_OPERATION_UPDATE) { 170 /* 171 * C_Digest can not be used to terminate a multi-part 172 * operation, so we'll leave the active digest operation 173 * flag on and let the application continue with the 174 * digest update operation. 175 * 176 * Decrement the session reference count. 177 * We hold the session lock, and REFRELE() 178 * will release the session lock for us. 179 */ 180 REFRELE(session_p, ses_lock_held); 181 return (CKR_FUNCTION_FAILED); 182 } 183 184 digest.cd_session = session_p->k_session; 185 (void) pthread_mutex_unlock(&session_p->session_mutex); 186 digest.cd_datalen = ulDataLen; 187 digest.cd_databuf = (char *)pData; 188 digest.cd_digestbuf = (char *)pDigest; 189 digest.cd_digestlen = *pulDigestLen; 190 191 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST, &digest)) < 0) { 192 if (errno != EINTR) 193 break; 194 } 195 if (r < 0) { 196 rv = CKR_FUNCTION_FAILED; 197 } else { 198 rv = crypto2pkcs11_error_number(digest.cd_return_value); 199 } 200 201 if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL)) 202 *pulDigestLen = digest.cd_digestlen; 203 204 if ((rv == CKR_BUFFER_TOO_SMALL) || 205 (rv == CKR_OK && pDigest == NULL)) { 206 /* 207 * We will not terminate the active digest operation flag, 208 * when the application-supplied buffer is too small, or 209 * the application asks for the length of buffer to hold 210 * the message digest. 211 * 212 * Decrement the session reference count. 213 * We do not hold the session lock. 214 */ 215 ses_lock_held = B_FALSE; 216 REFRELE(session_p, ses_lock_held); 217 return (rv); 218 } 219 220 clean_exit: 221 /* 222 * Terminates the active digest operation. 223 * Application needs to call C_DigestInit again for next 224 * digest operation. 225 */ 226 (void) pthread_mutex_lock(&session_p->session_mutex); 227 session_p->digest.flags = 0; 228 229 /* 230 * Decrement the session reference count. 231 * We hold the session lock, and REFRELE() 232 * will release the session lock for us. 233 */ 234 REFRELE(session_p, ses_lock_held); 235 236 return (rv); 237 } 238 239 240 CK_RV 241 C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, 242 CK_ULONG ulPartLen) 243 { 244 245 CK_RV rv; 246 kernel_session_t *session_p; 247 boolean_t ses_lock_held = B_TRUE; 248 crypto_digest_update_t digest_update; 249 int r; 250 251 if (!kernel_initialized) 252 return (CKR_CRYPTOKI_NOT_INITIALIZED); 253 254 /* 255 * Obtain the session pointer. Also, increment the session 256 * reference count. 257 */ 258 rv = handle2session(hSession, &session_p); 259 if (rv != CKR_OK) 260 return (rv); 261 262 if (pPart == NULL) { 263 rv = CKR_ARGUMENTS_BAD; 264 goto clean_exit; 265 } 266 267 /* Acquire the session lock */ 268 (void) pthread_mutex_lock(&session_p->session_mutex); 269 270 /* 271 * Application must call C_DigestInit before calling 272 * C_DigestUpdate. 273 */ 274 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 275 /* 276 * Decrement the session reference count. 277 * We hold the session lock, and REFRELE() 278 * will release the session lock for us. 279 */ 280 REFRELE(session_p, ses_lock_held); 281 return (CKR_OPERATION_NOT_INITIALIZED); 282 } 283 284 /* Set update flag to protect C_Digest */ 285 session_p->digest.flags |= CRYPTO_OPERATION_UPDATE; 286 287 digest_update.du_session = session_p->k_session; 288 (void) pthread_mutex_unlock(&session_p->session_mutex); 289 digest_update.du_datalen = ulPartLen; 290 digest_update.du_databuf = (char *)pPart; 291 292 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE, 293 &digest_update)) < 0) { 294 if (errno != EINTR) 295 break; 296 } 297 if (r < 0) { 298 rv = CKR_FUNCTION_FAILED; 299 } else { 300 rv = crypto2pkcs11_error_number(digest_update.du_return_value); 301 } 302 303 if (rv == CKR_OK) { 304 /* 305 * Decrement the session reference count. 306 * We do not hold the session lock. 307 */ 308 ses_lock_held = B_FALSE; 309 REFRELE(session_p, ses_lock_held); 310 return (CKR_OK); 311 } 312 313 clean_exit: 314 /* 315 * After an error occurred, terminate the current digest 316 * operation by resetting the active and update flags. 317 */ 318 (void) pthread_mutex_lock(&session_p->session_mutex); 319 session_p->digest.flags = 0; 320 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 328 return (rv); 329 } 330 331 332 CK_RV 333 C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) 334 { 335 336 CK_RV rv; 337 kernel_session_t *session_p; 338 kernel_object_t *key_p; 339 boolean_t ses_lock_held = B_TRUE; 340 CK_BYTE_PTR pPart; 341 CK_ULONG ulPartLen; 342 crypto_digest_key_t digest_key; 343 crypto_digest_update_t digest_update; 344 int r; 345 346 if (!kernel_initialized) 347 return (CKR_CRYPTOKI_NOT_INITIALIZED); 348 349 /* 350 * Obtain the session pointer. Also, increment the session 351 * reference count. 352 */ 353 rv = handle2session(hSession, &session_p); 354 if (rv != CKR_OK) 355 return (rv); 356 357 /* Obtain the object pointer. */ 358 HANDLE2OBJECT(hKey, key_p, rv); 359 if (rv != CKR_OK) { 360 (void) pthread_mutex_lock(&session_p->session_mutex); 361 session_p->digest.flags = 0; 362 REFRELE(session_p, ses_lock_held); 363 return (rv); 364 } 365 366 /* Check the key type */ 367 if (key_p->is_lib_obj && (key_p->class != CKO_SECRET_KEY)) { 368 rv = CKR_KEY_INDIGESTIBLE; 369 goto clean_exit; 370 } 371 372 /* 373 * Application must call C_DigestInit before calling 374 * C_DigestKey. 375 */ 376 (void) pthread_mutex_lock(&session_p->session_mutex); 377 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 378 /* 379 * Decrement the session reference count. 380 * We hold the session lock, and REFRELE() 381 * will release the session lock for us. 382 */ 383 OBJ_REFRELE(key_p); 384 REFRELE(session_p, ses_lock_held); 385 return (CKR_OPERATION_NOT_INITIALIZED); 386 } 387 session_p->digest.flags |= CRYPTO_OPERATION_UPDATE; 388 389 /* 390 * If the key object is from the HW provider, call CRYPTO_DIGEST_KEY 391 * ioctl. Otherwise, call CRYPTO_DIGEST_UPDATE ioctl and pass the key 392 * by value. 393 */ 394 if (key_p->is_lib_obj) { 395 digest_update.du_session = session_p->k_session; 396 } else { 397 digest_key.dk_session = session_p->k_session; 398 } 399 (void) pthread_mutex_unlock(&session_p->session_mutex); 400 401 if (!key_p->is_lib_obj) { 402 digest_key.dk_key.ck_format = CRYPTO_KEY_REFERENCE; 403 digest_key.dk_key.ck_obj_id = key_p->k_handle; 404 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_KEY, 405 &digest_key)) < 0) { 406 if (errno != EINTR) 407 break; 408 } 409 if (r < 0) { 410 rv = CKR_FUNCTION_FAILED; 411 } else { 412 rv = crypto2pkcs11_error_number( 413 digest_key.dk_return_value); 414 } 415 } else { 416 ulPartLen = OBJ_SEC_VALUE_LEN(key_p); 417 if (ulPartLen == 0) { 418 rv = CKR_KEY_SIZE_RANGE; 419 goto clean_exit; 420 } 421 422 pPart = (CK_BYTE_PTR) OBJ_SEC_VALUE(key_p); 423 if (pPart == NULL) { 424 rv = CKR_KEY_HANDLE_INVALID; 425 goto clean_exit; 426 } 427 428 digest_update.du_datalen = ulPartLen; 429 digest_update.du_databuf = (char *)pPart; 430 431 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE, 432 &digest_update)) < 0) { 433 if (errno != EINTR) 434 break; 435 } 436 if (r < 0) { 437 rv = CKR_FUNCTION_FAILED; 438 } else { 439 rv = crypto2pkcs11_error_number( 440 digest_update.du_return_value); 441 } 442 } 443 444 if (rv == CKR_OK) { 445 /* 446 * Decrement the session reference count. 447 * We do not hold the session lock. 448 */ 449 OBJ_REFRELE(key_p); 450 ses_lock_held = B_FALSE; 451 REFRELE(session_p, ses_lock_held); 452 return (CKR_OK); 453 } 454 455 clean_exit: 456 OBJ_REFRELE(key_p); 457 /* 458 * After an error occurred, terminate the current digest 459 * operation by resetting the active and update flags. 460 */ 461 (void) pthread_mutex_lock(&session_p->session_mutex); 462 session_p->digest.flags = 0; 463 464 /* 465 * Decrement the session reference count. 466 * We hold the session lock, and REFRELE() 467 * will release the session lock for us. 468 */ 469 REFRELE(session_p, ses_lock_held); 470 return (rv); 471 } 472 473 474 CK_RV 475 C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, 476 CK_ULONG_PTR pulDigestLen) 477 { 478 479 CK_RV rv; 480 kernel_session_t *session_p; 481 boolean_t ses_lock_held = B_TRUE; 482 crypto_digest_final_t digest_final; 483 int r; 484 485 if (!kernel_initialized) 486 return (CKR_CRYPTOKI_NOT_INITIALIZED); 487 488 /* 489 * Obtain the session pointer. Also, increment the session 490 * reference count. 491 */ 492 rv = handle2session(hSession, &session_p); 493 if (rv != CKR_OK) 494 return (rv); 495 496 if (pulDigestLen == NULL) { 497 rv = CKR_ARGUMENTS_BAD; 498 goto clean_exit; 499 } 500 501 /* Acquire the session lock */ 502 (void) pthread_mutex_lock(&session_p->session_mutex); 503 504 /* 505 * Application must call C_DigestInit before calling 506 * C_DigestFinal. 507 */ 508 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 509 /* 510 * Decrement the session reference count. 511 * We hold the session lock, and REFRELE() 512 * will release the session lock for us. 513 */ 514 REFRELE(session_p, ses_lock_held); 515 return (CKR_OPERATION_NOT_INITIALIZED); 516 } 517 518 digest_final.df_session = session_p->k_session; 519 (void) pthread_mutex_unlock(&session_p->session_mutex); 520 digest_final.df_digestlen = *pulDigestLen; 521 digest_final.df_digestbuf = (char *)pDigest; 522 523 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_FINAL, &digest_final)) < 0) { 524 if (errno != EINTR) 525 break; 526 } 527 if (r < 0) { 528 rv = CKR_FUNCTION_FAILED; 529 } else { 530 rv = crypto2pkcs11_error_number(digest_final.df_return_value); 531 } 532 533 if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL)) 534 *pulDigestLen = digest_final.df_digestlen; 535 536 if ((rv == CKR_BUFFER_TOO_SMALL) || 537 (rv == CKR_OK && pDigest == NULL)) { 538 /* 539 * We will not terminate the active digest operation flag, 540 * when the application-supplied buffer is too small, or 541 * the application asks for the length of buffer to hold 542 * the message digest. 543 * 544 * Decrement the session reference count. 545 * We do not hold the session lock. 546 */ 547 ses_lock_held = B_FALSE; 548 REFRELE(session_p, ses_lock_held); 549 return (rv); 550 } 551 552 clean_exit: 553 /* Terminates the active digest operation */ 554 (void) pthread_mutex_lock(&session_p->session_mutex); 555 session_p->digest.flags = 0; 556 557 /* 558 * Decrement the session reference count. 559 * We hold the session lock, and REFRELE() 560 * will release the session lock for us. 561 */ 562 REFRELE(session_p, ses_lock_held); 563 564 return (rv); 565 } 566