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.
250e986b9dSJason King  * Copyright 2018, Joyent, Inc.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <pthread.h>
297c478bd9Sstevel@tonic-gate #include <errno.h>
307c478bd9Sstevel@tonic-gate #include <sys/crypto/ioctl.h>
317c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
327c478bd9Sstevel@tonic-gate #include "kernelGlobal.h"
337c478bd9Sstevel@tonic-gate #include "kernelSession.h"
34ba5f469cSkrishna #include "kernelEmulate.h"
357c478bd9Sstevel@tonic-gate 
36b2a96221Skrishna static CK_RV
common_digest_init(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,boolean_t is_external_caller)37b2a96221Skrishna common_digest_init(CK_SESSION_HANDLE hSession,
38b2a96221Skrishna     CK_MECHANISM_PTR pMechanism, boolean_t is_external_caller)
397c478bd9Sstevel@tonic-gate {
407c478bd9Sstevel@tonic-gate 	CK_RV rv;
417c478bd9Sstevel@tonic-gate 	kernel_session_t *session_p;
42b232b5fcSZdenek Kotala 	boolean_t ses_lock_held = B_FALSE;
437c478bd9Sstevel@tonic-gate 	crypto_digest_init_t digest_init;
447c478bd9Sstevel@tonic-gate 	crypto_mech_type_t k_mech_type;
457c478bd9Sstevel@tonic-gate 	int r;
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
487c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate 	if (pMechanism == NULL)
517c478bd9Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate 	/*
547c478bd9Sstevel@tonic-gate 	 * Get the kernel's internal mechanism number.
557c478bd9Sstevel@tonic-gate 	 */
567c478bd9Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
577c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
587c478bd9Sstevel@tonic-gate 		return (rv);
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate 	/*
617c478bd9Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
627c478bd9Sstevel@tonic-gate 	 * reference count.
637c478bd9Sstevel@tonic-gate 	 */
647c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
657c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
667c478bd9Sstevel@tonic-gate 		return (rv);
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	/* Acquire the session lock */
697c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
70b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	/*
737c478bd9Sstevel@tonic-gate 	 * This active flag will remain ON until application calls either
747c478bd9Sstevel@tonic-gate 	 * C_Digest or C_DigestFinal to actually obtain the value of
757c478bd9Sstevel@tonic-gate 	 * the message digest.
767c478bd9Sstevel@tonic-gate 	 */
77b2a96221Skrishna 	session_p->digest.flags |= CRYPTO_OPERATION_ACTIVE;
78b2a96221Skrishna 
79b2a96221Skrishna 	if (SLOT_HAS_LIMITED_HASH(session_p) && is_external_caller) {
80b2a96221Skrishna 		session_p->digest.mech.mechanism = pMechanism->mechanism;
81b2a96221Skrishna 		session_p->digest.mech.pParameter = NULL;
82b2a96221Skrishna 		session_p->digest.mech.ulParameterLen = 0;
83b2a96221Skrishna 		session_p->digest.flags |= CRYPTO_EMULATE;
84b2a96221Skrishna 		rv = emulate_buf_init(session_p, EDIGEST_LENGTH, OP_DIGEST);
85b2a96221Skrishna 		REFRELE(session_p, ses_lock_held);
86b2a96221Skrishna 		return (rv);
87b2a96221Skrishna 	}
88b2a96221Skrishna 
897c478bd9Sstevel@tonic-gate 	digest_init.di_session = session_p->k_session;
907c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
91b232b5fcSZdenek Kotala 	ses_lock_held = B_FALSE;
927c478bd9Sstevel@tonic-gate 	digest_init.di_mech.cm_type = k_mech_type;
937c478bd9Sstevel@tonic-gate 	digest_init.di_mech.cm_param = pMechanism->pParameter;
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	/*
967c478bd9Sstevel@tonic-gate 	 * If pParameter is NULL, set cm_param_len to be 0, so that ioctl call
977c478bd9Sstevel@tonic-gate 	 * will have a clean input data.
987c478bd9Sstevel@tonic-gate 	 */
997c478bd9Sstevel@tonic-gate 	if (pMechanism->pParameter != NULL)
1007c478bd9Sstevel@tonic-gate 		digest_init.di_mech.cm_param_len = pMechanism->ulParameterLen;
1017c478bd9Sstevel@tonic-gate 	else
1027c478bd9Sstevel@tonic-gate 		digest_init.di_mech.cm_param_len = 0;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_INIT, &digest_init)) < 0) {
1057c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
1067c478bd9Sstevel@tonic-gate 			break;
1077c478bd9Sstevel@tonic-gate 	}
1087c478bd9Sstevel@tonic-gate 	if (r < 0) {
1097c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
1107c478bd9Sstevel@tonic-gate 	} else {
1117c478bd9Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(digest_init.di_return_value);
1127c478bd9Sstevel@tonic-gate 	}
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
1157c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&session_p->session_mutex);
116b232b5fcSZdenek Kotala 		ses_lock_held = B_TRUE;
1177c478bd9Sstevel@tonic-gate 		session_p->digest.flags &= ~CRYPTO_OPERATION_ACTIVE;
1187c478bd9Sstevel@tonic-gate 		/*
1197c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
1207c478bd9Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
1217c478bd9Sstevel@tonic-gate 		 * will release the session lock for us.
1227c478bd9Sstevel@tonic-gate 		 */
1237c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
1247c478bd9Sstevel@tonic-gate 		return (rv);
1257c478bd9Sstevel@tonic-gate 	}
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	/*
1287c478bd9Sstevel@tonic-gate 	 * Decrement the session reference count.
1297c478bd9Sstevel@tonic-gate 	 * We do not hold the session lock.
1307c478bd9Sstevel@tonic-gate 	 */
1317c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
1327c478bd9Sstevel@tonic-gate 	return (rv);
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate 
135b2a96221Skrishna CK_RV
C_DigestInit(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism)136b2a96221Skrishna C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism)
137b2a96221Skrishna {
138b2a96221Skrishna 	return (common_digest_init(hSession, pMechanism, B_TRUE));
139b2a96221Skrishna }
140b2a96221Skrishna 
1417c478bd9Sstevel@tonic-gate CK_RV
C_Digest(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pDigest,CK_ULONG_PTR pulDigestLen)1427c478bd9Sstevel@tonic-gate C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
1437c478bd9Sstevel@tonic-gate     CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate 	CK_RV rv;
1467c478bd9Sstevel@tonic-gate 	kernel_session_t *session_p;
147b232b5fcSZdenek Kotala 	boolean_t ses_lock_held = B_FALSE;
1487c478bd9Sstevel@tonic-gate 	crypto_digest_t digest;
1497c478bd9Sstevel@tonic-gate 	int r;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
1527c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	/*
1557c478bd9Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
1567c478bd9Sstevel@tonic-gate 	 * reference count.
1577c478bd9Sstevel@tonic-gate 	 */
1587c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
1597c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
1607c478bd9Sstevel@tonic-gate 		return (rv);
1617c478bd9Sstevel@tonic-gate 
1620e986b9dSJason King 	if ((pData == NULL && ulDataLen != 0) || pulDigestLen == NULL) {
1637c478bd9Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
1647c478bd9Sstevel@tonic-gate 		goto clean_exit;
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	/* Acquire the session lock */
1687c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
169b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	/* Application must call C_DigestInit before calling C_Digest */
1727c478bd9Sstevel@tonic-gate 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
1737c478bd9Sstevel@tonic-gate 		/*
1747c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
1757c478bd9Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
1767c478bd9Sstevel@tonic-gate 		 * will release the session lock for us.
1777c478bd9Sstevel@tonic-gate 		 */
1787c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
1797c478bd9Sstevel@tonic-gate 		return (CKR_OPERATION_NOT_INITIALIZED);
1807c478bd9Sstevel@tonic-gate 	}
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/*
1837c478bd9Sstevel@tonic-gate 	 * C_Digest must be called without intervening C_DigestUpdate
1847c478bd9Sstevel@tonic-gate 	 * calls.
1857c478bd9Sstevel@tonic-gate 	 */
1867c478bd9Sstevel@tonic-gate 	if (session_p->digest.flags & CRYPTO_OPERATION_UPDATE) {
1877c478bd9Sstevel@tonic-gate 		/*
1887c478bd9Sstevel@tonic-gate 		 * C_Digest can not be used to terminate a multi-part
1897c478bd9Sstevel@tonic-gate 		 * operation, so we'll leave the active digest operation
1907c478bd9Sstevel@tonic-gate 		 * flag on and let the application continue with the
1917c478bd9Sstevel@tonic-gate 		 * digest update operation.
1927c478bd9Sstevel@tonic-gate 		 *
1937c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
1947c478bd9Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
1957c478bd9Sstevel@tonic-gate 		 * will release the session lock for us.
1967c478bd9Sstevel@tonic-gate 		 */
1977c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
1987c478bd9Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate 
201ba5f469cSkrishna 	if (session_p->digest.flags & CRYPTO_EMULATE) {
202b2a96221Skrishna 		crypto_active_op_t *opp;
203b2a96221Skrishna 		CK_MECHANISM_PTR pMechanism;
204b2a96221Skrishna 
205b2a96221Skrishna 		opp = &(session_p->digest);
206b232b5fcSZdenek Kotala 		if (opp->context == NULL) {
207b232b5fcSZdenek Kotala 			REFRELE(session_p, ses_lock_held);
208b2a96221Skrishna 			return (CKR_ARGUMENTS_BAD);
209b232b5fcSZdenek Kotala 		}
210b2a96221Skrishna 		pMechanism = &(opp->mech);
211b2a96221Skrishna 
212ba5f469cSkrishna 		if ((ulDataLen < SLOT_THRESHOLD(session_p)) ||
2134df55fdeSJanie Lu 		    (ulDataLen > SLOT_HASH_MAX_INDATA_LEN(session_p))) {
214ba5f469cSkrishna 			session_p->digest.flags |= CRYPTO_EMULATE_USING_SW;
215ba5f469cSkrishna 			(void) pthread_mutex_unlock(&session_p->session_mutex);
216b232b5fcSZdenek Kotala 			ses_lock_held = B_FALSE;
217ba5f469cSkrishna 
218b2a96221Skrishna 			rv = do_soft_digest(get_spp(opp), pMechanism,
219b2a96221Skrishna 			    pData, ulDataLen, pDigest, pulDigestLen,
220b2a96221Skrishna 			    OP_INIT | OP_SINGLE);
221ba5f469cSkrishna 			goto done;
222b2a96221Skrishna 		} else if (!(session_p->digest.flags &
223b2a96221Skrishna 		    CRYPTO_EMULATE_INIT_DONE)) {
224b2a96221Skrishna 			session_p->digest.flags |= CRYPTO_EMULATE_INIT_DONE;
225b2a96221Skrishna 			(void) pthread_mutex_unlock(&session_p->session_mutex);
226b232b5fcSZdenek Kotala 			ses_lock_held = B_FALSE;
227b232b5fcSZdenek Kotala 
228b2a96221Skrishna 			rv = common_digest_init(hSession, pMechanism, B_FALSE);
229b2a96221Skrishna 			if (rv != CKR_OK)
230b2a96221Skrishna 				goto clean_exit;
231b2a96221Skrishna 			(void) pthread_mutex_lock(&session_p->session_mutex);
232b232b5fcSZdenek Kotala 			ses_lock_held = B_TRUE;
233ba5f469cSkrishna 		}
234ba5f469cSkrishna 	}
235ba5f469cSkrishna 
2367c478bd9Sstevel@tonic-gate 	digest.cd_session = session_p->k_session;
2377c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
238b232b5fcSZdenek Kotala 	ses_lock_held = B_FALSE;
2397c478bd9Sstevel@tonic-gate 	digest.cd_datalen =  ulDataLen;
2407c478bd9Sstevel@tonic-gate 	digest.cd_databuf = (char *)pData;
2417c478bd9Sstevel@tonic-gate 	digest.cd_digestbuf = (char *)pDigest;
2427c478bd9Sstevel@tonic-gate 	digest.cd_digestlen = *pulDigestLen;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST, &digest)) < 0) {
2457c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
2467c478bd9Sstevel@tonic-gate 			break;
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 	if (r < 0) {
2497c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
2507c478bd9Sstevel@tonic-gate 	} else {
2517c478bd9Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(digest.cd_return_value);
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL))
2557c478bd9Sstevel@tonic-gate 		*pulDigestLen = digest.cd_digestlen;
2567c478bd9Sstevel@tonic-gate 
257ba5f469cSkrishna done:
2587c478bd9Sstevel@tonic-gate 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
2597c478bd9Sstevel@tonic-gate 	    (rv == CKR_OK && pDigest == NULL)) {
2607c478bd9Sstevel@tonic-gate 		/*
2617c478bd9Sstevel@tonic-gate 		 * We will not terminate the active digest operation flag,
2627c478bd9Sstevel@tonic-gate 		 * when the application-supplied buffer is too small, or
2637c478bd9Sstevel@tonic-gate 		 * the application asks for the length of buffer to hold
2647c478bd9Sstevel@tonic-gate 		 * the message digest.
2657c478bd9Sstevel@tonic-gate 		 *
2667c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
2677c478bd9Sstevel@tonic-gate 		 * We do not hold the session lock.
2687c478bd9Sstevel@tonic-gate 		 */
2697c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
2707c478bd9Sstevel@tonic-gate 		return (rv);
2717c478bd9Sstevel@tonic-gate 	}
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate clean_exit:
2747c478bd9Sstevel@tonic-gate 	/*
2757c478bd9Sstevel@tonic-gate 	 * Terminates the active digest operation.
2767c478bd9Sstevel@tonic-gate 	 * Application needs to call C_DigestInit again for next
2777c478bd9Sstevel@tonic-gate 	 * digest operation.
2787c478bd9Sstevel@tonic-gate 	 */
2797c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
280b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
281ba5f469cSkrishna 
282ba5f469cSkrishna 	REINIT_OPBUF(&session_p->digest);
2837c478bd9Sstevel@tonic-gate 	session_p->digest.flags = 0;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	/*
2867c478bd9Sstevel@tonic-gate 	 * Decrement the session reference count.
2877c478bd9Sstevel@tonic-gate 	 * We hold the session lock, and REFRELE()
2887c478bd9Sstevel@tonic-gate 	 * will release the session lock for us.
2897c478bd9Sstevel@tonic-gate 	 */
2907c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	return (rv);
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate CK_RV
C_DigestUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,CK_ULONG ulPartLen)2967c478bd9Sstevel@tonic-gate C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
2977c478bd9Sstevel@tonic-gate     CK_ULONG ulPartLen)
2987c478bd9Sstevel@tonic-gate {
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	CK_RV rv;
3017c478bd9Sstevel@tonic-gate 	kernel_session_t *session_p;
302b232b5fcSZdenek Kotala 	boolean_t ses_lock_held = B_FALSE;
3037c478bd9Sstevel@tonic-gate 	crypto_digest_update_t digest_update;
3047c478bd9Sstevel@tonic-gate 	int r;
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
3077c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	/*
3107c478bd9Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
3117c478bd9Sstevel@tonic-gate 	 * reference count.
3127c478bd9Sstevel@tonic-gate 	 */
3137c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
3147c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
3157c478bd9Sstevel@tonic-gate 		return (rv);
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	if (pPart == NULL) {
3187c478bd9Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
3197c478bd9Sstevel@tonic-gate 		goto clean_exit;
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	/* Acquire the session lock */
3237c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
324b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	/*
3277c478bd9Sstevel@tonic-gate 	 * Application must call C_DigestInit before calling
3287c478bd9Sstevel@tonic-gate 	 * C_DigestUpdate.
3297c478bd9Sstevel@tonic-gate 	 */
3307c478bd9Sstevel@tonic-gate 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
3317c478bd9Sstevel@tonic-gate 		/*
3327c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
3337c478bd9Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
3347c478bd9Sstevel@tonic-gate 		 * will release the session lock for us.
3357c478bd9Sstevel@tonic-gate 		 */
3367c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
3377c478bd9Sstevel@tonic-gate 		return (CKR_OPERATION_NOT_INITIALIZED);
3387c478bd9Sstevel@tonic-gate 	}
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	/* Set update flag to protect C_Digest */
3417c478bd9Sstevel@tonic-gate 	session_p->digest.flags |= CRYPTO_OPERATION_UPDATE;
3427c478bd9Sstevel@tonic-gate 
343ba5f469cSkrishna 	if (session_p->digest.flags & CRYPTO_EMULATE) {
344ba5f469cSkrishna 		(void) pthread_mutex_unlock(&session_p->session_mutex);
345b232b5fcSZdenek Kotala 		ses_lock_held = B_FALSE;
346ba5f469cSkrishna 		rv = emulate_update(session_p, pPart, ulPartLen, OP_DIGEST);
347ba5f469cSkrishna 		goto done;
348ba5f469cSkrishna 	}
349ba5f469cSkrishna 
3507c478bd9Sstevel@tonic-gate 	digest_update.du_session = session_p->k_session;
3517c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
352b232b5fcSZdenek Kotala 	ses_lock_held = B_FALSE;
3537c478bd9Sstevel@tonic-gate 	digest_update.du_datalen =  ulPartLen;
3547c478bd9Sstevel@tonic-gate 	digest_update.du_databuf = (char *)pPart;
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE,
3577c478bd9Sstevel@tonic-gate 	    &digest_update)) < 0) {
3587c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
3597c478bd9Sstevel@tonic-gate 			break;
3607c478bd9Sstevel@tonic-gate 	}
3617c478bd9Sstevel@tonic-gate 	if (r < 0) {
3627c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
3637c478bd9Sstevel@tonic-gate 	} else {
3647c478bd9Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(digest_update.du_return_value);
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate 
367ba5f469cSkrishna done:
3687c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK) {
3697c478bd9Sstevel@tonic-gate 		/*
3707c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
3717c478bd9Sstevel@tonic-gate 		 * We do not hold the session lock.
3727c478bd9Sstevel@tonic-gate 		 */
3737c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
3747c478bd9Sstevel@tonic-gate 		return (CKR_OK);
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate clean_exit:
3787c478bd9Sstevel@tonic-gate 	/*
3797c478bd9Sstevel@tonic-gate 	 * After an error occurred, terminate the current digest
3807c478bd9Sstevel@tonic-gate 	 * operation by resetting the active and update flags.
3817c478bd9Sstevel@tonic-gate 	 */
3827c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
383b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
384ba5f469cSkrishna 	REINIT_OPBUF(&session_p->digest);
3857c478bd9Sstevel@tonic-gate 	session_p->digest.flags = 0;
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	/*
3887c478bd9Sstevel@tonic-gate 	 * Decrement the session reference count.
3897c478bd9Sstevel@tonic-gate 	 * We hold the session lock, and REFRELE()
3907c478bd9Sstevel@tonic-gate 	 * will release the session lock for us.
3917c478bd9Sstevel@tonic-gate 	 */
3927c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	return (rv);
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate CK_RV
C_DigestKey(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hKey)3997c478bd9Sstevel@tonic-gate C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey)
4007c478bd9Sstevel@tonic-gate {
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	CK_RV		rv;
4037c478bd9Sstevel@tonic-gate 	kernel_session_t	*session_p;
4047c478bd9Sstevel@tonic-gate 	kernel_object_t	*key_p;
405b232b5fcSZdenek Kotala 	boolean_t ses_lock_held = B_FALSE;
4067c478bd9Sstevel@tonic-gate 	CK_BYTE_PTR	pPart;
4077c478bd9Sstevel@tonic-gate 	CK_ULONG	ulPartLen;
4087c478bd9Sstevel@tonic-gate 	crypto_digest_key_t digest_key;
4097c478bd9Sstevel@tonic-gate 	crypto_digest_update_t digest_update;
4107c478bd9Sstevel@tonic-gate 	int r;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
4137c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	/*
4167c478bd9Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
4177c478bd9Sstevel@tonic-gate 	 * reference count.
4187c478bd9Sstevel@tonic-gate 	 */
4197c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
4207c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
4217c478bd9Sstevel@tonic-gate 		return (rv);
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	/* Obtain the object pointer. */
4247c478bd9Sstevel@tonic-gate 	HANDLE2OBJECT(hKey, key_p, rv);
42501223cbaSmcpowers 	if (rv != CKR_OK) {
42601223cbaSmcpowers 		(void) pthread_mutex_lock(&session_p->session_mutex);
427b232b5fcSZdenek Kotala 		ses_lock_held = B_TRUE;
428ba5f469cSkrishna 		REINIT_OPBUF(&session_p->digest);
42901223cbaSmcpowers 		session_p->digest.flags = 0;
43001223cbaSmcpowers 		REFRELE(session_p, ses_lock_held);
43101223cbaSmcpowers 		return (rv);
43201223cbaSmcpowers 	}
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	/* Check the key type */
4357c478bd9Sstevel@tonic-gate 	if (key_p->is_lib_obj && (key_p->class != CKO_SECRET_KEY)) {
4367c478bd9Sstevel@tonic-gate 		rv = CKR_KEY_INDIGESTIBLE;
4377c478bd9Sstevel@tonic-gate 		goto clean_exit;
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	/*
4417c478bd9Sstevel@tonic-gate 	 * Application must call C_DigestInit before calling
4427c478bd9Sstevel@tonic-gate 	 * C_DigestKey.
4437c478bd9Sstevel@tonic-gate 	 */
4447c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
445b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
446b232b5fcSZdenek Kotala 
4477c478bd9Sstevel@tonic-gate 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
4487c478bd9Sstevel@tonic-gate 		/*
4497c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
4507c478bd9Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
4517c478bd9Sstevel@tonic-gate 		 * will release the session lock for us.
4527c478bd9Sstevel@tonic-gate 		 */
45301223cbaSmcpowers 		OBJ_REFRELE(key_p);
4547c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
4557c478bd9Sstevel@tonic-gate 		return (CKR_OPERATION_NOT_INITIALIZED);
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 	session_p->digest.flags |= CRYPTO_OPERATION_UPDATE;
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	/*
4607c478bd9Sstevel@tonic-gate 	 * If the key object is from the HW provider, call CRYPTO_DIGEST_KEY
4617c478bd9Sstevel@tonic-gate 	 * ioctl. Otherwise, call CRYPTO_DIGEST_UPDATE ioctl and pass the key
4627c478bd9Sstevel@tonic-gate 	 * by value.
4637c478bd9Sstevel@tonic-gate 	 */
4647c478bd9Sstevel@tonic-gate 	if (key_p->is_lib_obj) {
4657c478bd9Sstevel@tonic-gate 		digest_update.du_session = session_p->k_session;
4667c478bd9Sstevel@tonic-gate 	} else {
4677c478bd9Sstevel@tonic-gate 		digest_key.dk_session = session_p->k_session;
4687c478bd9Sstevel@tonic-gate 	}
4697c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
470b232b5fcSZdenek Kotala 	ses_lock_held = B_FALSE;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	if (!key_p->is_lib_obj) {
473ba5f469cSkrishna 		if (session_p->digest.flags & CRYPTO_EMULATE) {
474ba5f469cSkrishna 			rv = CKR_FUNCTION_NOT_SUPPORTED;
475ba5f469cSkrishna 			goto clean_exit;
476ba5f469cSkrishna 		}
4777c478bd9Sstevel@tonic-gate 		digest_key.dk_key.ck_format = CRYPTO_KEY_REFERENCE;
4787c478bd9Sstevel@tonic-gate 		digest_key.dk_key.ck_obj_id = key_p->k_handle;
4797c478bd9Sstevel@tonic-gate 		while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_KEY,
4807c478bd9Sstevel@tonic-gate 		    &digest_key)) < 0) {
4817c478bd9Sstevel@tonic-gate 			if (errno != EINTR)
4827c478bd9Sstevel@tonic-gate 				break;
4837c478bd9Sstevel@tonic-gate 		}
4847c478bd9Sstevel@tonic-gate 		if (r < 0) {
4857c478bd9Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
4867c478bd9Sstevel@tonic-gate 		} else {
4877c478bd9Sstevel@tonic-gate 			rv = crypto2pkcs11_error_number(
4887c478bd9Sstevel@tonic-gate 			    digest_key.dk_return_value);
4897c478bd9Sstevel@tonic-gate 		}
4907c478bd9Sstevel@tonic-gate 	} else {
4917c478bd9Sstevel@tonic-gate 		ulPartLen = OBJ_SEC_VALUE_LEN(key_p);
4927c478bd9Sstevel@tonic-gate 		if (ulPartLen == 0) {
4937c478bd9Sstevel@tonic-gate 			rv = CKR_KEY_SIZE_RANGE;
4947c478bd9Sstevel@tonic-gate 			goto clean_exit;
4957c478bd9Sstevel@tonic-gate 		}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 		pPart = (CK_BYTE_PTR) OBJ_SEC_VALUE(key_p);
4987c478bd9Sstevel@tonic-gate 		if (pPart == NULL) {
4997c478bd9Sstevel@tonic-gate 			rv = CKR_KEY_HANDLE_INVALID;
5007c478bd9Sstevel@tonic-gate 			goto clean_exit;
5017c478bd9Sstevel@tonic-gate 		}
5027c478bd9Sstevel@tonic-gate 
503ba5f469cSkrishna 		(void) pthread_mutex_lock(&session_p->session_mutex);
504b232b5fcSZdenek Kotala 		ses_lock_held = B_TRUE;
505ba5f469cSkrishna 		if (session_p->digest.flags & CRYPTO_EMULATE) {
506ba5f469cSkrishna 			(void) pthread_mutex_unlock(&session_p->session_mutex);
507b232b5fcSZdenek Kotala 			ses_lock_held = B_FALSE;
508ba5f469cSkrishna 			rv = emulate_update(session_p, pPart,
509ba5f469cSkrishna 			    ulPartLen, OP_DIGEST);
510ba5f469cSkrishna 			goto done;
511ba5f469cSkrishna 		}
512ba5f469cSkrishna 		(void) pthread_mutex_unlock(&session_p->session_mutex);
513b232b5fcSZdenek Kotala 		ses_lock_held = B_FALSE;
514ba5f469cSkrishna 
5157c478bd9Sstevel@tonic-gate 		digest_update.du_datalen = ulPartLen;
5167c478bd9Sstevel@tonic-gate 		digest_update.du_databuf = (char *)pPart;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 		while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE,
5197c478bd9Sstevel@tonic-gate 		    &digest_update)) < 0) {
5207c478bd9Sstevel@tonic-gate 			if (errno != EINTR)
5217c478bd9Sstevel@tonic-gate 				break;
5227c478bd9Sstevel@tonic-gate 		}
5237c478bd9Sstevel@tonic-gate 		if (r < 0) {
5247c478bd9Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
5257c478bd9Sstevel@tonic-gate 		} else {
5267c478bd9Sstevel@tonic-gate 			rv = crypto2pkcs11_error_number(
5277c478bd9Sstevel@tonic-gate 			    digest_update.du_return_value);
5287c478bd9Sstevel@tonic-gate 		}
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate 
531ba5f469cSkrishna done:
5327c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK) {
5337c478bd9Sstevel@tonic-gate 		/*
5347c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
5357c478bd9Sstevel@tonic-gate 		 * We do not hold the session lock.
5367c478bd9Sstevel@tonic-gate 		 */
53701223cbaSmcpowers 		OBJ_REFRELE(key_p);
53801223cbaSmcpowers 		REFRELE(session_p, ses_lock_held);
5397c478bd9Sstevel@tonic-gate 		return (CKR_OK);
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate clean_exit:
54301223cbaSmcpowers 	OBJ_REFRELE(key_p);
5447c478bd9Sstevel@tonic-gate 	/*
5457c478bd9Sstevel@tonic-gate 	 * After an error occurred, terminate the current digest
5467c478bd9Sstevel@tonic-gate 	 * operation by resetting the active and update flags.
5477c478bd9Sstevel@tonic-gate 	 */
5487c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
549b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
550ba5f469cSkrishna 	REINIT_OPBUF(&session_p->digest);
5517c478bd9Sstevel@tonic-gate 	session_p->digest.flags = 0;
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	/*
5547c478bd9Sstevel@tonic-gate 	 * Decrement the session reference count.
5557c478bd9Sstevel@tonic-gate 	 * We hold the session lock, and REFRELE()
5567c478bd9Sstevel@tonic-gate 	 * will release the session lock for us.
5577c478bd9Sstevel@tonic-gate 	 */
5587c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
5597c478bd9Sstevel@tonic-gate 	return (rv);
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate CK_RV
C_DigestFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pDigest,CK_ULONG_PTR pulDigestLen)5647c478bd9Sstevel@tonic-gate C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest,
5657c478bd9Sstevel@tonic-gate     CK_ULONG_PTR pulDigestLen)
5667c478bd9Sstevel@tonic-gate {
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	CK_RV rv;
5697c478bd9Sstevel@tonic-gate 	kernel_session_t *session_p;
570b232b5fcSZdenek Kotala 	boolean_t ses_lock_held = B_FALSE;
5717c478bd9Sstevel@tonic-gate 	crypto_digest_final_t digest_final;
5727c478bd9Sstevel@tonic-gate 	int r;
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
5757c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	/*
5787c478bd9Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
5797c478bd9Sstevel@tonic-gate 	 * reference count.
5807c478bd9Sstevel@tonic-gate 	 */
5817c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
5827c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
5837c478bd9Sstevel@tonic-gate 		return (rv);
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	if (pulDigestLen == NULL) {
5867c478bd9Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
5877c478bd9Sstevel@tonic-gate 		goto clean_exit;
5887c478bd9Sstevel@tonic-gate 	}
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	/* Acquire the session lock */
5917c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
592b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	/*
5957c478bd9Sstevel@tonic-gate 	 * Application must call C_DigestInit before calling
5967c478bd9Sstevel@tonic-gate 	 * C_DigestFinal.
5977c478bd9Sstevel@tonic-gate 	 */
5987c478bd9Sstevel@tonic-gate 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
5997c478bd9Sstevel@tonic-gate 		/*
6007c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
6017c478bd9Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
6027c478bd9Sstevel@tonic-gate 		 * will release the session lock for us.
6037c478bd9Sstevel@tonic-gate 		 */
6047c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
6057c478bd9Sstevel@tonic-gate 		return (CKR_OPERATION_NOT_INITIALIZED);
6067c478bd9Sstevel@tonic-gate 	}
6077c478bd9Sstevel@tonic-gate 
608ba5f469cSkrishna 	/* The order of checks is important here */
609ba5f469cSkrishna 	if (session_p->digest.flags & CRYPTO_EMULATE_USING_SW) {
610ba5f469cSkrishna 		if (session_p->digest.flags & CRYPTO_EMULATE_UPDATE_DONE) {
611ba5f469cSkrishna 			(void) pthread_mutex_unlock(&session_p->session_mutex);
612b232b5fcSZdenek Kotala 			ses_lock_held = B_FALSE;
613ba5f469cSkrishna 			rv = do_soft_digest(get_spp(&session_p->digest),
614*798d97d3SToomas Soome 			    NULL, NULL, 0, pDigest, pulDigestLen, OP_FINAL);
615ba5f469cSkrishna 		} else {
616ba5f469cSkrishna 			/*
617ba5f469cSkrishna 			 * We end up here if an earlier C_DigestFinal() call
618ba5f469cSkrishna 			 * took the C_Digest() path and it had returned
619ba5f469cSkrishna 			 * CKR_BUFFER_TOO_SMALL.
620ba5f469cSkrishna 			 */
621ba5f469cSkrishna 			digest_buf_t *bufp = session_p->digest.context;
622ba5f469cSkrishna 			(void) pthread_mutex_unlock(&session_p->session_mutex);
623b232b5fcSZdenek Kotala 			ses_lock_held = B_FALSE;
624ba5f469cSkrishna 			if (bufp == NULL || bufp->buf == NULL) {
625ba5f469cSkrishna 				rv = CKR_ARGUMENTS_BAD;
626ba5f469cSkrishna 				goto clean_exit;
627ba5f469cSkrishna 			}
628ba5f469cSkrishna 			rv = do_soft_digest(get_spp(&session_p->digest),
629ba5f469cSkrishna 			    NULL, bufp->buf, bufp->indata_len,
630ba5f469cSkrishna 			    pDigest, pulDigestLen, OP_SINGLE);
631ba5f469cSkrishna 		}
632ba5f469cSkrishna 		goto done;
633ba5f469cSkrishna 	} else if (session_p->digest.flags & CRYPTO_EMULATE) {
634ba5f469cSkrishna 		digest_buf_t *bufp = session_p->digest.context;
635ba5f469cSkrishna 
636ba5f469cSkrishna 		/*
637ba5f469cSkrishna 		 * We are emulating a single-part operation now.
638ba5f469cSkrishna 		 * So, clear the flag.
639ba5f469cSkrishna 		 */
640ba5f469cSkrishna 		session_p->digest.flags &= ~CRYPTO_OPERATION_UPDATE;
641ba5f469cSkrishna 		if (bufp == NULL || bufp->buf == NULL) {
642ba5f469cSkrishna 			rv = CKR_ARGUMENTS_BAD;
643ba5f469cSkrishna 			goto clean_exit;
644ba5f469cSkrishna 		}
645ba5f469cSkrishna 		REFRELE(session_p, ses_lock_held);
646ba5f469cSkrishna 		rv = C_Digest(hSession, bufp->buf, bufp->indata_len,
647ba5f469cSkrishna 		    pDigest, pulDigestLen);
648ba5f469cSkrishna 		return (rv);
649ba5f469cSkrishna 	}
650ba5f469cSkrishna 
6517c478bd9Sstevel@tonic-gate 	digest_final.df_session = session_p->k_session;
6527c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
653b232b5fcSZdenek Kotala 	ses_lock_held = B_FALSE;
6547c478bd9Sstevel@tonic-gate 	digest_final.df_digestlen = *pulDigestLen;
6557c478bd9Sstevel@tonic-gate 	digest_final.df_digestbuf = (char *)pDigest;
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_FINAL, &digest_final)) < 0) {
6587c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
6597c478bd9Sstevel@tonic-gate 			break;
6607c478bd9Sstevel@tonic-gate 	}
6617c478bd9Sstevel@tonic-gate 	if (r < 0) {
6627c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
6637c478bd9Sstevel@tonic-gate 	} else {
6647c478bd9Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(digest_final.df_return_value);
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL))
6687c478bd9Sstevel@tonic-gate 		*pulDigestLen = digest_final.df_digestlen;
6697c478bd9Sstevel@tonic-gate 
670ba5f469cSkrishna done:
6717c478bd9Sstevel@tonic-gate 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
6727c478bd9Sstevel@tonic-gate 	    (rv == CKR_OK && pDigest == NULL)) {
6737c478bd9Sstevel@tonic-gate 		/*
6747c478bd9Sstevel@tonic-gate 		 * We will not terminate the active digest operation flag,
6757c478bd9Sstevel@tonic-gate 		 * when the application-supplied buffer is too small, or
6767c478bd9Sstevel@tonic-gate 		 * the application asks for the length of buffer to hold
6777c478bd9Sstevel@tonic-gate 		 * the message digest.
6787c478bd9Sstevel@tonic-gate 		 *
6797c478bd9Sstevel@tonic-gate 		 * Decrement the session reference count.
6807c478bd9Sstevel@tonic-gate 		 * We do not hold the session lock.
6817c478bd9Sstevel@tonic-gate 		 */
6827c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
6837c478bd9Sstevel@tonic-gate 		return (rv);
6847c478bd9Sstevel@tonic-gate 	}
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate clean_exit:
6877c478bd9Sstevel@tonic-gate 	/* Terminates the active digest operation */
6887c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
689b232b5fcSZdenek Kotala 	ses_lock_held = B_TRUE;
690ba5f469cSkrishna 	REINIT_OPBUF(&session_p->digest);
6917c478bd9Sstevel@tonic-gate 	session_p->digest.flags = 0;
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	/*
6947c478bd9Sstevel@tonic-gate 	 * Decrement the session reference count.
6957c478bd9Sstevel@tonic-gate 	 * We hold the session lock, and REFRELE()
6967c478bd9Sstevel@tonic-gate 	 * will release the session lock for us.
6977c478bd9Sstevel@tonic-gate 	 */
6987c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	return (rv);
7017c478bd9Sstevel@tonic-gate }
702