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 /*
22*95014fbbSDan 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 apply the command, 'cmd', to the
3923c57df7Smcpowers  * data in the uio structure.
4023c57df7Smcpowers  */
4123c57df7Smcpowers int
4223c57df7Smcpowers crypto_uio_data(crypto_data_t *data, uchar_t *buf, int len, cmd_type_t cmd,
4323c57df7Smcpowers     void *digest_ctx, void (*update)())
4423c57df7Smcpowers {
4523c57df7Smcpowers 	uio_t *uiop = data->cd_uio;
4623c57df7Smcpowers 	off_t offset = data->cd_offset;
4723c57df7Smcpowers 	size_t length = len;
4823c57df7Smcpowers 	uint_t vec_idx;
4923c57df7Smcpowers 	size_t cur_len;
5023c57df7Smcpowers 	uchar_t *datap;
5123c57df7Smcpowers 
5223c57df7Smcpowers 	ASSERT(data->cd_format == CRYPTO_DATA_UIO);
5323c57df7Smcpowers 	if (uiop->uio_segflg != UIO_SYSSPACE) {
5423c57df7Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
5523c57df7Smcpowers 	}
5623c57df7Smcpowers 
5723c57df7Smcpowers 	/*
5823c57df7Smcpowers 	 * Jump to the first iovec containing data to be
5923c57df7Smcpowers 	 * processed.
6023c57df7Smcpowers 	 */
6123c57df7Smcpowers 	for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
6223c57df7Smcpowers 	    offset >= uiop->uio_iov[vec_idx].iov_len;
6323c57df7Smcpowers 	    offset -= uiop->uio_iov[vec_idx++].iov_len)
6423c57df7Smcpowers 		;
6523c57df7Smcpowers 
6623c57df7Smcpowers 	if (vec_idx == uiop->uio_iovcnt) {
6723c57df7Smcpowers 		/*
6823c57df7Smcpowers 		 * The caller specified an offset that is larger than
6923c57df7Smcpowers 		 * the total size of the buffers it provided.
7023c57df7Smcpowers 		 */
7123c57df7Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
7223c57df7Smcpowers 	}
7323c57df7Smcpowers 
7423c57df7Smcpowers 	while (vec_idx < uiop->uio_iovcnt && length > 0) {
7523c57df7Smcpowers 		cur_len = MIN(uiop->uio_iov[vec_idx].iov_len -
7623c57df7Smcpowers 		    offset, length);
7723c57df7Smcpowers 
7823c57df7Smcpowers 		datap = (uchar_t *)(uiop->uio_iov[vec_idx].iov_base +
7923c57df7Smcpowers 		    offset);
8023c57df7Smcpowers 		switch (cmd) {
8123c57df7Smcpowers 		case COPY_FROM_DATA:
8223c57df7Smcpowers 			bcopy(datap, buf, cur_len);
8323c57df7Smcpowers 			buf += cur_len;
8423c57df7Smcpowers 			break;
8523c57df7Smcpowers 		case COPY_TO_DATA:
8623c57df7Smcpowers 			bcopy(buf, datap, cur_len);
8723c57df7Smcpowers 			buf += cur_len;
8823c57df7Smcpowers 			break;
8923c57df7Smcpowers 		case COMPARE_TO_DATA:
9023c57df7Smcpowers 			if (bcmp(datap, buf, cur_len))
9123c57df7Smcpowers 				return (CRYPTO_SIGNATURE_INVALID);
9223c57df7Smcpowers 			buf += cur_len;
9323c57df7Smcpowers 			break;
9423c57df7Smcpowers 		case MD5_DIGEST_DATA:
9523c57df7Smcpowers 		case SHA1_DIGEST_DATA:
9623c57df7Smcpowers 		case SHA2_DIGEST_DATA:
97e8c016efSMark Powers 		case GHASH_DATA:
9823c57df7Smcpowers 			update(digest_ctx, datap, cur_len);
9923c57df7Smcpowers 			break;
10023c57df7Smcpowers 		}
10123c57df7Smcpowers 
10223c57df7Smcpowers 		length -= cur_len;
10323c57df7Smcpowers 		vec_idx++;
10423c57df7Smcpowers 		offset = 0;
10523c57df7Smcpowers 	}
10623c57df7Smcpowers 
10723c57df7Smcpowers 	if (vec_idx == uiop->uio_iovcnt && length > 0) {
10823c57df7Smcpowers 		/*
10923c57df7Smcpowers 		 * The end of the specified iovec's was reached but
11023c57df7Smcpowers 		 * the length requested could not be processed.
11123c57df7Smcpowers 		 */
11223c57df7Smcpowers 		switch (cmd) {
11323c57df7Smcpowers 		case COPY_TO_DATA:
11423c57df7Smcpowers 			data->cd_length = len;
11523c57df7Smcpowers 			return (CRYPTO_BUFFER_TOO_SMALL);
11623c57df7Smcpowers 		default:
11723c57df7Smcpowers 			return (CRYPTO_DATA_LEN_RANGE);
11823c57df7Smcpowers 		}
11923c57df7Smcpowers 	}
12023c57df7Smcpowers 
12123c57df7Smcpowers 	return (CRYPTO_SUCCESS);
12223c57df7Smcpowers }
12323c57df7Smcpowers 
12423c57df7Smcpowers /*
12523c57df7Smcpowers  * Utility routine to apply the command, 'cmd', to the
12623c57df7Smcpowers  * data in the mblk structure.
12723c57df7Smcpowers  */
12823c57df7Smcpowers int
12923c57df7Smcpowers crypto_mblk_data(crypto_data_t *data, uchar_t *buf, int len, cmd_type_t cmd,
13023c57df7Smcpowers     void *digest_ctx, void (*update)())
13123c57df7Smcpowers {
13223c57df7Smcpowers 	off_t offset = data->cd_offset;
13323c57df7Smcpowers 	size_t length = len;
13423c57df7Smcpowers 	mblk_t *mp;
13523c57df7Smcpowers 	size_t cur_len;
13623c57df7Smcpowers 	uchar_t *datap;
13723c57df7Smcpowers 
13823c57df7Smcpowers 	ASSERT(data->cd_format == CRYPTO_DATA_MBLK);
13923c57df7Smcpowers 	/*
14023c57df7Smcpowers 	 * Jump to the first mblk_t containing data to be processed.
14123c57df7Smcpowers 	 */
14223c57df7Smcpowers 	for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp);
14323c57df7Smcpowers 	    offset -= MBLKL(mp), mp = mp->b_cont)
14423c57df7Smcpowers 		;
14523c57df7Smcpowers 	if (mp == NULL) {
14623c57df7Smcpowers 		/*
14723c57df7Smcpowers 		 * The caller specified an offset that is larger
14823c57df7Smcpowers 		 * than the total size of the buffers it provided.
14923c57df7Smcpowers 		 */
15023c57df7Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
15123c57df7Smcpowers 	}
15223c57df7Smcpowers 
15323c57df7Smcpowers 	/*
15423c57df7Smcpowers 	 * Now do the processing on the mblk chain.
15523c57df7Smcpowers 	 */
15623c57df7Smcpowers 	while (mp != NULL && length > 0) {
15723c57df7Smcpowers 		cur_len = MIN(MBLKL(mp) - offset, length);
15823c57df7Smcpowers 
15923c57df7Smcpowers 		datap = (uchar_t *)(mp->b_rptr + offset);
16023c57df7Smcpowers 		switch (cmd) {
16123c57df7Smcpowers 		case COPY_FROM_DATA:
16223c57df7Smcpowers 			bcopy(datap, buf, cur_len);
16323c57df7Smcpowers 			buf += cur_len;
16423c57df7Smcpowers 			break;
16523c57df7Smcpowers 		case COPY_TO_DATA:
16623c57df7Smcpowers 			bcopy(buf, datap, cur_len);
16723c57df7Smcpowers 			buf += cur_len;
16823c57df7Smcpowers 			break;
16923c57df7Smcpowers 		case COMPARE_TO_DATA:
17023c57df7Smcpowers 			if (bcmp(datap, buf, cur_len))
17123c57df7Smcpowers 				return (CRYPTO_SIGNATURE_INVALID);
17223c57df7Smcpowers 			buf += cur_len;
17323c57df7Smcpowers 			break;
17423c57df7Smcpowers 		case MD5_DIGEST_DATA:
17523c57df7Smcpowers 		case SHA1_DIGEST_DATA:
17623c57df7Smcpowers 		case SHA2_DIGEST_DATA:
177e8c016efSMark Powers 		case GHASH_DATA:
17823c57df7Smcpowers 			update(digest_ctx, datap, cur_len);
17923c57df7Smcpowers 			break;
18023c57df7Smcpowers 		}
18123c57df7Smcpowers 
18223c57df7Smcpowers 		length -= cur_len;
18323c57df7Smcpowers 		offset = 0;
18423c57df7Smcpowers 		mp = mp->b_cont;
18523c57df7Smcpowers 	}
18623c57df7Smcpowers 
18723c57df7Smcpowers 	if (mp == NULL && length > 0) {
18823c57df7Smcpowers 		/*
18923c57df7Smcpowers 		 * The end of the mblk was reached but the length
19023c57df7Smcpowers 		 * requested could not be processed.
19123c57df7Smcpowers 		 */
19223c57df7Smcpowers 		switch (cmd) {
19323c57df7Smcpowers 		case COPY_TO_DATA:
19423c57df7Smcpowers 			data->cd_length = len;
19523c57df7Smcpowers 			return (CRYPTO_BUFFER_TOO_SMALL);
19623c57df7Smcpowers 		default:
19723c57df7Smcpowers 			return (CRYPTO_DATA_LEN_RANGE);
19823c57df7Smcpowers 		}
19923c57df7Smcpowers 	}
20023c57df7Smcpowers 
20123c57df7Smcpowers 	return (CRYPTO_SUCCESS);
20223c57df7Smcpowers }
20323c57df7Smcpowers 
20423c57df7Smcpowers /*
20523c57df7Smcpowers  * Utility routine to copy a buffer to a crypto_data structure.
20623c57df7Smcpowers  */
20723c57df7Smcpowers int
20823c57df7Smcpowers crypto_put_output_data(uchar_t *buf, crypto_data_t *output, int len)
20923c57df7Smcpowers {
21023c57df7Smcpowers 	switch (output->cd_format) {
21123c57df7Smcpowers 	case CRYPTO_DATA_RAW:
21223c57df7Smcpowers 		if (output->cd_raw.iov_len < len) {
21323c57df7Smcpowers 			output->cd_length = len;
21423c57df7Smcpowers 			return (CRYPTO_BUFFER_TOO_SMALL);
21523c57df7Smcpowers 		}
21623c57df7Smcpowers 		bcopy(buf, (uchar_t *)(output->cd_raw.iov_base +
21723c57df7Smcpowers 		    output->cd_offset), len);
21823c57df7Smcpowers 		break;
21923c57df7Smcpowers 
22023c57df7Smcpowers 	case CRYPTO_DATA_UIO:
22123c57df7Smcpowers 		return (crypto_uio_data(output, buf, len,
22223c57df7Smcpowers 		    COPY_TO_DATA, NULL, NULL));
22323c57df7Smcpowers 
22423c57df7Smcpowers 	case CRYPTO_DATA_MBLK:
22523c57df7Smcpowers 		return (crypto_mblk_data(output, buf, len,
22623c57df7Smcpowers 		    COPY_TO_DATA, NULL, NULL));
22723c57df7Smcpowers 
22823c57df7Smcpowers 	default:
22923c57df7Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
23023c57df7Smcpowers 	}
23123c57df7Smcpowers 
23223c57df7Smcpowers 	return (CRYPTO_SUCCESS);
23323c57df7Smcpowers }
23423c57df7Smcpowers 
23523c57df7Smcpowers /*
23623c57df7Smcpowers  * Utility routine to get data from a crypto_data structure.
23723c57df7Smcpowers  *
23823c57df7Smcpowers  * '*dptr' contains a pointer to a buffer on return. 'buf'
23923c57df7Smcpowers  * is allocated by the caller and is ignored for CRYPTO_DATA_RAW case.
24023c57df7Smcpowers  */
24123c57df7Smcpowers int
24223c57df7Smcpowers crypto_get_input_data(crypto_data_t *input, uchar_t **dptr, uchar_t *buf)
24323c57df7Smcpowers {
24423c57df7Smcpowers 	int rv;
24523c57df7Smcpowers 
24623c57df7Smcpowers 	switch (input->cd_format) {
24723c57df7Smcpowers 	case CRYPTO_DATA_RAW:
24823c57df7Smcpowers 		if (input->cd_raw.iov_len < input->cd_length)
24923c57df7Smcpowers 			return (CRYPTO_ARGUMENTS_BAD);
25023c57df7Smcpowers 		*dptr = (uchar_t *)(input->cd_raw.iov_base +
25123c57df7Smcpowers 		    input->cd_offset);
25223c57df7Smcpowers 		break;
25323c57df7Smcpowers 
25423c57df7Smcpowers 	case CRYPTO_DATA_UIO:
25523c57df7Smcpowers 		if ((rv = crypto_uio_data(input, buf, input->cd_length,
25623c57df7Smcpowers 		    COPY_FROM_DATA, NULL, NULL)) != CRYPTO_SUCCESS)
25723c57df7Smcpowers 			return (rv);
25823c57df7Smcpowers 		*dptr = buf;
25923c57df7Smcpowers 		break;
26023c57df7Smcpowers 
26123c57df7Smcpowers 	case CRYPTO_DATA_MBLK:
26223c57df7Smcpowers 		if ((rv = crypto_mblk_data(input, buf, input->cd_length,
26323c57df7Smcpowers 		    COPY_FROM_DATA, NULL, NULL)) != CRYPTO_SUCCESS)
26423c57df7Smcpowers 			return (rv);
26523c57df7Smcpowers 		*dptr = buf;
26623c57df7Smcpowers 		break;
26723c57df7Smcpowers 
26823c57df7Smcpowers 	default:
26923c57df7Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
27023c57df7Smcpowers 	}
27123c57df7Smcpowers 
27223c57df7Smcpowers 	return (CRYPTO_SUCCESS);
27323c57df7Smcpowers }
27423c57df7Smcpowers 
27523c57df7Smcpowers int
27623c57df7Smcpowers crypto_copy_key_to_ctx(crypto_key_t *in_key, crypto_key_t **out_key,
27723c57df7Smcpowers     size_t *out_size, int kmflag)
27823c57df7Smcpowers {
27923c57df7Smcpowers 	int i, count;
28023c57df7Smcpowers 	size_t len;
28123c57df7Smcpowers 	caddr_t attr_val;
28223c57df7Smcpowers 	crypto_object_attribute_t *k_attrs = NULL;
28323c57df7Smcpowers 	crypto_key_t *key;
28423c57df7Smcpowers 
28523c57df7Smcpowers 	ASSERT(in_key->ck_format == CRYPTO_KEY_ATTR_LIST);
28623c57df7Smcpowers 
28723c57df7Smcpowers 	count = in_key->ck_count;
28823c57df7Smcpowers 	/* figure out how much memory to allocate for everything */
28923c57df7Smcpowers 	len = sizeof (crypto_key_t) +
29023c57df7Smcpowers 	    count * sizeof (crypto_object_attribute_t);
29123c57df7Smcpowers 	for (i = 0; i < count; i++) {
29223c57df7Smcpowers 		len += roundup(in_key->ck_attrs[i].oa_value_len,
29323c57df7Smcpowers 		    sizeof (caddr_t));
29423c57df7Smcpowers 	}
29523c57df7Smcpowers 
29623c57df7Smcpowers 	/* one big allocation for everything */
29723c57df7Smcpowers 	key = kmem_alloc(len, kmflag);
29823c57df7Smcpowers 	if (key == NULL)
29923c57df7Smcpowers 		return (CRYPTO_HOST_MEMORY);
300*95014fbbSDan OpenSolaris Anderson 	k_attrs = (crypto_object_attribute_t *)(void *)((caddr_t)key +
30123c57df7Smcpowers 	    sizeof (crypto_key_t));
30223c57df7Smcpowers 
30323c57df7Smcpowers 	attr_val = (caddr_t)k_attrs +
30423c57df7Smcpowers 	    count * sizeof (crypto_object_attribute_t);
30523c57df7Smcpowers 	for (i = 0; i < count; i++) {
30623c57df7Smcpowers 		k_attrs[i].oa_type = in_key->ck_attrs[i].oa_type;
30723c57df7Smcpowers 		bcopy(in_key->ck_attrs[i].oa_value, attr_val,
30823c57df7Smcpowers 		    in_key->ck_attrs[i].oa_value_len);
30923c57df7Smcpowers 		k_attrs[i].oa_value = attr_val;
31023c57df7Smcpowers 		k_attrs[i].oa_value_len = in_key->ck_attrs[i].oa_value_len;
31123c57df7Smcpowers 		attr_val += roundup(k_attrs[i].oa_value_len, sizeof (caddr_t));
31223c57df7Smcpowers 	}
31323c57df7Smcpowers 
31423c57df7Smcpowers 	key->ck_format = CRYPTO_KEY_ATTR_LIST;
31523c57df7Smcpowers 	key->ck_count = count;
31623c57df7Smcpowers 	key->ck_attrs = k_attrs;
31723c57df7Smcpowers 	*out_key = key;
31823c57df7Smcpowers 	*out_size = len;		/* save the size to be freed */
31923c57df7Smcpowers 
32023c57df7Smcpowers 	return (CRYPTO_SUCCESS);
32123c57df7Smcpowers }
32223c57df7Smcpowers 
32323c57df7Smcpowers int
32423c57df7Smcpowers crypto_digest_data(crypto_data_t *data, void *dctx, uchar_t *digest,
32523c57df7Smcpowers     void (*update)(), void (*final)(), uchar_t flag)
32623c57df7Smcpowers {
32723c57df7Smcpowers 	int rv, dlen;
32823c57df7Smcpowers 	uchar_t *dptr;
32923c57df7Smcpowers 
33023c57df7Smcpowers 	ASSERT(flag & CRYPTO_DO_MD5 || flag & CRYPTO_DO_SHA1 ||
33123c57df7Smcpowers 	    flag & CRYPTO_DO_SHA2);
33223c57df7Smcpowers 	if (data == NULL) {
33323c57df7Smcpowers 		ASSERT((flag & CRYPTO_DO_UPDATE) == 0);
33423c57df7Smcpowers 		goto dofinal;
33523c57df7Smcpowers 	}
33623c57df7Smcpowers 
33723c57df7Smcpowers 	dlen = data->cd_length;
33823c57df7Smcpowers 
33923c57df7Smcpowers 	if (flag & CRYPTO_DO_UPDATE) {
34023c57df7Smcpowers 
34123c57df7Smcpowers 		switch (data->cd_format) {
34223c57df7Smcpowers 		case CRYPTO_DATA_RAW:
34323c57df7Smcpowers 			dptr = (uchar_t *)(data->cd_raw.iov_base +
34423c57df7Smcpowers 			    data->cd_offset);
34523c57df7Smcpowers 
34623c57df7Smcpowers 			update(dctx, dptr, dlen);
34723c57df7Smcpowers 
34823c57df7Smcpowers 		break;
34923c57df7Smcpowers 
35023c57df7Smcpowers 		case CRYPTO_DATA_UIO:
35123c57df7Smcpowers 			if (flag & CRYPTO_DO_MD5)
35223c57df7Smcpowers 				rv = crypto_uio_data(data, NULL, dlen,
35323c57df7Smcpowers 				    MD5_DIGEST_DATA, dctx, update);
35423c57df7Smcpowers 
35523c57df7Smcpowers 			else if (flag & CRYPTO_DO_SHA1)
35623c57df7Smcpowers 				rv = crypto_uio_data(data, NULL, dlen,
35723c57df7Smcpowers 				    SHA1_DIGEST_DATA, dctx, update);
35823c57df7Smcpowers 
35923c57df7Smcpowers 			else
36023c57df7Smcpowers 				rv = crypto_uio_data(data, NULL, dlen,
36123c57df7Smcpowers 				    SHA2_DIGEST_DATA, dctx, update);
36223c57df7Smcpowers 
36323c57df7Smcpowers 			if (rv != CRYPTO_SUCCESS)
36423c57df7Smcpowers 				return (rv);
36523c57df7Smcpowers 
36623c57df7Smcpowers 			break;
36723c57df7Smcpowers 
36823c57df7Smcpowers 		case CRYPTO_DATA_MBLK:
36923c57df7Smcpowers 			if (flag & CRYPTO_DO_MD5)
37023c57df7Smcpowers 				rv = crypto_mblk_data(data, NULL, dlen,
37123c57df7Smcpowers 				    MD5_DIGEST_DATA, dctx, update);
37223c57df7Smcpowers 
37323c57df7Smcpowers 			else if (flag & CRYPTO_DO_SHA1)
37423c57df7Smcpowers 				rv = crypto_mblk_data(data, NULL, dlen,
37523c57df7Smcpowers 				    SHA1_DIGEST_DATA, dctx, update);
37623c57df7Smcpowers 
37723c57df7Smcpowers 			else
37823c57df7Smcpowers 				rv = crypto_mblk_data(data, NULL, dlen,
37923c57df7Smcpowers 				    SHA2_DIGEST_DATA, dctx, update);
38023c57df7Smcpowers 
38123c57df7Smcpowers 			if (rv != CRYPTO_SUCCESS)
38223c57df7Smcpowers 				return (rv);
38323c57df7Smcpowers 
38423c57df7Smcpowers 			break;
38523c57df7Smcpowers 		}
38623c57df7Smcpowers 	}
38723c57df7Smcpowers 
38823c57df7Smcpowers dofinal:
38923c57df7Smcpowers 	if (flag & CRYPTO_DO_FINAL) {
39023c57df7Smcpowers 		final(digest, dctx);
39123c57df7Smcpowers 	}
39223c57df7Smcpowers 
39323c57df7Smcpowers 	return (CRYPTO_SUCCESS);
39423c57df7Smcpowers }
39523c57df7Smcpowers 
39623c57df7Smcpowers int
39723c57df7Smcpowers crypto_update_iov(void *ctx, crypto_data_t *input, crypto_data_t *output,
39823c57df7Smcpowers     int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
39923c57df7Smcpowers     void (*copy_block)(uint8_t *, uint64_t *))
40023c57df7Smcpowers {
40123c57df7Smcpowers 	common_ctx_t *common_ctx = ctx;
40223c57df7Smcpowers 	int rv;
40323c57df7Smcpowers 
40423c57df7Smcpowers 	if (input->cd_miscdata != NULL) {
40523c57df7Smcpowers 		copy_block((uint8_t *)input->cd_miscdata,
40623c57df7Smcpowers 		    &common_ctx->cc_iv[0]);
40723c57df7Smcpowers 	}
40823c57df7Smcpowers 
40923c57df7Smcpowers 	if (input->cd_raw.iov_len < input->cd_length)
41023c57df7Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
41123c57df7Smcpowers 
41223c57df7Smcpowers 	rv = (cipher)(ctx, input->cd_raw.iov_base + input->cd_offset,
41323c57df7Smcpowers 	    input->cd_length, (input == output) ? NULL : output);
41423c57df7Smcpowers 
41523c57df7Smcpowers 	return (rv);
41623c57df7Smcpowers }
41723c57df7Smcpowers 
41823c57df7Smcpowers int
41923c57df7Smcpowers crypto_update_uio(void *ctx, crypto_data_t *input, crypto_data_t *output,
42023c57df7Smcpowers     int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
42123c57df7Smcpowers     void (*copy_block)(uint8_t *, uint64_t *))
42223c57df7Smcpowers {
42323c57df7Smcpowers 	common_ctx_t *common_ctx = ctx;
42423c57df7Smcpowers 	uio_t *uiop = input->cd_uio;
42523c57df7Smcpowers 	off_t offset = input->cd_offset;
42623c57df7Smcpowers 	size_t length = input->cd_length;
42723c57df7Smcpowers 	uint_t vec_idx;
42823c57df7Smcpowers 	size_t cur_len;
42923c57df7Smcpowers 
43023c57df7Smcpowers 	if (input->cd_miscdata != NULL) {
43123c57df7Smcpowers 		copy_block((uint8_t *)input->cd_miscdata,
43223c57df7Smcpowers 		    &common_ctx->cc_iv[0]);
43323c57df7Smcpowers 	}
43423c57df7Smcpowers 
43523c57df7Smcpowers 	if (input->cd_uio->uio_segflg != UIO_SYSSPACE) {
43623c57df7Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
43723c57df7Smcpowers 	}
43823c57df7Smcpowers 
43923c57df7Smcpowers 	/*
44023c57df7Smcpowers 	 * Jump to the first iovec containing data to be
44123c57df7Smcpowers 	 * processed.
44223c57df7Smcpowers 	 */
44323c57df7Smcpowers 	for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
44423c57df7Smcpowers 	    offset >= uiop->uio_iov[vec_idx].iov_len;
44523c57df7Smcpowers 	    offset -= uiop->uio_iov[vec_idx++].iov_len)
44623c57df7Smcpowers 		;
44723c57df7Smcpowers 	if (vec_idx == uiop->uio_iovcnt) {
44823c57df7Smcpowers 		/*
44923c57df7Smcpowers 		 * The caller specified an offset that is larger than the
45023c57df7Smcpowers 		 * total size of the buffers it provided.
45123c57df7Smcpowers 		 */
45223c57df7Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
45323c57df7Smcpowers 	}
45423c57df7Smcpowers 
45523c57df7Smcpowers 	/*
45623c57df7Smcpowers 	 * Now process the iovecs.
45723c57df7Smcpowers 	 */
45823c57df7Smcpowers 	while (vec_idx < uiop->uio_iovcnt && length > 0) {
45923c57df7Smcpowers 		cur_len = MIN(uiop->uio_iov[vec_idx].iov_len -
46023c57df7Smcpowers 		    offset, length);
46123c57df7Smcpowers 
46223c57df7Smcpowers 		(cipher)(ctx, uiop->uio_iov[vec_idx].iov_base + offset,
46323c57df7Smcpowers 		    cur_len, (input == output) ? NULL : output);
46423c57df7Smcpowers 
46523c57df7Smcpowers 		length -= cur_len;
46623c57df7Smcpowers 		vec_idx++;
46723c57df7Smcpowers 		offset = 0;
46823c57df7Smcpowers 	}
46923c57df7Smcpowers 
47023c57df7Smcpowers 	if (vec_idx == uiop->uio_iovcnt && length > 0) {
47123c57df7Smcpowers 		/*
47223c57df7Smcpowers 		 * The end of the specified iovec's was reached but
47323c57df7Smcpowers 		 * the length requested could not be processed, i.e.
47423c57df7Smcpowers 		 * The caller requested to digest more data than it provided.
47523c57df7Smcpowers 		 */
47623c57df7Smcpowers 
47723c57df7Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
47823c57df7Smcpowers 	}
47923c57df7Smcpowers 
48023c57df7Smcpowers 	return (CRYPTO_SUCCESS);
48123c57df7Smcpowers }
48223c57df7Smcpowers 
48323c57df7Smcpowers int
48423c57df7Smcpowers crypto_update_mp(void *ctx, crypto_data_t *input, crypto_data_t *output,
48523c57df7Smcpowers     int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
48623c57df7Smcpowers     void (*copy_block)(uint8_t *, uint64_t *))
48723c57df7Smcpowers {
48823c57df7Smcpowers 	common_ctx_t *common_ctx = ctx;
48923c57df7Smcpowers 	off_t offset = input->cd_offset;
49023c57df7Smcpowers 	size_t length = input->cd_length;
49123c57df7Smcpowers 	mblk_t *mp;
49223c57df7Smcpowers 	size_t cur_len;
49323c57df7Smcpowers 
49423c57df7Smcpowers 	if (input->cd_miscdata != NULL) {
49523c57df7Smcpowers 		copy_block((uint8_t *)input->cd_miscdata,
49623c57df7Smcpowers 		    &common_ctx->cc_iv[0]);
49723c57df7Smcpowers 	}
49823c57df7Smcpowers 
49923c57df7Smcpowers 	/*
50023c57df7Smcpowers 	 * Jump to the first mblk_t containing data to be processed.
50123c57df7Smcpowers 	 */
50223c57df7Smcpowers 	for (mp = input->cd_mp; mp != NULL && offset >= MBLKL(mp);
50323c57df7Smcpowers 	    offset -= MBLKL(mp), mp = mp->b_cont)
50423c57df7Smcpowers 		;
50523c57df7Smcpowers 	if (mp == NULL) {
50623c57df7Smcpowers 		/*
50723c57df7Smcpowers 		 * The caller specified an offset that is larger than the
50823c57df7Smcpowers 		 * total size of the buffers it provided.
50923c57df7Smcpowers 		 */
51023c57df7Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
51123c57df7Smcpowers 	}
51223c57df7Smcpowers 
51323c57df7Smcpowers 	/*
51423c57df7Smcpowers 	 * Now do the processing on the mblk chain.
51523c57df7Smcpowers 	 */
51623c57df7Smcpowers 	while (mp != NULL && length > 0) {
51723c57df7Smcpowers 		cur_len = MIN(MBLKL(mp) - offset, length);
51823c57df7Smcpowers 		(cipher)(ctx, (char *)(mp->b_rptr + offset), cur_len,
51923c57df7Smcpowers 		    (input == output) ? NULL : output);
52023c57df7Smcpowers 
52123c57df7Smcpowers 		length -= cur_len;
52223c57df7Smcpowers 		offset = 0;
52323c57df7Smcpowers 		mp = mp->b_cont;
52423c57df7Smcpowers 	}
52523c57df7Smcpowers 
52623c57df7Smcpowers 	if (mp == NULL && length > 0) {
52723c57df7Smcpowers 		/*
52823c57df7Smcpowers 		 * The end of the mblk was reached but the length requested
52923c57df7Smcpowers 		 * could not be processed, i.e. The caller requested
53023c57df7Smcpowers 		 * to digest more data than it provided.
53123c57df7Smcpowers 		 */
53223c57df7Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
53323c57df7Smcpowers 	}
53423c57df7Smcpowers 
53523c57df7Smcpowers 	return (CRYPTO_SUCCESS);
53623c57df7Smcpowers }
53723c57df7Smcpowers 
53823c57df7Smcpowers /*
53923c57df7Smcpowers  * Utility routine to look up a attribute of type, 'type',
54023c57df7Smcpowers  * in the key.
54123c57df7Smcpowers  */
54223c57df7Smcpowers int
54323c57df7Smcpowers crypto_get_key_attr(crypto_key_t *key, crypto_attr_type_t type,
54423c57df7Smcpowers     uchar_t **value, ssize_t *value_len)
54523c57df7Smcpowers {
54623c57df7Smcpowers 	int i;
54723c57df7Smcpowers 
54823c57df7Smcpowers 	ASSERT(key->ck_format == CRYPTO_KEY_ATTR_LIST);
54923c57df7Smcpowers 	for (i = 0; i < key->ck_count; i++) {
55023c57df7Smcpowers 		if (key->ck_attrs[i].oa_type == type) {
55123c57df7Smcpowers 			*value = (uchar_t *)key->ck_attrs[i].oa_value;
55223c57df7Smcpowers 			*value_len = key->ck_attrs[i].oa_value_len;
55323c57df7Smcpowers 			return (CRYPTO_SUCCESS);
55423c57df7Smcpowers 		}
55523c57df7Smcpowers 	}
55623c57df7Smcpowers 
55723c57df7Smcpowers 	return (CRYPTO_FAILED);
55823c57df7Smcpowers }
559