xref: /onnv-gate/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelEmulate.c (revision 11304:3092d1e303d6)
14072Skrishna /*
24072Skrishna  * CDDL HEADER START
34072Skrishna  *
44072Skrishna  * 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.
74072Skrishna  *
84072Skrishna  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94072Skrishna  * or http://www.opensolaris.org/os/licensing.
104072Skrishna  * See the License for the specific language governing permissions
114072Skrishna  * and limitations under the License.
124072Skrishna  *
134072Skrishna  * When distributing Covered Code, include this CDDL HEADER in each
144072Skrishna  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154072Skrishna  * If applicable, add the following below this CDDL HEADER, with the
164072Skrishna  * fields enclosed by brackets "[]" replaced with your own identifying
174072Skrishna  * information: Portions Copyright [yyyy] [name of copyright owner]
184072Skrishna  *
194072Skrishna  * CDDL HEADER END
204072Skrishna  */
214072Skrishna 
224072Skrishna /*
23*11304SJanie.Lu@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
244072Skrishna  * Use is subject to license terms.
254072Skrishna  */
264072Skrishna 
274072Skrishna #include <errno.h>
284072Skrishna #include <stdio.h>
294072Skrishna #include <strings.h>
304072Skrishna #include <sys/crypto/ioctl.h>
314072Skrishna #include <security/cryptoki.h>
324072Skrishna #include "kernelGlobal.h"
334072Skrishna #include "kernelSession.h"
344072Skrishna #include "kernelEmulate.h"
354072Skrishna 
364072Skrishna /*
374072Skrishna  * Helper routine to know if this is a HMAC. We can't just check
384072Skrishna  * the CKF_SIGN mech flag as it is set for non-HMAC mechs too.
394072Skrishna  */
404072Skrishna boolean_t
is_hmac(CK_MECHANISM_TYPE mechanism)414072Skrishna is_hmac(CK_MECHANISM_TYPE mechanism)
424072Skrishna {
434072Skrishna 	switch (mechanism) {
444072Skrishna 	case CKM_SSL3_MD5_MAC:
454072Skrishna 	case CKM_SSL3_SHA1_MAC:
464072Skrishna 	case CKM_MD5_HMAC_GENERAL:
474072Skrishna 	case CKM_MD5_HMAC:
484072Skrishna 	case CKM_SHA_1_HMAC_GENERAL:
494072Skrishna 	case CKM_SHA_1_HMAC:
504072Skrishna 	case CKM_SHA256_HMAC_GENERAL:
514072Skrishna 	case CKM_SHA256_HMAC:
524072Skrishna 	case CKM_SHA384_HMAC_GENERAL:
534072Skrishna 	case CKM_SHA384_HMAC:
544072Skrishna 	case CKM_SHA512_HMAC_GENERAL:
554072Skrishna 	case CKM_SHA512_HMAC:
564072Skrishna 		return (B_TRUE);
574072Skrishna 
584072Skrishna 	default:
594072Skrishna 		return (B_FALSE);
604072Skrishna 	}
614072Skrishna }
624072Skrishna 
634072Skrishna /*
645616Skrishna  * Helper routine to allocate an emulation structure for the session.
655616Skrishna  * buflen indicates the size of the scratch buffer to be allocated.
664072Skrishna  */
674072Skrishna CK_RV
emulate_buf_init(kernel_session_t * session_p,int buflen,int opflag)685616Skrishna emulate_buf_init(kernel_session_t *session_p, int buflen, int opflag)
694072Skrishna {
704072Skrishna 	digest_buf_t *bufp;
714072Skrishna 	crypto_active_op_t *opp;
724072Skrishna 
734072Skrishna 	opp = (opflag & OP_DIGEST) ? &(session_p->digest) : \
744072Skrishna 	    ((opflag & OP_SIGN) ? &(session_p->sign) : &(session_p->verify));
754072Skrishna 
764072Skrishna 	bufp = opp->context;
775616Skrishna 
785616Skrishna 	if (bufp != NULL) {
795616Skrishna 		bufp->indata_len = 0;
807452SBhargava.Yenduri@Sun.COM 		/*
817452SBhargava.Yenduri@Sun.COM 		 * We can reuse the context structure, digest_buf_t.
827452SBhargava.Yenduri@Sun.COM 		 * See if we can reuse the scratch buffer in the context too.
837452SBhargava.Yenduri@Sun.COM 		 */
845616Skrishna 		if (buflen > bufp->buf_len) {
857452SBhargava.Yenduri@Sun.COM 			free(bufp->buf);
867452SBhargava.Yenduri@Sun.COM 			bufp->buf = NULL;
877452SBhargava.Yenduri@Sun.COM 		}
887452SBhargava.Yenduri@Sun.COM 	} else {
897452SBhargava.Yenduri@Sun.COM 		bufp = opp->context = calloc(1, sizeof (digest_buf_t));
907452SBhargava.Yenduri@Sun.COM 		if (bufp == NULL) {
917452SBhargava.Yenduri@Sun.COM 			return (CKR_HOST_MEMORY);
925616Skrishna 		}
935616Skrishna 	}
945616Skrishna 
957452SBhargava.Yenduri@Sun.COM 	if (bufp->buf == NULL) {
965616Skrishna 		bufp->buf = malloc(buflen);
974072Skrishna 		if (bufp->buf == NULL) {
984072Skrishna 			free(bufp);
997452SBhargava.Yenduri@Sun.COM 			opp->context = NULL;
1004072Skrishna 			return (CKR_HOST_MEMORY);
1014072Skrishna 		}
1025616Skrishna 		bufp->buf_len = buflen;
1035616Skrishna 	}
1045616Skrishna 
1055616Skrishna 	return (CKR_OK);
1065616Skrishna }
1075616Skrishna 
1085616Skrishna /*
1095616Skrishna  * Setup the support necessary to do this operation in a
1105616Skrishna  * single part. We allocate a buffer to accumulate the
1115616Skrishna  * input data from later calls. We also get ready for
1125616Skrishna  * the case where we have to do it in software by initializing
1135616Skrishna  * a standby context. The opflag tells if this is a sign or verify.
1145616Skrishna  */
1155616Skrishna CK_RV
emulate_init(kernel_session_t * session_p,CK_MECHANISM_PTR pMechanism,crypto_key_t * keyp,int opflag)1165616Skrishna emulate_init(kernel_session_t *session_p, CK_MECHANISM_PTR pMechanism,
1175616Skrishna     crypto_key_t *keyp, int opflag)
1185616Skrishna {
1195616Skrishna 	CK_RV rv;
1205616Skrishna 	crypto_active_op_t *opp;
1215616Skrishna 
1225616Skrishna 	if ((rv = emulate_buf_init(session_p, EDIGEST_LENGTH, opflag)) !=
1235616Skrishna 	    CKR_OK)
1245616Skrishna 		return (rv);
1255616Skrishna 
1265616Skrishna 	opp = (opflag & OP_SIGN) ? &(session_p->sign) : &(session_p->verify);
1274072Skrishna 
1284072Skrishna 	opflag |= OP_INIT;
1295616Skrishna 	rv = do_soft_hmac_init(get_spp(opp), pMechanism, keyp->ck_data,
1305616Skrishna 	    keyp->ck_length >> 3, opflag);
1314072Skrishna 
1324072Skrishna 	return (rv);
1334072Skrishna }
1344072Skrishna 
1354072Skrishna #define	DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag)		\
1364072Skrishna 	if ((opflag) & OP_DIGEST) {				\
1374072Skrishna 		rv = do_soft_digest(get_spp(opp), NULL, pPart,	\
1384072Skrishna 		    ulPartLen, NULL, NULL, opflag);		\
1394072Skrishna 	} else {						\
1404072Skrishna 		rv = do_soft_hmac_update(get_spp(opp), pPart,	\
1414072Skrishna 		    ulPartLen, opflag);				\
1424072Skrishna 	}
1434072Skrishna 
1444072Skrishna /*
1454072Skrishna  * Accumulate the input data in the buffer, allocating a bigger
1464072Skrishna  * buffer if needed. If we reach the maximum input data size
1474072Skrishna  * that can be accumulated, start using the software from then on.
1484072Skrishna  * The opflag tells if this is a digest, sign or verify.
1494072Skrishna  */
1504072Skrishna CK_RV
emulate_update(kernel_session_t * session_p,CK_BYTE_PTR pPart,CK_ULONG ulPartLen,int opflag)1514072Skrishna emulate_update(kernel_session_t *session_p, CK_BYTE_PTR pPart,
1524072Skrishna     CK_ULONG ulPartLen, int opflag)
1534072Skrishna {
1544072Skrishna 	CK_RV rv;
155*11304SJanie.Lu@Sun.COM 	int maxlen;
1564072Skrishna 	digest_buf_t *bufp;
1574072Skrishna 	boolean_t use_soft = B_FALSE;
1584072Skrishna 	crypto_active_op_t *opp;
1594072Skrishna 
160*11304SJanie.Lu@Sun.COM 	if (opflag & OP_DIGEST) {
161*11304SJanie.Lu@Sun.COM 		opp = &(session_p->digest);
162*11304SJanie.Lu@Sun.COM 		if (!SLOT_HAS_LIMITED_HASH(session_p))
163*11304SJanie.Lu@Sun.COM 			return (CKR_ARGUMENTS_BAD);
164*11304SJanie.Lu@Sun.COM 		maxlen =  SLOT_HASH_MAX_INDATA_LEN(session_p);
165*11304SJanie.Lu@Sun.COM 	} else if (opflag & (OP_SIGN | OP_VERIFY)) {
166*11304SJanie.Lu@Sun.COM 		opp = (opflag & OP_SIGN) ?
167*11304SJanie.Lu@Sun.COM 		    &(session_p->sign) : &(session_p->verify);
168*11304SJanie.Lu@Sun.COM 		if (!SLOT_HAS_LIMITED_HMAC(session_p))
169*11304SJanie.Lu@Sun.COM 			return (CKR_ARGUMENTS_BAD);
170*11304SJanie.Lu@Sun.COM 		maxlen =  SLOT_HMAC_MAX_INDATA_LEN(session_p);
171*11304SJanie.Lu@Sun.COM 	} else
1724072Skrishna 		return (CKR_ARGUMENTS_BAD);
1734072Skrishna 
1744072Skrishna 	if (opp->flags & CRYPTO_EMULATE_USING_SW) {
1754072Skrishna 		opflag |= OP_UPDATE;
1764072Skrishna 		DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag);
1774072Skrishna 		opp->flags |= CRYPTO_EMULATE_UPDATE_DONE;
1784072Skrishna 		return (rv);
1794072Skrishna 	}
1804072Skrishna 
1814072Skrishna 	bufp = opp->context;
1824072Skrishna 	if (bufp == NULL) {
1834072Skrishna 		return (CKR_FUNCTION_FAILED);
1844072Skrishna 	}
1854072Skrishna 
1864072Skrishna 	/* Did we exceed the maximum allowed? */
187*11304SJanie.Lu@Sun.COM 	if (bufp->indata_len + ulPartLen > maxlen) {
1884072Skrishna 		use_soft = B_TRUE;
1894072Skrishna 	} else if (ulPartLen > (bufp->buf_len - bufp->indata_len))  {
1904072Skrishna 		int siz = ulPartLen < bufp->buf_len ?
1914072Skrishna 		    bufp->buf_len * 2 : bufp->buf_len + ulPartLen;
1924072Skrishna 		uint8_t *old = bufp->buf;
1934072Skrishna 
1944072Skrishna 		bufp->buf = realloc(bufp->buf, siz);
1954072Skrishna 		if (bufp->buf == NULL) {
1964072Skrishna 			/* Try harder rather than failing */
1974072Skrishna 			bufp->buf =  old;
1984072Skrishna 			use_soft = B_TRUE;
1994072Skrishna 		} else
2004072Skrishna 			bufp->buf_len = siz;
2014072Skrishna 	}
2024072Skrishna 
2034072Skrishna 	if (use_soft) {
2044072Skrishna 		opp->flags |= CRYPTO_EMULATE_USING_SW;
2054072Skrishna 
2065616Skrishna 		if (opflag & OP_DIGEST) {
2075616Skrishna 			CK_MECHANISM_PTR pMechanism;
2085616Skrishna 
2095616Skrishna 			pMechanism = &(opp->mech);
2105616Skrishna 			rv = do_soft_digest(get_spp(opp), pMechanism, NULL, 0,
2115616Skrishna 			    NULL, NULL, OP_INIT);
2125616Skrishna 			if (rv != CKR_OK)
2135616Skrishna 				return (rv);
2145616Skrishna 		}
2155616Skrishna 
2164072Skrishna 		opflag |= OP_UPDATE;
2174072Skrishna 		DO_SOFT_UPDATE(opp, bufp->buf, bufp->indata_len, opflag);
2184072Skrishna 		opp->flags |= CRYPTO_EMULATE_UPDATE_DONE;
2194072Skrishna 		if (rv == CKR_OK) {
2204072Skrishna 			DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag);
2214072Skrishna 		}
2224072Skrishna 
2234072Skrishna 		return (rv);
2244072Skrishna 	}
2254072Skrishna 
2264072Skrishna 	/* accumulate the update data */
2274072Skrishna 	bcopy(pPart, bufp->buf + bufp->indata_len, ulPartLen);
2284072Skrishna 	bufp->indata_len += ulPartLen;
2294072Skrishna 
2304072Skrishna 	return (CKR_OK);
2314072Skrishna }
232