1ba5f469cSkrishna /*
2ba5f469cSkrishna  * CDDL HEADER START
3ba5f469cSkrishna  *
4ba5f469cSkrishna  * 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.
7ba5f469cSkrishna  *
8ba5f469cSkrishna  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9ba5f469cSkrishna  * or http://www.opensolaris.org/os/licensing.
10ba5f469cSkrishna  * See the License for the specific language governing permissions
11ba5f469cSkrishna  * and limitations under the License.
12ba5f469cSkrishna  *
13ba5f469cSkrishna  * When distributing Covered Code, include this CDDL HEADER in each
14ba5f469cSkrishna  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15ba5f469cSkrishna  * If applicable, add the following below this CDDL HEADER, with the
16ba5f469cSkrishna  * fields enclosed by brackets "[]" replaced with your own identifying
17ba5f469cSkrishna  * information: Portions Copyright [yyyy] [name of copyright owner]
18ba5f469cSkrishna  *
19ba5f469cSkrishna  * CDDL HEADER END
20ba5f469cSkrishna  */
21ba5f469cSkrishna 
22ba5f469cSkrishna /*
23*4df55fdeSJanie Lu  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24ba5f469cSkrishna  * Use is subject to license terms.
25ba5f469cSkrishna  */
26ba5f469cSkrishna 
27ba5f469cSkrishna #include <errno.h>
28ba5f469cSkrishna #include <stdio.h>
29ba5f469cSkrishna #include <strings.h>
30ba5f469cSkrishna #include <sys/crypto/ioctl.h>
31ba5f469cSkrishna #include <security/cryptoki.h>
32ba5f469cSkrishna #include "kernelGlobal.h"
33ba5f469cSkrishna #include "kernelSession.h"
34ba5f469cSkrishna #include "kernelEmulate.h"
35ba5f469cSkrishna 
36ba5f469cSkrishna /*
37ba5f469cSkrishna  * Helper routine to know if this is a HMAC. We can't just check
38ba5f469cSkrishna  * the CKF_SIGN mech flag as it is set for non-HMAC mechs too.
39ba5f469cSkrishna  */
40ba5f469cSkrishna boolean_t
is_hmac(CK_MECHANISM_TYPE mechanism)41ba5f469cSkrishna is_hmac(CK_MECHANISM_TYPE mechanism)
42ba5f469cSkrishna {
43ba5f469cSkrishna 	switch (mechanism) {
44ba5f469cSkrishna 	case CKM_SSL3_MD5_MAC:
45ba5f469cSkrishna 	case CKM_SSL3_SHA1_MAC:
46ba5f469cSkrishna 	case CKM_MD5_HMAC_GENERAL:
47ba5f469cSkrishna 	case CKM_MD5_HMAC:
48ba5f469cSkrishna 	case CKM_SHA_1_HMAC_GENERAL:
49ba5f469cSkrishna 	case CKM_SHA_1_HMAC:
50ba5f469cSkrishna 	case CKM_SHA256_HMAC_GENERAL:
51ba5f469cSkrishna 	case CKM_SHA256_HMAC:
52ba5f469cSkrishna 	case CKM_SHA384_HMAC_GENERAL:
53ba5f469cSkrishna 	case CKM_SHA384_HMAC:
54ba5f469cSkrishna 	case CKM_SHA512_HMAC_GENERAL:
55ba5f469cSkrishna 	case CKM_SHA512_HMAC:
56ba5f469cSkrishna 		return (B_TRUE);
57ba5f469cSkrishna 
58ba5f469cSkrishna 	default:
59ba5f469cSkrishna 		return (B_FALSE);
60ba5f469cSkrishna 	}
61ba5f469cSkrishna }
62ba5f469cSkrishna 
63ba5f469cSkrishna /*
64b2a96221Skrishna  * Helper routine to allocate an emulation structure for the session.
65b2a96221Skrishna  * buflen indicates the size of the scratch buffer to be allocated.
66ba5f469cSkrishna  */
67ba5f469cSkrishna CK_RV
emulate_buf_init(kernel_session_t * session_p,int buflen,int opflag)68b2a96221Skrishna emulate_buf_init(kernel_session_t *session_p, int buflen, int opflag)
69ba5f469cSkrishna {
70ba5f469cSkrishna 	digest_buf_t *bufp;
71ba5f469cSkrishna 	crypto_active_op_t *opp;
72ba5f469cSkrishna 
73ba5f469cSkrishna 	opp = (opflag & OP_DIGEST) ? &(session_p->digest) : \
74ba5f469cSkrishna 	    ((opflag & OP_SIGN) ? &(session_p->sign) : &(session_p->verify));
75ba5f469cSkrishna 
76ba5f469cSkrishna 	bufp = opp->context;
77b2a96221Skrishna 
78b2a96221Skrishna 	if (bufp != NULL) {
79b2a96221Skrishna 		bufp->indata_len = 0;
800d94eea1SKrishna Yenduri 		/*
810d94eea1SKrishna Yenduri 		 * We can reuse the context structure, digest_buf_t.
820d94eea1SKrishna Yenduri 		 * See if we can reuse the scratch buffer in the context too.
830d94eea1SKrishna Yenduri 		 */
84b2a96221Skrishna 		if (buflen > bufp->buf_len) {
850d94eea1SKrishna Yenduri 			free(bufp->buf);
860d94eea1SKrishna Yenduri 			bufp->buf = NULL;
87b2a96221Skrishna 		}
880d94eea1SKrishna Yenduri 	} else {
890d94eea1SKrishna Yenduri 		bufp = opp->context = calloc(1, sizeof (digest_buf_t));
90ba5f469cSkrishna 		if (bufp == NULL) {
91ba5f469cSkrishna 			return (CKR_HOST_MEMORY);
92ba5f469cSkrishna 		}
930d94eea1SKrishna Yenduri 	}
94ba5f469cSkrishna 
950d94eea1SKrishna Yenduri 	if (bufp->buf == NULL) {
96b2a96221Skrishna 		bufp->buf = malloc(buflen);
97ba5f469cSkrishna 		if (bufp->buf == NULL) {
98ba5f469cSkrishna 			free(bufp);
990d94eea1SKrishna Yenduri 			opp->context = NULL;
100ba5f469cSkrishna 			return (CKR_HOST_MEMORY);
101ba5f469cSkrishna 		}
102b2a96221Skrishna 		bufp->buf_len = buflen;
103b2a96221Skrishna 	}
104b2a96221Skrishna 
105b2a96221Skrishna 	return (CKR_OK);
106b2a96221Skrishna }
107b2a96221Skrishna 
108b2a96221Skrishna /*
109b2a96221Skrishna  * Setup the support necessary to do this operation in a
110b2a96221Skrishna  * single part. We allocate a buffer to accumulate the
111b2a96221Skrishna  * input data from later calls. We also get ready for
112b2a96221Skrishna  * the case where we have to do it in software by initializing
113b2a96221Skrishna  * a standby context. The opflag tells if this is a sign or verify.
114b2a96221Skrishna  */
115b2a96221Skrishna CK_RV
emulate_init(kernel_session_t * session_p,CK_MECHANISM_PTR pMechanism,crypto_key_t * keyp,int opflag)116b2a96221Skrishna emulate_init(kernel_session_t *session_p, CK_MECHANISM_PTR pMechanism,
117b2a96221Skrishna     crypto_key_t *keyp, int opflag)
118b2a96221Skrishna {
119b2a96221Skrishna 	CK_RV rv;
120b2a96221Skrishna 	crypto_active_op_t *opp;
121b2a96221Skrishna 
122b2a96221Skrishna 	if ((rv = emulate_buf_init(session_p, EDIGEST_LENGTH, opflag)) !=
123b2a96221Skrishna 	    CKR_OK)
124b2a96221Skrishna 		return (rv);
125b2a96221Skrishna 
126b2a96221Skrishna 	opp = (opflag & OP_SIGN) ? &(session_p->sign) : &(session_p->verify);
127ba5f469cSkrishna 
128ba5f469cSkrishna 	opflag |= OP_INIT;
129b2a96221Skrishna 	rv = do_soft_hmac_init(get_spp(opp), pMechanism, keyp->ck_data,
130b2a96221Skrishna 	    keyp->ck_length >> 3, opflag);
131ba5f469cSkrishna 
132ba5f469cSkrishna 	return (rv);
133ba5f469cSkrishna }
134ba5f469cSkrishna 
135ba5f469cSkrishna #define	DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag)		\
136ba5f469cSkrishna 	if ((opflag) & OP_DIGEST) {				\
137ba5f469cSkrishna 		rv = do_soft_digest(get_spp(opp), NULL, pPart,	\
138ba5f469cSkrishna 		    ulPartLen, NULL, NULL, opflag);		\
139ba5f469cSkrishna 	} else {						\
140ba5f469cSkrishna 		rv = do_soft_hmac_update(get_spp(opp), pPart,	\
141ba5f469cSkrishna 		    ulPartLen, opflag);				\
142ba5f469cSkrishna 	}
143ba5f469cSkrishna 
144ba5f469cSkrishna /*
145ba5f469cSkrishna  * Accumulate the input data in the buffer, allocating a bigger
146ba5f469cSkrishna  * buffer if needed. If we reach the maximum input data size
147ba5f469cSkrishna  * that can be accumulated, start using the software from then on.
148ba5f469cSkrishna  * The opflag tells if this is a digest, sign or verify.
149ba5f469cSkrishna  */
150ba5f469cSkrishna CK_RV
emulate_update(kernel_session_t * session_p,CK_BYTE_PTR pPart,CK_ULONG ulPartLen,int opflag)151ba5f469cSkrishna emulate_update(kernel_session_t *session_p, CK_BYTE_PTR pPart,
152ba5f469cSkrishna     CK_ULONG ulPartLen, int opflag)
153ba5f469cSkrishna {
154ba5f469cSkrishna 	CK_RV rv;
155*4df55fdeSJanie Lu 	int maxlen;
156ba5f469cSkrishna 	digest_buf_t *bufp;
157ba5f469cSkrishna 	boolean_t use_soft = B_FALSE;
158ba5f469cSkrishna 	crypto_active_op_t *opp;
159ba5f469cSkrishna 
160*4df55fdeSJanie Lu 	if (opflag & OP_DIGEST) {
161*4df55fdeSJanie Lu 		opp = &(session_p->digest);
162*4df55fdeSJanie Lu 		if (!SLOT_HAS_LIMITED_HASH(session_p))
163*4df55fdeSJanie Lu 			return (CKR_ARGUMENTS_BAD);
164*4df55fdeSJanie Lu 		maxlen =  SLOT_HASH_MAX_INDATA_LEN(session_p);
165*4df55fdeSJanie Lu 	} else if (opflag & (OP_SIGN | OP_VERIFY)) {
166*4df55fdeSJanie Lu 		opp = (opflag & OP_SIGN) ?
167*4df55fdeSJanie Lu 		    &(session_p->sign) : &(session_p->verify);
168*4df55fdeSJanie Lu 		if (!SLOT_HAS_LIMITED_HMAC(session_p))
169*4df55fdeSJanie Lu 			return (CKR_ARGUMENTS_BAD);
170*4df55fdeSJanie Lu 		maxlen =  SLOT_HMAC_MAX_INDATA_LEN(session_p);
171*4df55fdeSJanie Lu 	} else
172ba5f469cSkrishna 		return (CKR_ARGUMENTS_BAD);
173ba5f469cSkrishna 
174ba5f469cSkrishna 	if (opp->flags & CRYPTO_EMULATE_USING_SW) {
175ba5f469cSkrishna 		opflag |= OP_UPDATE;
176ba5f469cSkrishna 		DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag);
177ba5f469cSkrishna 		opp->flags |= CRYPTO_EMULATE_UPDATE_DONE;
178ba5f469cSkrishna 		return (rv);
179ba5f469cSkrishna 	}
180ba5f469cSkrishna 
181ba5f469cSkrishna 	bufp = opp->context;
182ba5f469cSkrishna 	if (bufp == NULL) {
183ba5f469cSkrishna 		return (CKR_FUNCTION_FAILED);
184ba5f469cSkrishna 	}
185ba5f469cSkrishna 
186ba5f469cSkrishna 	/* Did we exceed the maximum allowed? */
187*4df55fdeSJanie Lu 	if (bufp->indata_len + ulPartLen > maxlen) {
188ba5f469cSkrishna 		use_soft = B_TRUE;
189ba5f469cSkrishna 	} else if (ulPartLen > (bufp->buf_len - bufp->indata_len))  {
190ba5f469cSkrishna 		int siz = ulPartLen < bufp->buf_len ?
191ba5f469cSkrishna 		    bufp->buf_len * 2 : bufp->buf_len + ulPartLen;
192ba5f469cSkrishna 		uint8_t *old = bufp->buf;
193ba5f469cSkrishna 
194ba5f469cSkrishna 		bufp->buf = realloc(bufp->buf, siz);
195ba5f469cSkrishna 		if (bufp->buf == NULL) {
196ba5f469cSkrishna 			/* Try harder rather than failing */
197ba5f469cSkrishna 			bufp->buf =  old;
198ba5f469cSkrishna 			use_soft = B_TRUE;
199ba5f469cSkrishna 		} else
200ba5f469cSkrishna 			bufp->buf_len = siz;
201ba5f469cSkrishna 	}
202ba5f469cSkrishna 
203ba5f469cSkrishna 	if (use_soft) {
204ba5f469cSkrishna 		opp->flags |= CRYPTO_EMULATE_USING_SW;
205ba5f469cSkrishna 
206b2a96221Skrishna 		if (opflag & OP_DIGEST) {
207b2a96221Skrishna 			CK_MECHANISM_PTR pMechanism;
208b2a96221Skrishna 
209b2a96221Skrishna 			pMechanism = &(opp->mech);
210b2a96221Skrishna 			rv = do_soft_digest(get_spp(opp), pMechanism, NULL, 0,
211b2a96221Skrishna 			    NULL, NULL, OP_INIT);
212b2a96221Skrishna 			if (rv != CKR_OK)
213b2a96221Skrishna 				return (rv);
214b2a96221Skrishna 		}
215b2a96221Skrishna 
216ba5f469cSkrishna 		opflag |= OP_UPDATE;
217ba5f469cSkrishna 		DO_SOFT_UPDATE(opp, bufp->buf, bufp->indata_len, opflag);
218ba5f469cSkrishna 		opp->flags |= CRYPTO_EMULATE_UPDATE_DONE;
219ba5f469cSkrishna 		if (rv == CKR_OK) {
220ba5f469cSkrishna 			DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag);
221ba5f469cSkrishna 		}
222ba5f469cSkrishna 
223ba5f469cSkrishna 		return (rv);
224ba5f469cSkrishna 	}
225ba5f469cSkrishna 
226ba5f469cSkrishna 	/* accumulate the update data */
227ba5f469cSkrishna 	bcopy(pPart, bufp->buf + bufp->indata_len, ulPartLen);
228ba5f469cSkrishna 	bufp->indata_len += ulPartLen;
229ba5f469cSkrishna 
230ba5f469cSkrishna 	return (CKR_OK);
231ba5f469cSkrishna }
232