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