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