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 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/strsun.h>
27 #include <sys/systm.h>
28 #include <sys/sysmacros.h>
29 #include <sys/kmem.h>
30 #include <sys/md5.h>
31 #include <sys/sha1.h>
32 #include <sys/sha2.h>
33 #include <modes/modes.h>
34 #include <sys/crypto/common.h>
35 #include <sys/crypto/impl.h>
36
37 /*
38 * Utility routine to get data from a crypto_data structure.
39 *
40 * '*dptr' contains a pointer to a buffer on return. 'buf'
41 * is allocated by the caller and is ignored for CRYPTO_DATA_RAW case.
42 */
43 int
crypto_get_input_data(crypto_data_t * input,uchar_t ** dptr,uchar_t * buf)44 crypto_get_input_data(crypto_data_t *input, uchar_t **dptr, uchar_t *buf)
45 {
46 int rv;
47
48 switch (input->cd_format) {
49 case CRYPTO_DATA_RAW:
50 if (input->cd_raw.iov_len < input->cd_length)
51 return (CRYPTO_ARGUMENTS_BAD);
52 *dptr = (uchar_t *)(input->cd_raw.iov_base +
53 input->cd_offset);
54 break;
55
56 case CRYPTO_DATA_UIO:
57 if ((rv = crypto_uio_data(input, buf, input->cd_length,
58 COPY_FROM_DATA, NULL, NULL)) != CRYPTO_SUCCESS)
59 return (rv);
60 *dptr = buf;
61 break;
62
63 case CRYPTO_DATA_MBLK:
64 if ((rv = crypto_mblk_data(input, buf, input->cd_length,
65 COPY_FROM_DATA, NULL, NULL)) != CRYPTO_SUCCESS)
66 return (rv);
67 *dptr = buf;
68 break;
69
70 default:
71 return (CRYPTO_ARGUMENTS_BAD);
72 }
73
74 return (CRYPTO_SUCCESS);
75 }
76
77 int
crypto_copy_key_to_ctx(crypto_key_t * in_key,crypto_key_t ** out_key,size_t * out_size,int kmflag)78 crypto_copy_key_to_ctx(crypto_key_t *in_key, crypto_key_t **out_key,
79 size_t *out_size, int kmflag)
80 {
81 int i, count;
82 size_t len;
83 caddr_t attr_val;
84 crypto_object_attribute_t *k_attrs = NULL;
85 crypto_key_t *key;
86
87 ASSERT(in_key->ck_format == CRYPTO_KEY_ATTR_LIST);
88
89 count = in_key->ck_count;
90 /* figure out how much memory to allocate for everything */
91 len = sizeof (crypto_key_t) +
92 count * sizeof (crypto_object_attribute_t);
93 for (i = 0; i < count; i++) {
94 len += roundup(in_key->ck_attrs[i].oa_value_len,
95 sizeof (caddr_t));
96 }
97
98 /* one big allocation for everything */
99 key = kmem_alloc(len, kmflag);
100 if (key == NULL)
101 return (CRYPTO_HOST_MEMORY);
102 k_attrs = (crypto_object_attribute_t *)(void *)((caddr_t)key +
103 sizeof (crypto_key_t));
104
105 attr_val = (caddr_t)k_attrs +
106 count * sizeof (crypto_object_attribute_t);
107 for (i = 0; i < count; i++) {
108 k_attrs[i].oa_type = in_key->ck_attrs[i].oa_type;
109 bcopy(in_key->ck_attrs[i].oa_value, attr_val,
110 in_key->ck_attrs[i].oa_value_len);
111 k_attrs[i].oa_value = attr_val;
112 k_attrs[i].oa_value_len = in_key->ck_attrs[i].oa_value_len;
113 attr_val += roundup(k_attrs[i].oa_value_len, sizeof (caddr_t));
114 }
115
116 key->ck_format = CRYPTO_KEY_ATTR_LIST;
117 key->ck_count = count;
118 key->ck_attrs = k_attrs;
119 *out_key = key;
120 *out_size = len; /* save the size to be freed */
121
122 return (CRYPTO_SUCCESS);
123 }
124
125 int
crypto_digest_data(crypto_data_t * data,void * dctx,uchar_t * digest,void (* update)(),void (* final)(),uchar_t flag)126 crypto_digest_data(crypto_data_t *data, void *dctx, uchar_t *digest,
127 void (*update)(), void (*final)(), uchar_t flag)
128 {
129 int rv, dlen;
130 uchar_t *dptr;
131
132 ASSERT(flag & CRYPTO_DO_MD5 || flag & CRYPTO_DO_SHA1 ||
133 flag & CRYPTO_DO_SHA2);
134 if (data == NULL) {
135 ASSERT((flag & CRYPTO_DO_UPDATE) == 0);
136 goto dofinal;
137 }
138
139 dlen = data->cd_length;
140
141 if (flag & CRYPTO_DO_UPDATE) {
142
143 switch (data->cd_format) {
144 case CRYPTO_DATA_RAW:
145 dptr = (uchar_t *)(data->cd_raw.iov_base +
146 data->cd_offset);
147
148 update(dctx, dptr, dlen);
149
150 break;
151
152 case CRYPTO_DATA_UIO:
153 if (flag & CRYPTO_DO_MD5)
154 rv = crypto_uio_data(data, NULL, dlen,
155 MD5_DIGEST_DATA, dctx, update);
156
157 else if (flag & CRYPTO_DO_SHA1)
158 rv = crypto_uio_data(data, NULL, dlen,
159 SHA1_DIGEST_DATA, dctx, update);
160
161 else
162 rv = crypto_uio_data(data, NULL, dlen,
163 SHA2_DIGEST_DATA, dctx, update);
164
165 if (rv != CRYPTO_SUCCESS)
166 return (rv);
167
168 break;
169
170 case CRYPTO_DATA_MBLK:
171 if (flag & CRYPTO_DO_MD5)
172 rv = crypto_mblk_data(data, NULL, dlen,
173 MD5_DIGEST_DATA, dctx, update);
174
175 else if (flag & CRYPTO_DO_SHA1)
176 rv = crypto_mblk_data(data, NULL, dlen,
177 SHA1_DIGEST_DATA, dctx, update);
178
179 else
180 rv = crypto_mblk_data(data, NULL, dlen,
181 SHA2_DIGEST_DATA, dctx, update);
182
183 if (rv != CRYPTO_SUCCESS)
184 return (rv);
185
186 break;
187 }
188 }
189
190 dofinal:
191 if (flag & CRYPTO_DO_FINAL) {
192 final(digest, dctx);
193 }
194
195 return (CRYPTO_SUCCESS);
196 }
197
198 int
crypto_update_iov(void * ctx,crypto_data_t * input,crypto_data_t * output,int (* cipher)(void *,caddr_t,size_t,crypto_data_t *),void (* copy_block)(uint8_t *,uint64_t *))199 crypto_update_iov(void *ctx, crypto_data_t *input, crypto_data_t *output,
200 int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
201 void (*copy_block)(uint8_t *, uint64_t *))
202 {
203 common_ctx_t *common_ctx = ctx;
204 int rv;
205
206 if (input->cd_miscdata != NULL) {
207 copy_block((uint8_t *)input->cd_miscdata,
208 &common_ctx->cc_iv[0]);
209 }
210
211 if (input->cd_raw.iov_len < input->cd_length)
212 return (CRYPTO_ARGUMENTS_BAD);
213
214 rv = (cipher)(ctx, input->cd_raw.iov_base + input->cd_offset,
215 input->cd_length, (input == output) ? NULL : output);
216
217 return (rv);
218 }
219
220 int
crypto_update_uio(void * ctx,crypto_data_t * input,crypto_data_t * output,int (* cipher)(void *,caddr_t,size_t,crypto_data_t *),void (* copy_block)(uint8_t *,uint64_t *))221 crypto_update_uio(void *ctx, crypto_data_t *input, crypto_data_t *output,
222 int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
223 void (*copy_block)(uint8_t *, uint64_t *))
224 {
225 common_ctx_t *common_ctx = ctx;
226 uio_t *uiop = input->cd_uio;
227 off_t offset = input->cd_offset;
228 size_t length = input->cd_length;
229 uint_t vec_idx;
230 size_t cur_len;
231
232 if (input->cd_miscdata != NULL) {
233 copy_block((uint8_t *)input->cd_miscdata,
234 &common_ctx->cc_iv[0]);
235 }
236
237 if (input->cd_uio->uio_segflg != UIO_SYSSPACE) {
238 return (CRYPTO_ARGUMENTS_BAD);
239 }
240
241 /*
242 * Jump to the first iovec containing data to be
243 * processed.
244 */
245 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
246 offset >= uiop->uio_iov[vec_idx].iov_len;
247 offset -= uiop->uio_iov[vec_idx++].iov_len)
248 ;
249 if (vec_idx == uiop->uio_iovcnt && length > 0) {
250 /*
251 * The caller specified an offset that is larger than the
252 * total size of the buffers it provided.
253 */
254 return (CRYPTO_DATA_LEN_RANGE);
255 }
256
257 /*
258 * Now process the iovecs.
259 */
260 while (vec_idx < uiop->uio_iovcnt && length > 0) {
261 cur_len = MIN(uiop->uio_iov[vec_idx].iov_len -
262 offset, length);
263
264 (cipher)(ctx, uiop->uio_iov[vec_idx].iov_base + offset,
265 cur_len, (input == output) ? NULL : output);
266
267 length -= cur_len;
268 vec_idx++;
269 offset = 0;
270 }
271
272 if (vec_idx == uiop->uio_iovcnt && length > 0) {
273 /*
274 * The end of the specified iovec's was reached but
275 * the length requested could not be processed, i.e.
276 * The caller requested to digest more data than it provided.
277 */
278
279 return (CRYPTO_DATA_LEN_RANGE);
280 }
281
282 return (CRYPTO_SUCCESS);
283 }
284
285 int
crypto_update_mp(void * ctx,crypto_data_t * input,crypto_data_t * output,int (* cipher)(void *,caddr_t,size_t,crypto_data_t *),void (* copy_block)(uint8_t *,uint64_t *))286 crypto_update_mp(void *ctx, crypto_data_t *input, crypto_data_t *output,
287 int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
288 void (*copy_block)(uint8_t *, uint64_t *))
289 {
290 common_ctx_t *common_ctx = ctx;
291 off_t offset = input->cd_offset;
292 size_t length = input->cd_length;
293 mblk_t *mp;
294 size_t cur_len;
295
296 if (input->cd_miscdata != NULL) {
297 copy_block((uint8_t *)input->cd_miscdata,
298 &common_ctx->cc_iv[0]);
299 }
300
301 /*
302 * Jump to the first mblk_t containing data to be processed.
303 */
304 for (mp = input->cd_mp; mp != NULL && offset >= MBLKL(mp);
305 offset -= MBLKL(mp), mp = mp->b_cont)
306 ;
307 if (mp == NULL) {
308 /*
309 * The caller specified an offset that is larger than the
310 * total size of the buffers it provided.
311 */
312 return (CRYPTO_DATA_LEN_RANGE);
313 }
314
315 /*
316 * Now do the processing on the mblk chain.
317 */
318 while (mp != NULL && length > 0) {
319 cur_len = MIN(MBLKL(mp) - offset, length);
320 (cipher)(ctx, (char *)(mp->b_rptr + offset), cur_len,
321 (input == output) ? NULL : output);
322
323 length -= cur_len;
324 offset = 0;
325 mp = mp->b_cont;
326 }
327
328 if (mp == NULL && length > 0) {
329 /*
330 * The end of the mblk was reached but the length requested
331 * could not be processed, i.e. The caller requested
332 * to digest more data than it provided.
333 */
334 return (CRYPTO_DATA_LEN_RANGE);
335 }
336
337 return (CRYPTO_SUCCESS);
338 }
339
340 /*
341 * Utility routine to look up a attribute of type, 'type',
342 * in the key.
343 */
344 int
crypto_get_key_attr(crypto_key_t * key,crypto_attr_type_t type,uchar_t ** value,ssize_t * value_len)345 crypto_get_key_attr(crypto_key_t *key, crypto_attr_type_t type,
346 uchar_t **value, ssize_t *value_len)
347 {
348 int i;
349
350 ASSERT(key->ck_format == CRYPTO_KEY_ATTR_LIST);
351 for (i = 0; i < key->ck_count; i++) {
352 if (key->ck_attrs[i].oa_type == type) {
353 *value = (uchar_t *)key->ck_attrs[i].oa_value;
354 *value_len = key->ck_attrs[i].oa_value_len;
355 return (CRYPTO_SUCCESS);
356 }
357 }
358
359 return (CRYPTO_FAILED);
360 }
361