xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelEmulate.c (revision 03100a6332bd4edc7a53091fcf7c9a7131bcdaa7)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <errno.h>
30 #include <stdio.h>
31 #include <strings.h>
32 #include <sys/crypto/ioctl.h>
33 #include <security/cryptoki.h>
34 #include "kernelGlobal.h"
35 #include "kernelSession.h"
36 #include "kernelEmulate.h"
37 
38 /*
39  * Helper routine to know if this is a HMAC. We can't just check
40  * the CKF_SIGN mech flag as it is set for non-HMAC mechs too.
41  */
42 boolean_t
43 is_hmac(CK_MECHANISM_TYPE mechanism)
44 {
45 	switch (mechanism) {
46 	case CKM_SSL3_MD5_MAC:
47 	case CKM_SSL3_SHA1_MAC:
48 	case CKM_MD5_HMAC_GENERAL:
49 	case CKM_MD5_HMAC:
50 	case CKM_SHA_1_HMAC_GENERAL:
51 	case CKM_SHA_1_HMAC:
52 	case CKM_SHA256_HMAC_GENERAL:
53 	case CKM_SHA256_HMAC:
54 	case CKM_SHA384_HMAC_GENERAL:
55 	case CKM_SHA384_HMAC:
56 	case CKM_SHA512_HMAC_GENERAL:
57 	case CKM_SHA512_HMAC:
58 		return (B_TRUE);
59 
60 	default:
61 		return (B_FALSE);
62 	}
63 }
64 
65 /*
66  * Setup the support necessary to do this operation in a
67  * single part. We allocate a buffer to accumulate the
68  * input data from later calls. We also get ready for
69  * the case where we have to do it in software by initializing
70  * a standby context. The opflag tells if this is a digest, sign or verify.
71  */
72 CK_RV
73 emulate_init(kernel_session_t *session_p, CK_MECHANISM_PTR pMechanism,
74     crypto_key_t *keyp, int opflag)
75 {
76 	CK_RV rv;
77 	digest_buf_t *bufp;
78 	crypto_active_op_t *opp;
79 
80 	opp = (opflag & OP_DIGEST) ? &(session_p->digest) : \
81 	    ((opflag & OP_SIGN) ? &(session_p->sign) : &(session_p->verify));
82 
83 	bufp = opp->context;
84 	if (bufp == NULL) {
85 		bufp = calloc(1, sizeof (digest_buf_t));
86 		if (bufp == NULL) {
87 			return (CKR_HOST_MEMORY);
88 		}
89 
90 		bufp->buf = malloc(EDIGEST_LENGTH);
91 		if (bufp->buf == NULL) {
92 			free(bufp);
93 			return (CKR_HOST_MEMORY);
94 		}
95 		bufp->buf_len = EDIGEST_LENGTH;
96 		bufp->indata_len = 0;
97 		opp->context = bufp;
98 	} else
99 		bufp->indata_len = 0;
100 
101 	opflag |= OP_INIT;
102 	if (opflag & OP_DIGEST) {
103 		rv = do_soft_digest(get_spp(opp), pMechanism, NULL, 0,
104 		    NULL, NULL, opflag);
105 	} else {
106 		rv = do_soft_hmac_init(get_spp(opp), pMechanism, keyp->ck_data,
107 		    keyp->ck_length >> 3, opflag);
108 	}
109 
110 	return (rv);
111 }
112 
113 #define	DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag)		\
114 	if ((opflag) & OP_DIGEST) {				\
115 		rv = do_soft_digest(get_spp(opp), NULL, pPart,	\
116 		    ulPartLen, NULL, NULL, opflag);		\
117 	} else {						\
118 		rv = do_soft_hmac_update(get_spp(opp), pPart,	\
119 		    ulPartLen, opflag);				\
120 	}
121 
122 /*
123  * Accumulate the input data in the buffer, allocating a bigger
124  * buffer if needed. If we reach the maximum input data size
125  * that can be accumulated, start using the software from then on.
126  * The opflag tells if this is a digest, sign or verify.
127  */
128 CK_RV
129 emulate_update(kernel_session_t *session_p, CK_BYTE_PTR pPart,
130     CK_ULONG ulPartLen, int opflag)
131 {
132 	CK_RV rv;
133 	digest_buf_t *bufp;
134 	boolean_t use_soft = B_FALSE;
135 	crypto_active_op_t *opp;
136 
137 	opp = (opflag & OP_DIGEST) ? &(session_p->digest) : \
138 	    ((opflag & OP_SIGN) ? &(session_p->sign) : &(session_p->verify));
139 
140 	if (!SLOT_HAS_LIMITED_HASH(session_p))
141 		return (CKR_ARGUMENTS_BAD);
142 
143 	if (opp->flags & CRYPTO_EMULATE_USING_SW) {
144 		opflag |= OP_UPDATE;
145 		DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag);
146 		opp->flags |= CRYPTO_EMULATE_UPDATE_DONE;
147 		return (rv);
148 	}
149 
150 	bufp = opp->context;
151 	if (bufp == NULL) {
152 		return (CKR_FUNCTION_FAILED);
153 	}
154 
155 	/* Did we exceed the maximum allowed? */
156 	if (bufp->indata_len + ulPartLen > SLOT_MAX_INDATA_LEN(session_p)) {
157 		use_soft = B_TRUE;
158 	} else if (ulPartLen > (bufp->buf_len - bufp->indata_len))  {
159 		int siz = ulPartLen < bufp->buf_len ?
160 		    bufp->buf_len * 2 : bufp->buf_len + ulPartLen;
161 		uint8_t *old = bufp->buf;
162 
163 		bufp->buf = realloc(bufp->buf, siz);
164 		if (bufp->buf == NULL) {
165 			/* Try harder rather than failing */
166 			bufp->buf =  old;
167 			use_soft = B_TRUE;
168 		} else
169 			bufp->buf_len = siz;
170 	}
171 
172 	if (use_soft) {
173 		opp->flags |= CRYPTO_EMULATE_USING_SW;
174 
175 		opflag |= OP_UPDATE;
176 		DO_SOFT_UPDATE(opp, bufp->buf, bufp->indata_len, opflag);
177 		opp->flags |= CRYPTO_EMULATE_UPDATE_DONE;
178 		if (rv == CKR_OK) {
179 			DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag);
180 		}
181 
182 		return (rv);
183 	}
184 
185 	/* accumulate the update data */
186 	bcopy(pPart, bufp->buf + bufp->indata_len, ulPartLen);
187 	bufp->indata_len += ulPartLen;
188 
189 	return (CKR_OK);
190 }
191