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