5869 Need AES CMAC support in KCF+PKCS11
[unleashed.git] / usr / src / uts / common / crypto / core / kcf_prov_lib.c
blob65322bfb3c62da5d5e5befffada59086a0e5fe3a
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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>
38 * Utility routine to get data from a crypto_data structure.
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.
43 int
44 crypto_get_input_data(crypto_data_t *input, uchar_t **dptr, uchar_t *buf)
46 int rv;
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;
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;
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;
70 default:
71 return (CRYPTO_ARGUMENTS_BAD);
74 return (CRYPTO_SUCCESS);
77 int
78 crypto_copy_key_to_ctx(crypto_key_t *in_key, crypto_key_t **out_key,
79 size_t *out_size, int kmflag)
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;
87 ASSERT(in_key->ck_format == CRYPTO_KEY_ATTR_LIST);
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));
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));
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));
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 */
122 return (CRYPTO_SUCCESS);
126 crypto_digest_data(crypto_data_t *data, void *dctx, uchar_t *digest,
127 void (*update)(), void (*final)(), uchar_t flag)
129 int rv, dlen;
130 uchar_t *dptr;
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;
139 dlen = data->cd_length;
141 if (flag & CRYPTO_DO_UPDATE) {
143 switch (data->cd_format) {
144 case CRYPTO_DATA_RAW:
145 dptr = (uchar_t *)(data->cd_raw.iov_base +
146 data->cd_offset);
148 update(dctx, dptr, dlen);
150 break;
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);
157 else if (flag & CRYPTO_DO_SHA1)
158 rv = crypto_uio_data(data, NULL, dlen,
159 SHA1_DIGEST_DATA, dctx, update);
161 else
162 rv = crypto_uio_data(data, NULL, dlen,
163 SHA2_DIGEST_DATA, dctx, update);
165 if (rv != CRYPTO_SUCCESS)
166 return (rv);
168 break;
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);
175 else if (flag & CRYPTO_DO_SHA1)
176 rv = crypto_mblk_data(data, NULL, dlen,
177 SHA1_DIGEST_DATA, dctx, update);
179 else
180 rv = crypto_mblk_data(data, NULL, dlen,
181 SHA2_DIGEST_DATA, dctx, update);
183 if (rv != CRYPTO_SUCCESS)
184 return (rv);
186 break;
190 dofinal:
191 if (flag & CRYPTO_DO_FINAL) {
192 final(digest, dctx);
195 return (CRYPTO_SUCCESS);
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 *))
203 common_ctx_t *common_ctx = ctx;
204 int rv;
206 if (input->cd_miscdata != NULL) {
207 copy_block((uint8_t *)input->cd_miscdata,
208 &common_ctx->cc_iv[0]);
211 if (input->cd_raw.iov_len < input->cd_length)
212 return (CRYPTO_ARGUMENTS_BAD);
214 rv = (cipher)(ctx, input->cd_raw.iov_base + input->cd_offset,
215 input->cd_length, (input == output) ? NULL : output);
217 return (rv);
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 *))
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;
232 if (input->cd_miscdata != NULL) {
233 copy_block((uint8_t *)input->cd_miscdata,
234 &common_ctx->cc_iv[0]);
237 if (input->cd_uio->uio_segflg != UIO_SYSSPACE) {
238 return (CRYPTO_ARGUMENTS_BAD);
242 * Jump to the first iovec containing data to be
243 * processed.
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)
249 if (vec_idx == uiop->uio_iovcnt) {
251 * The caller specified an offset that is larger than the
252 * total size of the buffers it provided.
254 return (CRYPTO_DATA_LEN_RANGE);
258 * Now process the iovecs.
260 while (vec_idx < uiop->uio_iovcnt && length > 0) {
261 cur_len = MIN(uiop->uio_iov[vec_idx].iov_len -
262 offset, length);
264 (cipher)(ctx, uiop->uio_iov[vec_idx].iov_base + offset,
265 cur_len, (input == output) ? NULL : output);
267 length -= cur_len;
268 vec_idx++;
269 offset = 0;
272 if (vec_idx == uiop->uio_iovcnt && length > 0) {
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.
279 return (CRYPTO_DATA_LEN_RANGE);
282 return (CRYPTO_SUCCESS);
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 *))
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;
296 if (input->cd_miscdata != NULL) {
297 copy_block((uint8_t *)input->cd_miscdata,
298 &common_ctx->cc_iv[0]);
302 * Jump to the first mblk_t containing data to be processed.
304 for (mp = input->cd_mp; mp != NULL && offset >= MBLKL(mp);
305 offset -= MBLKL(mp), mp = mp->b_cont)
307 if (mp == NULL) {
309 * The caller specified an offset that is larger than the
310 * total size of the buffers it provided.
312 return (CRYPTO_DATA_LEN_RANGE);
316 * Now do the processing on the mblk chain.
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);
323 length -= cur_len;
324 offset = 0;
325 mp = mp->b_cont;
328 if (mp == NULL && length > 0) {
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.
334 return (CRYPTO_DATA_LEN_RANGE);
337 return (CRYPTO_SUCCESS);
341 * Utility routine to look up a attribute of type, 'type',
342 * in the key.
345 crypto_get_key_attr(crypto_key_t *key, crypto_attr_type_t type,
346 uchar_t **value, ssize_t *value_len)
348 int i;
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);
359 return (CRYPTO_FAILED);