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