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 2009 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, key->ck_length >> 3); 251 252 ctx->cc_provider_private = keystream; 253 254 /* EXPORT DELETE END */ 255 256 return (CRYPTO_SUCCESS); 257 } 258 259 static int 260 rc4_crypt(crypto_ctx_t *ctx, crypto_data_t *input, crypto_data_t *output, 261 crypto_req_handle_t req) 262 { 263 int ret; 264 265 ret = rc4_crypt_update(ctx, input, output, req); 266 267 if (ret != CRYPTO_BUFFER_TOO_SMALL) 268 (void) rc4_free_context(ctx); 269 270 return (ret); 271 } 272 273 /* ARGSUSED */ 274 static int 275 rc4_crypt_update(crypto_ctx_t *ctx, crypto_data_t *input, crypto_data_t *output, 276 crypto_req_handle_t req) 277 { 278 int ret = CRYPTO_SUCCESS; 279 280 /* EXPORT DELETE START */ 281 282 ARCFour_key *key; 283 off_t saveoffset; 284 285 ASSERT(ctx->cc_provider_private != NULL); 286 287 if ((ctx->cc_flags & CRYPTO_USE_OPSTATE) && ctx->cc_opstate != NULL) 288 key = ctx->cc_opstate; 289 else 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 (_PTRDIFF(mp1->b_wptr, start) > left) { 330 len = left; 331 arcfour_crypt(key, start, start, len); 332 mp1 = NULL; 333 } else { 334 len = _PTRDIFF(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 ; 358 if (vec_idx == uiop->uio_iovcnt) { 359 return (CRYPTO_DATA_LEN_RANGE); 360 } 361 362 /* 363 * Now process the iovecs. 364 */ 365 while (vec_idx < uiop->uio_iovcnt && length > 0) { 366 uchar_t *start; 367 iovec_t *iovp = &(uiop->uio_iov[vec_idx]); 368 369 cur_len = MIN(iovp->iov_len - offset, length); 370 371 start = (uchar_t *)(iovp->iov_base + offset); 372 arcfour_crypt(key, start + offset, 373 start + offset, cur_len); 374 375 length -= cur_len; 376 vec_idx++; 377 offset = 0; 378 } 379 380 if (vec_idx == uiop->uio_iovcnt && length > 0) { 381 382 return (CRYPTO_DATA_LEN_RANGE); 383 } 384 break; 385 } 386 } 387 return (CRYPTO_SUCCESS); 388 } 389 390 /* 391 * We need to just return the length needed to store the output. 392 * We should not destroy the context for the following case. 393 */ 394 395 if (input->cd_length > output->cd_length) { 396 output->cd_length = input->cd_length; 397 return (CRYPTO_BUFFER_TOO_SMALL); 398 } 399 400 saveoffset = output->cd_offset; 401 402 switch (input->cd_format) { 403 case CRYPTO_DATA_RAW: { 404 char *start, *end; 405 start = input->cd_raw.iov_base + input->cd_offset; 406 407 end = input->cd_raw.iov_base + input->cd_raw.iov_len; 408 409 if (start + input->cd_length > end) 410 return (CRYPTO_DATA_LEN_RANGE); 411 412 ret = crypto_arcfour_crypt(key, (uchar_t *)start, output, 413 input->cd_length); 414 415 if (ret != CRYPTO_SUCCESS) 416 return (ret); 417 break; 418 } 419 case CRYPTO_DATA_MBLK: { 420 uchar_t *start, *end; 421 size_t len, left; 422 mblk_t *mp = input->cd_mp, *mp1, *mp2; 423 424 ASSERT(mp != NULL); 425 426 mp1 = advance_position(mp, input->cd_offset, &start); 427 428 if (mp1 == NULL) 429 return (CRYPTO_DATA_LEN_RANGE); 430 431 mp2 = advance_position(mp, input->cd_offset + input->cd_length, 432 &end); 433 434 if (mp2 == NULL) 435 return (CRYPTO_DATA_LEN_RANGE); 436 437 left = input->cd_length; 438 while (mp1 != NULL) { 439 if (_PTRDIFF(mp1->b_wptr, start) > left) { 440 len = left; 441 ret = crypto_arcfour_crypt(key, start, output, 442 len); 443 if (ret != CRYPTO_SUCCESS) 444 return (ret); 445 mp1 = NULL; 446 } else { 447 len = _PTRDIFF(mp1->b_wptr, start); 448 ret = crypto_arcfour_crypt(key, start, output, 449 len); 450 if (ret != CRYPTO_SUCCESS) 451 return (ret); 452 mp1 = mp1->b_cont; 453 start = mp1->b_rptr; 454 left -= len; 455 output->cd_offset += len; 456 } 457 } 458 break; 459 } 460 case CRYPTO_DATA_UIO: { 461 uio_t *uiop = input->cd_uio; 462 off_t offset = input->cd_offset; 463 size_t length = input->cd_length; 464 uint_t vec_idx; 465 size_t cur_len; 466 467 /* 468 * Jump to the first iovec containing data to be 469 * processed. 470 */ 471 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 472 offset >= uiop->uio_iov[vec_idx].iov_len; 473 offset -= uiop->uio_iov[vec_idx++].iov_len) 474 ; 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 (_PTRDIFF(mp1->b_wptr, start) > left) { 611 len = left; 612 arcfour_crypt(key, in, start, len); 613 mp1 = NULL; 614 } else { 615 len = _PTRDIFF(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 ; 639 if (vec_idx == uiop->uio_iovcnt) { 640 return (CRYPTO_DATA_LEN_RANGE); 641 } 642 643 /* 644 * Now process the iovecs. 645 */ 646 while (vec_idx < uiop->uio_iovcnt && len > 0) { 647 uchar_t *start; 648 iovec_t *iovp = &(uiop->uio_iov[vec_idx]); 649 cur_len = MIN(iovp->iov_len - offset, len); 650 651 start = (uchar_t *)(iovp->iov_base + offset); 652 arcfour_crypt(key, start + offset, 653 start + offset, cur_len); 654 655 len -= cur_len; 656 vec_idx++; 657 offset = 0; 658 } 659 660 if (vec_idx == uiop->uio_iovcnt && len > 0) { 661 return (CRYPTO_DATA_LEN_RANGE); 662 } 663 break; 664 } 665 default: 666 return (CRYPTO_DATA_INVALID); 667 } 668 return (CRYPTO_SUCCESS); 669 } 670 671 /* 672 * Advances 'offset' bytes from the beginning of the first block in 'mp', 673 * possibly jumping across b_cont boundary 674 * '*cpp' is set to the position of the byte we want, and the block where 675 * 'cpp' is returned. 676 */ 677 static mblk_t * 678 advance_position(mblk_t *mp, off_t offset, uchar_t **cpp) 679 { 680 mblk_t *mp1 = mp; 681 size_t l; 682 off_t o = offset; 683 684 while (mp1 != NULL) { 685 l = MBLKL(mp1); 686 687 if (l <= o) { 688 o -= l; 689 mp1 = mp1->b_cont; 690 } else { 691 *cpp = (uchar_t *)(mp1->b_rptr + o); 692 break; 693 } 694 } 695 return (mp1); 696 } 697