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 if ((ret = mod_install(&modlinkage)) != 0) 156 return (ret); 157 158 /* Register with KCF. If the registration fails, remove the module. */ 159 if (crypto_register_provider(&rc4_prov_info, &rc4_prov_handle)) { 160 (void) mod_remove(&modlinkage); 161 return (EACCES); 162 } 163 164 return (0); 165 } 166 167 int 168 _fini(void) 169 { 170 /* Unregister from KCF if module is registered */ 171 if (rc4_prov_handle != NULL) { 172 if (crypto_unregister_provider(rc4_prov_handle)) 173 return (EBUSY); 174 175 rc4_prov_handle = NULL; 176 } 177 178 return (mod_remove(&modlinkage)); 179 } 180 181 int 182 _info(struct modinfo *modinfop) 183 { 184 return (mod_info(&modlinkage, modinfop)); 185 } 186 187 188 /* 189 * KCF software provider control entry points. 190 */ 191 /* ARGSUSED */ 192 static void 193 rc4_provider_status(crypto_provider_handle_t provider, uint_t *status) 194 { 195 *status = CRYPTO_PROVIDER_READY; 196 } 197 198 /* ARGSUSED */ 199 static int 200 rc4_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 201 crypto_key_t *key, crypto_spi_ctx_template_t template, 202 crypto_req_handle_t req) 203 { 204 205 /* EXPORT DELETE START */ 206 207 ARCFour_key *keystream; 208 209 if ((mechanism)->cm_type != RC4_MECH_INFO_TYPE) 210 return (CRYPTO_MECHANISM_INVALID); 211 212 if (key->ck_format != CRYPTO_KEY_RAW) 213 return (CRYPTO_KEY_TYPE_INCONSISTENT); 214 215 if (key->ck_length < ARCFOUR_MIN_KEY_BITS || 216 key->ck_length > ARCFOUR_MAX_KEY_BITS) { 217 return (CRYPTO_KEY_SIZE_RANGE); 218 } 219 220 /* 221 * Allocate an RC4 key stream. 222 */ 223 if ((keystream = kmem_alloc(sizeof (ARCFour_key), 224 crypto_kmflag(req))) == NULL) 225 return (CRYPTO_HOST_MEMORY); 226 227 arcfour_key_init(keystream, key->ck_data, 228 CRYPTO_BITS2BYTES(key->ck_length)); 229 230 ctx->cc_provider_private = keystream; 231 232 /* EXPORT DELETE END */ 233 234 return (CRYPTO_SUCCESS); 235 } 236 237 static int 238 rc4_crypt(crypto_ctx_t *ctx, crypto_data_t *input, crypto_data_t *output, 239 crypto_req_handle_t req) 240 { 241 int ret; 242 243 ret = rc4_crypt_update(ctx, input, output, req); 244 245 if (ret != CRYPTO_BUFFER_TOO_SMALL) 246 (void) rc4_free_context(ctx); 247 248 return (ret); 249 } 250 251 /* ARGSUSED */ 252 static int 253 rc4_crypt_update(crypto_ctx_t *ctx, crypto_data_t *input, crypto_data_t *output, 254 crypto_req_handle_t req) 255 { 256 int ret = CRYPTO_SUCCESS; 257 258 /* EXPORT DELETE START */ 259 260 ARCFour_key *key; 261 off_t saveoffset; 262 263 ASSERT(ctx->cc_provider_private != NULL); 264 265 if ((ctx->cc_flags & CRYPTO_USE_OPSTATE) && ctx->cc_opstate != NULL) 266 key = ctx->cc_opstate; 267 else 268 key = ctx->cc_provider_private; 269 270 /* Simple case: in-line encipherment */ 271 272 if (output == NULL) { 273 switch (input->cd_format) { 274 case CRYPTO_DATA_RAW: { 275 char *start, *end; 276 start = input->cd_raw.iov_base + input->cd_offset; 277 278 end = input->cd_raw.iov_base + input->cd_raw.iov_len; 279 280 if (start + input->cd_length > end) 281 return (CRYPTO_DATA_INVALID); 282 283 arcfour_crypt(key, (uchar_t *)start, (uchar_t *)start, 284 input->cd_length); 285 break; 286 } 287 case CRYPTO_DATA_MBLK: { 288 uchar_t *start, *end; 289 size_t len, left; 290 mblk_t *mp = input->cd_mp, *mp1, *mp2; 291 292 ASSERT(mp != NULL); 293 294 mp1 = advance_position(mp, input->cd_offset, &start); 295 296 if (mp1 == NULL) 297 return (CRYPTO_DATA_LEN_RANGE); 298 299 mp2 = advance_position(mp, input->cd_offset + 300 input->cd_length, &end); 301 302 if (mp2 == NULL) 303 return (CRYPTO_DATA_LEN_RANGE); 304 305 left = input->cd_length; 306 while (mp1 != NULL) { 307 if (_PTRDIFF(mp1->b_wptr, start) > left) { 308 len = left; 309 arcfour_crypt(key, start, start, len); 310 mp1 = NULL; 311 } else { 312 len = _PTRDIFF(mp1->b_wptr, start); 313 arcfour_crypt(key, start, start, len); 314 mp1 = mp1->b_cont; 315 start = mp1->b_rptr; 316 left -= len; 317 } 318 } 319 break; 320 } 321 case CRYPTO_DATA_UIO: { 322 uio_t *uiop = input->cd_uio; 323 off_t offset = input->cd_offset; 324 size_t length = input->cd_length; 325 uint_t vec_idx; 326 size_t cur_len; 327 328 /* 329 * Jump to the first iovec containing data to be 330 * processed. 331 */ 332 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 333 offset >= uiop->uio_iov[vec_idx].iov_len; 334 offset -= uiop->uio_iov[vec_idx++].iov_len) 335 ; 336 if (vec_idx == uiop->uio_iovcnt) { 337 return (CRYPTO_DATA_LEN_RANGE); 338 } 339 340 /* 341 * Now process the iovecs. 342 */ 343 while (vec_idx < uiop->uio_iovcnt && length > 0) { 344 uchar_t *start; 345 iovec_t *iovp = &(uiop->uio_iov[vec_idx]); 346 347 cur_len = MIN(iovp->iov_len - offset, length); 348 349 start = (uchar_t *)(iovp->iov_base + offset); 350 arcfour_crypt(key, start + offset, 351 start + offset, cur_len); 352 353 length -= cur_len; 354 vec_idx++; 355 offset = 0; 356 } 357 358 if (vec_idx == uiop->uio_iovcnt && length > 0) { 359 360 return (CRYPTO_DATA_LEN_RANGE); 361 } 362 break; 363 } 364 } 365 return (CRYPTO_SUCCESS); 366 } 367 368 /* 369 * We need to just return the length needed to store the output. 370 * We should not destroy the context for the following case. 371 */ 372 373 if (input->cd_length > output->cd_length) { 374 output->cd_length = input->cd_length; 375 return (CRYPTO_BUFFER_TOO_SMALL); 376 } 377 378 saveoffset = output->cd_offset; 379 380 switch (input->cd_format) { 381 case CRYPTO_DATA_RAW: { 382 char *start, *end; 383 start = input->cd_raw.iov_base + input->cd_offset; 384 385 end = input->cd_raw.iov_base + input->cd_raw.iov_len; 386 387 if (start + input->cd_length > end) 388 return (CRYPTO_DATA_LEN_RANGE); 389 390 ret = crypto_arcfour_crypt(key, (uchar_t *)start, output, 391 input->cd_length); 392 393 if (ret != CRYPTO_SUCCESS) 394 return (ret); 395 break; 396 } 397 case CRYPTO_DATA_MBLK: { 398 uchar_t *start, *end; 399 size_t len, left; 400 mblk_t *mp = input->cd_mp, *mp1, *mp2; 401 402 ASSERT(mp != NULL); 403 404 mp1 = advance_position(mp, input->cd_offset, &start); 405 406 if (mp1 == NULL) 407 return (CRYPTO_DATA_LEN_RANGE); 408 409 mp2 = advance_position(mp, input->cd_offset + input->cd_length, 410 &end); 411 412 if (mp2 == NULL) 413 return (CRYPTO_DATA_LEN_RANGE); 414 415 left = input->cd_length; 416 while (mp1 != NULL) { 417 if (_PTRDIFF(mp1->b_wptr, start) > left) { 418 len = left; 419 ret = crypto_arcfour_crypt(key, start, output, 420 len); 421 if (ret != CRYPTO_SUCCESS) 422 return (ret); 423 mp1 = NULL; 424 } else { 425 len = _PTRDIFF(mp1->b_wptr, start); 426 ret = crypto_arcfour_crypt(key, start, output, 427 len); 428 if (ret != CRYPTO_SUCCESS) 429 return (ret); 430 mp1 = mp1->b_cont; 431 start = mp1->b_rptr; 432 left -= len; 433 output->cd_offset += len; 434 } 435 } 436 break; 437 } 438 case CRYPTO_DATA_UIO: { 439 uio_t *uiop = input->cd_uio; 440 off_t offset = input->cd_offset; 441 size_t length = input->cd_length; 442 uint_t vec_idx; 443 size_t cur_len; 444 445 /* 446 * Jump to the first iovec containing data to be 447 * processed. 448 */ 449 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 450 offset >= uiop->uio_iov[vec_idx].iov_len; 451 offset -= uiop->uio_iov[vec_idx++].iov_len) 452 ; 453 if (vec_idx == uiop->uio_iovcnt) { 454 return (CRYPTO_DATA_LEN_RANGE); 455 } 456 457 /* 458 * Now process the iovecs. 459 */ 460 while (vec_idx < uiop->uio_iovcnt && length > 0) { 461 uchar_t *start; 462 iovec_t *iovp = &(uiop->uio_iov[vec_idx]); 463 cur_len = MIN(iovp->iov_len - offset, length); 464 465 start = (uchar_t *)(iovp->iov_base + offset); 466 ret = crypto_arcfour_crypt(key, start + offset, 467 output, cur_len); 468 if (ret != CRYPTO_SUCCESS) 469 return (ret); 470 471 length -= cur_len; 472 vec_idx++; 473 offset = 0; 474 output->cd_offset += cur_len; 475 } 476 477 if (vec_idx == uiop->uio_iovcnt && length > 0) { 478 479 return (CRYPTO_DATA_LEN_RANGE); 480 } 481 } 482 } 483 484 output->cd_offset = saveoffset; 485 output->cd_length = input->cd_length; 486 487 /* EXPORT DELETE END */ 488 489 return (ret); 490 } 491 492 /* ARGSUSED */ 493 static int rc4_crypt_final(crypto_ctx_t *ctx, crypto_data_t *data, 494 crypto_req_handle_t req) 495 { 496 /* No final part for streams ciphers. Just free the context */ 497 if (data != NULL) 498 data->cd_length = 0; 499 500 return (rc4_free_context(ctx)); 501 } 502 503 /* ARGSUSED */ 504 static int 505 rc4_crypt_atomic(crypto_provider_handle_t handle, crypto_session_id_t session, 506 crypto_mechanism_t *mechanism, crypto_key_t *key, crypto_data_t *input, 507 crypto_data_t *output, crypto_spi_ctx_template_t template, 508 crypto_req_handle_t req) 509 { 510 crypto_ctx_t ctx; 511 int ret; 512 513 bzero(&ctx, sizeof (crypto_ctx_t)); 514 ret = rc4_common_init(&ctx, mechanism, key, template, req); 515 516 if (ret != CRYPTO_SUCCESS) 517 return (ret); 518 519 ret = rc4_crypt_update(&ctx, input, output, req); 520 521 (void) rc4_free_context(&ctx); 522 523 return (ret); 524 } 525 526 /* ARGSUSED */ 527 static int 528 rc4_free_context(crypto_ctx_t *ctx) 529 { 530 531 /* EXPORT DELETE START */ 532 533 ARCFour_key *keystream = ctx->cc_provider_private; 534 535 if (keystream != NULL) { 536 bzero(keystream, sizeof (ARCFour_key)); 537 kmem_free(keystream, sizeof (ARCFour_key)); 538 ctx->cc_provider_private = NULL; 539 } 540 541 /* EXPORT DELETE END */ 542 543 return (CRYPTO_SUCCESS); 544 } 545 546 /* Encrypts a contiguous input 'in' into the 'out' crypto_data_t */ 547 548 static int 549 crypto_arcfour_crypt(ARCFour_key *key, uchar_t *in, crypto_data_t *out, 550 int length) 551 { 552 switch (out->cd_format) { 553 case CRYPTO_DATA_RAW: { 554 uchar_t *start, *end; 555 start = (uchar_t *)(out->cd_raw.iov_base + 556 out->cd_offset); 557 558 end = (uchar_t *)(out->cd_raw.iov_base + 559 out->cd_raw.iov_len); 560 561 if (start + out->cd_length > end) 562 return (CRYPTO_DATA_LEN_RANGE); 563 564 arcfour_crypt(key, in, start, length); 565 566 return (CRYPTO_SUCCESS); 567 } 568 case CRYPTO_DATA_MBLK: { 569 uchar_t *start, *end; 570 size_t len, left; 571 mblk_t *mp = out->cd_mp, *mp1, *mp2; 572 573 ASSERT(mp != NULL); 574 575 mp1 = advance_position(mp, out->cd_offset, &start); 576 577 if (mp1 == NULL) 578 return (CRYPTO_DATA_LEN_RANGE); 579 580 mp2 = advance_position(mp, out->cd_offset + 581 out->cd_length, &end); 582 583 if (mp2 == NULL) 584 return (CRYPTO_DATA_LEN_RANGE); 585 586 left = length; 587 while (mp1 != NULL) { 588 if (_PTRDIFF(mp1->b_wptr, start) > left) { 589 len = left; 590 arcfour_crypt(key, in, start, len); 591 mp1 = NULL; 592 } else { 593 len = _PTRDIFF(mp1->b_wptr, start); 594 arcfour_crypt(key, in, start, len); 595 mp1 = mp1->b_cont; 596 start = mp1->b_rptr; 597 left -= len; 598 } 599 } 600 break; 601 } 602 case CRYPTO_DATA_UIO: { 603 uio_t *uiop = out->cd_uio; 604 off_t offset = out->cd_offset; 605 size_t len = length; 606 uint_t vec_idx; 607 size_t cur_len; 608 609 /* 610 * Jump to the first iovec containing data to be 611 * processed. 612 */ 613 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 614 offset >= uiop->uio_iov[vec_idx].iov_len; 615 offset -= uiop->uio_iov[vec_idx++].iov_len) 616 ; 617 if (vec_idx == uiop->uio_iovcnt) { 618 return (CRYPTO_DATA_LEN_RANGE); 619 } 620 621 /* 622 * Now process the iovecs. 623 */ 624 while (vec_idx < uiop->uio_iovcnt && len > 0) { 625 uchar_t *start; 626 iovec_t *iovp = &(uiop->uio_iov[vec_idx]); 627 cur_len = MIN(iovp->iov_len - offset, len); 628 629 start = (uchar_t *)(iovp->iov_base + offset); 630 arcfour_crypt(key, start + offset, 631 start + offset, cur_len); 632 633 len -= cur_len; 634 vec_idx++; 635 offset = 0; 636 } 637 638 if (vec_idx == uiop->uio_iovcnt && len > 0) { 639 return (CRYPTO_DATA_LEN_RANGE); 640 } 641 break; 642 } 643 default: 644 return (CRYPTO_DATA_INVALID); 645 } 646 return (CRYPTO_SUCCESS); 647 } 648 649 /* 650 * Advances 'offset' bytes from the beginning of the first block in 'mp', 651 * possibly jumping across b_cont boundary 652 * '*cpp' is set to the position of the byte we want, and the block where 653 * 'cpp' is returned. 654 */ 655 static mblk_t * 656 advance_position(mblk_t *mp, off_t offset, uchar_t **cpp) 657 { 658 mblk_t *mp1 = mp; 659 size_t l; 660 off_t o = offset; 661 662 while (mp1 != NULL) { 663 l = MBLKL(mp1); 664 665 if (l <= o) { 666 o -= l; 667 mp1 = mp1->b_cont; 668 } else { 669 *cpp = (uchar_t *)(mp1->b_rptr + o); 670 break; 671 } 672 } 673 return (mp1); 674 } 675