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