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 * Copyright 2018, Joyent, Inc. 25 */ 26 27 #include <pthread.h> 28 #include <security/cryptoki.h> 29 #include "softGlobal.h" 30 #include "softOps.h" 31 #include "softSession.h" 32 33 34 CK_RV 35 C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) 36 { 37 38 CK_RV rv; 39 soft_session_t *session_p; 40 boolean_t lock_held = B_TRUE; 41 42 if (!softtoken_initialized) 43 return (CKR_CRYPTOKI_NOT_INITIALIZED); 44 45 /* 46 * Obtain the session pointer. Also, increment the session 47 * reference count. 48 */ 49 rv = handle2session(hSession, &session_p); 50 if (rv != CKR_OK) 51 return (rv); 52 53 if (pMechanism == NULL) { 54 rv = CKR_ARGUMENTS_BAD; 55 goto clean_exit; 56 } 57 58 /* Acquire the session lock */ 59 (void) pthread_mutex_lock(&session_p->session_mutex); 60 61 /* Check to see if digest operation is already active */ 62 if (session_p->digest.flags & CRYPTO_OPERATION_ACTIVE) { 63 /* 64 * Free the memory to avoid memory leak. 65 * digest.context is only a flat structure. 66 */ 67 soft_digest_cleanup(session_p, lock_held); 68 } 69 70 /* 71 * This active flag will remain ON until application calls either 72 * C_Digest or C_DigestFinal to actually obtain the value of 73 * the message digest. 74 */ 75 session_p->digest.flags = CRYPTO_OPERATION_ACTIVE; 76 77 (void) pthread_mutex_unlock(&session_p->session_mutex); 78 79 rv = soft_digest_init(session_p, pMechanism); 80 81 if (rv != CKR_OK) { 82 (void) pthread_mutex_lock(&session_p->session_mutex); 83 session_p->digest.flags &= ~CRYPTO_OPERATION_ACTIVE; 84 /* 85 * Decrement the session reference count. 86 * We hold the session lock, and SES_REFRELE() 87 * will release the session lock for us. 88 */ 89 SES_REFRELE(session_p, lock_held); 90 return (rv); 91 } 92 93 clean_exit: 94 /* 95 * Decrement the session reference count. 96 * We do not hold the session lock. 97 */ 98 lock_held = B_FALSE; 99 SES_REFRELE(session_p, lock_held); 100 return (rv); 101 } 102 103 104 CK_RV 105 C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, 106 CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) 107 { 108 109 CK_RV rv; 110 soft_session_t *session_p; 111 boolean_t lock_held = B_TRUE; 112 113 if (!softtoken_initialized) 114 return (CKR_CRYPTOKI_NOT_INITIALIZED); 115 116 /* 117 * Obtain the session pointer. Also, increment the session 118 * reference count. 119 */ 120 rv = handle2session(hSession, &session_p); 121 if (rv != CKR_OK) 122 return (rv); 123 124 if ((pData == NULL && ulDataLen != 0) || pulDigestLen == NULL) { 125 rv = CKR_ARGUMENTS_BAD; 126 goto clean_exit; 127 } 128 129 /* Acquire the session lock */ 130 (void) pthread_mutex_lock(&session_p->session_mutex); 131 132 /* Application must call C_DigestInit before calling C_Digest */ 133 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 134 /* 135 * Decrement the session reference count. 136 * We hold the session lock, and SES_REFRELE() 137 * will release the session lock for us. 138 */ 139 SES_REFRELE(session_p, lock_held); 140 return (CKR_OPERATION_NOT_INITIALIZED); 141 } 142 143 /* 144 * C_Digest must be called without intervening C_DigestUpdate 145 * calls. 146 */ 147 if (session_p->digest.flags & CRYPTO_OPERATION_UPDATE) { 148 /* 149 * C_Digest can not be used to terminate a multi-part 150 * operation, so we'll leave the active digest operation 151 * flag on and let the application continue with the 152 * digest update operation. 153 * 154 * Decrement the session reference count. 155 * We hold the session lock, and SES_REFRELE() 156 * will release the session lock for us. 157 */ 158 SES_REFRELE(session_p, lock_held); 159 return (CKR_FUNCTION_FAILED); 160 } 161 162 (void) pthread_mutex_unlock(&session_p->session_mutex); 163 164 rv = soft_digest(session_p, pData, ulDataLen, pDigest, pulDigestLen); 165 166 if ((rv == CKR_BUFFER_TOO_SMALL) || 167 (pDigest == NULL && rv == CKR_OK)) { 168 /* 169 * We will not terminate the active digest operation flag, 170 * when the application-supplied buffer is too small, or 171 * the application asks for the length of buffer to hold 172 * the message digest. 173 * 174 * Decrement the session reference count. 175 * We do not hold the session lock. 176 */ 177 lock_held = B_FALSE; 178 SES_REFRELE(session_p, lock_held); 179 return (rv); 180 } 181 182 clean_exit: 183 /* 184 * Terminates the active digest operation. 185 * Application needs to call C_DigestInit again for next 186 * digest operation. 187 */ 188 (void) pthread_mutex_lock(&session_p->session_mutex); 189 190 soft_digest_cleanup(session_p, lock_held); 191 192 /* 193 * Decrement the session reference count. 194 * We hold the session lock, and SES_REFRELE() 195 * will release the session lock for us. 196 */ 197 SES_REFRELE(session_p, lock_held); 198 199 return (rv); 200 } 201 202 203 CK_RV 204 C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, 205 CK_ULONG ulPartLen) 206 { 207 208 CK_RV rv; 209 soft_session_t *session_p; 210 boolean_t lock_held = B_TRUE; 211 212 if (!softtoken_initialized) 213 return (CKR_CRYPTOKI_NOT_INITIALIZED); 214 215 /* 216 * Obtain the session pointer. Also, increment the session 217 * reference count. 218 */ 219 rv = handle2session(hSession, &session_p); 220 if (rv != CKR_OK) 221 return (rv); 222 223 if (pPart == NULL) { 224 rv = CKR_ARGUMENTS_BAD; 225 goto clean_exit; 226 } 227 228 /* Acquire the session lock */ 229 (void) pthread_mutex_lock(&session_p->session_mutex); 230 231 /* 232 * Application must call C_DigestInit before calling 233 * C_DigestUpdate. 234 */ 235 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 236 /* 237 * Decrement the session reference count. 238 * We hold the session lock, and SES_REFRELE() 239 * will release the session lock for us. 240 */ 241 SES_REFRELE(session_p, lock_held); 242 return (CKR_OPERATION_NOT_INITIALIZED); 243 } 244 245 /* Set update flag to protect C_Digest */ 246 session_p->digest.flags |= CRYPTO_OPERATION_UPDATE; 247 248 (void) pthread_mutex_unlock(&session_p->session_mutex); 249 250 rv = soft_digest_update(session_p, pPart, ulPartLen); 251 252 if (rv == CKR_OK) { 253 /* 254 * Decrement the session reference count. 255 * We do not hold the session lock. 256 */ 257 lock_held = B_FALSE; 258 SES_REFRELE(session_p, lock_held); 259 return (CKR_OK); 260 } 261 262 clean_exit: 263 /* 264 * After an error occurred, terminate the current digest 265 * operation by resetting the active and update flags. 266 */ 267 (void) pthread_mutex_lock(&session_p->session_mutex); 268 269 soft_digest_cleanup(session_p, lock_held); 270 271 /* 272 * Decrement the session reference count. 273 * We hold the session lock, and SES_REFRELE() 274 * will release the session lock for us. 275 */ 276 SES_REFRELE(session_p, lock_held); 277 278 return (rv); 279 } 280 281 282 CK_RV 283 C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) 284 { 285 286 CK_RV rv; 287 soft_session_t *session_p; 288 soft_object_t *key_p; 289 boolean_t lock_held = B_TRUE; 290 291 if (!softtoken_initialized) 292 return (CKR_CRYPTOKI_NOT_INITIALIZED); 293 294 /* 295 * Obtain the session pointer. Also, increment the session 296 * reference count. 297 */ 298 rv = handle2session(hSession, &session_p); 299 if (rv != CKR_OK) 300 return (rv); 301 302 /* Obtain the object pointer. */ 303 HANDLE2OBJECT(hKey, key_p, rv); 304 if (rv != CKR_OK) 305 goto clean_exit; 306 307 (void) pthread_mutex_lock(&session_p->session_mutex); 308 309 /* 310 * Application must call C_DigestInit before calling 311 * C_DigestKey. 312 */ 313 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 314 /* 315 * Decrement the session reference count. 316 * We hold the session lock, and SES_REFRELE() 317 * will release the session lock for us. 318 */ 319 OBJ_REFRELE(key_p); 320 SES_REFRELE(session_p, lock_held); 321 return (CKR_OPERATION_NOT_INITIALIZED); 322 } 323 324 /* 325 * Remember the fact that a key was thrown into the mix, so that 326 * C_DigestFinal bzero()'s the digest context before freeing it. 327 */ 328 session_p->digest.flags |= (CRYPTO_KEY_DIGESTED | 329 CRYPTO_OPERATION_UPDATE); 330 331 (void) pthread_mutex_unlock(&session_p->session_mutex); 332 333 rv = soft_digest_key(session_p, key_p); 334 335 if (rv == CKR_OK) { 336 /* 337 * Decrement the session reference count. 338 * We do not hold the session lock. 339 */ 340 lock_held = B_FALSE; 341 OBJ_REFRELE(key_p); 342 SES_REFRELE(session_p, lock_held); 343 return (CKR_OK); 344 } 345 346 OBJ_REFRELE(key_p); 347 clean_exit: 348 /* 349 * After an error occurred, terminate the current digest 350 * operation by resetting the active and update flags. 351 */ 352 (void) pthread_mutex_lock(&session_p->session_mutex); 353 354 soft_digest_cleanup(session_p, lock_held); 355 356 /* 357 * Decrement the session reference count. 358 * We hold the session lock, and SES_REFRELE() 359 * will release the session lock for us. 360 */ 361 SES_REFRELE(session_p, lock_held); 362 return (rv); 363 } 364 365 366 CK_RV 367 C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, 368 CK_ULONG_PTR pulDigestLen) 369 { 370 371 CK_RV rv; 372 soft_session_t *session_p; 373 boolean_t lock_held = B_TRUE; 374 375 if (!softtoken_initialized) 376 return (CKR_CRYPTOKI_NOT_INITIALIZED); 377 378 /* 379 * Obtain the session pointer. Also, increment the session 380 * reference count. 381 */ 382 rv = handle2session(hSession, &session_p); 383 if (rv != CKR_OK) 384 return (rv); 385 386 if (pulDigestLen == NULL) { 387 rv = CKR_ARGUMENTS_BAD; 388 goto clean_exit; 389 } 390 391 /* Acquire the session lock */ 392 (void) pthread_mutex_lock(&session_p->session_mutex); 393 394 /* 395 * Application must call C_DigestInit before calling 396 * C_DigestFinal. 397 */ 398 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 399 /* 400 * Decrement the session reference count. 401 * We hold the session lock, and SES_REFRELE() 402 * will release the session lock for us. 403 */ 404 SES_REFRELE(session_p, lock_held); 405 return (CKR_OPERATION_NOT_INITIALIZED); 406 } 407 408 (void) pthread_mutex_unlock(&session_p->session_mutex); 409 410 rv = soft_digest_final(session_p, pDigest, pulDigestLen); 411 412 if ((rv == CKR_BUFFER_TOO_SMALL) || 413 (pDigest == NULL && rv == CKR_OK)) { 414 /* 415 * We will not terminate the active digest operation flag, 416 * when the application-supplied buffer is too small, or 417 * the application asks for the length of buffer to hold 418 * the message digest. 419 * 420 * Decrement the session reference count. 421 * We do not hold the session lock. 422 */ 423 lock_held = B_FALSE; 424 SES_REFRELE(session_p, lock_held); 425 return (rv); 426 } 427 428 clean_exit: 429 /* Terminates the active digest operation */ 430 (void) pthread_mutex_lock(&session_p->session_mutex); 431 432 soft_digest_cleanup(session_p, lock_held); 433 434 /* 435 * Decrement the session reference count. 436 * We hold the session lock, and SES_REFRELE() 437 * will release the session lock for us. 438 */ 439 SES_REFRELE(session_p, lock_held); 440 441 return (rv); 442 } 443