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