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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * In kernel module, the md5 module is created with two modlinkages: 29 * - a modlmisc that allows consumers to directly call the entry points 30 * MD5Init, MD5Update, and MD5Final. 31 * - a modlcrypto that allows the module to register with the Kernel 32 * Cryptographic Framework (KCF) as a software provider for the MD5 33 * mechanisms. 34 */ 35 36 #include <sys/types.h> 37 #include <sys/systm.h> 38 #include <sys/modctl.h> 39 #include <sys/cmn_err.h> 40 #include <sys/ddi.h> 41 #include <sys/crypto/common.h> 42 #include <sys/crypto/spi.h> 43 #include <sys/sysmacros.h> 44 #include <sys/strsun.h> 45 #include <sys/note.h> 46 #include <sys/md5.h> 47 48 extern struct mod_ops mod_miscops; 49 extern struct mod_ops mod_cryptoops; 50 51 /* 52 * Module linkage information for the kernel. 53 */ 54 55 static struct modlmisc modlmisc = { 56 &mod_miscops, 57 "MD5 Message-Digest Algorithm" 58 }; 59 60 static struct modlcrypto modlcrypto = { 61 &mod_cryptoops, 62 "MD5 Kernel SW Provider" 63 }; 64 65 static struct modlinkage modlinkage = { 66 MODREV_1, 67 (void *)&modlmisc, 68 (void *)&modlcrypto, 69 NULL 70 }; 71 72 /* 73 * CSPI information (entry points, provider info, etc.) 74 */ 75 76 typedef enum md5_mech_type { 77 MD5_MECH_INFO_TYPE, /* SUN_CKM_MD5 */ 78 MD5_HMAC_MECH_INFO_TYPE, /* SUN_CKM_MD5_HMAC */ 79 MD5_HMAC_GEN_MECH_INFO_TYPE /* SUN_CKM_MD5_HMAC_GENERAL */ 80 } md5_mech_type_t; 81 82 #define MD5_DIGEST_LENGTH 16 /* MD5 digest length in bytes */ 83 #define MD5_HMAC_BLOCK_SIZE 64 /* MD5 block size */ 84 #define MD5_HMAC_MIN_KEY_LEN 1 /* MD5-HMAC min key length in bytes */ 85 #define MD5_HMAC_MAX_KEY_LEN INT_MAX /* MD5-HMAC max key length in bytes */ 86 #define MD5_HMAC_INTS_PER_BLOCK (MD5_HMAC_BLOCK_SIZE/sizeof (uint32_t)) 87 88 /* 89 * Context for MD5 mechanism. 90 */ 91 typedef struct md5_ctx { 92 md5_mech_type_t mc_mech_type; /* type of context */ 93 MD5_CTX mc_md5_ctx; /* MD5 context */ 94 } md5_ctx_t; 95 96 /* 97 * Context for MD5-HMAC and MD5-HMAC-GENERAL mechanisms. 98 */ 99 typedef struct md5_hmac_ctx { 100 md5_mech_type_t hc_mech_type; /* type of context */ 101 uint32_t hc_digest_len; /* digest len in bytes */ 102 MD5_CTX hc_icontext; /* inner MD5 context */ 103 MD5_CTX hc_ocontext; /* outer MD5 context */ 104 } md5_hmac_ctx_t; 105 106 /* 107 * Macros to access the MD5 or MD5-HMAC contexts from a context passed 108 * by KCF to one of the entry points. 109 */ 110 111 #define PROV_MD5_CTX(ctx) ((md5_ctx_t *)(ctx)->cc_provider_private) 112 #define PROV_MD5_HMAC_CTX(ctx) ((md5_hmac_ctx_t *)(ctx)->cc_provider_private) 113 /* to extract the digest length passed as mechanism parameter */ 114 115 #define PROV_MD5_GET_DIGEST_LEN(m, len) { \ 116 if (IS_P2ALIGNED((m)->cm_param, sizeof (ulong_t))) \ 117 (len) = (uint32_t)*((ulong_t *)mechanism->cm_param); \ 118 else { \ 119 ulong_t tmp_ulong; \ 120 bcopy((m)->cm_param, &tmp_ulong, sizeof (ulong_t)); \ 121 (len) = (uint32_t)tmp_ulong; \ 122 } \ 123 } 124 125 #define PROV_MD5_DIGEST_KEY(ctx, key, len, digest) { \ 126 MD5Init(ctx); \ 127 MD5Update(ctx, key, len); \ 128 MD5Final(digest, ctx); \ 129 } 130 131 /* 132 * Mechanism info structure passed to KCF during registration. 133 */ 134 static crypto_mech_info_t md5_mech_info_tab[] = { 135 /* MD5 */ 136 {SUN_CKM_MD5, MD5_MECH_INFO_TYPE, 137 CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC, 138 0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS}, 139 /* MD5-HMAC */ 140 {SUN_CKM_MD5_HMAC, MD5_HMAC_MECH_INFO_TYPE, 141 CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 142 MD5_HMAC_MIN_KEY_LEN, MD5_HMAC_MAX_KEY_LEN, 143 CRYPTO_KEYSIZE_UNIT_IN_BYTES}, 144 /* MD5-HMAC GENERAL */ 145 {SUN_CKM_MD5_HMAC_GENERAL, MD5_HMAC_GEN_MECH_INFO_TYPE, 146 CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 147 MD5_HMAC_MIN_KEY_LEN, MD5_HMAC_MAX_KEY_LEN, 148 CRYPTO_KEYSIZE_UNIT_IN_BYTES} 149 }; 150 151 static void md5_provider_status(crypto_provider_handle_t, uint_t *); 152 153 static crypto_control_ops_t md5_control_ops = { 154 md5_provider_status 155 }; 156 157 static int md5_digest_init(crypto_ctx_t *, crypto_mechanism_t *, 158 crypto_req_handle_t); 159 static int md5_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *, 160 crypto_req_handle_t); 161 static int md5_digest_update(crypto_ctx_t *, crypto_data_t *, 162 crypto_req_handle_t); 163 static int md5_digest_final(crypto_ctx_t *, crypto_data_t *, 164 crypto_req_handle_t); 165 static int md5_digest_atomic(crypto_provider_handle_t, crypto_session_id_t, 166 crypto_mechanism_t *, crypto_data_t *, crypto_data_t *, 167 crypto_req_handle_t); 168 169 static crypto_digest_ops_t md5_digest_ops = { 170 md5_digest_init, 171 md5_digest, 172 md5_digest_update, 173 NULL, 174 md5_digest_final, 175 md5_digest_atomic 176 }; 177 178 static int md5_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *, 179 crypto_spi_ctx_template_t, crypto_req_handle_t); 180 static int md5_mac_update(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t); 181 static int md5_mac_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t); 182 static int md5_mac_atomic(crypto_provider_handle_t, crypto_session_id_t, 183 crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *, 184 crypto_spi_ctx_template_t, crypto_req_handle_t); 185 static int md5_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t, 186 crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *, 187 crypto_spi_ctx_template_t, crypto_req_handle_t); 188 189 static crypto_mac_ops_t md5_mac_ops = { 190 md5_mac_init, 191 NULL, 192 md5_mac_update, 193 md5_mac_final, 194 md5_mac_atomic, 195 md5_mac_verify_atomic 196 }; 197 198 static int md5_create_ctx_template(crypto_provider_handle_t, 199 crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *, 200 size_t *, crypto_req_handle_t); 201 static int md5_free_context(crypto_ctx_t *); 202 203 static crypto_ctx_ops_t md5_ctx_ops = { 204 md5_create_ctx_template, 205 md5_free_context 206 }; 207 208 static crypto_ops_t md5_crypto_ops = { 209 &md5_control_ops, 210 &md5_digest_ops, 211 NULL, 212 &md5_mac_ops, 213 NULL, 214 NULL, 215 NULL, 216 NULL, 217 NULL, 218 NULL, 219 NULL, 220 NULL, 221 NULL, 222 &md5_ctx_ops 223 }; 224 225 static crypto_provider_info_t md5_prov_info = { 226 CRYPTO_SPI_VERSION_1, 227 "MD5 Software Provider", 228 CRYPTO_SW_PROVIDER, 229 {&modlinkage}, 230 NULL, 231 &md5_crypto_ops, 232 sizeof (md5_mech_info_tab)/sizeof (crypto_mech_info_t), 233 md5_mech_info_tab 234 }; 235 236 static crypto_kcf_provider_handle_t md5_prov_handle = NULL; 237 238 int 239 _init(void) 240 { 241 int ret; 242 243 if ((ret = mod_install(&modlinkage)) != 0) 244 return (ret); 245 246 /* 247 * Register with KCF. If the registration fails, log an 248 * error but do not uninstall the module, since the functionality 249 * provided by misc/md5 should still be available. 250 */ 251 if ((ret = crypto_register_provider(&md5_prov_info, 252 &md5_prov_handle)) != CRYPTO_SUCCESS) 253 cmn_err(CE_WARN, "md5 _init: " 254 "crypto_register_provider() failed (0x%x)", ret); 255 256 return (0); 257 } 258 259 int 260 _fini(void) 261 { 262 int ret; 263 264 /* 265 * Unregister from KCF if previous registration succeeded. 266 */ 267 if (md5_prov_handle != NULL) { 268 if ((ret = crypto_unregister_provider(md5_prov_handle)) != 269 CRYPTO_SUCCESS) { 270 cmn_err(CE_WARN, "md5 _fini: " 271 "crypto_unregister_provider() failed (0x%x)", ret); 272 return (EBUSY); 273 } 274 md5_prov_handle = NULL; 275 } 276 277 return (mod_remove(&modlinkage)); 278 } 279 280 int 281 _info(struct modinfo *modinfop) 282 { 283 return (mod_info(&modlinkage, modinfop)); 284 } 285 286 /* 287 * KCF software provider control entry points. 288 */ 289 /* ARGSUSED */ 290 static void 291 md5_provider_status(crypto_provider_handle_t provider, uint_t *status) 292 { 293 *status = CRYPTO_PROVIDER_READY; 294 } 295 296 /* 297 * KCF software provider digest entry points. 298 */ 299 300 static int 301 md5_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 302 crypto_req_handle_t req) 303 { 304 if (mechanism->cm_type != MD5_MECH_INFO_TYPE) 305 return (CRYPTO_MECHANISM_INVALID); 306 307 /* 308 * Allocate and initialize MD5 context. 309 */ 310 ctx->cc_provider_private = kmem_alloc(sizeof (md5_ctx_t), 311 crypto_kmflag(req)); 312 if (ctx->cc_provider_private == NULL) 313 return (CRYPTO_HOST_MEMORY); 314 315 PROV_MD5_CTX(ctx)->mc_mech_type = MD5_MECH_INFO_TYPE; 316 MD5Init(&PROV_MD5_CTX(ctx)->mc_md5_ctx); 317 318 return (CRYPTO_SUCCESS); 319 } 320 321 /* 322 * Helper MD5 digest update function for uio data. 323 */ 324 static int 325 md5_digest_update_uio(MD5_CTX *md5_ctx, crypto_data_t *data) 326 { 327 off_t offset = data->cd_offset; 328 size_t length = data->cd_length; 329 uint_t vec_idx; 330 size_t cur_len; 331 332 /* we support only kernel buffer */ 333 if (data->cd_uio->uio_segflg != UIO_SYSSPACE) 334 return (CRYPTO_ARGUMENTS_BAD); 335 336 /* 337 * Jump to the first iovec containing data to be 338 * digested. 339 */ 340 for (vec_idx = 0; vec_idx < data->cd_uio->uio_iovcnt && 341 offset >= data->cd_uio->uio_iov[vec_idx].iov_len; 342 offset -= data->cd_uio->uio_iov[vec_idx++].iov_len) 343 ; 344 if (vec_idx == data->cd_uio->uio_iovcnt) { 345 /* 346 * The caller specified an offset that is larger than the 347 * total size of the buffers it provided. 348 */ 349 return (CRYPTO_DATA_LEN_RANGE); 350 } 351 352 /* 353 * Now do the digesting on the iovecs. 354 */ 355 while (vec_idx < data->cd_uio->uio_iovcnt && length > 0) { 356 cur_len = MIN(data->cd_uio->uio_iov[vec_idx].iov_len - 357 offset, length); 358 359 MD5Update(md5_ctx, data->cd_uio->uio_iov[vec_idx].iov_base + 360 offset, cur_len); 361 362 length -= cur_len; 363 vec_idx++; 364 offset = 0; 365 } 366 367 if (vec_idx == data->cd_uio->uio_iovcnt && length > 0) { 368 /* 369 * The end of the specified iovec's was reached but 370 * the length requested could not be processed, i.e. 371 * The caller requested to digest more data than it provided. 372 */ 373 return (CRYPTO_DATA_LEN_RANGE); 374 } 375 376 return (CRYPTO_SUCCESS); 377 } 378 379 /* 380 * Helper MD5 digest final function for uio data. 381 * digest_len is the length of the desired digest. If digest_len 382 * is smaller than the default MD5 digest length, the caller 383 * must pass a scratch buffer, digest_scratch, which must 384 * be at least MD5_DIGEST_LENGTH bytes. 385 */ 386 static int 387 md5_digest_final_uio(MD5_CTX *md5_ctx, crypto_data_t *digest, 388 ulong_t digest_len, uchar_t *digest_scratch) 389 { 390 off_t offset = digest->cd_offset; 391 uint_t vec_idx; 392 393 /* we support only kernel buffer */ 394 if (digest->cd_uio->uio_segflg != UIO_SYSSPACE) 395 return (CRYPTO_ARGUMENTS_BAD); 396 397 /* 398 * Jump to the first iovec containing ptr to the digest to 399 * be returned. 400 */ 401 for (vec_idx = 0; offset >= digest->cd_uio->uio_iov[vec_idx].iov_len && 402 vec_idx < digest->cd_uio->uio_iovcnt; 403 offset -= digest->cd_uio->uio_iov[vec_idx++].iov_len) 404 ; 405 if (vec_idx == digest->cd_uio->uio_iovcnt) { 406 /* 407 * The caller specified an offset that is 408 * larger than the total size of the buffers 409 * it provided. 410 */ 411 return (CRYPTO_DATA_LEN_RANGE); 412 } 413 414 if (offset + digest_len <= 415 digest->cd_uio->uio_iov[vec_idx].iov_len) { 416 /* 417 * The computed MD5 digest will fit in the current 418 * iovec. 419 */ 420 if (digest_len != MD5_DIGEST_LENGTH) { 421 /* 422 * The caller requested a short digest. Digest 423 * into a scratch buffer and return to 424 * the user only what was requested. 425 */ 426 MD5Final(digest_scratch, md5_ctx); 427 bcopy(digest_scratch, (uchar_t *)digest-> 428 cd_uio->uio_iov[vec_idx].iov_base + offset, 429 digest_len); 430 } else { 431 MD5Final((uchar_t *)digest-> 432 cd_uio->uio_iov[vec_idx].iov_base + offset, 433 md5_ctx); 434 } 435 } else { 436 /* 437 * The computed digest will be crossing one or more iovec's. 438 * This is bad performance-wise but we need to support it. 439 * Allocate a small scratch buffer on the stack and 440 * copy it piece meal to the specified digest iovec's. 441 */ 442 uchar_t digest_tmp[MD5_DIGEST_LENGTH]; 443 off_t scratch_offset = 0; 444 size_t length = digest_len; 445 size_t cur_len; 446 447 MD5Final(digest_tmp, md5_ctx); 448 449 while (vec_idx < digest->cd_uio->uio_iovcnt && length > 0) { 450 cur_len = MIN(digest->cd_uio->uio_iov[vec_idx].iov_len - 451 offset, length); 452 bcopy(digest_tmp + scratch_offset, 453 digest->cd_uio->uio_iov[vec_idx].iov_base + offset, 454 cur_len); 455 456 length -= cur_len; 457 vec_idx++; 458 scratch_offset += cur_len; 459 offset = 0; 460 } 461 462 if (vec_idx == digest->cd_uio->uio_iovcnt && length > 0) { 463 /* 464 * The end of the specified iovec's was reached but 465 * the length requested could not be processed, i.e. 466 * The caller requested to digest more data than it 467 * provided. 468 */ 469 return (CRYPTO_DATA_LEN_RANGE); 470 } 471 } 472 473 return (CRYPTO_SUCCESS); 474 } 475 476 /* 477 * Helper MD5 digest update for mblk's. 478 */ 479 static int 480 md5_digest_update_mblk(MD5_CTX *md5_ctx, crypto_data_t *data) 481 { 482 off_t offset = data->cd_offset; 483 size_t length = data->cd_length; 484 mblk_t *mp; 485 size_t cur_len; 486 487 /* 488 * Jump to the first mblk_t containing data to be digested. 489 */ 490 for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp); 491 offset -= MBLKL(mp), mp = mp->b_cont) 492 ; 493 if (mp == NULL) { 494 /* 495 * The caller specified an offset that is larger than the 496 * total size of the buffers it provided. 497 */ 498 return (CRYPTO_DATA_LEN_RANGE); 499 } 500 501 /* 502 * Now do the digesting on the mblk chain. 503 */ 504 while (mp != NULL && length > 0) { 505 cur_len = MIN(MBLKL(mp) - offset, length); 506 MD5Update(md5_ctx, mp->b_rptr + offset, cur_len); 507 length -= cur_len; 508 offset = 0; 509 mp = mp->b_cont; 510 } 511 512 if (mp == NULL && length > 0) { 513 /* 514 * The end of the mblk was reached but the length requested 515 * could not be processed, i.e. The caller requested 516 * to digest more data than it provided. 517 */ 518 return (CRYPTO_DATA_LEN_RANGE); 519 } 520 521 return (CRYPTO_SUCCESS); 522 } 523 524 /* 525 * Helper MD5 digest final for mblk's. 526 * digest_len is the length of the desired digest. If digest_len 527 * is smaller than the default MD5 digest length, the caller 528 * must pass a scratch buffer, digest_scratch, which must 529 * be at least MD5_DIGEST_LENGTH bytes. 530 */ 531 static int 532 md5_digest_final_mblk(MD5_CTX *md5_ctx, crypto_data_t *digest, 533 ulong_t digest_len, uchar_t *digest_scratch) 534 { 535 off_t offset = digest->cd_offset; 536 mblk_t *mp; 537 538 /* 539 * Jump to the first mblk_t that will be used to store the digest. 540 */ 541 for (mp = digest->cd_mp; mp != NULL && offset >= MBLKL(mp); 542 offset -= MBLKL(mp), mp = mp->b_cont) 543 ; 544 if (mp == NULL) { 545 /* 546 * The caller specified an offset that is larger than the 547 * total size of the buffers it provided. 548 */ 549 return (CRYPTO_DATA_LEN_RANGE); 550 } 551 552 if (offset + digest_len <= MBLKL(mp)) { 553 /* 554 * The computed MD5 digest will fit in the current mblk. 555 * Do the MD5Final() in-place. 556 */ 557 if (digest_len != MD5_DIGEST_LENGTH) { 558 /* 559 * The caller requested a short digest. Digest 560 * into a scratch buffer and return to 561 * the user only what was requested. 562 */ 563 MD5Final(digest_scratch, md5_ctx); 564 bcopy(digest_scratch, mp->b_rptr + offset, digest_len); 565 } else { 566 MD5Final(mp->b_rptr + offset, md5_ctx); 567 } 568 } else { 569 /* 570 * The computed digest will be crossing one or more mblk's. 571 * This is bad performance-wise but we need to support it. 572 * Allocate a small scratch buffer on the stack and 573 * copy it piece meal to the specified digest iovec's. 574 */ 575 uchar_t digest_tmp[MD5_DIGEST_LENGTH]; 576 off_t scratch_offset = 0; 577 size_t length = digest_len; 578 size_t cur_len; 579 580 MD5Final(digest_tmp, md5_ctx); 581 582 while (mp != NULL && length > 0) { 583 cur_len = MIN(MBLKL(mp) - offset, length); 584 bcopy(digest_tmp + scratch_offset, 585 mp->b_rptr + offset, cur_len); 586 587 length -= cur_len; 588 mp = mp->b_cont; 589 scratch_offset += cur_len; 590 offset = 0; 591 } 592 593 if (mp == NULL && length > 0) { 594 /* 595 * The end of the specified mblk was reached but 596 * the length requested could not be processed, i.e. 597 * The caller requested to digest more data than it 598 * provided. 599 */ 600 return (CRYPTO_DATA_LEN_RANGE); 601 } 602 } 603 604 return (CRYPTO_SUCCESS); 605 } 606 607 /* ARGSUSED */ 608 static int 609 md5_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest, 610 crypto_req_handle_t req) 611 { 612 int ret = CRYPTO_SUCCESS; 613 614 ASSERT(ctx->cc_provider_private != NULL); 615 616 /* 617 * We need to just return the length needed to store the output. 618 * We should not destroy the context for the following cases. 619 */ 620 if ((digest->cd_length == 0) || 621 (digest->cd_length < MD5_DIGEST_LENGTH)) { 622 digest->cd_length = MD5_DIGEST_LENGTH; 623 return (CRYPTO_BUFFER_TOO_SMALL); 624 } 625 626 /* 627 * Do the MD5 update on the specified input data. 628 */ 629 switch (data->cd_format) { 630 case CRYPTO_DATA_RAW: 631 MD5Update(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 632 data->cd_raw.iov_base + data->cd_offset, 633 data->cd_length); 634 break; 635 case CRYPTO_DATA_UIO: 636 ret = md5_digest_update_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 637 data); 638 break; 639 case CRYPTO_DATA_MBLK: 640 ret = md5_digest_update_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 641 data); 642 break; 643 default: 644 ret = CRYPTO_ARGUMENTS_BAD; 645 } 646 647 if (ret != CRYPTO_SUCCESS) { 648 /* the update failed, free context and bail */ 649 kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t)); 650 ctx->cc_provider_private = NULL; 651 digest->cd_length = 0; 652 return (ret); 653 } 654 655 /* 656 * Do an MD5 final, must be done separately since the digest 657 * type can be different than the input data type. 658 */ 659 switch (digest->cd_format) { 660 case CRYPTO_DATA_RAW: 661 MD5Final((unsigned char *)digest->cd_raw.iov_base + 662 digest->cd_offset, &PROV_MD5_CTX(ctx)->mc_md5_ctx); 663 break; 664 case CRYPTO_DATA_UIO: 665 ret = md5_digest_final_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 666 digest, MD5_DIGEST_LENGTH, NULL); 667 break; 668 case CRYPTO_DATA_MBLK: 669 ret = md5_digest_final_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 670 digest, MD5_DIGEST_LENGTH, NULL); 671 break; 672 default: 673 ret = CRYPTO_ARGUMENTS_BAD; 674 } 675 676 /* all done, free context and return */ 677 678 if (ret == CRYPTO_SUCCESS) { 679 digest->cd_length = MD5_DIGEST_LENGTH; 680 } else { 681 digest->cd_length = 0; 682 } 683 684 kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t)); 685 ctx->cc_provider_private = NULL; 686 return (ret); 687 } 688 689 /* ARGSUSED */ 690 static int 691 md5_digest_update(crypto_ctx_t *ctx, crypto_data_t *data, 692 crypto_req_handle_t req) 693 { 694 int ret = CRYPTO_SUCCESS; 695 696 ASSERT(ctx->cc_provider_private != NULL); 697 698 /* 699 * Do the MD5 update on the specified input data. 700 */ 701 switch (data->cd_format) { 702 case CRYPTO_DATA_RAW: 703 MD5Update(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 704 data->cd_raw.iov_base + data->cd_offset, 705 data->cd_length); 706 break; 707 case CRYPTO_DATA_UIO: 708 ret = md5_digest_update_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 709 data); 710 break; 711 case CRYPTO_DATA_MBLK: 712 ret = md5_digest_update_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 713 data); 714 break; 715 default: 716 ret = CRYPTO_ARGUMENTS_BAD; 717 } 718 719 return (ret); 720 } 721 722 /* ARGSUSED */ 723 static int 724 md5_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest, 725 crypto_req_handle_t req) 726 { 727 int ret = CRYPTO_SUCCESS; 728 729 ASSERT(ctx->cc_provider_private != NULL); 730 731 /* 732 * We need to just return the length needed to store the output. 733 * We should not destroy the context for the following cases. 734 */ 735 if ((digest->cd_length == 0) || 736 (digest->cd_length < MD5_DIGEST_LENGTH)) { 737 digest->cd_length = MD5_DIGEST_LENGTH; 738 return (CRYPTO_BUFFER_TOO_SMALL); 739 } 740 741 /* 742 * Do an MD5 final. 743 */ 744 switch (digest->cd_format) { 745 case CRYPTO_DATA_RAW: 746 MD5Final((unsigned char *)digest->cd_raw.iov_base + 747 digest->cd_offset, &PROV_MD5_CTX(ctx)->mc_md5_ctx); 748 break; 749 case CRYPTO_DATA_UIO: 750 ret = md5_digest_final_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 751 digest, MD5_DIGEST_LENGTH, NULL); 752 break; 753 case CRYPTO_DATA_MBLK: 754 ret = md5_digest_final_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 755 digest, MD5_DIGEST_LENGTH, NULL); 756 break; 757 default: 758 ret = CRYPTO_ARGUMENTS_BAD; 759 } 760 761 /* all done, free context and return */ 762 763 if (ret == CRYPTO_SUCCESS) { 764 digest->cd_length = MD5_DIGEST_LENGTH; 765 } else { 766 digest->cd_length = 0; 767 } 768 769 kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t)); 770 ctx->cc_provider_private = NULL; 771 772 return (ret); 773 } 774 775 /* ARGSUSED */ 776 static int 777 md5_digest_atomic(crypto_provider_handle_t provider, 778 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 779 crypto_data_t *data, crypto_data_t *digest, 780 crypto_req_handle_t req) 781 { 782 int ret = CRYPTO_SUCCESS; 783 MD5_CTX md5_ctx; 784 785 if (mechanism->cm_type != MD5_MECH_INFO_TYPE) 786 return (CRYPTO_MECHANISM_INVALID); 787 788 /* 789 * Do the MD5 init. 790 */ 791 MD5Init(&md5_ctx); 792 793 /* 794 * Do the MD5 update on the specified input data. 795 */ 796 switch (data->cd_format) { 797 case CRYPTO_DATA_RAW: 798 MD5Update(&md5_ctx, data->cd_raw.iov_base + data->cd_offset, 799 data->cd_length); 800 break; 801 case CRYPTO_DATA_UIO: 802 ret = md5_digest_update_uio(&md5_ctx, data); 803 break; 804 case CRYPTO_DATA_MBLK: 805 ret = md5_digest_update_mblk(&md5_ctx, data); 806 break; 807 default: 808 ret = CRYPTO_ARGUMENTS_BAD; 809 } 810 811 if (ret != CRYPTO_SUCCESS) { 812 /* the update failed, bail */ 813 digest->cd_length = 0; 814 return (ret); 815 } 816 817 /* 818 * Do an MD5 final, must be done separately since the digest 819 * type can be different than the input data type. 820 */ 821 switch (digest->cd_format) { 822 case CRYPTO_DATA_RAW: 823 MD5Final((unsigned char *)digest->cd_raw.iov_base + 824 digest->cd_offset, &md5_ctx); 825 break; 826 case CRYPTO_DATA_UIO: 827 ret = md5_digest_final_uio(&md5_ctx, digest, 828 MD5_DIGEST_LENGTH, NULL); 829 break; 830 case CRYPTO_DATA_MBLK: 831 ret = md5_digest_final_mblk(&md5_ctx, digest, 832 MD5_DIGEST_LENGTH, NULL); 833 break; 834 default: 835 ret = CRYPTO_ARGUMENTS_BAD; 836 } 837 838 if (ret == CRYPTO_SUCCESS) { 839 digest->cd_length = MD5_DIGEST_LENGTH; 840 } else { 841 digest->cd_length = 0; 842 } 843 844 return (ret); 845 } 846 847 /* 848 * KCF software provider mac entry points. 849 * 850 * MD5 HMAC is: MD5(key XOR opad, MD5(key XOR ipad, text)) 851 * 852 * Init: 853 * The initialization routine initializes what we denote 854 * as the inner and outer contexts by doing 855 * - for inner context: MD5(key XOR ipad) 856 * - for outer context: MD5(key XOR opad) 857 * 858 * Update: 859 * Each subsequent MD5 HMAC update will result in an 860 * update of the inner context with the specified data. 861 * 862 * Final: 863 * The MD5 HMAC final will do a MD5 final operation on the 864 * inner context, and the resulting digest will be used 865 * as the data for an update on the outer context. Last 866 * but not least, an MD5 final on the outer context will 867 * be performed to obtain the MD5 HMAC digest to return 868 * to the user. 869 */ 870 871 /* 872 * Initialize a MD5-HMAC context. 873 */ 874 static void 875 md5_mac_init_ctx(md5_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes) 876 { 877 uint32_t ipad[MD5_HMAC_INTS_PER_BLOCK]; 878 uint32_t opad[MD5_HMAC_INTS_PER_BLOCK]; 879 uint_t i; 880 881 bzero(ipad, MD5_HMAC_BLOCK_SIZE); 882 bzero(opad, MD5_HMAC_BLOCK_SIZE); 883 884 bcopy(keyval, ipad, length_in_bytes); 885 bcopy(keyval, opad, length_in_bytes); 886 887 /* XOR key with ipad (0x36) and opad (0x5c) */ 888 for (i = 0; i < MD5_HMAC_INTS_PER_BLOCK; i++) { 889 ipad[i] ^= 0x36363636; 890 opad[i] ^= 0x5c5c5c5c; 891 } 892 893 /* perform MD5 on ipad */ 894 MD5Init(&ctx->hc_icontext); 895 MD5Update(&ctx->hc_icontext, ipad, MD5_HMAC_BLOCK_SIZE); 896 897 /* perform MD5 on opad */ 898 MD5Init(&ctx->hc_ocontext); 899 MD5Update(&ctx->hc_ocontext, opad, MD5_HMAC_BLOCK_SIZE); 900 } 901 902 /* 903 * Initializes a multi-part MAC operation. 904 */ 905 static int 906 md5_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 907 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 908 crypto_req_handle_t req) 909 { 910 int ret = CRYPTO_SUCCESS; 911 uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 912 913 if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE && 914 mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE) 915 return (CRYPTO_MECHANISM_INVALID); 916 917 /* Add support for key by attributes (RFE 4706552) */ 918 if (key->ck_format != CRYPTO_KEY_RAW) 919 return (CRYPTO_ARGUMENTS_BAD); 920 921 ctx->cc_provider_private = kmem_alloc(sizeof (md5_hmac_ctx_t), 922 crypto_kmflag(req)); 923 if (ctx->cc_provider_private == NULL) 924 return (CRYPTO_HOST_MEMORY); 925 926 if (ctx_template != NULL) { 927 /* reuse context template */ 928 bcopy(ctx_template, PROV_MD5_HMAC_CTX(ctx), 929 sizeof (md5_hmac_ctx_t)); 930 } else { 931 /* no context template, compute context */ 932 if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) { 933 uchar_t digested_key[MD5_DIGEST_LENGTH]; 934 md5_hmac_ctx_t *hmac_ctx = ctx->cc_provider_private; 935 936 /* 937 * Hash the passed-in key to get a smaller key. 938 * The inner context is used since it hasn't been 939 * initialized yet. 940 */ 941 PROV_MD5_DIGEST_KEY(&hmac_ctx->hc_icontext, 942 key->ck_data, keylen_in_bytes, digested_key); 943 md5_mac_init_ctx(PROV_MD5_HMAC_CTX(ctx), 944 digested_key, MD5_DIGEST_LENGTH); 945 } else { 946 md5_mac_init_ctx(PROV_MD5_HMAC_CTX(ctx), 947 key->ck_data, keylen_in_bytes); 948 } 949 } 950 951 /* 952 * Get the mechanism parameters, if applicable. 953 */ 954 PROV_MD5_HMAC_CTX(ctx)->hc_mech_type = mechanism->cm_type; 955 if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) { 956 if (mechanism->cm_param == NULL || 957 mechanism->cm_param_len != sizeof (ulong_t)) 958 ret = CRYPTO_MECHANISM_PARAM_INVALID; 959 PROV_MD5_GET_DIGEST_LEN(mechanism, 960 PROV_MD5_HMAC_CTX(ctx)->hc_digest_len); 961 if (PROV_MD5_HMAC_CTX(ctx)->hc_digest_len > 962 MD5_DIGEST_LENGTH) 963 ret = CRYPTO_MECHANISM_PARAM_INVALID; 964 } 965 966 if (ret != CRYPTO_SUCCESS) { 967 bzero(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t)); 968 kmem_free(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t)); 969 ctx->cc_provider_private = NULL; 970 } 971 972 return (ret); 973 } 974 975 976 /* ARGSUSED */ 977 static int 978 md5_mac_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req) 979 { 980 int ret = CRYPTO_SUCCESS; 981 982 ASSERT(ctx->cc_provider_private != NULL); 983 984 /* 985 * Do an MD5 update of the inner context using the specified 986 * data. 987 */ 988 switch (data->cd_format) { 989 case CRYPTO_DATA_RAW: 990 MD5Update(&PROV_MD5_HMAC_CTX(ctx)->hc_icontext, 991 data->cd_raw.iov_base + data->cd_offset, 992 data->cd_length); 993 break; 994 case CRYPTO_DATA_UIO: 995 ret = md5_digest_update_uio( 996 &PROV_MD5_HMAC_CTX(ctx)->hc_icontext, data); 997 break; 998 case CRYPTO_DATA_MBLK: 999 ret = md5_digest_update_mblk( 1000 &PROV_MD5_HMAC_CTX(ctx)->hc_icontext, data); 1001 break; 1002 default: 1003 ret = CRYPTO_ARGUMENTS_BAD; 1004 } 1005 1006 return (ret); 1007 } 1008 1009 /* ARGSUSED */ 1010 static int 1011 md5_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac, crypto_req_handle_t req) 1012 { 1013 int ret = CRYPTO_SUCCESS; 1014 uchar_t digest[MD5_DIGEST_LENGTH]; 1015 uint32_t digest_len = MD5_DIGEST_LENGTH; 1016 1017 ASSERT(ctx->cc_provider_private != NULL); 1018 1019 if (PROV_MD5_HMAC_CTX(ctx)->hc_mech_type == MD5_HMAC_GEN_MECH_INFO_TYPE) 1020 digest_len = PROV_MD5_HMAC_CTX(ctx)->hc_digest_len; 1021 1022 /* 1023 * We need to just return the length needed to store the output. 1024 * We should not destroy the context for the following cases. 1025 */ 1026 if ((mac->cd_length == 0) || (mac->cd_length < digest_len)) { 1027 mac->cd_length = digest_len; 1028 return (CRYPTO_BUFFER_TOO_SMALL); 1029 } 1030 1031 /* 1032 * Do an MD5 final on the inner context. 1033 */ 1034 MD5Final(digest, &PROV_MD5_HMAC_CTX(ctx)->hc_icontext); 1035 1036 /* 1037 * Do an MD5 update on the outer context, feeding the inner 1038 * digest as data. 1039 */ 1040 MD5Update(&PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, digest, 1041 MD5_DIGEST_LENGTH); 1042 1043 /* 1044 * Do an MD5 final on the outer context, storing the computing 1045 * digest in the users buffer. 1046 */ 1047 switch (mac->cd_format) { 1048 case CRYPTO_DATA_RAW: 1049 if (digest_len != MD5_DIGEST_LENGTH) { 1050 /* 1051 * The caller requested a short digest. Digest 1052 * into a scratch buffer and return to 1053 * the user only what was requested. 1054 */ 1055 MD5Final(digest, 1056 &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext); 1057 bcopy(digest, (unsigned char *)mac->cd_raw.iov_base + 1058 mac->cd_offset, digest_len); 1059 } else { 1060 MD5Final((unsigned char *)mac->cd_raw.iov_base + 1061 mac->cd_offset, 1062 &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext); 1063 } 1064 break; 1065 case CRYPTO_DATA_UIO: 1066 ret = md5_digest_final_uio( 1067 &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, mac, 1068 digest_len, digest); 1069 break; 1070 case CRYPTO_DATA_MBLK: 1071 ret = md5_digest_final_mblk( 1072 &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, mac, 1073 digest_len, digest); 1074 break; 1075 default: 1076 ret = CRYPTO_ARGUMENTS_BAD; 1077 } 1078 1079 if (ret == CRYPTO_SUCCESS) { 1080 mac->cd_length = digest_len; 1081 } else { 1082 mac->cd_length = 0; 1083 } 1084 1085 bzero(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t)); 1086 kmem_free(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t)); 1087 ctx->cc_provider_private = NULL; 1088 1089 return (ret); 1090 } 1091 1092 #define MD5_MAC_UPDATE(data, ctx, ret) { \ 1093 switch (data->cd_format) { \ 1094 case CRYPTO_DATA_RAW: \ 1095 MD5Update(&(ctx).hc_icontext, \ 1096 data->cd_raw.iov_base + data->cd_offset, \ 1097 data->cd_length); \ 1098 break; \ 1099 case CRYPTO_DATA_UIO: \ 1100 ret = md5_digest_update_uio(&(ctx).hc_icontext, data); \ 1101 break; \ 1102 case CRYPTO_DATA_MBLK: \ 1103 ret = md5_digest_update_mblk(&(ctx).hc_icontext, \ 1104 data); \ 1105 break; \ 1106 default: \ 1107 ret = CRYPTO_ARGUMENTS_BAD; \ 1108 } \ 1109 } 1110 1111 1112 /* ARGSUSED */ 1113 static int 1114 md5_mac_atomic(crypto_provider_handle_t provider, 1115 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 1116 crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, 1117 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 1118 { 1119 int ret = CRYPTO_SUCCESS; 1120 uchar_t digest[MD5_DIGEST_LENGTH]; 1121 md5_hmac_ctx_t md5_hmac_ctx; 1122 uint32_t digest_len = MD5_DIGEST_LENGTH; 1123 uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 1124 1125 if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE && 1126 mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE) 1127 return (CRYPTO_MECHANISM_INVALID); 1128 1129 /* Add support for key by attributes (RFE 4706552) */ 1130 if (key->ck_format != CRYPTO_KEY_RAW) 1131 return (CRYPTO_ARGUMENTS_BAD); 1132 1133 if (ctx_template != NULL) { 1134 /* reuse context template */ 1135 bcopy(ctx_template, &md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1136 } else { 1137 /* no context template, compute context */ 1138 if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) { 1139 /* 1140 * Hash the passed-in key to get a smaller key. 1141 * The inner context is used since it hasn't been 1142 * initialized yet. 1143 */ 1144 PROV_MD5_DIGEST_KEY(&md5_hmac_ctx.hc_icontext, 1145 key->ck_data, keylen_in_bytes, digest); 1146 md5_mac_init_ctx(&md5_hmac_ctx, digest, 1147 MD5_DIGEST_LENGTH); 1148 } else { 1149 md5_mac_init_ctx(&md5_hmac_ctx, key->ck_data, 1150 keylen_in_bytes); 1151 } 1152 } 1153 1154 /* 1155 * Get the mechanism parameters, if applicable. 1156 */ 1157 if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) { 1158 if (mechanism->cm_param == NULL || 1159 mechanism->cm_param_len != sizeof (ulong_t)) { 1160 ret = CRYPTO_MECHANISM_PARAM_INVALID; 1161 goto bail; 1162 } 1163 PROV_MD5_GET_DIGEST_LEN(mechanism, digest_len); 1164 if (digest_len > MD5_DIGEST_LENGTH) { 1165 ret = CRYPTO_MECHANISM_PARAM_INVALID; 1166 goto bail; 1167 } 1168 } 1169 1170 /* do an MD5 update of the inner context using the specified data */ 1171 MD5_MAC_UPDATE(data, md5_hmac_ctx, ret); 1172 if (ret != CRYPTO_SUCCESS) 1173 /* the update failed, free context and bail */ 1174 goto bail; 1175 1176 /* do an MD5 final on the inner context */ 1177 MD5Final(digest, &md5_hmac_ctx.hc_icontext); 1178 1179 /* 1180 * Do an MD5 update on the outer context, feeding the inner 1181 * digest as data. 1182 */ 1183 MD5Update(&md5_hmac_ctx.hc_ocontext, digest, MD5_DIGEST_LENGTH); 1184 1185 /* 1186 * Do an MD5 final on the outer context, storing the computed 1187 * digest in the users buffer. 1188 */ 1189 switch (mac->cd_format) { 1190 case CRYPTO_DATA_RAW: 1191 if (digest_len != MD5_DIGEST_LENGTH) { 1192 /* 1193 * The caller requested a short digest. Digest 1194 * into a scratch buffer and return to 1195 * the user only what was requested. 1196 */ 1197 MD5Final(digest, &md5_hmac_ctx.hc_ocontext); 1198 bcopy(digest, (unsigned char *)mac->cd_raw.iov_base + 1199 mac->cd_offset, digest_len); 1200 } else { 1201 MD5Final((unsigned char *)mac->cd_raw.iov_base + 1202 mac->cd_offset, &md5_hmac_ctx.hc_ocontext); 1203 } 1204 break; 1205 case CRYPTO_DATA_UIO: 1206 ret = md5_digest_final_uio(&md5_hmac_ctx.hc_ocontext, mac, 1207 digest_len, digest); 1208 break; 1209 case CRYPTO_DATA_MBLK: 1210 ret = md5_digest_final_mblk(&md5_hmac_ctx.hc_ocontext, mac, 1211 digest_len, digest); 1212 break; 1213 default: 1214 ret = CRYPTO_ARGUMENTS_BAD; 1215 } 1216 1217 if (ret == CRYPTO_SUCCESS) { 1218 mac->cd_length = digest_len; 1219 } else { 1220 mac->cd_length = 0; 1221 } 1222 /* Extra paranoia: zeroizing the local context on the stack */ 1223 bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1224 1225 return (ret); 1226 bail: 1227 bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1228 mac->cd_length = 0; 1229 return (ret); 1230 } 1231 1232 /* ARGSUSED */ 1233 static int 1234 md5_mac_verify_atomic(crypto_provider_handle_t provider, 1235 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 1236 crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, 1237 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 1238 { 1239 int ret = CRYPTO_SUCCESS; 1240 uchar_t digest[MD5_DIGEST_LENGTH]; 1241 md5_hmac_ctx_t md5_hmac_ctx; 1242 uint32_t digest_len = MD5_DIGEST_LENGTH; 1243 uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 1244 1245 if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE && 1246 mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE) 1247 return (CRYPTO_MECHANISM_INVALID); 1248 1249 /* Add support for key by attributes (RFE 4706552) */ 1250 if (key->ck_format != CRYPTO_KEY_RAW) 1251 return (CRYPTO_ARGUMENTS_BAD); 1252 1253 if (ctx_template != NULL) { 1254 /* reuse context template */ 1255 bcopy(ctx_template, &md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1256 } else { 1257 /* no context template, compute context */ 1258 if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) { 1259 /* 1260 * Hash the passed-in key to get a smaller key. 1261 * The inner context is used since it hasn't been 1262 * initialized yet. 1263 */ 1264 PROV_MD5_DIGEST_KEY(&md5_hmac_ctx.hc_icontext, 1265 key->ck_data, keylen_in_bytes, digest); 1266 md5_mac_init_ctx(&md5_hmac_ctx, digest, 1267 MD5_DIGEST_LENGTH); 1268 } else { 1269 md5_mac_init_ctx(&md5_hmac_ctx, key->ck_data, 1270 keylen_in_bytes); 1271 } 1272 } 1273 1274 /* 1275 * Get the mechanism parameters, if applicable. 1276 */ 1277 if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) { 1278 if (mechanism->cm_param == NULL || 1279 mechanism->cm_param_len != sizeof (ulong_t)) { 1280 ret = CRYPTO_MECHANISM_PARAM_INVALID; 1281 goto bail; 1282 } 1283 PROV_MD5_GET_DIGEST_LEN(mechanism, digest_len); 1284 if (digest_len > MD5_DIGEST_LENGTH) { 1285 ret = CRYPTO_MECHANISM_PARAM_INVALID; 1286 goto bail; 1287 } 1288 } 1289 1290 if (mac->cd_length != digest_len) { 1291 ret = CRYPTO_INVALID_MAC; 1292 goto bail; 1293 } 1294 1295 /* do an MD5 update of the inner context using the specified data */ 1296 MD5_MAC_UPDATE(data, md5_hmac_ctx, ret); 1297 if (ret != CRYPTO_SUCCESS) 1298 /* the update failed, free context and bail */ 1299 goto bail; 1300 1301 /* do an MD5 final on the inner context */ 1302 MD5Final(digest, &md5_hmac_ctx.hc_icontext); 1303 1304 /* 1305 * Do an MD5 update on the outer context, feeding the inner 1306 * digest as data. 1307 */ 1308 MD5Update(&md5_hmac_ctx.hc_ocontext, digest, MD5_DIGEST_LENGTH); 1309 1310 /* 1311 * Do an MD5 final on the outer context, storing the computed 1312 * digest in the local digest buffer. 1313 */ 1314 MD5Final(digest, &md5_hmac_ctx.hc_ocontext); 1315 1316 /* 1317 * Compare the computed digest against the expected digest passed 1318 * as argument. 1319 */ 1320 switch (mac->cd_format) { 1321 1322 case CRYPTO_DATA_RAW: 1323 if (bcmp(digest, (unsigned char *)mac->cd_raw.iov_base + 1324 mac->cd_offset, digest_len) != 0) 1325 ret = CRYPTO_INVALID_MAC; 1326 break; 1327 1328 case CRYPTO_DATA_UIO: { 1329 off_t offset = mac->cd_offset; 1330 uint_t vec_idx; 1331 off_t scratch_offset = 0; 1332 size_t length = digest_len; 1333 size_t cur_len; 1334 1335 /* we support only kernel buffer */ 1336 if (mac->cd_uio->uio_segflg != UIO_SYSSPACE) 1337 return (CRYPTO_ARGUMENTS_BAD); 1338 1339 /* jump to the first iovec containing the expected digest */ 1340 for (vec_idx = 0; 1341 offset >= mac->cd_uio->uio_iov[vec_idx].iov_len && 1342 vec_idx < mac->cd_uio->uio_iovcnt; 1343 offset -= mac->cd_uio->uio_iov[vec_idx++].iov_len) 1344 ; 1345 if (vec_idx == mac->cd_uio->uio_iovcnt) { 1346 /* 1347 * The caller specified an offset that is 1348 * larger than the total size of the buffers 1349 * it provided. 1350 */ 1351 ret = CRYPTO_DATA_LEN_RANGE; 1352 break; 1353 } 1354 1355 /* do the comparison of computed digest vs specified one */ 1356 while (vec_idx < mac->cd_uio->uio_iovcnt && length > 0) { 1357 cur_len = MIN(mac->cd_uio->uio_iov[vec_idx].iov_len - 1358 offset, length); 1359 1360 if (bcmp(digest + scratch_offset, 1361 mac->cd_uio->uio_iov[vec_idx].iov_base + offset, 1362 cur_len) != 0) { 1363 ret = CRYPTO_INVALID_MAC; 1364 break; 1365 } 1366 1367 length -= cur_len; 1368 vec_idx++; 1369 scratch_offset += cur_len; 1370 offset = 0; 1371 } 1372 break; 1373 } 1374 1375 case CRYPTO_DATA_MBLK: { 1376 off_t offset = mac->cd_offset; 1377 mblk_t *mp; 1378 off_t scratch_offset = 0; 1379 size_t length = digest_len; 1380 size_t cur_len; 1381 1382 /* jump to the first mblk_t containing the expected digest */ 1383 for (mp = mac->cd_mp; mp != NULL && offset >= MBLKL(mp); 1384 offset -= MBLKL(mp), mp = mp->b_cont) 1385 ; 1386 if (mp == NULL) { 1387 /* 1388 * The caller specified an offset that is larger than 1389 * the total size of the buffers it provided. 1390 */ 1391 ret = CRYPTO_DATA_LEN_RANGE; 1392 break; 1393 } 1394 1395 while (mp != NULL && length > 0) { 1396 cur_len = MIN(MBLKL(mp) - offset, length); 1397 if (bcmp(digest + scratch_offset, 1398 mp->b_rptr + offset, cur_len) != 0) { 1399 ret = CRYPTO_INVALID_MAC; 1400 break; 1401 } 1402 1403 length -= cur_len; 1404 mp = mp->b_cont; 1405 scratch_offset += cur_len; 1406 offset = 0; 1407 } 1408 break; 1409 } 1410 1411 default: 1412 ret = CRYPTO_ARGUMENTS_BAD; 1413 } 1414 1415 bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1416 return (ret); 1417 bail: 1418 bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1419 mac->cd_length = 0; 1420 return (ret); 1421 } 1422 1423 /* 1424 * KCF software provider context management entry points. 1425 */ 1426 1427 /* ARGSUSED */ 1428 static int 1429 md5_create_ctx_template(crypto_provider_handle_t provider, 1430 crypto_mechanism_t *mechanism, crypto_key_t *key, 1431 crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size, 1432 crypto_req_handle_t req) 1433 { 1434 md5_hmac_ctx_t *md5_hmac_ctx_tmpl; 1435 uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 1436 1437 if ((mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE) && 1438 (mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE)) 1439 return (CRYPTO_MECHANISM_INVALID); 1440 1441 /* Add support for key by attributes (RFE 4706552) */ 1442 if (key->ck_format != CRYPTO_KEY_RAW) 1443 return (CRYPTO_ARGUMENTS_BAD); 1444 1445 /* 1446 * Allocate and initialize MD5 context. 1447 */ 1448 md5_hmac_ctx_tmpl = kmem_alloc(sizeof (md5_hmac_ctx_t), 1449 crypto_kmflag(req)); 1450 if (md5_hmac_ctx_tmpl == NULL) 1451 return (CRYPTO_HOST_MEMORY); 1452 1453 if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) { 1454 uchar_t digested_key[MD5_DIGEST_LENGTH]; 1455 1456 /* 1457 * Hash the passed-in key to get a smaller key. 1458 * The inner context is used since it hasn't been 1459 * initialized yet. 1460 */ 1461 PROV_MD5_DIGEST_KEY(&md5_hmac_ctx_tmpl->hc_icontext, 1462 key->ck_data, keylen_in_bytes, digested_key); 1463 md5_mac_init_ctx(md5_hmac_ctx_tmpl, digested_key, 1464 MD5_DIGEST_LENGTH); 1465 } else { 1466 md5_mac_init_ctx(md5_hmac_ctx_tmpl, key->ck_data, 1467 keylen_in_bytes); 1468 } 1469 1470 md5_hmac_ctx_tmpl->hc_mech_type = mechanism->cm_type; 1471 *ctx_template = (crypto_spi_ctx_template_t)md5_hmac_ctx_tmpl; 1472 *ctx_template_size = sizeof (md5_hmac_ctx_t); 1473 1474 return (CRYPTO_SUCCESS); 1475 } 1476 1477 static int 1478 md5_free_context(crypto_ctx_t *ctx) 1479 { 1480 uint_t ctx_len; 1481 md5_mech_type_t mech_type; 1482 1483 if (ctx->cc_provider_private == NULL) 1484 return (CRYPTO_SUCCESS); 1485 1486 /* 1487 * We have to free either MD5 or MD5-HMAC contexts, which 1488 * have different lengths. 1489 */ 1490 1491 mech_type = PROV_MD5_CTX(ctx)->mc_mech_type; 1492 if (mech_type == MD5_MECH_INFO_TYPE) 1493 ctx_len = sizeof (md5_ctx_t); 1494 else { 1495 ASSERT(mech_type == MD5_HMAC_MECH_INFO_TYPE || 1496 mech_type == MD5_HMAC_GEN_MECH_INFO_TYPE); 1497 ctx_len = sizeof (md5_hmac_ctx_t); 1498 } 1499 1500 bzero(ctx->cc_provider_private, ctx_len); 1501 kmem_free(ctx->cc_provider_private, ctx_len); 1502 ctx->cc_provider_private = NULL; 1503 1504 return (CRYPTO_SUCCESS); 1505 } 1506