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" 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 ; 360 if (vec_idx == uiop->uio_iovcnt) { 361 return (CRYPTO_DATA_LEN_RANGE); 362 } 363 364 /* 365 * Now process the iovecs. 366 */ 367 while (vec_idx < uiop->uio_iovcnt && length > 0) { 368 uchar_t *start; 369 iovec_t *iovp = &(uiop->uio_iov[vec_idx]); 370 371 cur_len = MIN(iovp->iov_len - offset, length); 372 373 start = (uchar_t *)(iovp->iov_base + offset); 374 arcfour_crypt(key, start + offset, 375 start + offset, cur_len); 376 377 length -= cur_len; 378 vec_idx++; 379 offset = 0; 380 } 381 382 if (vec_idx == uiop->uio_iovcnt && length > 0) { 383 384 return (CRYPTO_DATA_LEN_RANGE); 385 } 386 break; 387 } 388 } 389 return (CRYPTO_SUCCESS); 390 } 391 392 /* 393 * We need to just return the length needed to store the output. 394 * We should not destroy the context for the following case. 395 */ 396 397 if (input->cd_length > output->cd_length) { 398 output->cd_length = input->cd_length; 399 return (CRYPTO_BUFFER_TOO_SMALL); 400 } 401 402 saveoffset = output->cd_offset; 403 404 switch (input->cd_format) { 405 case CRYPTO_DATA_RAW: { 406 char *start, *end; 407 start = input->cd_raw.iov_base + input->cd_offset; 408 409 end = input->cd_raw.iov_base + input->cd_raw.iov_len; 410 411 if (start + input->cd_length > end) 412 return (CRYPTO_DATA_LEN_RANGE); 413 414 ret = crypto_arcfour_crypt(key, (uchar_t *)start, output, 415 input->cd_length); 416 417 if (ret != CRYPTO_SUCCESS) 418 return (ret); 419 break; 420 } 421 case CRYPTO_DATA_MBLK: { 422 uchar_t *start, *end; 423 size_t len, left; 424 mblk_t *mp = input->cd_mp, *mp1, *mp2; 425 426 ASSERT(mp != NULL); 427 428 mp1 = advance_position(mp, input->cd_offset, &start); 429 430 if (mp1 == NULL) 431 return (CRYPTO_DATA_LEN_RANGE); 432 433 mp2 = advance_position(mp, input->cd_offset + input->cd_length, 434 &end); 435 436 if (mp2 == NULL) 437 return (CRYPTO_DATA_LEN_RANGE); 438 439 left = input->cd_length; 440 while (mp1 != NULL) { 441 if (mp1->b_wptr - start > left) { 442 len = left; 443 ret = crypto_arcfour_crypt(key, start, output, 444 len); 445 if (ret != CRYPTO_SUCCESS) 446 return (ret); 447 mp1 = NULL; 448 } else { 449 len = mp1->b_wptr - start; 450 ret = crypto_arcfour_crypt(key, start, output, 451 len); 452 if (ret != CRYPTO_SUCCESS) 453 return (ret); 454 mp1 = mp1->b_cont; 455 start = mp1->b_rptr; 456 left -= len; 457 output->cd_offset += len; 458 } 459 } 460 break; 461 } 462 case CRYPTO_DATA_UIO: { 463 uio_t *uiop = input->cd_uio; 464 off_t offset = input->cd_offset; 465 size_t length = input->cd_length; 466 uint_t vec_idx; 467 size_t cur_len; 468 469 /* 470 * Jump to the first iovec containing data to be 471 * processed. 472 */ 473 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 474 offset >= uiop->uio_iov[vec_idx].iov_len; 475 offset -= uiop->uio_iov[vec_idx++].iov_len) 476 ; 477 if (vec_idx == uiop->uio_iovcnt) { 478 return (CRYPTO_DATA_LEN_RANGE); 479 } 480 481 /* 482 * Now process the iovecs. 483 */ 484 while (vec_idx < uiop->uio_iovcnt && length > 0) { 485 uchar_t *start; 486 iovec_t *iovp = &(uiop->uio_iov[vec_idx]); 487 cur_len = MIN(iovp->iov_len - offset, length); 488 489 start = (uchar_t *)(iovp->iov_base + offset); 490 ret = crypto_arcfour_crypt(key, start + offset, 491 output, cur_len); 492 if (ret != CRYPTO_SUCCESS) 493 return (ret); 494 495 length -= cur_len; 496 vec_idx++; 497 offset = 0; 498 output->cd_offset += cur_len; 499 } 500 501 if (vec_idx == uiop->uio_iovcnt && length > 0) { 502 503 return (CRYPTO_DATA_LEN_RANGE); 504 } 505 } 506 } 507 508 output->cd_offset = saveoffset; 509 output->cd_length = input->cd_length; 510 511 /* EXPORT DELETE END */ 512 513 return (ret); 514 } 515 516 /* ARGSUSED */ 517 static int rc4_crypt_final(crypto_ctx_t *ctx, crypto_data_t *data, 518 crypto_req_handle_t req) 519 { 520 /* No final part for streams ciphers. Just free the context */ 521 if (data != NULL) 522 data->cd_length = 0; 523 524 return (rc4_free_context(ctx)); 525 } 526 527 /* ARGSUSED */ 528 static int 529 rc4_crypt_atomic(crypto_provider_handle_t handle, crypto_session_id_t session, 530 crypto_mechanism_t *mechanism, crypto_key_t *key, crypto_data_t *input, 531 crypto_data_t *output, crypto_spi_ctx_template_t template, 532 crypto_req_handle_t req) 533 { 534 crypto_ctx_t ctx; 535 int ret; 536 537 bzero(&ctx, sizeof (crypto_ctx_t)); 538 ret = rc4_common_init(&ctx, mechanism, key, template, req); 539 540 if (ret != CRYPTO_SUCCESS) 541 return (ret); 542 543 ret = rc4_crypt_update(&ctx, input, output, req); 544 545 (void) rc4_free_context(&ctx); 546 547 return (ret); 548 } 549 550 /* ARGSUSED */ 551 static int 552 rc4_free_context(crypto_ctx_t *ctx) 553 { 554 555 /* EXPORT DELETE START */ 556 557 ARCFour_key *keystream = ctx->cc_provider_private; 558 559 if (keystream != NULL) { 560 bzero(keystream, sizeof (ARCFour_key)); 561 kmem_free(keystream, sizeof (ARCFour_key)); 562 ctx->cc_provider_private = NULL; 563 } 564 565 /* EXPORT DELETE END */ 566 567 return (CRYPTO_SUCCESS); 568 } 569 570 /* Encrypts a contiguous input 'in' into the 'out' crypto_data_t */ 571 572 static int 573 crypto_arcfour_crypt(ARCFour_key *key, uchar_t *in, crypto_data_t *out, 574 int length) 575 { 576 switch (out->cd_format) { 577 case CRYPTO_DATA_RAW: { 578 uchar_t *start, *end; 579 start = (uchar_t *)(out->cd_raw.iov_base + 580 out->cd_offset); 581 582 end = (uchar_t *)(out->cd_raw.iov_base + 583 out->cd_raw.iov_len); 584 585 if (start + out->cd_length > end) 586 return (CRYPTO_DATA_LEN_RANGE); 587 588 arcfour_crypt(key, in, start, length); 589 590 return (CRYPTO_SUCCESS); 591 } 592 case CRYPTO_DATA_MBLK: { 593 uchar_t *start, *end; 594 size_t len, left; 595 mblk_t *mp = out->cd_mp, *mp1, *mp2; 596 597 ASSERT(mp != NULL); 598 599 mp1 = advance_position(mp, out->cd_offset, &start); 600 601 if (mp1 == NULL) 602 return (CRYPTO_DATA_LEN_RANGE); 603 604 mp2 = advance_position(mp, out->cd_offset + 605 out->cd_length, &end); 606 607 if (mp2 == NULL) 608 return (CRYPTO_DATA_LEN_RANGE); 609 610 left = length; 611 while (mp1 != NULL) { 612 if (mp1->b_wptr - start > left) { 613 len = left; 614 arcfour_crypt(key, in, start, len); 615 mp1 = NULL; 616 } else { 617 len = mp1->b_wptr - start; 618 arcfour_crypt(key, in, start, len); 619 mp1 = mp1->b_cont; 620 start = mp1->b_rptr; 621 left -= len; 622 } 623 } 624 break; 625 } 626 case CRYPTO_DATA_UIO: { 627 uio_t *uiop = out->cd_uio; 628 off_t offset = out->cd_offset; 629 size_t len = length; 630 uint_t vec_idx; 631 size_t cur_len; 632 633 /* 634 * Jump to the first iovec containing data to be 635 * processed. 636 */ 637 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 638 offset >= uiop->uio_iov[vec_idx].iov_len; 639 offset -= uiop->uio_iov[vec_idx++].iov_len) 640 ; 641 if (vec_idx == uiop->uio_iovcnt) { 642 return (CRYPTO_DATA_LEN_RANGE); 643 } 644 645 /* 646 * Now process the iovecs. 647 */ 648 while (vec_idx < uiop->uio_iovcnt && len > 0) { 649 uchar_t *start; 650 iovec_t *iovp = &(uiop->uio_iov[vec_idx]); 651 cur_len = MIN(iovp->iov_len - offset, len); 652 653 start = (uchar_t *)(iovp->iov_base + offset); 654 arcfour_crypt(key, start + offset, 655 start + offset, cur_len); 656 657 len -= cur_len; 658 vec_idx++; 659 offset = 0; 660 } 661 662 if (vec_idx == uiop->uio_iovcnt && len > 0) { 663 return (CRYPTO_DATA_LEN_RANGE); 664 } 665 break; 666 } 667 default: 668 return (CRYPTO_DATA_INVALID); 669 } 670 return (CRYPTO_SUCCESS); 671 } 672 673 /* 674 * Advances 'offset' bytes from the beginning of the first block in 'mp', 675 * possibly jumping across b_cont boundary 676 * '*cpp' is set to the position of the byte we want, and the block where 677 * 'cpp' is returned. 678 */ 679 static mblk_t * 680 advance_position(mblk_t *mp, off_t offset, uchar_t **cpp) 681 { 682 mblk_t *mp1 = mp; 683 size_t l; 684 off_t o = offset; 685 686 while (mp1 != NULL) { 687 l = MBLKL(mp1); 688 689 if (l <= o) { 690 o -= l; 691 mp1 = mp1->b_cont; 692 } else { 693 *cpp = (uchar_t *)(mp1->b_rptr + o); 694 break; 695 } 696 } 697 return (mp1); 698 } 699