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