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 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 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 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 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 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) { 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 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 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