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 2009 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 apply the command, 'cmd', to the 39 * data in the uio structure. 40 */ 41 int 42 crypto_uio_data(crypto_data_t *data, uchar_t *buf, int len, cmd_type_t cmd, 43 void *digest_ctx, void (*update)()) 44 { 45 uio_t *uiop = data->cd_uio; 46 off_t offset = data->cd_offset; 47 size_t length = len; 48 uint_t vec_idx; 49 size_t cur_len; 50 uchar_t *datap; 51 52 ASSERT(data->cd_format == CRYPTO_DATA_UIO); 53 if (uiop->uio_segflg != UIO_SYSSPACE) { 54 return (CRYPTO_ARGUMENTS_BAD); 55 } 56 57 /* 58 * Jump to the first iovec containing data to be 59 * processed. 60 */ 61 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 62 offset >= uiop->uio_iov[vec_idx].iov_len; 63 offset -= uiop->uio_iov[vec_idx++].iov_len) 64 ; 65 66 if (vec_idx == uiop->uio_iovcnt) { 67 /* 68 * The caller specified an offset that is larger than 69 * the total size of the buffers it provided. 70 */ 71 return (CRYPTO_DATA_LEN_RANGE); 72 } 73 74 while (vec_idx < uiop->uio_iovcnt && length > 0) { 75 cur_len = MIN(uiop->uio_iov[vec_idx].iov_len - 76 offset, length); 77 78 datap = (uchar_t *)(uiop->uio_iov[vec_idx].iov_base + 79 offset); 80 switch (cmd) { 81 case COPY_FROM_DATA: 82 bcopy(datap, buf, cur_len); 83 buf += cur_len; 84 break; 85 case COPY_TO_DATA: 86 bcopy(buf, datap, cur_len); 87 buf += cur_len; 88 break; 89 case COMPARE_TO_DATA: 90 if (bcmp(datap, buf, cur_len)) 91 return (CRYPTO_SIGNATURE_INVALID); 92 buf += cur_len; 93 break; 94 case MD5_DIGEST_DATA: 95 case SHA1_DIGEST_DATA: 96 case SHA2_DIGEST_DATA: 97 case GHASH_DATA: 98 update(digest_ctx, datap, cur_len); 99 break; 100 } 101 102 length -= cur_len; 103 vec_idx++; 104 offset = 0; 105 } 106 107 if (vec_idx == uiop->uio_iovcnt && length > 0) { 108 /* 109 * The end of the specified iovec's was reached but 110 * the length requested could not be processed. 111 */ 112 switch (cmd) { 113 case COPY_TO_DATA: 114 data->cd_length = len; 115 return (CRYPTO_BUFFER_TOO_SMALL); 116 default: 117 return (CRYPTO_DATA_LEN_RANGE); 118 } 119 } 120 121 return (CRYPTO_SUCCESS); 122 } 123 124 /* 125 * Utility routine to apply the command, 'cmd', to the 126 * data in the mblk structure. 127 */ 128 int 129 crypto_mblk_data(crypto_data_t *data, uchar_t *buf, int len, cmd_type_t cmd, 130 void *digest_ctx, void (*update)()) 131 { 132 off_t offset = data->cd_offset; 133 size_t length = len; 134 mblk_t *mp; 135 size_t cur_len; 136 uchar_t *datap; 137 138 ASSERT(data->cd_format == CRYPTO_DATA_MBLK); 139 /* 140 * Jump to the first mblk_t containing data to be processed. 141 */ 142 for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp); 143 offset -= MBLKL(mp), mp = mp->b_cont) 144 ; 145 if (mp == NULL) { 146 /* 147 * The caller specified an offset that is larger 148 * than the total size of the buffers it provided. 149 */ 150 return (CRYPTO_DATA_LEN_RANGE); 151 } 152 153 /* 154 * Now do the processing on the mblk chain. 155 */ 156 while (mp != NULL && length > 0) { 157 cur_len = MIN(MBLKL(mp) - offset, length); 158 159 datap = (uchar_t *)(mp->b_rptr + offset); 160 switch (cmd) { 161 case COPY_FROM_DATA: 162 bcopy(datap, buf, cur_len); 163 buf += cur_len; 164 break; 165 case COPY_TO_DATA: 166 bcopy(buf, datap, cur_len); 167 buf += cur_len; 168 break; 169 case COMPARE_TO_DATA: 170 if (bcmp(datap, buf, cur_len)) 171 return (CRYPTO_SIGNATURE_INVALID); 172 buf += cur_len; 173 break; 174 case MD5_DIGEST_DATA: 175 case SHA1_DIGEST_DATA: 176 case SHA2_DIGEST_DATA: 177 case GHASH_DATA: 178 update(digest_ctx, datap, cur_len); 179 break; 180 } 181 182 length -= cur_len; 183 offset = 0; 184 mp = mp->b_cont; 185 } 186 187 if (mp == NULL && length > 0) { 188 /* 189 * The end of the mblk was reached but the length 190 * requested could not be processed. 191 */ 192 switch (cmd) { 193 case COPY_TO_DATA: 194 data->cd_length = len; 195 return (CRYPTO_BUFFER_TOO_SMALL); 196 default: 197 return (CRYPTO_DATA_LEN_RANGE); 198 } 199 } 200 201 return (CRYPTO_SUCCESS); 202 } 203 204 /* 205 * Utility routine to copy a buffer to a crypto_data structure. 206 */ 207 int 208 crypto_put_output_data(uchar_t *buf, crypto_data_t *output, int len) 209 { 210 switch (output->cd_format) { 211 case CRYPTO_DATA_RAW: 212 if (output->cd_raw.iov_len < len) { 213 output->cd_length = len; 214 return (CRYPTO_BUFFER_TOO_SMALL); 215 } 216 bcopy(buf, (uchar_t *)(output->cd_raw.iov_base + 217 output->cd_offset), len); 218 break; 219 220 case CRYPTO_DATA_UIO: 221 return (crypto_uio_data(output, buf, len, 222 COPY_TO_DATA, NULL, NULL)); 223 224 case CRYPTO_DATA_MBLK: 225 return (crypto_mblk_data(output, buf, len, 226 COPY_TO_DATA, NULL, NULL)); 227 228 default: 229 return (CRYPTO_ARGUMENTS_BAD); 230 } 231 232 return (CRYPTO_SUCCESS); 233 } 234 235 /* 236 * Utility routine to get data from a crypto_data structure. 237 * 238 * '*dptr' contains a pointer to a buffer on return. 'buf' 239 * is allocated by the caller and is ignored for CRYPTO_DATA_RAW case. 240 */ 241 int 242 crypto_get_input_data(crypto_data_t *input, uchar_t **dptr, uchar_t *buf) 243 { 244 int rv; 245 246 switch (input->cd_format) { 247 case CRYPTO_DATA_RAW: 248 if (input->cd_raw.iov_len < input->cd_length) 249 return (CRYPTO_ARGUMENTS_BAD); 250 *dptr = (uchar_t *)(input->cd_raw.iov_base + 251 input->cd_offset); 252 break; 253 254 case CRYPTO_DATA_UIO: 255 if ((rv = crypto_uio_data(input, buf, input->cd_length, 256 COPY_FROM_DATA, NULL, NULL)) != CRYPTO_SUCCESS) 257 return (rv); 258 *dptr = buf; 259 break; 260 261 case CRYPTO_DATA_MBLK: 262 if ((rv = crypto_mblk_data(input, buf, input->cd_length, 263 COPY_FROM_DATA, NULL, NULL)) != CRYPTO_SUCCESS) 264 return (rv); 265 *dptr = buf; 266 break; 267 268 default: 269 return (CRYPTO_ARGUMENTS_BAD); 270 } 271 272 return (CRYPTO_SUCCESS); 273 } 274 275 int 276 crypto_copy_key_to_ctx(crypto_key_t *in_key, crypto_key_t **out_key, 277 size_t *out_size, int kmflag) 278 { 279 int i, count; 280 size_t len; 281 caddr_t attr_val; 282 crypto_object_attribute_t *k_attrs = NULL; 283 crypto_key_t *key; 284 285 ASSERT(in_key->ck_format == CRYPTO_KEY_ATTR_LIST); 286 287 count = in_key->ck_count; 288 /* figure out how much memory to allocate for everything */ 289 len = sizeof (crypto_key_t) + 290 count * sizeof (crypto_object_attribute_t); 291 for (i = 0; i < count; i++) { 292 len += roundup(in_key->ck_attrs[i].oa_value_len, 293 sizeof (caddr_t)); 294 } 295 296 /* one big allocation for everything */ 297 key = kmem_alloc(len, kmflag); 298 if (key == NULL) 299 return (CRYPTO_HOST_MEMORY); 300 k_attrs = (crypto_object_attribute_t *)((caddr_t)key + 301 sizeof (crypto_key_t)); 302 303 attr_val = (caddr_t)k_attrs + 304 count * sizeof (crypto_object_attribute_t); 305 for (i = 0; i < count; i++) { 306 k_attrs[i].oa_type = in_key->ck_attrs[i].oa_type; 307 bcopy(in_key->ck_attrs[i].oa_value, attr_val, 308 in_key->ck_attrs[i].oa_value_len); 309 k_attrs[i].oa_value = attr_val; 310 k_attrs[i].oa_value_len = in_key->ck_attrs[i].oa_value_len; 311 attr_val += roundup(k_attrs[i].oa_value_len, sizeof (caddr_t)); 312 } 313 314 key->ck_format = CRYPTO_KEY_ATTR_LIST; 315 key->ck_count = count; 316 key->ck_attrs = k_attrs; 317 *out_key = key; 318 *out_size = len; /* save the size to be freed */ 319 320 return (CRYPTO_SUCCESS); 321 } 322 323 int 324 crypto_digest_data(crypto_data_t *data, void *dctx, uchar_t *digest, 325 void (*update)(), void (*final)(), uchar_t flag) 326 { 327 int rv, dlen; 328 uchar_t *dptr; 329 330 ASSERT(flag & CRYPTO_DO_MD5 || flag & CRYPTO_DO_SHA1 || 331 flag & CRYPTO_DO_SHA2); 332 if (data == NULL) { 333 ASSERT((flag & CRYPTO_DO_UPDATE) == 0); 334 goto dofinal; 335 } 336 337 dlen = data->cd_length; 338 339 if (flag & CRYPTO_DO_UPDATE) { 340 341 switch (data->cd_format) { 342 case CRYPTO_DATA_RAW: 343 dptr = (uchar_t *)(data->cd_raw.iov_base + 344 data->cd_offset); 345 346 update(dctx, dptr, dlen); 347 348 break; 349 350 case CRYPTO_DATA_UIO: 351 if (flag & CRYPTO_DO_MD5) 352 rv = crypto_uio_data(data, NULL, dlen, 353 MD5_DIGEST_DATA, dctx, update); 354 355 else if (flag & CRYPTO_DO_SHA1) 356 rv = crypto_uio_data(data, NULL, dlen, 357 SHA1_DIGEST_DATA, dctx, update); 358 359 else 360 rv = crypto_uio_data(data, NULL, dlen, 361 SHA2_DIGEST_DATA, dctx, update); 362 363 if (rv != CRYPTO_SUCCESS) 364 return (rv); 365 366 break; 367 368 case CRYPTO_DATA_MBLK: 369 if (flag & CRYPTO_DO_MD5) 370 rv = crypto_mblk_data(data, NULL, dlen, 371 MD5_DIGEST_DATA, dctx, update); 372 373 else if (flag & CRYPTO_DO_SHA1) 374 rv = crypto_mblk_data(data, NULL, dlen, 375 SHA1_DIGEST_DATA, dctx, update); 376 377 else 378 rv = crypto_mblk_data(data, NULL, dlen, 379 SHA2_DIGEST_DATA, dctx, update); 380 381 if (rv != CRYPTO_SUCCESS) 382 return (rv); 383 384 break; 385 } 386 } 387 388 dofinal: 389 if (flag & CRYPTO_DO_FINAL) { 390 final(digest, dctx); 391 } 392 393 return (CRYPTO_SUCCESS); 394 } 395 396 int 397 crypto_update_iov(void *ctx, crypto_data_t *input, crypto_data_t *output, 398 int (*cipher)(void *, caddr_t, size_t, crypto_data_t *), 399 void (*copy_block)(uint8_t *, uint64_t *)) 400 { 401 common_ctx_t *common_ctx = ctx; 402 int rv; 403 404 if (input->cd_miscdata != NULL) { 405 copy_block((uint8_t *)input->cd_miscdata, 406 &common_ctx->cc_iv[0]); 407 } 408 409 if (input->cd_raw.iov_len < input->cd_length) 410 return (CRYPTO_ARGUMENTS_BAD); 411 412 rv = (cipher)(ctx, input->cd_raw.iov_base + input->cd_offset, 413 input->cd_length, (input == output) ? NULL : output); 414 415 return (rv); 416 } 417 418 int 419 crypto_update_uio(void *ctx, crypto_data_t *input, crypto_data_t *output, 420 int (*cipher)(void *, caddr_t, size_t, crypto_data_t *), 421 void (*copy_block)(uint8_t *, uint64_t *)) 422 { 423 common_ctx_t *common_ctx = ctx; 424 uio_t *uiop = input->cd_uio; 425 off_t offset = input->cd_offset; 426 size_t length = input->cd_length; 427 uint_t vec_idx; 428 size_t cur_len; 429 430 if (input->cd_miscdata != NULL) { 431 copy_block((uint8_t *)input->cd_miscdata, 432 &common_ctx->cc_iv[0]); 433 } 434 435 if (input->cd_uio->uio_segflg != UIO_SYSSPACE) { 436 return (CRYPTO_ARGUMENTS_BAD); 437 } 438 439 /* 440 * Jump to the first iovec containing data to be 441 * processed. 442 */ 443 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 444 offset >= uiop->uio_iov[vec_idx].iov_len; 445 offset -= uiop->uio_iov[vec_idx++].iov_len) 446 ; 447 if (vec_idx == uiop->uio_iovcnt) { 448 /* 449 * The caller specified an offset that is larger than the 450 * total size of the buffers it provided. 451 */ 452 return (CRYPTO_DATA_LEN_RANGE); 453 } 454 455 /* 456 * Now process the iovecs. 457 */ 458 while (vec_idx < uiop->uio_iovcnt && length > 0) { 459 cur_len = MIN(uiop->uio_iov[vec_idx].iov_len - 460 offset, length); 461 462 (cipher)(ctx, uiop->uio_iov[vec_idx].iov_base + offset, 463 cur_len, (input == output) ? NULL : output); 464 465 length -= cur_len; 466 vec_idx++; 467 offset = 0; 468 } 469 470 if (vec_idx == uiop->uio_iovcnt && length > 0) { 471 /* 472 * The end of the specified iovec's was reached but 473 * the length requested could not be processed, i.e. 474 * The caller requested to digest more data than it provided. 475 */ 476 477 return (CRYPTO_DATA_LEN_RANGE); 478 } 479 480 return (CRYPTO_SUCCESS); 481 } 482 483 int 484 crypto_update_mp(void *ctx, crypto_data_t *input, crypto_data_t *output, 485 int (*cipher)(void *, caddr_t, size_t, crypto_data_t *), 486 void (*copy_block)(uint8_t *, uint64_t *)) 487 { 488 common_ctx_t *common_ctx = ctx; 489 off_t offset = input->cd_offset; 490 size_t length = input->cd_length; 491 mblk_t *mp; 492 size_t cur_len; 493 494 if (input->cd_miscdata != NULL) { 495 copy_block((uint8_t *)input->cd_miscdata, 496 &common_ctx->cc_iv[0]); 497 } 498 499 /* 500 * Jump to the first mblk_t containing data to be processed. 501 */ 502 for (mp = input->cd_mp; mp != NULL && offset >= MBLKL(mp); 503 offset -= MBLKL(mp), mp = mp->b_cont) 504 ; 505 if (mp == NULL) { 506 /* 507 * The caller specified an offset that is larger than the 508 * total size of the buffers it provided. 509 */ 510 return (CRYPTO_DATA_LEN_RANGE); 511 } 512 513 /* 514 * Now do the processing on the mblk chain. 515 */ 516 while (mp != NULL && length > 0) { 517 cur_len = MIN(MBLKL(mp) - offset, length); 518 (cipher)(ctx, (char *)(mp->b_rptr + offset), cur_len, 519 (input == output) ? NULL : output); 520 521 length -= cur_len; 522 offset = 0; 523 mp = mp->b_cont; 524 } 525 526 if (mp == NULL && length > 0) { 527 /* 528 * The end of the mblk was reached but the length requested 529 * could not be processed, i.e. The caller requested 530 * to digest more data than it provided. 531 */ 532 return (CRYPTO_DATA_LEN_RANGE); 533 } 534 535 return (CRYPTO_SUCCESS); 536 } 537 538 /* 539 * Utility routine to look up a attribute of type, 'type', 540 * in the key. 541 */ 542 int 543 crypto_get_key_attr(crypto_key_t *key, crypto_attr_type_t type, 544 uchar_t **value, ssize_t *value_len) 545 { 546 int i; 547 548 ASSERT(key->ck_format == CRYPTO_KEY_ATTR_LIST); 549 for (i = 0; i < key->ck_count; i++) { 550 if (key->ck_attrs[i].oa_type == type) { 551 *value = (uchar_t *)key->ck_attrs[i].oa_value; 552 *value_len = key->ck_attrs[i].oa_value_len; 553 return (CRYPTO_SUCCESS); 554 } 555 } 556 557 return (CRYPTO_FAILED); 558 } 559