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 2007 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 /* 29 * RC4 provider for the Kernel Cryptographic Framework (KCF) 30 */ 31 32 #include <sys/types.h> 33 #include <sys/systm.h> 34 #include <sys/modctl.h> 35 #include <sys/cmn_err.h> 36 #include <sys/ddi.h> 37 #include <sys/crypto/common.h> 38 #include <sys/crypto/spi.h> 39 #include <sys/sysmacros.h> 40 #include <sys/strsun.h> 41 #include <arcfour.h> 42 43 extern struct mod_ops mod_cryptoops; 44 45 /* 46 * Module linkage information for the kernel. 47 */ 48 static struct modlcrypto modlcrypto = { 49 &mod_cryptoops, 50 "RC4 Kernel SW Provider %I%" 51 }; 52 53 static struct modlinkage modlinkage = { 54 MODREV_1, 55 (void *)&modlcrypto, 56 NULL 57 }; 58 59 /* 60 * CSPI information (entry points, provider info, etc.) 61 */ 62 63 #define RC4_MECH_INFO_TYPE 0 64 /* 65 * Mechanism info structure passed to KCF during registration. 66 */ 67 static crypto_mech_info_t rc4_mech_info_tab[] = { 68 {SUN_CKM_RC4, RC4_MECH_INFO_TYPE, 69 CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC | 70 CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC, 71 ARCFOUR_MIN_KEY_BITS, ARCFOUR_MAX_KEY_BITS, 72 CRYPTO_KEYSIZE_UNIT_IN_BITS | CRYPTO_CAN_SHARE_OPSTATE} 73 }; 74 75 static void rc4_provider_status(crypto_provider_handle_t, uint_t *); 76 77 static crypto_control_ops_t rc4_control_ops = { 78 rc4_provider_status 79 }; 80 81 static int rc4_common_init(crypto_ctx_t *, crypto_mechanism_t *, 82 crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 83 84 static int rc4_crypt_update(crypto_ctx_t *, crypto_data_t *, crypto_data_t *, 85 crypto_req_handle_t); 86 87 static int rc4_crypt_final(crypto_ctx_t *, crypto_data_t *, 88 crypto_req_handle_t); 89 90 static int rc4_crypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *, 91 crypto_req_handle_t); 92 93 static int rc4_crypt_atomic(crypto_provider_handle_t, crypto_session_id_t, 94 crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, 95 crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 96 97 98 static crypto_cipher_ops_t rc4_cipher_ops = { 99 rc4_common_init, 100 rc4_crypt, 101 rc4_crypt_update, 102 rc4_crypt_final, 103 rc4_crypt_atomic, 104 rc4_common_init, 105 rc4_crypt, 106 rc4_crypt_update, 107 rc4_crypt_final, 108 rc4_crypt_atomic 109 }; 110 111 static int rc4_free_context(crypto_ctx_t *); 112 113 static crypto_ctx_ops_t rc4_ctx_ops = { 114 NULL, 115 rc4_free_context 116 }; 117 118 static crypto_ops_t rc4_crypto_ops = { 119 &rc4_control_ops, 120 NULL, 121 &rc4_cipher_ops, 122 NULL, 123 NULL, 124 NULL, 125 NULL, 126 NULL, 127 NULL, 128 NULL, 129 NULL, 130 NULL, 131 NULL, 132 &rc4_ctx_ops 133 }; 134 135 static crypto_provider_info_t rc4_prov_info = { 136 CRYPTO_SPI_VERSION_1, 137 "RC4 Software Provider", 138 CRYPTO_SW_PROVIDER, 139 {&modlinkage}, 140 NULL, 141 &rc4_crypto_ops, 142 sizeof (rc4_mech_info_tab)/sizeof (crypto_mech_info_t), 143 rc4_mech_info_tab 144 }; 145 146 static crypto_kcf_provider_handle_t rc4_prov_handle = NULL; 147 148 static mblk_t *advance_position(mblk_t *, off_t, uchar_t **); 149 static int crypto_arcfour_crypt(ARCFour_key *, uchar_t *, crypto_data_t *, 150 int); 151 152 int 153 _init(void) 154 { 155 int ret; 156 157 /* 158 * Register with KCF. If the registration fails, log an error 159 * and uninstall the module. 160 */ 161 if ((ret = crypto_register_provider(&rc4_prov_info, 162 &rc4_prov_handle)) != CRYPTO_SUCCESS) { 163 cmn_err(CE_WARN, "_init: crypto_register_provider(%s)" 164 "failed (0x%x)", "arcfour", ret); 165 return (EACCES); 166 } 167 168 if ((ret = mod_install(&modlinkage)) != 0) { 169 int rv; 170 171 ASSERT(rc4_prov_handle != NULL); 172 /* We should not return if the unregister returns busy. */ 173 while ((rv = crypto_unregister_provider(rc4_prov_handle)) 174 == CRYPTO_BUSY) { 175 cmn_err(CE_WARN, "_init: crypto_unregister_provider(%s)" 176 " failed (0x%x). Retrying.", "arcfour", rv); 177 /* wait 10 seconds and try again. */ 178 delay(10 * drv_usectohz(1000000)); 179 } 180 } 181 182 return (0); 183 } 184 185 int 186 _fini(void) 187 { 188 int ret; 189 190 /* 191 * Unregister from KCF if previous registration succeeded. 192 */ 193 if (rc4_prov_handle != NULL) { 194 if ((ret = crypto_unregister_provider(rc4_prov_handle)) != 195 CRYPTO_SUCCESS) { 196 cmn_err(CE_WARN, "_fini: crypto_unregister_provider(%s)" 197 " failed (0x%x)", "arcfour", ret); 198 return (EBUSY); 199 } 200 rc4_prov_handle = NULL; 201 } 202 203 return (mod_remove(&modlinkage)); 204 } 205 206 int 207 _info(struct modinfo *modinfop) 208 { 209 return (mod_info(&modlinkage, modinfop)); 210 } 211 212 213 /* 214 * KCF software provider control entry points. 215 */ 216 /* ARGSUSED */ 217 static void 218 rc4_provider_status(crypto_provider_handle_t provider, uint_t *status) 219 { 220 *status = CRYPTO_PROVIDER_READY; 221 } 222 223 /* ARGSUSED */ 224 static int 225 rc4_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 226 crypto_key_t *key, crypto_spi_ctx_template_t template, 227 crypto_req_handle_t req) 228 { 229 230 /* EXPORT DELETE START */ 231 232 ARCFour_key *keystream; 233 234 if ((mechanism)->cm_type != RC4_MECH_INFO_TYPE) 235 return (CRYPTO_MECHANISM_INVALID); 236 237 if (key->ck_format != CRYPTO_KEY_RAW) 238 return (CRYPTO_KEY_TYPE_INCONSISTENT); 239 240 if (key->ck_length < ARCFOUR_MIN_KEY_BITS || 241 key->ck_length > ARCFOUR_MAX_KEY_BITS) { 242 return (CRYPTO_KEY_SIZE_RANGE); 243 } 244 245 /* 246 * Allocate an RC4 key stream. 247 */ 248 if ((keystream = kmem_alloc(sizeof (ARCFour_key), 249 crypto_kmflag(req))) == NULL) 250 return (CRYPTO_HOST_MEMORY); 251 252 arcfour_key_init(keystream, key->ck_data, key->ck_length >> 3); 253 254 ctx->cc_provider_private = keystream; 255 256 /* EXPORT DELETE END */ 257 258 return (CRYPTO_SUCCESS); 259 } 260 261 static int 262 rc4_crypt(crypto_ctx_t *ctx, crypto_data_t *input, crypto_data_t *output, 263 crypto_req_handle_t req) 264 { 265 int ret; 266 267 ret = rc4_crypt_update(ctx, input, output, req); 268 269 if (ret != CRYPTO_BUFFER_TOO_SMALL) 270 (void) rc4_free_context(ctx); 271 272 return (ret); 273 } 274 275 /* ARGSUSED */ 276 static int 277 rc4_crypt_update(crypto_ctx_t *ctx, crypto_data_t *input, crypto_data_t *output, 278 crypto_req_handle_t req) 279 { 280 int ret = CRYPTO_SUCCESS; 281 282 /* EXPORT DELETE START */ 283 284 ARCFour_key *key; 285 off_t saveoffset; 286 287 ASSERT(ctx->cc_provider_private != NULL); 288 289 if ((ctx->cc_flags & CRYPTO_USE_OPSTATE) && ctx->cc_opstate != NULL) 290 key = ctx->cc_opstate; 291 else 292 key = ctx->cc_provider_private; 293 294 /* Simple case: in-line encipherment */ 295 296 if (output == NULL) { 297 switch (input->cd_format) { 298 case CRYPTO_DATA_RAW: { 299 char *start, *end; 300 start = input->cd_raw.iov_base + input->cd_offset; 301 302 end = input->cd_raw.iov_base + input->cd_raw.iov_len; 303 304 if (start + input->cd_length > end) 305 return (CRYPTO_DATA_INVALID); 306 307 arcfour_crypt(key, (uchar_t *)start, (uchar_t *)start, 308 input->cd_length); 309 break; 310 } 311 case CRYPTO_DATA_MBLK: { 312 uchar_t *start, *end; 313 size_t len, left; 314 mblk_t *mp = input->cd_mp, *mp1, *mp2; 315 316 ASSERT(mp != NULL); 317 318 mp1 = advance_position(mp, input->cd_offset, &start); 319 320 if (mp1 == NULL) 321 return (CRYPTO_DATA_LEN_RANGE); 322 323 mp2 = advance_position(mp, input->cd_offset + 324 input->cd_length, &end); 325 326 if (mp2 == NULL) 327 return (CRYPTO_DATA_LEN_RANGE); 328 329 left = input->cd_length; 330 while (mp1 != NULL) { 331 if (mp1->b_wptr - start > left) { 332 len = left; 333 arcfour_crypt(key, start, start, len); 334 mp1 = NULL; 335 } else { 336 len = mp1->b_wptr - start; 337 arcfour_crypt(key, start, start, len); 338 mp1 = mp1->b_cont; 339 start = mp1->b_rptr; 340 left -= len; 341 } 342 } 343 break; 344 } 345 case CRYPTO_DATA_UIO: { 346 uio_t *uiop = input->cd_uio; 347 off_t offset = input->cd_offset; 348 size_t length = input->cd_length; 349 uint_t vec_idx; 350 size_t cur_len; 351 352 /* 353 * Jump to the first iovec containing data to be 354 * processed. 355 */ 356 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 357 offset >= uiop->uio_iov[vec_idx].iov_len; 358 offset -= uiop->uio_iov[vec_idx++].iov_len); 359 if (vec_idx == uiop->uio_iovcnt) { 360 return (CRYPTO_DATA_LEN_RANGE); 361 } 362 363 /* 364 * Now process the iovecs. 365 */ 366 while (vec_idx < uiop->uio_iovcnt && length > 0) { 367 uchar_t *start; 368 iovec_t *iovp = &(uiop->uio_iov[vec_idx]); 369 370 cur_len = MIN(iovp->iov_len - offset, length); 371 372 start = (uchar_t *)(iovp->iov_base + offset); 373 arcfour_crypt(key, start + offset, 374 start + offset, cur_len); 375 376 length -= cur_len; 377 vec_idx++; 378 offset = 0; 379 } 380 381 if (vec_idx == uiop->uio_iovcnt && length > 0) { 382 383 return (CRYPTO_DATA_LEN_RANGE); 384 } 385 break; 386 } 387 } 388 return (CRYPTO_SUCCESS); 389 } 390 391 /* 392 * We need to just return the length needed to store the output. 393 * We should not destroy the context for the following case. 394 */ 395 396 if (input->cd_length > output->cd_length) { 397 output->cd_length = input->cd_length; 398 return (CRYPTO_BUFFER_TOO_SMALL); 399 } 400 401 saveoffset = output->cd_offset; 402 403 switch (input->cd_format) { 404 case CRYPTO_DATA_RAW: { 405 char *start, *end; 406 start = input->cd_raw.iov_base + input->cd_offset; 407 408 end = input->cd_raw.iov_base + input->cd_raw.iov_len; 409 410 if (start + input->cd_length > end) 411 return (CRYPTO_DATA_LEN_RANGE); 412 413 ret = crypto_arcfour_crypt(key, (uchar_t *)start, output, 414 input->cd_length); 415 416 if (ret != CRYPTO_SUCCESS) 417 return (ret); 418 break; 419 } 420 case CRYPTO_DATA_MBLK: { 421 uchar_t *start, *end; 422 size_t len, left; 423 mblk_t *mp = input->cd_mp, *mp1, *mp2; 424 425 ASSERT(mp != NULL); 426 427 mp1 = advance_position(mp, input->cd_offset, &start); 428 429 if (mp1 == NULL) 430 return (CRYPTO_DATA_LEN_RANGE); 431 432 mp2 = advance_position(mp, input->cd_offset + input->cd_length, 433 &end); 434 435 if (mp2 == NULL) 436 return (CRYPTO_DATA_LEN_RANGE); 437 438 left = input->cd_length; 439 while (mp1 != NULL) { 440 if (mp1->b_wptr - start > left) { 441 len = left; 442 ret = crypto_arcfour_crypt(key, start, output, 443 len); 444 if (ret != CRYPTO_SUCCESS) 445 return (ret); 446 mp1 = NULL; 447 } else { 448 len = mp1->b_wptr - start; 449 ret = crypto_arcfour_crypt(key, start, output, 450 len); 451 if (ret != CRYPTO_SUCCESS) 452 return (ret); 453 mp1 = mp1->b_cont; 454 start = mp1->b_rptr; 455 left -= len; 456 output->cd_offset += len; 457 } 458 } 459 break; 460 } 461 case CRYPTO_DATA_UIO: { 462 uio_t *uiop = input->cd_uio; 463 off_t offset = input->cd_offset; 464 size_t length = input->cd_length; 465 uint_t vec_idx; 466 size_t cur_len; 467 468 /* 469 * Jump to the first iovec containing data to be 470 * processed. 471 */ 472 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 473 offset >= uiop->uio_iov[vec_idx].iov_len; 474 offset -= uiop->uio_iov[vec_idx++].iov_len); 475 if (vec_idx == uiop->uio_iovcnt) { 476 return (CRYPTO_DATA_LEN_RANGE); 477 } 478 479 /* 480 * Now process the iovecs. 481 */ 482 while (vec_idx < uiop->uio_iovcnt && length > 0) { 483 uchar_t *start; 484 iovec_t *iovp = &(uiop->uio_iov[vec_idx]); 485 cur_len = MIN(iovp->iov_len - offset, length); 486 487 start = (uchar_t *)(iovp->iov_base + offset); 488 ret = crypto_arcfour_crypt(key, start + offset, 489 output, cur_len); 490 if (ret != CRYPTO_SUCCESS) 491 return (ret); 492 493 length -= cur_len; 494 vec_idx++; 495 offset = 0; 496 output->cd_offset += cur_len; 497 } 498 499 if (vec_idx == uiop->uio_iovcnt && length > 0) { 500 501 return (CRYPTO_DATA_LEN_RANGE); 502 } 503 } 504 } 505 506 output->cd_offset = saveoffset; 507 output->cd_length = input->cd_length; 508 509 /* EXPORT DELETE END */ 510 511 return (ret); 512 } 513 514 /* ARGSUSED */ 515 static int rc4_crypt_final(crypto_ctx_t *ctx, crypto_data_t *data, 516 crypto_req_handle_t req) 517 { 518 /* No final part for streams ciphers. Just free the context */ 519 if (data != NULL) 520 data->cd_length = 0; 521 522 return (rc4_free_context(ctx)); 523 } 524 525 /* ARGSUSED */ 526 static int 527 rc4_crypt_atomic(crypto_provider_handle_t handle, crypto_session_id_t session, 528 crypto_mechanism_t *mechanism, crypto_key_t *key, crypto_data_t *input, 529 crypto_data_t *output, crypto_spi_ctx_template_t template, 530 crypto_req_handle_t req) 531 { 532 crypto_ctx_t ctx; 533 int ret; 534 535 bzero(&ctx, sizeof (crypto_ctx_t)); 536 ret = rc4_common_init(&ctx, mechanism, key, template, req); 537 538 if (ret != CRYPTO_SUCCESS) 539 return (ret); 540 541 ret = rc4_crypt_update(&ctx, input, output, req); 542 543 (void) rc4_free_context(&ctx); 544 545 return (ret); 546 } 547 548 /* ARGSUSED */ 549 static int 550 rc4_free_context(crypto_ctx_t *ctx) 551 { 552 553 /* EXPORT DELETE START */ 554 555 ARCFour_key *keystream = ctx->cc_provider_private; 556 557 if (keystream != NULL) { 558 bzero(keystream, sizeof (ARCFour_key)); 559 kmem_free(keystream, sizeof (ARCFour_key)); 560 ctx->cc_provider_private = NULL; 561 } 562 563 /* EXPORT DELETE END */ 564 565 return (CRYPTO_SUCCESS); 566 } 567 568 /* Encrypts a contiguous input 'in' into the 'out' crypto_data_t */ 569 570 static int 571 crypto_arcfour_crypt(ARCFour_key *key, uchar_t *in, crypto_data_t *out, 572 int length) 573 { 574 switch (out->cd_format) { 575 case CRYPTO_DATA_RAW: { 576 uchar_t *start, *end; 577 start = (uchar_t *)(out->cd_raw.iov_base + 578 out->cd_offset); 579 580 end = (uchar_t *)(out->cd_raw.iov_base + 581 out->cd_raw.iov_len); 582 583 if (start + out->cd_length > end) 584 return (CRYPTO_DATA_LEN_RANGE); 585 586 arcfour_crypt(key, in, start, length); 587 588 return (CRYPTO_SUCCESS); 589 } 590 case CRYPTO_DATA_MBLK: { 591 uchar_t *start, *end; 592 size_t len, left; 593 mblk_t *mp = out->cd_mp, *mp1, *mp2; 594 595 ASSERT(mp != NULL); 596 597 mp1 = advance_position(mp, out->cd_offset, &start); 598 599 if (mp1 == NULL) 600 return (CRYPTO_DATA_LEN_RANGE); 601 602 mp2 = advance_position(mp, out->cd_offset + 603 out->cd_length, &end); 604 605 if (mp2 == NULL) 606 return (CRYPTO_DATA_LEN_RANGE); 607 608 left = length; 609 while (mp1 != NULL) { 610 if (mp1->b_wptr - start > left) { 611 len = left; 612 arcfour_crypt(key, in, start, len); 613 mp1 = NULL; 614 } else { 615 len = mp1->b_wptr - start; 616 arcfour_crypt(key, in, start, len); 617 mp1 = mp1->b_cont; 618 start = mp1->b_rptr; 619 left -= len; 620 } 621 } 622 break; 623 } 624 case CRYPTO_DATA_UIO: { 625 uio_t *uiop = out->cd_uio; 626 off_t offset = out->cd_offset; 627 size_t len = length; 628 uint_t vec_idx; 629 size_t cur_len; 630 631 /* 632 * Jump to the first iovec containing data to be 633 * processed. 634 */ 635 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 636 offset >= uiop->uio_iov[vec_idx].iov_len; 637 offset -= uiop->uio_iov[vec_idx++].iov_len); 638 if (vec_idx == uiop->uio_iovcnt) { 639 return (CRYPTO_DATA_LEN_RANGE); 640 } 641 642 /* 643 * Now process the iovecs. 644 */ 645 while (vec_idx < uiop->uio_iovcnt && len > 0) { 646 uchar_t *start; 647 iovec_t *iovp = &(uiop->uio_iov[vec_idx]); 648 cur_len = MIN(iovp->iov_len - offset, len); 649 650 start = (uchar_t *)(iovp->iov_base + offset); 651 arcfour_crypt(key, start + offset, 652 start + offset, cur_len); 653 654 len -= cur_len; 655 vec_idx++; 656 offset = 0; 657 } 658 659 if (vec_idx == uiop->uio_iovcnt && len > 0) { 660 return (CRYPTO_DATA_LEN_RANGE); 661 } 662 break; 663 } 664 default: 665 return (CRYPTO_DATA_INVALID); 666 } 667 return (CRYPTO_SUCCESS); 668 } 669 670 /* 671 * Advances 'offset' bytes from the beginning of the first block in 'mp', 672 * possibly jumping across b_cont boundary 673 * '*cpp' is set to the position of the byte we want, and the block where 674 * 'cpp' is returned. 675 */ 676 static mblk_t * 677 advance_position(mblk_t *mp, off_t offset, uchar_t **cpp) 678 { 679 mblk_t *mp1 = mp; 680 size_t l; 681 off_t o = offset; 682 683 while (mp1 != NULL) { 684 l = MBLKL(mp1); 685 686 if (l <= o) { 687 o -= l; 688 mp1 = mp1->b_cont; 689 } else { 690 *cpp = (uchar_t *)(mp1->b_rptr + o); 691 break; 692 } 693 } 694 return (mp1); 695 } 696