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