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