123c57df7Smcpowers /*
223c57df7Smcpowers  * CDDL HEADER START
323c57df7Smcpowers  *
423c57df7Smcpowers  * The contents of this file are subject to the terms of the
523c57df7Smcpowers  * Common Development and Distribution License (the "License").
623c57df7Smcpowers  * You may not use this file except in compliance with the License.
723c57df7Smcpowers  *
823c57df7Smcpowers  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
923c57df7Smcpowers  * or http://www.opensolaris.org/os/licensing.
1023c57df7Smcpowers  * See the License for the specific language governing permissions
1123c57df7Smcpowers  * and limitations under the License.
1223c57df7Smcpowers  *
1323c57df7Smcpowers  * When distributing Covered Code, include this CDDL HEADER in each
1423c57df7Smcpowers  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1523c57df7Smcpowers  * If applicable, add the following below this CDDL HEADER, with the
1623c57df7Smcpowers  * fields enclosed by brackets "[]" replaced with your own identifying
1723c57df7Smcpowers  * information: Portions Copyright [yyyy] [name of copyright owner]
1823c57df7Smcpowers  *
1923c57df7Smcpowers  * CDDL HEADER END
2023c57df7Smcpowers  */
2123c57df7Smcpowers /*
2295014fbbSDan OpenSolaris Anderson  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2323c57df7Smcpowers  * Use is subject to license terms.
2423c57df7Smcpowers  */
2523c57df7Smcpowers 
2623c57df7Smcpowers #include <sys/strsun.h>
2723c57df7Smcpowers #include <sys/systm.h>
2823c57df7Smcpowers #include <sys/sysmacros.h>
2923c57df7Smcpowers #include <sys/kmem.h>
3023c57df7Smcpowers #include <sys/md5.h>
3123c57df7Smcpowers #include <sys/sha1.h>
3223c57df7Smcpowers #include <sys/sha2.h>
3323c57df7Smcpowers #include <modes/modes.h>
3423c57df7Smcpowers #include <sys/crypto/common.h>
3523c57df7Smcpowers #include <sys/crypto/impl.h>
3623c57df7Smcpowers 
3723c57df7Smcpowers /*
3823c57df7Smcpowers  * Utility routine to get data from a crypto_data structure.
3923c57df7Smcpowers  *
4023c57df7Smcpowers  * '*dptr' contains a pointer to a buffer on return. 'buf'
4123c57df7Smcpowers  * is allocated by the caller and is ignored for CRYPTO_DATA_RAW case.
4223c57df7Smcpowers  */
4323c57df7Smcpowers int
crypto_get_input_data(crypto_data_t * input,uchar_t ** dptr,uchar_t * buf)4423c57df7Smcpowers crypto_get_input_data(crypto_data_t *input, uchar_t **dptr, uchar_t *buf)
4523c57df7Smcpowers {
4623c57df7Smcpowers 	int rv;
4723c57df7Smcpowers 
4823c57df7Smcpowers 	switch (input->cd_format) {
4923c57df7Smcpowers 	case CRYPTO_DATA_RAW:
5023c57df7Smcpowers 		if (input->cd_raw.iov_len < input->cd_length)
5123c57df7Smcpowers 			return (CRYPTO_ARGUMENTS_BAD);
5223c57df7Smcpowers 		*dptr = (uchar_t *)(input->cd_raw.iov_base +
5323c57df7Smcpowers 		    input->cd_offset);
5423c57df7Smcpowers 		break;
5523c57df7Smcpowers 
5623c57df7Smcpowers 	case CRYPTO_DATA_UIO:
5723c57df7Smcpowers 		if ((rv = crypto_uio_data(input, buf, input->cd_length,
5823c57df7Smcpowers 		    COPY_FROM_DATA, NULL, NULL)) != CRYPTO_SUCCESS)
5923c57df7Smcpowers 			return (rv);
6023c57df7Smcpowers 		*dptr = buf;
6123c57df7Smcpowers 		break;
6223c57df7Smcpowers 
6323c57df7Smcpowers 	case CRYPTO_DATA_MBLK:
6423c57df7Smcpowers 		if ((rv = crypto_mblk_data(input, buf, input->cd_length,
6523c57df7Smcpowers 		    COPY_FROM_DATA, NULL, NULL)) != CRYPTO_SUCCESS)
6623c57df7Smcpowers 			return (rv);
6723c57df7Smcpowers 		*dptr = buf;
6823c57df7Smcpowers 		break;
6923c57df7Smcpowers 
7023c57df7Smcpowers 	default:
7123c57df7Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
7223c57df7Smcpowers 	}
7323c57df7Smcpowers 
7423c57df7Smcpowers 	return (CRYPTO_SUCCESS);
7523c57df7Smcpowers }
7623c57df7Smcpowers 
7723c57df7Smcpowers int
crypto_copy_key_to_ctx(crypto_key_t * in_key,crypto_key_t ** out_key,size_t * out_size,int kmflag)7823c57df7Smcpowers crypto_copy_key_to_ctx(crypto_key_t *in_key, crypto_key_t **out_key,
7923c57df7Smcpowers     size_t *out_size, int kmflag)
8023c57df7Smcpowers {
8123c57df7Smcpowers 	int i, count;
8223c57df7Smcpowers 	size_t len;
8323c57df7Smcpowers 	caddr_t attr_val;
8423c57df7Smcpowers 	crypto_object_attribute_t *k_attrs = NULL;
8523c57df7Smcpowers 	crypto_key_t *key;
8623c57df7Smcpowers 
8723c57df7Smcpowers 	ASSERT(in_key->ck_format == CRYPTO_KEY_ATTR_LIST);
8823c57df7Smcpowers 
8923c57df7Smcpowers 	count = in_key->ck_count;
9023c57df7Smcpowers 	/* figure out how much memory to allocate for everything */
9123c57df7Smcpowers 	len = sizeof (crypto_key_t) +
9223c57df7Smcpowers 	    count * sizeof (crypto_object_attribute_t);
9323c57df7Smcpowers 	for (i = 0; i < count; i++) {
9423c57df7Smcpowers 		len += roundup(in_key->ck_attrs[i].oa_value_len,
9523c57df7Smcpowers 		    sizeof (caddr_t));
9623c57df7Smcpowers 	}
9723c57df7Smcpowers 
9823c57df7Smcpowers 	/* one big allocation for everything */
9923c57df7Smcpowers 	key = kmem_alloc(len, kmflag);
10023c57df7Smcpowers 	if (key == NULL)
10123c57df7Smcpowers 		return (CRYPTO_HOST_MEMORY);
10295014fbbSDan OpenSolaris Anderson 	k_attrs = (crypto_object_attribute_t *)(void *)((caddr_t)key +
10323c57df7Smcpowers 	    sizeof (crypto_key_t));
10423c57df7Smcpowers 
10523c57df7Smcpowers 	attr_val = (caddr_t)k_attrs +
10623c57df7Smcpowers 	    count * sizeof (crypto_object_attribute_t);
10723c57df7Smcpowers 	for (i = 0; i < count; i++) {
10823c57df7Smcpowers 		k_attrs[i].oa_type = in_key->ck_attrs[i].oa_type;
10923c57df7Smcpowers 		bcopy(in_key->ck_attrs[i].oa_value, attr_val,
11023c57df7Smcpowers 		    in_key->ck_attrs[i].oa_value_len);
11123c57df7Smcpowers 		k_attrs[i].oa_value = attr_val;
11223c57df7Smcpowers 		k_attrs[i].oa_value_len = in_key->ck_attrs[i].oa_value_len;
11323c57df7Smcpowers 		attr_val += roundup(k_attrs[i].oa_value_len, sizeof (caddr_t));
11423c57df7Smcpowers 	}
11523c57df7Smcpowers 
11623c57df7Smcpowers 	key->ck_format = CRYPTO_KEY_ATTR_LIST;
11723c57df7Smcpowers 	key->ck_count = count;
11823c57df7Smcpowers 	key->ck_attrs = k_attrs;
11923c57df7Smcpowers 	*out_key = key;
12023c57df7Smcpowers 	*out_size = len;		/* save the size to be freed */
12123c57df7Smcpowers 
12223c57df7Smcpowers 	return (CRYPTO_SUCCESS);
12323c57df7Smcpowers }
12423c57df7Smcpowers 
12523c57df7Smcpowers int
crypto_digest_data(crypto_data_t * data,void * dctx,uchar_t * digest,void (* update)(),void (* final)(),uchar_t flag)12623c57df7Smcpowers crypto_digest_data(crypto_data_t *data, void *dctx, uchar_t *digest,
12723c57df7Smcpowers     void (*update)(), void (*final)(), uchar_t flag)
12823c57df7Smcpowers {
12923c57df7Smcpowers 	int rv, dlen;
13023c57df7Smcpowers 	uchar_t *dptr;
13123c57df7Smcpowers 
13223c57df7Smcpowers 	ASSERT(flag & CRYPTO_DO_MD5 || flag & CRYPTO_DO_SHA1 ||
13323c57df7Smcpowers 	    flag & CRYPTO_DO_SHA2);
13423c57df7Smcpowers 	if (data == NULL) {
13523c57df7Smcpowers 		ASSERT((flag & CRYPTO_DO_UPDATE) == 0);
13623c57df7Smcpowers 		goto dofinal;
13723c57df7Smcpowers 	}
13823c57df7Smcpowers 
13923c57df7Smcpowers 	dlen = data->cd_length;
14023c57df7Smcpowers 
14123c57df7Smcpowers 	if (flag & CRYPTO_DO_UPDATE) {
14223c57df7Smcpowers 
14323c57df7Smcpowers 		switch (data->cd_format) {
14423c57df7Smcpowers 		case CRYPTO_DATA_RAW:
14523c57df7Smcpowers 			dptr = (uchar_t *)(data->cd_raw.iov_base +
14623c57df7Smcpowers 			    data->cd_offset);
14723c57df7Smcpowers 
14823c57df7Smcpowers 			update(dctx, dptr, dlen);
14923c57df7Smcpowers 
15023c57df7Smcpowers 		break;
15123c57df7Smcpowers 
15223c57df7Smcpowers 		case CRYPTO_DATA_UIO:
15323c57df7Smcpowers 			if (flag & CRYPTO_DO_MD5)
15423c57df7Smcpowers 				rv = crypto_uio_data(data, NULL, dlen,
15523c57df7Smcpowers 				    MD5_DIGEST_DATA, dctx, update);
15623c57df7Smcpowers 
15723c57df7Smcpowers 			else if (flag & CRYPTO_DO_SHA1)
15823c57df7Smcpowers 				rv = crypto_uio_data(data, NULL, dlen,
15923c57df7Smcpowers 				    SHA1_DIGEST_DATA, dctx, update);
16023c57df7Smcpowers 
16123c57df7Smcpowers 			else
16223c57df7Smcpowers 				rv = crypto_uio_data(data, NULL, dlen,
16323c57df7Smcpowers 				    SHA2_DIGEST_DATA, dctx, update);
16423c57df7Smcpowers 
16523c57df7Smcpowers 			if (rv != CRYPTO_SUCCESS)
16623c57df7Smcpowers 				return (rv);
16723c57df7Smcpowers 
16823c57df7Smcpowers 			break;
16923c57df7Smcpowers 
17023c57df7Smcpowers 		case CRYPTO_DATA_MBLK:
17123c57df7Smcpowers 			if (flag & CRYPTO_DO_MD5)
17223c57df7Smcpowers 				rv = crypto_mblk_data(data, NULL, dlen,
17323c57df7Smcpowers 				    MD5_DIGEST_DATA, dctx, update);
17423c57df7Smcpowers 
17523c57df7Smcpowers 			else if (flag & CRYPTO_DO_SHA1)
17623c57df7Smcpowers 				rv = crypto_mblk_data(data, NULL, dlen,
17723c57df7Smcpowers 				    SHA1_DIGEST_DATA, dctx, update);
17823c57df7Smcpowers 
17923c57df7Smcpowers 			else
18023c57df7Smcpowers 				rv = crypto_mblk_data(data, NULL, dlen,
18123c57df7Smcpowers 				    SHA2_DIGEST_DATA, dctx, update);
18223c57df7Smcpowers 
18323c57df7Smcpowers 			if (rv != CRYPTO_SUCCESS)
18423c57df7Smcpowers 				return (rv);
18523c57df7Smcpowers 
18623c57df7Smcpowers 			break;
18723c57df7Smcpowers 		}
18823c57df7Smcpowers 	}
18923c57df7Smcpowers 
19023c57df7Smcpowers dofinal:
19123c57df7Smcpowers 	if (flag & CRYPTO_DO_FINAL) {
19223c57df7Smcpowers 		final(digest, dctx);
19323c57df7Smcpowers 	}
19423c57df7Smcpowers 
19523c57df7Smcpowers 	return (CRYPTO_SUCCESS);
19623c57df7Smcpowers }
19723c57df7Smcpowers 
19823c57df7Smcpowers 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 *))19923c57df7Smcpowers crypto_update_iov(void *ctx, crypto_data_t *input, crypto_data_t *output,
20023c57df7Smcpowers     int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
20123c57df7Smcpowers     void (*copy_block)(uint8_t *, uint64_t *))
20223c57df7Smcpowers {
20323c57df7Smcpowers 	common_ctx_t *common_ctx = ctx;
20423c57df7Smcpowers 	int rv;
20523c57df7Smcpowers 
20623c57df7Smcpowers 	if (input->cd_miscdata != NULL) {
20723c57df7Smcpowers 		copy_block((uint8_t *)input->cd_miscdata,
20823c57df7Smcpowers 		    &common_ctx->cc_iv[0]);
20923c57df7Smcpowers 	}
21023c57df7Smcpowers 
21123c57df7Smcpowers 	if (input->cd_raw.iov_len < input->cd_length)
21223c57df7Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
21323c57df7Smcpowers 
21423c57df7Smcpowers 	rv = (cipher)(ctx, input->cd_raw.iov_base + input->cd_offset,
21523c57df7Smcpowers 	    input->cd_length, (input == output) ? NULL : output);
21623c57df7Smcpowers 
21723c57df7Smcpowers 	return (rv);
21823c57df7Smcpowers }
21923c57df7Smcpowers 
22023c57df7Smcpowers 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 *))22123c57df7Smcpowers crypto_update_uio(void *ctx, crypto_data_t *input, crypto_data_t *output,
22223c57df7Smcpowers     int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
22323c57df7Smcpowers     void (*copy_block)(uint8_t *, uint64_t *))
22423c57df7Smcpowers {
22523c57df7Smcpowers 	common_ctx_t *common_ctx = ctx;
22623c57df7Smcpowers 	uio_t *uiop = input->cd_uio;
22723c57df7Smcpowers 	off_t offset = input->cd_offset;
22823c57df7Smcpowers 	size_t length = input->cd_length;
22923c57df7Smcpowers 	uint_t vec_idx;
23023c57df7Smcpowers 	size_t cur_len;
23123c57df7Smcpowers 
23223c57df7Smcpowers 	if (input->cd_miscdata != NULL) {
23323c57df7Smcpowers 		copy_block((uint8_t *)input->cd_miscdata,
23423c57df7Smcpowers 		    &common_ctx->cc_iv[0]);
23523c57df7Smcpowers 	}
23623c57df7Smcpowers 
23723c57df7Smcpowers 	if (input->cd_uio->uio_segflg != UIO_SYSSPACE) {
23823c57df7Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
23923c57df7Smcpowers 	}
24023c57df7Smcpowers 
24123c57df7Smcpowers 	/*
24223c57df7Smcpowers 	 * Jump to the first iovec containing data to be
24323c57df7Smcpowers 	 * processed.
24423c57df7Smcpowers 	 */
24523c57df7Smcpowers 	for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
24623c57df7Smcpowers 	    offset >= uiop->uio_iov[vec_idx].iov_len;
24723c57df7Smcpowers 	    offset -= uiop->uio_iov[vec_idx++].iov_len)
24823c57df7Smcpowers 		;
249*eb633035STom Caputi 	if (vec_idx == uiop->uio_iovcnt && length > 0) {
25023c57df7Smcpowers 		/*
25123c57df7Smcpowers 		 * The caller specified an offset that is larger than the
25223c57df7Smcpowers 		 * total size of the buffers it provided.
25323c57df7Smcpowers 		 */
25423c57df7Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
25523c57df7Smcpowers 	}
25623c57df7Smcpowers 
25723c57df7Smcpowers 	/*
25823c57df7Smcpowers 	 * Now process the iovecs.
25923c57df7Smcpowers 	 */
26023c57df7Smcpowers 	while (vec_idx < uiop->uio_iovcnt && length > 0) {
26123c57df7Smcpowers 		cur_len = MIN(uiop->uio_iov[vec_idx].iov_len -
26223c57df7Smcpowers 		    offset, length);
26323c57df7Smcpowers 
26423c57df7Smcpowers 		(cipher)(ctx, uiop->uio_iov[vec_idx].iov_base + offset,
26523c57df7Smcpowers 		    cur_len, (input == output) ? NULL : output);
26623c57df7Smcpowers 
26723c57df7Smcpowers 		length -= cur_len;
26823c57df7Smcpowers 		vec_idx++;
26923c57df7Smcpowers 		offset = 0;
27023c57df7Smcpowers 	}
27123c57df7Smcpowers 
27223c57df7Smcpowers 	if (vec_idx == uiop->uio_iovcnt && length > 0) {
27323c57df7Smcpowers 		/*
27423c57df7Smcpowers 		 * The end of the specified iovec's was reached but
27523c57df7Smcpowers 		 * the length requested could not be processed, i.e.
27623c57df7Smcpowers 		 * The caller requested to digest more data than it provided.
27723c57df7Smcpowers 		 */
27823c57df7Smcpowers 
27923c57df7Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
28023c57df7Smcpowers 	}
28123c57df7Smcpowers 
28223c57df7Smcpowers 	return (CRYPTO_SUCCESS);
28323c57df7Smcpowers }
28423c57df7Smcpowers 
28523c57df7Smcpowers 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 *))28623c57df7Smcpowers crypto_update_mp(void *ctx, crypto_data_t *input, crypto_data_t *output,
28723c57df7Smcpowers     int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
28823c57df7Smcpowers     void (*copy_block)(uint8_t *, uint64_t *))
28923c57df7Smcpowers {
29023c57df7Smcpowers 	common_ctx_t *common_ctx = ctx;
29123c57df7Smcpowers 	off_t offset = input->cd_offset;
29223c57df7Smcpowers 	size_t length = input->cd_length;
29323c57df7Smcpowers 	mblk_t *mp;
29423c57df7Smcpowers 	size_t cur_len;
29523c57df7Smcpowers 
29623c57df7Smcpowers 	if (input->cd_miscdata != NULL) {
29723c57df7Smcpowers 		copy_block((uint8_t *)input->cd_miscdata,
29823c57df7Smcpowers 		    &common_ctx->cc_iv[0]);
29923c57df7Smcpowers 	}
30023c57df7Smcpowers 
30123c57df7Smcpowers 	/*
30223c57df7Smcpowers 	 * Jump to the first mblk_t containing data to be processed.
30323c57df7Smcpowers 	 */
30423c57df7Smcpowers 	for (mp = input->cd_mp; mp != NULL && offset >= MBLKL(mp);
30523c57df7Smcpowers 	    offset -= MBLKL(mp), mp = mp->b_cont)
30623c57df7Smcpowers 		;
30723c57df7Smcpowers 	if (mp == NULL) {
30823c57df7Smcpowers 		/*
30923c57df7Smcpowers 		 * The caller specified an offset that is larger than the
31023c57df7Smcpowers 		 * total size of the buffers it provided.
31123c57df7Smcpowers 		 */
31223c57df7Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
31323c57df7Smcpowers 	}
31423c57df7Smcpowers 
31523c57df7Smcpowers 	/*
31623c57df7Smcpowers 	 * Now do the processing on the mblk chain.
31723c57df7Smcpowers 	 */
31823c57df7Smcpowers 	while (mp != NULL && length > 0) {
31923c57df7Smcpowers 		cur_len = MIN(MBLKL(mp) - offset, length);
32023c57df7Smcpowers 		(cipher)(ctx, (char *)(mp->b_rptr + offset), cur_len,
32123c57df7Smcpowers 		    (input == output) ? NULL : output);
32223c57df7Smcpowers 
32323c57df7Smcpowers 		length -= cur_len;
32423c57df7Smcpowers 		offset = 0;
32523c57df7Smcpowers 		mp = mp->b_cont;
32623c57df7Smcpowers 	}
32723c57df7Smcpowers 
32823c57df7Smcpowers 	if (mp == NULL && length > 0) {
32923c57df7Smcpowers 		/*
33023c57df7Smcpowers 		 * The end of the mblk was reached but the length requested
33123c57df7Smcpowers 		 * could not be processed, i.e. The caller requested
33223c57df7Smcpowers 		 * to digest more data than it provided.
33323c57df7Smcpowers 		 */
33423c57df7Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
33523c57df7Smcpowers 	}
33623c57df7Smcpowers 
33723c57df7Smcpowers 	return (CRYPTO_SUCCESS);
33823c57df7Smcpowers }
33923c57df7Smcpowers 
34023c57df7Smcpowers /*
34123c57df7Smcpowers  * Utility routine to look up a attribute of type, 'type',
34223c57df7Smcpowers  * in the key.
34323c57df7Smcpowers  */
34423c57df7Smcpowers int
crypto_get_key_attr(crypto_key_t * key,crypto_attr_type_t type,uchar_t ** value,ssize_t * value_len)34523c57df7Smcpowers crypto_get_key_attr(crypto_key_t *key, crypto_attr_type_t type,
34623c57df7Smcpowers     uchar_t **value, ssize_t *value_len)
34723c57df7Smcpowers {
34823c57df7Smcpowers 	int i;
34923c57df7Smcpowers 
35023c57df7Smcpowers 	ASSERT(key->ck_format == CRYPTO_KEY_ATTR_LIST);
35123c57df7Smcpowers 	for (i = 0; i < key->ck_count; i++) {
35223c57df7Smcpowers 		if (key->ck_attrs[i].oa_type == type) {
35323c57df7Smcpowers 			*value = (uchar_t *)key->ck_attrs[i].oa_value;
35423c57df7Smcpowers 			*value_len = key->ck_attrs[i].oa_value_len;
35523c57df7Smcpowers 			return (CRYPTO_SUCCESS);
35623c57df7Smcpowers 		}
35723c57df7Smcpowers 	}
35823c57df7Smcpowers 
35923c57df7Smcpowers 	return (CRYPTO_FAILED);
36023c57df7Smcpowers }
361