xref: /titanic_44/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelDigest.c (revision 551bc2a66868b5cb5be6b70ab9f55515e77a39a9)
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