xref: /titanic_50/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelDigest.c (revision 4df55fde49134f9735f84011f23a767c75e393c7)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5ba5f469cSkrishna  * Common Development and Distribution License (the "License").
6ba5f469cSkrishna  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21ba5f469cSkrishna 
227c478bd9Sstevel@tonic-gate /*
23b232b5fcSZdenek Kotala  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <pthread.h>
287c478bd9Sstevel@tonic-gate #include <errno.h>
297c478bd9Sstevel@tonic-gate #include <sys/crypto/ioctl.h>
307c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
317c478bd9Sstevel@tonic-gate #include "kernelGlobal.h"
327c478bd9Sstevel@tonic-gate #include "kernelSession.h"
33ba5f469cSkrishna #include "kernelEmulate.h"
347c478bd9Sstevel@tonic-gate 
35b2a96221Skrishna static CK_RV
common_digest_init(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,boolean_t is_external_caller)36b2a96221Skrishna common_digest_init(CK_SESSION_HANDLE hSession,
37b2a96221Skrishna     CK_MECHANISM_PTR pMechanism, boolean_t is_external_caller)
387c478bd9Sstevel@tonic-gate {
397c478bd9Sstevel@tonic-gate 	CK_RV rv;
407c478bd9Sstevel@tonic-gate 	kernel_session_t *session_p;
41b232b5fcSZdenek Kotala 	boolean_t ses_lock_held = B_FALSE;
427c478bd9Sstevel@tonic-gate 	crypto_digest_init_t digest_init;
437c478bd9Sstevel@tonic-gate 	crypto_mech_type_t k_mech_type;
447c478bd9Sstevel@tonic-gate 	int r;
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
477c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate 	if (pMechanism == NULL)
507c478bd9Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate 	/*
537c478bd9Sstevel@tonic-gate 	 * Get the kernel's internal mechanism number.
547c478bd9Sstevel@tonic-gate 	 */
557c478bd9Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
567c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
577c478bd9Sstevel@tonic-gate 		return (rv);
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate 	/*
607c478bd9Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
617c478bd9Sstevel@tonic-gate 	 * reference count.
627c478bd9Sstevel@tonic-gate 	 */
637c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
647c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
657c478bd9Sstevel@tonic-gate 		return (rv);
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 	/* Acquire the session lock */
687c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
69b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	/*
727c478bd9Sstevel@tonic-gate 	 * This active flag will remain ON until application calls either
737c478bd9Sstevel@tonic-gate 	 * C_Digest or C_DigestFinal to actually obtain the value of
747c478bd9Sstevel@tonic-gate 	 * the message digest.
757c478bd9Sstevel@tonic-gate 	 */
76b2a96221Skrishna 	session_p->digest.flags |= CRYPTO_OPERATION_ACTIVE;
77b2a96221Skrishna 
78b2a96221Skrishna 	if (SLOT_HAS_LIMITED_HASH(session_p) && is_external_caller) {
79b2a96221Skrishna 		session_p->digest.mech.mechanism = pMechanism->mechanism;
80b2a96221Skrishna 		session_p->digest.mech.pParameter = NULL;
81b2a96221Skrishna 		session_p->digest.mech.ulParameterLen = 0;
82b2a96221Skrishna 		session_p->digest.flags |= CRYPTO_EMULATE;
83b2a96221Skrishna 		rv = emulate_buf_init(session_p, EDIGEST_LENGTH, OP_DIGEST);
84b2a96221Skrishna 		REFRELE(session_p, ses_lock_held);
85b2a96221Skrishna 		return (rv);
86b2a96221Skrishna 	}
87b2a96221Skrishna 
887c478bd9Sstevel@tonic-gate 	digest_init.di_session = session_p->k_session;
897c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
90b232b5fcSZdenek Kotala 	ses_lock_held = B_FALSE;
917c478bd9Sstevel@tonic-gate 	digest_init.di_mech.cm_type = k_mech_type;
927c478bd9Sstevel@tonic-gate 	digest_init.di_mech.cm_param = pMechanism->pParameter;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	/*
957c478bd9Sstevel@tonic-gate 	 * If pParameter is NULL, set cm_param_len to be 0, so that ioctl call
967c478bd9Sstevel@tonic-gate 	 * will have a clean input data.
977c478bd9Sstevel@tonic-gate 	 */
987c478bd9Sstevel@tonic-gate 	if (pMechanism->pParameter != NULL)
997c478bd9Sstevel@tonic-gate 		digest_init.di_mech.cm_param_len = pMechanism->ulParameterLen;
1007c478bd9Sstevel@tonic-gate 	else
1017c478bd9Sstevel@tonic-gate 		digest_init.di_mech.cm_param_len = 0;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_INIT, &digest_init)) < 0) {
1047c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
1057c478bd9Sstevel@tonic-gate 			break;
1067c478bd9Sstevel@tonic-gate 	}
1077c478bd9Sstevel@tonic-gate 	if (r < 0) {
1087c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
1097c478bd9Sstevel@tonic-gate 	} else {
1107c478bd9Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(digest_init.di_return_value);
1117c478bd9Sstevel@tonic-gate 	}
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
1147c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&session_p->session_mutex);
115b232b5fcSZdenek Kotala 		ses_lock_held = B_TRUE;
1167c478bd9Sstevel@tonic-gate 		session_p->digest.flags &= ~CRYPTO_OPERATION_ACTIVE;
1177c478bd9Sstevel@tonic-gate 		/*
1187c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
1197c478bd9Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
1207c478bd9Sstevel@tonic-gate 		 * will release the session lock for us.
1217c478bd9Sstevel@tonic-gate 		 */
1227c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
1237c478bd9Sstevel@tonic-gate 		return (rv);
1247c478bd9Sstevel@tonic-gate 	}
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	/*
1277c478bd9Sstevel@tonic-gate 	 * Decrement the session reference count.
1287c478bd9Sstevel@tonic-gate 	 * We do not hold the session lock.
1297c478bd9Sstevel@tonic-gate 	 */
1307c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
1317c478bd9Sstevel@tonic-gate 	return (rv);
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate CK_RV
C_DigestInit(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism)135b2a96221Skrishna C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism)
136b2a96221Skrishna {
137b2a96221Skrishna 	return (common_digest_init(hSession, pMechanism, B_TRUE));
138b2a96221Skrishna }
139b2a96221Skrishna 
140b2a96221Skrishna CK_RV
C_Digest(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pDigest,CK_ULONG_PTR pulDigestLen)1417c478bd9Sstevel@tonic-gate C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
1427c478bd9Sstevel@tonic-gate     CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
1437c478bd9Sstevel@tonic-gate {
1447c478bd9Sstevel@tonic-gate 	CK_RV rv;
1457c478bd9Sstevel@tonic-gate 	kernel_session_t *session_p;
146b232b5fcSZdenek Kotala 	boolean_t ses_lock_held = B_FALSE;
1477c478bd9Sstevel@tonic-gate 	crypto_digest_t digest;
1487c478bd9Sstevel@tonic-gate 	int r;
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
1517c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	/*
1547c478bd9Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
1557c478bd9Sstevel@tonic-gate 	 * reference count.
1567c478bd9Sstevel@tonic-gate 	 */
1577c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
1587c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
1597c478bd9Sstevel@tonic-gate 		return (rv);
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	if (pData == NULL || pulDigestLen == NULL) {
1627c478bd9Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
1637c478bd9Sstevel@tonic-gate 		goto clean_exit;
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	/* Acquire the session lock */
1677c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
168b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	/* Application must call C_DigestInit before calling C_Digest */
1717c478bd9Sstevel@tonic-gate 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
1727c478bd9Sstevel@tonic-gate 		/*
1737c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
1747c478bd9Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
1757c478bd9Sstevel@tonic-gate 		 * will release the session lock for us.
1767c478bd9Sstevel@tonic-gate 		 */
1777c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
1787c478bd9Sstevel@tonic-gate 		return (CKR_OPERATION_NOT_INITIALIZED);
1797c478bd9Sstevel@tonic-gate 	}
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	/*
1827c478bd9Sstevel@tonic-gate 	 * C_Digest must be called without intervening C_DigestUpdate
1837c478bd9Sstevel@tonic-gate 	 * calls.
1847c478bd9Sstevel@tonic-gate 	 */
1857c478bd9Sstevel@tonic-gate 	if (session_p->digest.flags & CRYPTO_OPERATION_UPDATE) {
1867c478bd9Sstevel@tonic-gate 		/*
1877c478bd9Sstevel@tonic-gate 		 * C_Digest can not be used to terminate a multi-part
1887c478bd9Sstevel@tonic-gate 		 * operation, so we'll leave the active digest operation
1897c478bd9Sstevel@tonic-gate 		 * flag on and let the application continue with the
1907c478bd9Sstevel@tonic-gate 		 * digest update operation.
1917c478bd9Sstevel@tonic-gate 		 *
1927c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
1937c478bd9Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
1947c478bd9Sstevel@tonic-gate 		 * will release the session lock for us.
1957c478bd9Sstevel@tonic-gate 		 */
1967c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
1977c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 
200ba5f469cSkrishna 	if (session_p->digest.flags & CRYPTO_EMULATE) {
201b2a96221Skrishna 		crypto_active_op_t *opp;
202b2a96221Skrishna 		CK_MECHANISM_PTR pMechanism;
203b2a96221Skrishna 
204b2a96221Skrishna 		opp = &(session_p->digest);
205b232b5fcSZdenek Kotala 		if (opp->context == NULL) {
206b232b5fcSZdenek Kotala 			REFRELE(session_p, ses_lock_held);
207b2a96221Skrishna 			return (CKR_ARGUMENTS_BAD);
208b232b5fcSZdenek Kotala 		}
209b2a96221Skrishna 		pMechanism = &(opp->mech);
210b2a96221Skrishna 
211ba5f469cSkrishna 		if ((ulDataLen < SLOT_THRESHOLD(session_p)) ||
212*4df55fdeSJanie Lu 		    (ulDataLen > SLOT_HASH_MAX_INDATA_LEN(session_p))) {
213ba5f469cSkrishna 			session_p->digest.flags |= CRYPTO_EMULATE_USING_SW;
214ba5f469cSkrishna 			(void) pthread_mutex_unlock(&session_p->session_mutex);
215b232b5fcSZdenek Kotala 			ses_lock_held = B_FALSE;
216ba5f469cSkrishna 
217b2a96221Skrishna 			rv = do_soft_digest(get_spp(opp), pMechanism,
218b2a96221Skrishna 			    pData, ulDataLen, pDigest, pulDigestLen,
219b2a96221Skrishna 			    OP_INIT | OP_SINGLE);
220ba5f469cSkrishna 			goto done;
221b2a96221Skrishna 		} else if (!(session_p->digest.flags &
222b2a96221Skrishna 		    CRYPTO_EMULATE_INIT_DONE)) {
223b2a96221Skrishna 			session_p->digest.flags |= CRYPTO_EMULATE_INIT_DONE;
224b2a96221Skrishna 			(void) pthread_mutex_unlock(&session_p->session_mutex);
225b232b5fcSZdenek Kotala 			ses_lock_held = B_FALSE;
226b232b5fcSZdenek Kotala 
227b2a96221Skrishna 			rv = common_digest_init(hSession, pMechanism, B_FALSE);
228b2a96221Skrishna 			if (rv != CKR_OK)
229b2a96221Skrishna 				goto clean_exit;
230b2a96221Skrishna 			(void) pthread_mutex_lock(&session_p->session_mutex);
231b232b5fcSZdenek Kotala 			ses_lock_held = B_TRUE;
232ba5f469cSkrishna 		}
233ba5f469cSkrishna 	}
234ba5f469cSkrishna 
2357c478bd9Sstevel@tonic-gate 	digest.cd_session = session_p->k_session;
2367c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
237b232b5fcSZdenek Kotala 	ses_lock_held = B_FALSE;
2387c478bd9Sstevel@tonic-gate 	digest.cd_datalen =  ulDataLen;
2397c478bd9Sstevel@tonic-gate 	digest.cd_databuf = (char *)pData;
2407c478bd9Sstevel@tonic-gate 	digest.cd_digestbuf = (char *)pDigest;
2417c478bd9Sstevel@tonic-gate 	digest.cd_digestlen = *pulDigestLen;
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST, &digest)) < 0) {
2447c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
2457c478bd9Sstevel@tonic-gate 			break;
2467c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate 	if (r < 0) {
2487c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
2497c478bd9Sstevel@tonic-gate 	} else {
2507c478bd9Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(digest.cd_return_value);
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL))
2547c478bd9Sstevel@tonic-gate 		*pulDigestLen = digest.cd_digestlen;
2557c478bd9Sstevel@tonic-gate 
256ba5f469cSkrishna done:
2577c478bd9Sstevel@tonic-gate 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
2587c478bd9Sstevel@tonic-gate 	    (rv == CKR_OK && pDigest == NULL)) {
2597c478bd9Sstevel@tonic-gate 		/*
2607c478bd9Sstevel@tonic-gate 		 * We will not terminate the active digest operation flag,
2617c478bd9Sstevel@tonic-gate 		 * when the application-supplied buffer is too small, or
2627c478bd9Sstevel@tonic-gate 		 * the application asks for the length of buffer to hold
2637c478bd9Sstevel@tonic-gate 		 * the message digest.
2647c478bd9Sstevel@tonic-gate 		 *
2657c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
2667c478bd9Sstevel@tonic-gate 		 * We do not hold the session lock.
2677c478bd9Sstevel@tonic-gate 		 */
2687c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
2697c478bd9Sstevel@tonic-gate 		return (rv);
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate clean_exit:
2737c478bd9Sstevel@tonic-gate 	/*
2747c478bd9Sstevel@tonic-gate 	 * Terminates the active digest operation.
2757c478bd9Sstevel@tonic-gate 	 * Application needs to call C_DigestInit again for next
2767c478bd9Sstevel@tonic-gate 	 * digest operation.
2777c478bd9Sstevel@tonic-gate 	 */
2787c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
279b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
280ba5f469cSkrishna 
281ba5f469cSkrishna 	REINIT_OPBUF(&session_p->digest);
2827c478bd9Sstevel@tonic-gate 	session_p->digest.flags = 0;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	/*
2857c478bd9Sstevel@tonic-gate 	 * Decrement the session reference count.
2867c478bd9Sstevel@tonic-gate 	 * We hold the session lock, and REFRELE()
2877c478bd9Sstevel@tonic-gate 	 * will release the session lock for us.
2887c478bd9Sstevel@tonic-gate 	 */
2897c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	return (rv);
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate CK_RV
C_DigestUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,CK_ULONG ulPartLen)2957c478bd9Sstevel@tonic-gate C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
2967c478bd9Sstevel@tonic-gate     CK_ULONG ulPartLen)
2977c478bd9Sstevel@tonic-gate {
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	CK_RV rv;
3007c478bd9Sstevel@tonic-gate 	kernel_session_t *session_p;
301b232b5fcSZdenek Kotala 	boolean_t ses_lock_held = B_FALSE;
3027c478bd9Sstevel@tonic-gate 	crypto_digest_update_t digest_update;
3037c478bd9Sstevel@tonic-gate 	int r;
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
3067c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	/*
3097c478bd9Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
3107c478bd9Sstevel@tonic-gate 	 * reference count.
3117c478bd9Sstevel@tonic-gate 	 */
3127c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
3137c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
3147c478bd9Sstevel@tonic-gate 		return (rv);
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	if (pPart == NULL) {
3177c478bd9Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
3187c478bd9Sstevel@tonic-gate 		goto clean_exit;
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	/* Acquire the session lock */
3227c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
323b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	/*
3267c478bd9Sstevel@tonic-gate 	 * Application must call C_DigestInit before calling
3277c478bd9Sstevel@tonic-gate 	 * C_DigestUpdate.
3287c478bd9Sstevel@tonic-gate 	 */
3297c478bd9Sstevel@tonic-gate 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
3307c478bd9Sstevel@tonic-gate 		/*
3317c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
3327c478bd9Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
3337c478bd9Sstevel@tonic-gate 		 * will release the session lock for us.
3347c478bd9Sstevel@tonic-gate 		 */
3357c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
3367c478bd9Sstevel@tonic-gate 		return (CKR_OPERATION_NOT_INITIALIZED);
3377c478bd9Sstevel@tonic-gate 	}
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	/* Set update flag to protect C_Digest */
3407c478bd9Sstevel@tonic-gate 	session_p->digest.flags |= CRYPTO_OPERATION_UPDATE;
3417c478bd9Sstevel@tonic-gate 
342ba5f469cSkrishna 	if (session_p->digest.flags & CRYPTO_EMULATE) {
343ba5f469cSkrishna 		(void) pthread_mutex_unlock(&session_p->session_mutex);
344b232b5fcSZdenek Kotala 		ses_lock_held = B_FALSE;
345ba5f469cSkrishna 		rv = emulate_update(session_p, pPart, ulPartLen, OP_DIGEST);
346ba5f469cSkrishna 		goto done;
347ba5f469cSkrishna 	}
348ba5f469cSkrishna 
3497c478bd9Sstevel@tonic-gate 	digest_update.du_session = session_p->k_session;
3507c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
351b232b5fcSZdenek Kotala 	ses_lock_held = B_FALSE;
3527c478bd9Sstevel@tonic-gate 	digest_update.du_datalen =  ulPartLen;
3537c478bd9Sstevel@tonic-gate 	digest_update.du_databuf = (char *)pPart;
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE,
3567c478bd9Sstevel@tonic-gate 	    &digest_update)) < 0) {
3577c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
3587c478bd9Sstevel@tonic-gate 			break;
3597c478bd9Sstevel@tonic-gate 	}
3607c478bd9Sstevel@tonic-gate 	if (r < 0) {
3617c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
3627c478bd9Sstevel@tonic-gate 	} else {
3637c478bd9Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(digest_update.du_return_value);
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 
366ba5f469cSkrishna done:
3677c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK) {
3687c478bd9Sstevel@tonic-gate 		/*
3697c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
3707c478bd9Sstevel@tonic-gate 		 * We do not hold the session lock.
3717c478bd9Sstevel@tonic-gate 		 */
3727c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
3737c478bd9Sstevel@tonic-gate 		return (CKR_OK);
3747c478bd9Sstevel@tonic-gate 	}
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate clean_exit:
3777c478bd9Sstevel@tonic-gate 	/*
3787c478bd9Sstevel@tonic-gate 	 * After an error occurred, terminate the current digest
3797c478bd9Sstevel@tonic-gate 	 * operation by resetting the active and update flags.
3807c478bd9Sstevel@tonic-gate 	 */
3817c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
382b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
383ba5f469cSkrishna 	REINIT_OPBUF(&session_p->digest);
3847c478bd9Sstevel@tonic-gate 	session_p->digest.flags = 0;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	/*
3877c478bd9Sstevel@tonic-gate 	 * Decrement the session reference count.
3887c478bd9Sstevel@tonic-gate 	 * We hold the session lock, and REFRELE()
3897c478bd9Sstevel@tonic-gate 	 * will release the session lock for us.
3907c478bd9Sstevel@tonic-gate 	 */
3917c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	return (rv);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate CK_RV
C_DigestKey(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hKey)3987c478bd9Sstevel@tonic-gate C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey)
3997c478bd9Sstevel@tonic-gate {
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	CK_RV		rv;
4027c478bd9Sstevel@tonic-gate 	kernel_session_t	*session_p;
4037c478bd9Sstevel@tonic-gate 	kernel_object_t	*key_p;
404b232b5fcSZdenek Kotala 	boolean_t ses_lock_held = B_FALSE;
4057c478bd9Sstevel@tonic-gate 	CK_BYTE_PTR	pPart;
4067c478bd9Sstevel@tonic-gate 	CK_ULONG	ulPartLen;
4077c478bd9Sstevel@tonic-gate 	crypto_digest_key_t digest_key;
4087c478bd9Sstevel@tonic-gate 	crypto_digest_update_t digest_update;
4097c478bd9Sstevel@tonic-gate 	int r;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
4127c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	/*
4157c478bd9Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
4167c478bd9Sstevel@tonic-gate 	 * reference count.
4177c478bd9Sstevel@tonic-gate 	 */
4187c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
4197c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
4207c478bd9Sstevel@tonic-gate 		return (rv);
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	/* Obtain the object pointer. */
4237c478bd9Sstevel@tonic-gate 	HANDLE2OBJECT(hKey, key_p, rv);
42401223cbaSmcpowers 	if (rv != CKR_OK) {
42501223cbaSmcpowers 		(void) pthread_mutex_lock(&session_p->session_mutex);
426b232b5fcSZdenek Kotala 		ses_lock_held = B_TRUE;
427ba5f469cSkrishna 		REINIT_OPBUF(&session_p->digest);
42801223cbaSmcpowers 		session_p->digest.flags = 0;
42901223cbaSmcpowers 		REFRELE(session_p, ses_lock_held);
43001223cbaSmcpowers 		return (rv);
43101223cbaSmcpowers 	}
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	/* Check the key type */
4347c478bd9Sstevel@tonic-gate 	if (key_p->is_lib_obj && (key_p->class != CKO_SECRET_KEY)) {
4357c478bd9Sstevel@tonic-gate 		rv = CKR_KEY_INDIGESTIBLE;
4367c478bd9Sstevel@tonic-gate 		goto clean_exit;
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	/*
4407c478bd9Sstevel@tonic-gate 	 * Application must call C_DigestInit before calling
4417c478bd9Sstevel@tonic-gate 	 * C_DigestKey.
4427c478bd9Sstevel@tonic-gate 	 */
4437c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
444b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
445b232b5fcSZdenek Kotala 
4467c478bd9Sstevel@tonic-gate 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
4477c478bd9Sstevel@tonic-gate 		/*
4487c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
4497c478bd9Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
4507c478bd9Sstevel@tonic-gate 		 * will release the session lock for us.
4517c478bd9Sstevel@tonic-gate 		 */
45201223cbaSmcpowers 		OBJ_REFRELE(key_p);
4537c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
4547c478bd9Sstevel@tonic-gate 		return (CKR_OPERATION_NOT_INITIALIZED);
4557c478bd9Sstevel@tonic-gate 	}
4567c478bd9Sstevel@tonic-gate 	session_p->digest.flags |= CRYPTO_OPERATION_UPDATE;
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	/*
4597c478bd9Sstevel@tonic-gate 	 * If the key object is from the HW provider, call CRYPTO_DIGEST_KEY
4607c478bd9Sstevel@tonic-gate 	 * ioctl. Otherwise, call CRYPTO_DIGEST_UPDATE ioctl and pass the key
4617c478bd9Sstevel@tonic-gate 	 * by value.
4627c478bd9Sstevel@tonic-gate 	 */
4637c478bd9Sstevel@tonic-gate 	if (key_p->is_lib_obj) {
4647c478bd9Sstevel@tonic-gate 		digest_update.du_session = session_p->k_session;
4657c478bd9Sstevel@tonic-gate 	} else {
4667c478bd9Sstevel@tonic-gate 		digest_key.dk_session = session_p->k_session;
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
469b232b5fcSZdenek Kotala 	ses_lock_held = B_FALSE;
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	if (!key_p->is_lib_obj) {
472ba5f469cSkrishna 		if (session_p->digest.flags & CRYPTO_EMULATE) {
473ba5f469cSkrishna 			rv = CKR_FUNCTION_NOT_SUPPORTED;
474ba5f469cSkrishna 			goto clean_exit;
475ba5f469cSkrishna 		}
4767c478bd9Sstevel@tonic-gate 		digest_key.dk_key.ck_format = CRYPTO_KEY_REFERENCE;
4777c478bd9Sstevel@tonic-gate 		digest_key.dk_key.ck_obj_id = key_p->k_handle;
4787c478bd9Sstevel@tonic-gate 		while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_KEY,
4797c478bd9Sstevel@tonic-gate 		    &digest_key)) < 0) {
4807c478bd9Sstevel@tonic-gate 			if (errno != EINTR)
4817c478bd9Sstevel@tonic-gate 				break;
4827c478bd9Sstevel@tonic-gate 		}
4837c478bd9Sstevel@tonic-gate 		if (r < 0) {
4847c478bd9Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
4857c478bd9Sstevel@tonic-gate 		} else {
4867c478bd9Sstevel@tonic-gate 			rv = crypto2pkcs11_error_number(
4877c478bd9Sstevel@tonic-gate 			    digest_key.dk_return_value);
4887c478bd9Sstevel@tonic-gate 		}
4897c478bd9Sstevel@tonic-gate 	} else {
4907c478bd9Sstevel@tonic-gate 		ulPartLen = OBJ_SEC_VALUE_LEN(key_p);
4917c478bd9Sstevel@tonic-gate 		if (ulPartLen == 0) {
4927c478bd9Sstevel@tonic-gate 			rv = CKR_KEY_SIZE_RANGE;
4937c478bd9Sstevel@tonic-gate 			goto clean_exit;
4947c478bd9Sstevel@tonic-gate 		}
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 		pPart = (CK_BYTE_PTR) OBJ_SEC_VALUE(key_p);
4977c478bd9Sstevel@tonic-gate 		if (pPart == NULL) {
4987c478bd9Sstevel@tonic-gate 			rv = CKR_KEY_HANDLE_INVALID;
4997c478bd9Sstevel@tonic-gate 			goto clean_exit;
5007c478bd9Sstevel@tonic-gate 		}
5017c478bd9Sstevel@tonic-gate 
502ba5f469cSkrishna 		(void) pthread_mutex_lock(&session_p->session_mutex);
503b232b5fcSZdenek Kotala 		ses_lock_held = B_TRUE;
504ba5f469cSkrishna 		if (session_p->digest.flags & CRYPTO_EMULATE) {
505ba5f469cSkrishna 			(void) pthread_mutex_unlock(&session_p->session_mutex);
506b232b5fcSZdenek Kotala 			ses_lock_held = B_FALSE;
507ba5f469cSkrishna 			rv = emulate_update(session_p, pPart,
508ba5f469cSkrishna 			    ulPartLen, OP_DIGEST);
509ba5f469cSkrishna 			goto done;
510ba5f469cSkrishna 		}
511ba5f469cSkrishna 		(void) pthread_mutex_unlock(&session_p->session_mutex);
512b232b5fcSZdenek Kotala 		ses_lock_held = B_FALSE;
513ba5f469cSkrishna 
5147c478bd9Sstevel@tonic-gate 		digest_update.du_datalen = ulPartLen;
5157c478bd9Sstevel@tonic-gate 		digest_update.du_databuf = (char *)pPart;
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 		while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE,
5187c478bd9Sstevel@tonic-gate 		    &digest_update)) < 0) {
5197c478bd9Sstevel@tonic-gate 			if (errno != EINTR)
5207c478bd9Sstevel@tonic-gate 				break;
5217c478bd9Sstevel@tonic-gate 		}
5227c478bd9Sstevel@tonic-gate 		if (r < 0) {
5237c478bd9Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
5247c478bd9Sstevel@tonic-gate 		} else {
5257c478bd9Sstevel@tonic-gate 			rv = crypto2pkcs11_error_number(
5267c478bd9Sstevel@tonic-gate 			    digest_update.du_return_value);
5277c478bd9Sstevel@tonic-gate 		}
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate 
530ba5f469cSkrishna done:
5317c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK) {
5327c478bd9Sstevel@tonic-gate 		/*
5337c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
5347c478bd9Sstevel@tonic-gate 		 * We do not hold the session lock.
5357c478bd9Sstevel@tonic-gate 		 */
53601223cbaSmcpowers 		OBJ_REFRELE(key_p);
53701223cbaSmcpowers 		REFRELE(session_p, ses_lock_held);
5387c478bd9Sstevel@tonic-gate 		return (CKR_OK);
5397c478bd9Sstevel@tonic-gate 	}
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate clean_exit:
54201223cbaSmcpowers 	OBJ_REFRELE(key_p);
5437c478bd9Sstevel@tonic-gate 	/*
5447c478bd9Sstevel@tonic-gate 	 * After an error occurred, terminate the current digest
5457c478bd9Sstevel@tonic-gate 	 * operation by resetting the active and update flags.
5467c478bd9Sstevel@tonic-gate 	 */
5477c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
548b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
549ba5f469cSkrishna 	REINIT_OPBUF(&session_p->digest);
5507c478bd9Sstevel@tonic-gate 	session_p->digest.flags = 0;
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	/*
5537c478bd9Sstevel@tonic-gate 	 * Decrement the session reference count.
5547c478bd9Sstevel@tonic-gate 	 * We hold the session lock, and REFRELE()
5557c478bd9Sstevel@tonic-gate 	 * will release the session lock for us.
5567c478bd9Sstevel@tonic-gate 	 */
5577c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
5587c478bd9Sstevel@tonic-gate 	return (rv);
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate CK_RV
C_DigestFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pDigest,CK_ULONG_PTR pulDigestLen)5637c478bd9Sstevel@tonic-gate C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest,
5647c478bd9Sstevel@tonic-gate     CK_ULONG_PTR pulDigestLen)
5657c478bd9Sstevel@tonic-gate {
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	CK_RV rv;
5687c478bd9Sstevel@tonic-gate 	kernel_session_t *session_p;
569b232b5fcSZdenek Kotala 	boolean_t ses_lock_held = B_FALSE;
5707c478bd9Sstevel@tonic-gate 	crypto_digest_final_t digest_final;
5717c478bd9Sstevel@tonic-gate 	int r;
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
5747c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	/*
5777c478bd9Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
5787c478bd9Sstevel@tonic-gate 	 * reference count.
5797c478bd9Sstevel@tonic-gate 	 */
5807c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
5817c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
5827c478bd9Sstevel@tonic-gate 		return (rv);
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	if (pulDigestLen == NULL) {
5857c478bd9Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
5867c478bd9Sstevel@tonic-gate 		goto clean_exit;
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	/* Acquire the session lock */
5907c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
591b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	/*
5947c478bd9Sstevel@tonic-gate 	 * Application must call C_DigestInit before calling
5957c478bd9Sstevel@tonic-gate 	 * C_DigestFinal.
5967c478bd9Sstevel@tonic-gate 	 */
5977c478bd9Sstevel@tonic-gate 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
5987c478bd9Sstevel@tonic-gate 		/*
5997c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
6007c478bd9Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
6017c478bd9Sstevel@tonic-gate 		 * will release the session lock for us.
6027c478bd9Sstevel@tonic-gate 		 */
6037c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
6047c478bd9Sstevel@tonic-gate 		return (CKR_OPERATION_NOT_INITIALIZED);
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 
607ba5f469cSkrishna 	/* The order of checks is important here */
608ba5f469cSkrishna 	if (session_p->digest.flags & CRYPTO_EMULATE_USING_SW) {
609ba5f469cSkrishna 		if (session_p->digest.flags & CRYPTO_EMULATE_UPDATE_DONE) {
610ba5f469cSkrishna 			(void) pthread_mutex_unlock(&session_p->session_mutex);
611b232b5fcSZdenek Kotala 			ses_lock_held = B_FALSE;
612ba5f469cSkrishna 			rv = do_soft_digest(get_spp(&session_p->digest),
613ba5f469cSkrishna 			    NULL, NULL, NULL, pDigest, pulDigestLen, OP_FINAL);
614ba5f469cSkrishna 		} else {
615ba5f469cSkrishna 			/*
616ba5f469cSkrishna 			 * We end up here if an earlier C_DigestFinal() call
617ba5f469cSkrishna 			 * took the C_Digest() path and it had returned
618ba5f469cSkrishna 			 * CKR_BUFFER_TOO_SMALL.
619ba5f469cSkrishna 			 */
620ba5f469cSkrishna 			digest_buf_t *bufp = session_p->digest.context;
621ba5f469cSkrishna 			(void) pthread_mutex_unlock(&session_p->session_mutex);
622b232b5fcSZdenek Kotala 			ses_lock_held = B_FALSE;
623ba5f469cSkrishna 			if (bufp == NULL || bufp->buf == NULL) {
624ba5f469cSkrishna 				rv = CKR_ARGUMENTS_BAD;
625ba5f469cSkrishna 				goto clean_exit;
626ba5f469cSkrishna 			}
627ba5f469cSkrishna 			rv = do_soft_digest(get_spp(&session_p->digest),
628ba5f469cSkrishna 			    NULL, bufp->buf, bufp->indata_len,
629ba5f469cSkrishna 			    pDigest, pulDigestLen, OP_SINGLE);
630ba5f469cSkrishna 		}
631ba5f469cSkrishna 		goto done;
632ba5f469cSkrishna 	} else if (session_p->digest.flags & CRYPTO_EMULATE) {
633ba5f469cSkrishna 		digest_buf_t *bufp = session_p->digest.context;
634ba5f469cSkrishna 
635ba5f469cSkrishna 		/*
636ba5f469cSkrishna 		 * We are emulating a single-part operation now.
637ba5f469cSkrishna 		 * So, clear the flag.
638ba5f469cSkrishna 		 */
639ba5f469cSkrishna 		session_p->digest.flags &= ~CRYPTO_OPERATION_UPDATE;
640ba5f469cSkrishna 		if (bufp == NULL || bufp->buf == NULL) {
641ba5f469cSkrishna 			rv = CKR_ARGUMENTS_BAD;
642ba5f469cSkrishna 			goto clean_exit;
643ba5f469cSkrishna 		}
644ba5f469cSkrishna 		REFRELE(session_p, ses_lock_held);
645ba5f469cSkrishna 		rv = C_Digest(hSession, bufp->buf, bufp->indata_len,
646ba5f469cSkrishna 		    pDigest, pulDigestLen);
647ba5f469cSkrishna 		return (rv);
648ba5f469cSkrishna 	}
649ba5f469cSkrishna 
6507c478bd9Sstevel@tonic-gate 	digest_final.df_session = session_p->k_session;
6517c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
652b232b5fcSZdenek Kotala 	ses_lock_held = B_FALSE;
6537c478bd9Sstevel@tonic-gate 	digest_final.df_digestlen = *pulDigestLen;
6547c478bd9Sstevel@tonic-gate 	digest_final.df_digestbuf = (char *)pDigest;
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_FINAL, &digest_final)) < 0) {
6577c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
6587c478bd9Sstevel@tonic-gate 			break;
6597c478bd9Sstevel@tonic-gate 	}
6607c478bd9Sstevel@tonic-gate 	if (r < 0) {
6617c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
6627c478bd9Sstevel@tonic-gate 	} else {
6637c478bd9Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(digest_final.df_return_value);
6647c478bd9Sstevel@tonic-gate 	}
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL))
6677c478bd9Sstevel@tonic-gate 		*pulDigestLen = digest_final.df_digestlen;
6687c478bd9Sstevel@tonic-gate 
669ba5f469cSkrishna done:
6707c478bd9Sstevel@tonic-gate 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
6717c478bd9Sstevel@tonic-gate 	    (rv == CKR_OK && pDigest == NULL)) {
6727c478bd9Sstevel@tonic-gate 		/*
6737c478bd9Sstevel@tonic-gate 		 * We will not terminate the active digest operation flag,
6747c478bd9Sstevel@tonic-gate 		 * when the application-supplied buffer is too small, or
6757c478bd9Sstevel@tonic-gate 		 * the application asks for the length of buffer to hold
6767c478bd9Sstevel@tonic-gate 		 * the message digest.
6777c478bd9Sstevel@tonic-gate 		 *
6787c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
6797c478bd9Sstevel@tonic-gate 		 * We do not hold the session lock.
6807c478bd9Sstevel@tonic-gate 		 */
6817c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
6827c478bd9Sstevel@tonic-gate 		return (rv);
6837c478bd9Sstevel@tonic-gate 	}
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate clean_exit:
6867c478bd9Sstevel@tonic-gate 	/* Terminates the active digest operation */
6877c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
688b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
689ba5f469cSkrishna 	REINIT_OPBUF(&session_p->digest);
6907c478bd9Sstevel@tonic-gate 	session_p->digest.flags = 0;
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	/*
6937c478bd9Sstevel@tonic-gate 	 * Decrement the session reference count.
6947c478bd9Sstevel@tonic-gate 	 * We hold the session lock, and REFRELE()
6957c478bd9Sstevel@tonic-gate 	 * will release the session lock for us.
6967c478bd9Sstevel@tonic-gate 	 */
6977c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	return (rv);
7007c478bd9Sstevel@tonic-gate }
701