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