xref: /onnv-gate/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelDigest.c (revision 11304:3092d1e303d6)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54072Skrishna  * Common Development and Distribution License (the "License").
64072Skrishna  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
214072Skrishna 
220Sstevel@tonic-gate /*
239800SZdenek.Kotala@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <pthread.h>
280Sstevel@tonic-gate #include <errno.h>
290Sstevel@tonic-gate #include <sys/crypto/ioctl.h>
300Sstevel@tonic-gate #include <security/cryptoki.h>
310Sstevel@tonic-gate #include "kernelGlobal.h"
320Sstevel@tonic-gate #include "kernelSession.h"
334072Skrishna #include "kernelEmulate.h"
340Sstevel@tonic-gate 
355616Skrishna static CK_RV
common_digest_init(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,boolean_t is_external_caller)365616Skrishna common_digest_init(CK_SESSION_HANDLE hSession,
375616Skrishna     CK_MECHANISM_PTR pMechanism, boolean_t is_external_caller)
380Sstevel@tonic-gate {
390Sstevel@tonic-gate 	CK_RV rv;
400Sstevel@tonic-gate 	kernel_session_t *session_p;
419800SZdenek.Kotala@Sun.COM 	boolean_t ses_lock_held = B_FALSE;
420Sstevel@tonic-gate 	crypto_digest_init_t digest_init;
430Sstevel@tonic-gate 	crypto_mech_type_t k_mech_type;
440Sstevel@tonic-gate 	int r;
450Sstevel@tonic-gate 
460Sstevel@tonic-gate 	if (!kernel_initialized)
470Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
480Sstevel@tonic-gate 
490Sstevel@tonic-gate 	if (pMechanism == NULL)
500Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
510Sstevel@tonic-gate 
520Sstevel@tonic-gate 	/*
530Sstevel@tonic-gate 	 * Get the kernel's internal mechanism number.
540Sstevel@tonic-gate 	 */
550Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
560Sstevel@tonic-gate 	if (rv != CKR_OK)
570Sstevel@tonic-gate 		return (rv);
580Sstevel@tonic-gate 
590Sstevel@tonic-gate 	/*
600Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
610Sstevel@tonic-gate 	 * reference count.
620Sstevel@tonic-gate 	 */
630Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
640Sstevel@tonic-gate 	if (rv != CKR_OK)
650Sstevel@tonic-gate 		return (rv);
660Sstevel@tonic-gate 
670Sstevel@tonic-gate 	/* Acquire the session lock */
680Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
699800SZdenek.Kotala@Sun.COM 	ses_lock_held = B_TRUE;
700Sstevel@tonic-gate 
710Sstevel@tonic-gate 	/*
720Sstevel@tonic-gate 	 * This active flag will remain ON until application calls either
730Sstevel@tonic-gate 	 * C_Digest or C_DigestFinal to actually obtain the value of
740Sstevel@tonic-gate 	 * the message digest.
750Sstevel@tonic-gate 	 */
765616Skrishna 	session_p->digest.flags |= CRYPTO_OPERATION_ACTIVE;
775616Skrishna 
785616Skrishna 	if (SLOT_HAS_LIMITED_HASH(session_p) && is_external_caller) {
795616Skrishna 		session_p->digest.mech.mechanism = pMechanism->mechanism;
805616Skrishna 		session_p->digest.mech.pParameter = NULL;
815616Skrishna 		session_p->digest.mech.ulParameterLen = 0;
825616Skrishna 		session_p->digest.flags |= CRYPTO_EMULATE;
835616Skrishna 		rv = emulate_buf_init(session_p, EDIGEST_LENGTH, OP_DIGEST);
845616Skrishna 		REFRELE(session_p, ses_lock_held);
855616Skrishna 		return (rv);
865616Skrishna 	}
875616Skrishna 
880Sstevel@tonic-gate 	digest_init.di_session = session_p->k_session;
890Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
909800SZdenek.Kotala@Sun.COM 	ses_lock_held = B_FALSE;
910Sstevel@tonic-gate 	digest_init.di_mech.cm_type = k_mech_type;
920Sstevel@tonic-gate 	digest_init.di_mech.cm_param = pMechanism->pParameter;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	/*
950Sstevel@tonic-gate 	 * If pParameter is NULL, set cm_param_len to be 0, so that ioctl call
960Sstevel@tonic-gate 	 * will have a clean input data.
970Sstevel@tonic-gate 	 */
980Sstevel@tonic-gate 	if (pMechanism->pParameter != NULL)
990Sstevel@tonic-gate 		digest_init.di_mech.cm_param_len = pMechanism->ulParameterLen;
1000Sstevel@tonic-gate 	else
1010Sstevel@tonic-gate 		digest_init.di_mech.cm_param_len = 0;
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_INIT, &digest_init)) < 0) {
1040Sstevel@tonic-gate 		if (errno != EINTR)
1050Sstevel@tonic-gate 			break;
1060Sstevel@tonic-gate 	}
1070Sstevel@tonic-gate 	if (r < 0) {
1080Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
1090Sstevel@tonic-gate 	} else {
1100Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(digest_init.di_return_value);
1110Sstevel@tonic-gate 	}
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	if (rv != CKR_OK) {
1140Sstevel@tonic-gate 		(void) pthread_mutex_lock(&session_p->session_mutex);
1159800SZdenek.Kotala@Sun.COM 		ses_lock_held = B_TRUE;
1160Sstevel@tonic-gate 		session_p->digest.flags &= ~CRYPTO_OPERATION_ACTIVE;
1170Sstevel@tonic-gate 		/*
1180Sstevel@tonic-gate 		 * Decrement the session reference count.
1190Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
1200Sstevel@tonic-gate 		 * will release the session lock for us.
1210Sstevel@tonic-gate 		 */
1220Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
1230Sstevel@tonic-gate 		return (rv);
1240Sstevel@tonic-gate 	}
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	/*
1270Sstevel@tonic-gate 	 * Decrement the session reference count.
1280Sstevel@tonic-gate 	 * We do not hold the session lock.
1290Sstevel@tonic-gate 	 */
1300Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
1310Sstevel@tonic-gate 	return (rv);
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate CK_RV
C_DigestInit(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism)1355616Skrishna C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism)
1365616Skrishna {
1375616Skrishna 	return (common_digest_init(hSession, pMechanism, B_TRUE));
1385616Skrishna }
1395616Skrishna 
1405616Skrishna CK_RV
C_Digest(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pDigest,CK_ULONG_PTR pulDigestLen)1410Sstevel@tonic-gate C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
1420Sstevel@tonic-gate     CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
1430Sstevel@tonic-gate {
1440Sstevel@tonic-gate 	CK_RV rv;
1450Sstevel@tonic-gate 	kernel_session_t *session_p;
1469800SZdenek.Kotala@Sun.COM 	boolean_t ses_lock_held = B_FALSE;
1470Sstevel@tonic-gate 	crypto_digest_t digest;
1480Sstevel@tonic-gate 	int r;
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	if (!kernel_initialized)
1510Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	/*
1540Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
1550Sstevel@tonic-gate 	 * reference count.
1560Sstevel@tonic-gate 	 */
1570Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
1580Sstevel@tonic-gate 	if (rv != CKR_OK)
1590Sstevel@tonic-gate 		return (rv);
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	if (pData == NULL || pulDigestLen == NULL) {
1620Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
1630Sstevel@tonic-gate 		goto clean_exit;
1640Sstevel@tonic-gate 	}
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	/* Acquire the session lock */
1670Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
1689800SZdenek.Kotala@Sun.COM 	ses_lock_held = B_TRUE;
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	/* Application must call C_DigestInit before calling C_Digest */
1710Sstevel@tonic-gate 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
1720Sstevel@tonic-gate 		/*
1730Sstevel@tonic-gate 		 * Decrement the session reference count.
1740Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
1750Sstevel@tonic-gate 		 * will release the session lock for us.
1760Sstevel@tonic-gate 		 */
1770Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
1780Sstevel@tonic-gate 		return (CKR_OPERATION_NOT_INITIALIZED);
1790Sstevel@tonic-gate 	}
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	/*
1820Sstevel@tonic-gate 	 * C_Digest must be called without intervening C_DigestUpdate
1830Sstevel@tonic-gate 	 * calls.
1840Sstevel@tonic-gate 	 */
1850Sstevel@tonic-gate 	if (session_p->digest.flags & CRYPTO_OPERATION_UPDATE) {
1860Sstevel@tonic-gate 		/*
1870Sstevel@tonic-gate 		 * C_Digest can not be used to terminate a multi-part
1880Sstevel@tonic-gate 		 * operation, so we'll leave the active digest operation
1890Sstevel@tonic-gate 		 * flag on and let the application continue with the
1900Sstevel@tonic-gate 		 * digest update operation.
1910Sstevel@tonic-gate 		 *
1920Sstevel@tonic-gate 		 * Decrement the session reference count.
1930Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
1940Sstevel@tonic-gate 		 * will release the session lock for us.
1950Sstevel@tonic-gate 		 */
1960Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
1970Sstevel@tonic-gate 		return (CKR_FUNCTION_FAILED);
1980Sstevel@tonic-gate 	}
1990Sstevel@tonic-gate 
2004072Skrishna 	if (session_p->digest.flags & CRYPTO_EMULATE) {
2015616Skrishna 		crypto_active_op_t *opp;
2025616Skrishna 		CK_MECHANISM_PTR pMechanism;
2035616Skrishna 
2045616Skrishna 		opp = &(session_p->digest);
2059800SZdenek.Kotala@Sun.COM 		if (opp->context == NULL) {
2069800SZdenek.Kotala@Sun.COM 			REFRELE(session_p, ses_lock_held);
2075616Skrishna 			return (CKR_ARGUMENTS_BAD);
2089800SZdenek.Kotala@Sun.COM 		}
2095616Skrishna 		pMechanism = &(opp->mech);
2105616Skrishna 
2114072Skrishna 		if ((ulDataLen < SLOT_THRESHOLD(session_p)) ||
212*11304SJanie.Lu@Sun.COM 		    (ulDataLen > SLOT_HASH_MAX_INDATA_LEN(session_p))) {
2134072Skrishna 			session_p->digest.flags |= CRYPTO_EMULATE_USING_SW;
2144072Skrishna 			(void) pthread_mutex_unlock(&session_p->session_mutex);
2159800SZdenek.Kotala@Sun.COM 			ses_lock_held = B_FALSE;
2164072Skrishna 
2175616Skrishna 			rv = do_soft_digest(get_spp(opp), pMechanism,
2185616Skrishna 			    pData, ulDataLen, pDigest, pulDigestLen,
2195616Skrishna 			    OP_INIT | OP_SINGLE);
2204072Skrishna 			goto done;
2215616Skrishna 		} else if (!(session_p->digest.flags &
2225616Skrishna 		    CRYPTO_EMULATE_INIT_DONE)) {
2235616Skrishna 			session_p->digest.flags |= CRYPTO_EMULATE_INIT_DONE;
2245616Skrishna 			(void) pthread_mutex_unlock(&session_p->session_mutex);
2259800SZdenek.Kotala@Sun.COM 			ses_lock_held = B_FALSE;
2269800SZdenek.Kotala@Sun.COM 
2275616Skrishna 			rv = common_digest_init(hSession, pMechanism, B_FALSE);
2285616Skrishna 			if (rv != CKR_OK)
2295616Skrishna 				goto clean_exit;
2305616Skrishna 			(void) pthread_mutex_lock(&session_p->session_mutex);
2319800SZdenek.Kotala@Sun.COM 			ses_lock_held = B_TRUE;
2324072Skrishna 		}
2334072Skrishna 	}
2344072Skrishna 
2350Sstevel@tonic-gate 	digest.cd_session = session_p->k_session;
2360Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
2379800SZdenek.Kotala@Sun.COM 	ses_lock_held = B_FALSE;
2380Sstevel@tonic-gate 	digest.cd_datalen =  ulDataLen;
2390Sstevel@tonic-gate 	digest.cd_databuf = (char *)pData;
2400Sstevel@tonic-gate 	digest.cd_digestbuf = (char *)pDigest;
2410Sstevel@tonic-gate 	digest.cd_digestlen = *pulDigestLen;
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST, &digest)) < 0) {
2440Sstevel@tonic-gate 		if (errno != EINTR)
2450Sstevel@tonic-gate 			break;
2460Sstevel@tonic-gate 	}
2470Sstevel@tonic-gate 	if (r < 0) {
2480Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
2490Sstevel@tonic-gate 	} else {
2500Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(digest.cd_return_value);
2510Sstevel@tonic-gate 	}
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL))
2540Sstevel@tonic-gate 		*pulDigestLen = digest.cd_digestlen;
2550Sstevel@tonic-gate 
2564072Skrishna done:
2570Sstevel@tonic-gate 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
2580Sstevel@tonic-gate 	    (rv == CKR_OK && pDigest == NULL)) {
2590Sstevel@tonic-gate 		/*
2600Sstevel@tonic-gate 		 * We will not terminate the active digest operation flag,
2610Sstevel@tonic-gate 		 * when the application-supplied buffer is too small, or
2620Sstevel@tonic-gate 		 * the application asks for the length of buffer to hold
2630Sstevel@tonic-gate 		 * the message digest.
2640Sstevel@tonic-gate 		 *
2650Sstevel@tonic-gate 		 * Decrement the session reference count.
2660Sstevel@tonic-gate 		 * We do not hold the session lock.
2670Sstevel@tonic-gate 		 */
2680Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
2690Sstevel@tonic-gate 		return (rv);
2700Sstevel@tonic-gate 	}
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate clean_exit:
2730Sstevel@tonic-gate 	/*
2740Sstevel@tonic-gate 	 * Terminates the active digest operation.
2750Sstevel@tonic-gate 	 * Application needs to call C_DigestInit again for next
2760Sstevel@tonic-gate 	 * digest operation.
2770Sstevel@tonic-gate 	 */
2780Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
2799800SZdenek.Kotala@Sun.COM 	ses_lock_held = B_TRUE;
2804072Skrishna 
2814072Skrishna 	REINIT_OPBUF(&session_p->digest);
2820Sstevel@tonic-gate 	session_p->digest.flags = 0;
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	/*
2850Sstevel@tonic-gate 	 * Decrement the session reference count.
2860Sstevel@tonic-gate 	 * We hold the session lock, and REFRELE()
2870Sstevel@tonic-gate 	 * will release the session lock for us.
2880Sstevel@tonic-gate 	 */
2890Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	return (rv);
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate CK_RV
C_DigestUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,CK_ULONG ulPartLen)2950Sstevel@tonic-gate C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
2960Sstevel@tonic-gate     CK_ULONG ulPartLen)
2970Sstevel@tonic-gate {
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	CK_RV rv;
3000Sstevel@tonic-gate 	kernel_session_t *session_p;
3019800SZdenek.Kotala@Sun.COM 	boolean_t ses_lock_held = B_FALSE;
3020Sstevel@tonic-gate 	crypto_digest_update_t digest_update;
3030Sstevel@tonic-gate 	int r;
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	if (!kernel_initialized)
3060Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	/*
3090Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
3100Sstevel@tonic-gate 	 * reference count.
3110Sstevel@tonic-gate 	 */
3120Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
3130Sstevel@tonic-gate 	if (rv != CKR_OK)
3140Sstevel@tonic-gate 		return (rv);
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	if (pPart == NULL) {
3170Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
3180Sstevel@tonic-gate 		goto clean_exit;
3190Sstevel@tonic-gate 	}
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	/* Acquire the session lock */
3220Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
3239800SZdenek.Kotala@Sun.COM 	ses_lock_held = B_TRUE;
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	/*
3260Sstevel@tonic-gate 	 * Application must call C_DigestInit before calling
3270Sstevel@tonic-gate 	 * C_DigestUpdate.
3280Sstevel@tonic-gate 	 */
3290Sstevel@tonic-gate 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
3300Sstevel@tonic-gate 		/*
3310Sstevel@tonic-gate 		 * Decrement the session reference count.
3320Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
3330Sstevel@tonic-gate 		 * will release the session lock for us.
3340Sstevel@tonic-gate 		 */
3350Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
3360Sstevel@tonic-gate 		return (CKR_OPERATION_NOT_INITIALIZED);
3370Sstevel@tonic-gate 	}
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	/* Set update flag to protect C_Digest */
3400Sstevel@tonic-gate 	session_p->digest.flags |= CRYPTO_OPERATION_UPDATE;
3410Sstevel@tonic-gate 
3424072Skrishna 	if (session_p->digest.flags & CRYPTO_EMULATE) {
3434072Skrishna 		(void) pthread_mutex_unlock(&session_p->session_mutex);
3449800SZdenek.Kotala@Sun.COM 		ses_lock_held = B_FALSE;
3454072Skrishna 		rv = emulate_update(session_p, pPart, ulPartLen, OP_DIGEST);
3464072Skrishna 		goto done;
3474072Skrishna 	}
3484072Skrishna 
3490Sstevel@tonic-gate 	digest_update.du_session = session_p->k_session;
3500Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
3519800SZdenek.Kotala@Sun.COM 	ses_lock_held = B_FALSE;
3520Sstevel@tonic-gate 	digest_update.du_datalen =  ulPartLen;
3530Sstevel@tonic-gate 	digest_update.du_databuf = (char *)pPart;
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE,
3560Sstevel@tonic-gate 	    &digest_update)) < 0) {
3570Sstevel@tonic-gate 		if (errno != EINTR)
3580Sstevel@tonic-gate 			break;
3590Sstevel@tonic-gate 	}
3600Sstevel@tonic-gate 	if (r < 0) {
3610Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
3620Sstevel@tonic-gate 	} else {
3630Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(digest_update.du_return_value);
3640Sstevel@tonic-gate 	}
3650Sstevel@tonic-gate 
3664072Skrishna done:
3670Sstevel@tonic-gate 	if (rv == CKR_OK) {
3680Sstevel@tonic-gate 		/*
3690Sstevel@tonic-gate 		 * Decrement the session reference count.
3700Sstevel@tonic-gate 		 * We do not hold the session lock.
3710Sstevel@tonic-gate 		 */
3720Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
3730Sstevel@tonic-gate 		return (CKR_OK);
3740Sstevel@tonic-gate 	}
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate clean_exit:
3770Sstevel@tonic-gate 	/*
3780Sstevel@tonic-gate 	 * After an error occurred, terminate the current digest
3790Sstevel@tonic-gate 	 * operation by resetting the active and update flags.
3800Sstevel@tonic-gate 	 */
3810Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
3829800SZdenek.Kotala@Sun.COM 	ses_lock_held = B_TRUE;
3834072Skrishna 	REINIT_OPBUF(&session_p->digest);
3840Sstevel@tonic-gate 	session_p->digest.flags = 0;
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	/*
3870Sstevel@tonic-gate 	 * Decrement the session reference count.
3880Sstevel@tonic-gate 	 * We hold the session lock, and REFRELE()
3890Sstevel@tonic-gate 	 * will release the session lock for us.
3900Sstevel@tonic-gate 	 */
3910Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	return (rv);
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate CK_RV
C_DigestKey(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hKey)3980Sstevel@tonic-gate C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey)
3990Sstevel@tonic-gate {
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	CK_RV		rv;
4020Sstevel@tonic-gate 	kernel_session_t	*session_p;
4030Sstevel@tonic-gate 	kernel_object_t	*key_p;
4049800SZdenek.Kotala@Sun.COM 	boolean_t ses_lock_held = B_FALSE;
4050Sstevel@tonic-gate 	CK_BYTE_PTR	pPart;
4060Sstevel@tonic-gate 	CK_ULONG	ulPartLen;
4070Sstevel@tonic-gate 	crypto_digest_key_t digest_key;
4080Sstevel@tonic-gate 	crypto_digest_update_t digest_update;
4090Sstevel@tonic-gate 	int r;
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	if (!kernel_initialized)
4120Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	/*
4150Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
4160Sstevel@tonic-gate 	 * reference count.
4170Sstevel@tonic-gate 	 */
4180Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
4190Sstevel@tonic-gate 	if (rv != CKR_OK)
4200Sstevel@tonic-gate 		return (rv);
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	/* Obtain the object pointer. */
4230Sstevel@tonic-gate 	HANDLE2OBJECT(hKey, key_p, rv);
424214Smcpowers 	if (rv != CKR_OK) {
425214Smcpowers 		(void) pthread_mutex_lock(&session_p->session_mutex);
4269800SZdenek.Kotala@Sun.COM 		ses_lock_held = B_TRUE;
4274072Skrishna 		REINIT_OPBUF(&session_p->digest);
428214Smcpowers 		session_p->digest.flags = 0;
429214Smcpowers 		REFRELE(session_p, ses_lock_held);
430214Smcpowers 		return (rv);
431214Smcpowers 	}
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	/* Check the key type */
4340Sstevel@tonic-gate 	if (key_p->is_lib_obj && (key_p->class != CKO_SECRET_KEY)) {
4350Sstevel@tonic-gate 		rv = CKR_KEY_INDIGESTIBLE;
4360Sstevel@tonic-gate 		goto clean_exit;
4370Sstevel@tonic-gate 	}
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	/*
4400Sstevel@tonic-gate 	 * Application must call C_DigestInit before calling
4410Sstevel@tonic-gate 	 * C_DigestKey.
4420Sstevel@tonic-gate 	 */
4430Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
4449800SZdenek.Kotala@Sun.COM 	ses_lock_held = B_TRUE;
4459800SZdenek.Kotala@Sun.COM 
4460Sstevel@tonic-gate 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
4470Sstevel@tonic-gate 		/*
4480Sstevel@tonic-gate 		 * Decrement the session reference count.
4490Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
4500Sstevel@tonic-gate 		 * will release the session lock for us.
4510Sstevel@tonic-gate 		 */
452214Smcpowers 		OBJ_REFRELE(key_p);
4530Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
4540Sstevel@tonic-gate 		return (CKR_OPERATION_NOT_INITIALIZED);
4550Sstevel@tonic-gate 	}
4560Sstevel@tonic-gate 	session_p->digest.flags |= CRYPTO_OPERATION_UPDATE;
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	/*
4590Sstevel@tonic-gate 	 * If the key object is from the HW provider, call CRYPTO_DIGEST_KEY
4600Sstevel@tonic-gate 	 * ioctl. Otherwise, call CRYPTO_DIGEST_UPDATE ioctl and pass the key
4610Sstevel@tonic-gate 	 * by value.
4620Sstevel@tonic-gate 	 */
4630Sstevel@tonic-gate 	if (key_p->is_lib_obj) {
4640Sstevel@tonic-gate 		digest_update.du_session = session_p->k_session;
4650Sstevel@tonic-gate 	} else {
4660Sstevel@tonic-gate 		digest_key.dk_session = session_p->k_session;
4670Sstevel@tonic-gate 	}
4680Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
4699800SZdenek.Kotala@Sun.COM 	ses_lock_held = B_FALSE;
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	if (!key_p->is_lib_obj) {
4724072Skrishna 		if (session_p->digest.flags & CRYPTO_EMULATE) {
4734072Skrishna 			rv = CKR_FUNCTION_NOT_SUPPORTED;
4744072Skrishna 			goto clean_exit;
4754072Skrishna 		}
4760Sstevel@tonic-gate 		digest_key.dk_key.ck_format = CRYPTO_KEY_REFERENCE;
4770Sstevel@tonic-gate 		digest_key.dk_key.ck_obj_id = key_p->k_handle;
4780Sstevel@tonic-gate 		while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_KEY,
4790Sstevel@tonic-gate 		    &digest_key)) < 0) {
4800Sstevel@tonic-gate 			if (errno != EINTR)
4810Sstevel@tonic-gate 				break;
4820Sstevel@tonic-gate 		}
4830Sstevel@tonic-gate 		if (r < 0) {
4840Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
4850Sstevel@tonic-gate 		} else {
4860Sstevel@tonic-gate 			rv = crypto2pkcs11_error_number(
4870Sstevel@tonic-gate 			    digest_key.dk_return_value);
4880Sstevel@tonic-gate 		}
4890Sstevel@tonic-gate 	} else {
4900Sstevel@tonic-gate 		ulPartLen = OBJ_SEC_VALUE_LEN(key_p);
4910Sstevel@tonic-gate 		if (ulPartLen == 0) {
4920Sstevel@tonic-gate 			rv = CKR_KEY_SIZE_RANGE;
4930Sstevel@tonic-gate 			goto clean_exit;
4940Sstevel@tonic-gate 		}
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 		pPart = (CK_BYTE_PTR) OBJ_SEC_VALUE(key_p);
4970Sstevel@tonic-gate 		if (pPart == NULL) {
4980Sstevel@tonic-gate 			rv = CKR_KEY_HANDLE_INVALID;
4990Sstevel@tonic-gate 			goto clean_exit;
5000Sstevel@tonic-gate 		}
5010Sstevel@tonic-gate 
5024072Skrishna 		(void) pthread_mutex_lock(&session_p->session_mutex);
5039800SZdenek.Kotala@Sun.COM 		ses_lock_held = B_TRUE;
5044072Skrishna 		if (session_p->digest.flags & CRYPTO_EMULATE) {
5054072Skrishna 			(void) pthread_mutex_unlock(&session_p->session_mutex);
5069800SZdenek.Kotala@Sun.COM 			ses_lock_held = B_FALSE;
5074072Skrishna 			rv = emulate_update(session_p, pPart,
5084072Skrishna 			    ulPartLen, OP_DIGEST);
5094072Skrishna 			goto done;
5104072Skrishna 		}
5114072Skrishna 		(void) pthread_mutex_unlock(&session_p->session_mutex);
5129800SZdenek.Kotala@Sun.COM 		ses_lock_held = B_FALSE;
5134072Skrishna 
5140Sstevel@tonic-gate 		digest_update.du_datalen = ulPartLen;
5150Sstevel@tonic-gate 		digest_update.du_databuf = (char *)pPart;
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 		while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE,
5180Sstevel@tonic-gate 		    &digest_update)) < 0) {
5190Sstevel@tonic-gate 			if (errno != EINTR)
5200Sstevel@tonic-gate 				break;
5210Sstevel@tonic-gate 		}
5220Sstevel@tonic-gate 		if (r < 0) {
5230Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
5240Sstevel@tonic-gate 		} else {
5250Sstevel@tonic-gate 			rv = crypto2pkcs11_error_number(
5260Sstevel@tonic-gate 			    digest_update.du_return_value);
5270Sstevel@tonic-gate 		}
5280Sstevel@tonic-gate 	}
5290Sstevel@tonic-gate 
5304072Skrishna done:
5310Sstevel@tonic-gate 	if (rv == CKR_OK) {
5320Sstevel@tonic-gate 		/*
5330Sstevel@tonic-gate 		 * Decrement the session reference count.
5340Sstevel@tonic-gate 		 * We do not hold the session lock.
5350Sstevel@tonic-gate 		 */
536214Smcpowers 		OBJ_REFRELE(key_p);
5370Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
5380Sstevel@tonic-gate 		return (CKR_OK);
5390Sstevel@tonic-gate 	}
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate clean_exit:
542214Smcpowers 	OBJ_REFRELE(key_p);
5430Sstevel@tonic-gate 	/*
5440Sstevel@tonic-gate 	 * After an error occurred, terminate the current digest
5450Sstevel@tonic-gate 	 * operation by resetting the active and update flags.
5460Sstevel@tonic-gate 	 */
5470Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
5489800SZdenek.Kotala@Sun.COM 	ses_lock_held = B_TRUE;
5494072Skrishna 	REINIT_OPBUF(&session_p->digest);
5500Sstevel@tonic-gate 	session_p->digest.flags = 0;
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	/*
5530Sstevel@tonic-gate 	 * Decrement the session reference count.
5540Sstevel@tonic-gate 	 * We hold the session lock, and REFRELE()
5550Sstevel@tonic-gate 	 * will release the session lock for us.
5560Sstevel@tonic-gate 	 */
5570Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
5580Sstevel@tonic-gate 	return (rv);
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate CK_RV
C_DigestFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pDigest,CK_ULONG_PTR pulDigestLen)5630Sstevel@tonic-gate C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest,
5640Sstevel@tonic-gate     CK_ULONG_PTR pulDigestLen)
5650Sstevel@tonic-gate {
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	CK_RV rv;
5680Sstevel@tonic-gate 	kernel_session_t *session_p;
5699800SZdenek.Kotala@Sun.COM 	boolean_t ses_lock_held = B_FALSE;
5700Sstevel@tonic-gate 	crypto_digest_final_t digest_final;
5710Sstevel@tonic-gate 	int r;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	if (!kernel_initialized)
5740Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	/*
5770Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
5780Sstevel@tonic-gate 	 * reference count.
5790Sstevel@tonic-gate 	 */
5800Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
5810Sstevel@tonic-gate 	if (rv != CKR_OK)
5820Sstevel@tonic-gate 		return (rv);
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	if (pulDigestLen == NULL) {
5850Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
5860Sstevel@tonic-gate 		goto clean_exit;
5870Sstevel@tonic-gate 	}
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	/* Acquire the session lock */
5900Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
5919800SZdenek.Kotala@Sun.COM 	ses_lock_held = B_TRUE;
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	/*
5940Sstevel@tonic-gate 	 * Application must call C_DigestInit before calling
5950Sstevel@tonic-gate 	 * C_DigestFinal.
5960Sstevel@tonic-gate 	 */
5970Sstevel@tonic-gate 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
5980Sstevel@tonic-gate 		/*
5990Sstevel@tonic-gate 		 * Decrement the session reference count.
6000Sstevel@tonic-gate 		 * We hold the session lock, and REFRELE()
6010Sstevel@tonic-gate 		 * will release the session lock for us.
6020Sstevel@tonic-gate 		 */
6030Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
6040Sstevel@tonic-gate 		return (CKR_OPERATION_NOT_INITIALIZED);
6050Sstevel@tonic-gate 	}
6060Sstevel@tonic-gate 
6074072Skrishna 	/* The order of checks is important here */
6084072Skrishna 	if (session_p->digest.flags & CRYPTO_EMULATE_USING_SW) {
6094072Skrishna 		if (session_p->digest.flags & CRYPTO_EMULATE_UPDATE_DONE) {
6104072Skrishna 			(void) pthread_mutex_unlock(&session_p->session_mutex);
6119800SZdenek.Kotala@Sun.COM 			ses_lock_held = B_FALSE;
6124072Skrishna 			rv = do_soft_digest(get_spp(&session_p->digest),
6134072Skrishna 			    NULL, NULL, NULL, pDigest, pulDigestLen, OP_FINAL);
6144072Skrishna 		} else {
6154072Skrishna 			/*
6164072Skrishna 			 * We end up here if an earlier C_DigestFinal() call
6174072Skrishna 			 * took the C_Digest() path and it had returned
6184072Skrishna 			 * CKR_BUFFER_TOO_SMALL.
6194072Skrishna 			 */
6204072Skrishna 			digest_buf_t *bufp = session_p->digest.context;
6214072Skrishna 			(void) pthread_mutex_unlock(&session_p->session_mutex);
6229800SZdenek.Kotala@Sun.COM 			ses_lock_held = B_FALSE;
6234072Skrishna 			if (bufp == NULL || bufp->buf == NULL) {
6244072Skrishna 				rv = CKR_ARGUMENTS_BAD;
6254072Skrishna 				goto clean_exit;
6264072Skrishna 			}
6274072Skrishna 			rv = do_soft_digest(get_spp(&session_p->digest),
6284072Skrishna 			    NULL, bufp->buf, bufp->indata_len,
6294072Skrishna 			    pDigest, pulDigestLen, OP_SINGLE);
6304072Skrishna 		}
6314072Skrishna 		goto done;
6324072Skrishna 	} else if (session_p->digest.flags & CRYPTO_EMULATE) {
6334072Skrishna 		digest_buf_t *bufp = session_p->digest.context;
6344072Skrishna 
6354072Skrishna 		/*
6364072Skrishna 		 * We are emulating a single-part operation now.
6374072Skrishna 		 * So, clear the flag.
6384072Skrishna 		 */
6394072Skrishna 		session_p->digest.flags &= ~CRYPTO_OPERATION_UPDATE;
6404072Skrishna 		if (bufp == NULL || bufp->buf == NULL) {
6414072Skrishna 			rv = CKR_ARGUMENTS_BAD;
6424072Skrishna 			goto clean_exit;
6434072Skrishna 		}
6444072Skrishna 		REFRELE(session_p, ses_lock_held);
6454072Skrishna 		rv = C_Digest(hSession, bufp->buf, bufp->indata_len,
6464072Skrishna 		    pDigest, pulDigestLen);
6474072Skrishna 		return (rv);
6484072Skrishna 	}
6494072Skrishna 
6500Sstevel@tonic-gate 	digest_final.df_session = session_p->k_session;
6510Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
6529800SZdenek.Kotala@Sun.COM 	ses_lock_held = B_FALSE;
6530Sstevel@tonic-gate 	digest_final.df_digestlen = *pulDigestLen;
6540Sstevel@tonic-gate 	digest_final.df_digestbuf = (char *)pDigest;
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_FINAL, &digest_final)) < 0) {
6570Sstevel@tonic-gate 		if (errno != EINTR)
6580Sstevel@tonic-gate 			break;
6590Sstevel@tonic-gate 	}
6600Sstevel@tonic-gate 	if (r < 0) {
6610Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
6620Sstevel@tonic-gate 	} else {
6630Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(digest_final.df_return_value);
6640Sstevel@tonic-gate 	}
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL))
6670Sstevel@tonic-gate 		*pulDigestLen = digest_final.df_digestlen;
6680Sstevel@tonic-gate 
6694072Skrishna done:
6700Sstevel@tonic-gate 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
6710Sstevel@tonic-gate 	    (rv == CKR_OK && pDigest == NULL)) {
6720Sstevel@tonic-gate 		/*
6730Sstevel@tonic-gate 		 * We will not terminate the active digest operation flag,
6740Sstevel@tonic-gate 		 * when the application-supplied buffer is too small, or
6750Sstevel@tonic-gate 		 * the application asks for the length of buffer to hold
6760Sstevel@tonic-gate 		 * the message digest.
6770Sstevel@tonic-gate 		 *
6780Sstevel@tonic-gate 		 * Decrement the session reference count.
6790Sstevel@tonic-gate 		 * We do not hold the session lock.
6800Sstevel@tonic-gate 		 */
6810Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
6820Sstevel@tonic-gate 		return (rv);
6830Sstevel@tonic-gate 	}
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate clean_exit:
6860Sstevel@tonic-gate 	/* Terminates the active digest operation */
6870Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
6889800SZdenek.Kotala@Sun.COM 	ses_lock_held = B_TRUE;
6894072Skrishna 	REINIT_OPBUF(&session_p->digest);
6900Sstevel@tonic-gate 	session_p->digest.flags = 0;
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	/*
6930Sstevel@tonic-gate 	 * Decrement the session reference count.
6940Sstevel@tonic-gate 	 * We hold the session lock, and REFRELE()
6950Sstevel@tonic-gate 	 * will release the session lock for us.
6960Sstevel@tonic-gate 	 */
6970Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	return (rv);
7000Sstevel@tonic-gate }
701