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 2006 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 %I%" 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 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 if (vec_idx == digest->cd_uio->uio_iovcnt) { 405 /* 406 * The caller specified an offset that is 407 * larger than the total size of the buffers 408 * it provided. 409 */ 410 return (CRYPTO_DATA_LEN_RANGE); 411 } 412 413 if (offset + digest_len <= 414 digest->cd_uio->uio_iov[vec_idx].iov_len) { 415 /* 416 * The computed MD5 digest will fit in the current 417 * iovec. 418 */ 419 if (digest_len != MD5_DIGEST_LENGTH) { 420 /* 421 * The caller requested a short digest. Digest 422 * into a scratch buffer and return to 423 * the user only what was requested. 424 */ 425 MD5Final(digest_scratch, md5_ctx); 426 bcopy(digest_scratch, (uchar_t *)digest-> 427 cd_uio->uio_iov[vec_idx].iov_base + offset, 428 digest_len); 429 } else { 430 MD5Final((uchar_t *)digest-> 431 cd_uio->uio_iov[vec_idx].iov_base + offset, 432 md5_ctx); 433 } 434 } else { 435 /* 436 * The computed digest will be crossing one or more iovec's. 437 * This is bad performance-wise but we need to support it. 438 * Allocate a small scratch buffer on the stack and 439 * copy it piece meal to the specified digest iovec's. 440 */ 441 uchar_t digest_tmp[MD5_DIGEST_LENGTH]; 442 off_t scratch_offset = 0; 443 size_t length = digest_len; 444 size_t cur_len; 445 446 MD5Final(digest_tmp, md5_ctx); 447 448 while (vec_idx < digest->cd_uio->uio_iovcnt && length > 0) { 449 cur_len = MIN(digest->cd_uio->uio_iov[vec_idx].iov_len - 450 offset, length); 451 bcopy(digest_tmp + scratch_offset, 452 digest->cd_uio->uio_iov[vec_idx].iov_base + offset, 453 cur_len); 454 455 length -= cur_len; 456 vec_idx++; 457 scratch_offset += cur_len; 458 offset = 0; 459 } 460 461 if (vec_idx == digest->cd_uio->uio_iovcnt && length > 0) { 462 /* 463 * The end of the specified iovec's was reached but 464 * the length requested could not be processed, i.e. 465 * The caller requested to digest more data than it 466 * provided. 467 */ 468 return (CRYPTO_DATA_LEN_RANGE); 469 } 470 } 471 472 return (CRYPTO_SUCCESS); 473 } 474 475 /* 476 * Helper MD5 digest update for mblk's. 477 */ 478 static int 479 md5_digest_update_mblk(MD5_CTX *md5_ctx, crypto_data_t *data) 480 { 481 off_t offset = data->cd_offset; 482 size_t length = data->cd_length; 483 mblk_t *mp; 484 size_t cur_len; 485 486 /* 487 * Jump to the first mblk_t containing data to be digested. 488 */ 489 for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp); 490 offset -= MBLKL(mp), mp = mp->b_cont); 491 if (mp == NULL) { 492 /* 493 * The caller specified an offset that is larger than the 494 * total size of the buffers it provided. 495 */ 496 return (CRYPTO_DATA_LEN_RANGE); 497 } 498 499 /* 500 * Now do the digesting on the mblk chain. 501 */ 502 while (mp != NULL && length > 0) { 503 cur_len = MIN(MBLKL(mp) - offset, length); 504 MD5Update(md5_ctx, mp->b_rptr + offset, cur_len); 505 length -= cur_len; 506 offset = 0; 507 mp = mp->b_cont; 508 } 509 510 if (mp == NULL && length > 0) { 511 /* 512 * The end of the mblk was reached but the length requested 513 * could not be processed, i.e. The caller requested 514 * to digest more data than it provided. 515 */ 516 return (CRYPTO_DATA_LEN_RANGE); 517 } 518 519 return (CRYPTO_SUCCESS); 520 } 521 522 /* 523 * Helper MD5 digest final for mblk's. 524 * digest_len is the length of the desired digest. If digest_len 525 * is smaller than the default MD5 digest length, the caller 526 * must pass a scratch buffer, digest_scratch, which must 527 * be at least MD5_DIGEST_LENGTH bytes. 528 */ 529 static int 530 md5_digest_final_mblk(MD5_CTX *md5_ctx, crypto_data_t *digest, 531 ulong_t digest_len, uchar_t *digest_scratch) 532 { 533 off_t offset = digest->cd_offset; 534 mblk_t *mp; 535 536 /* 537 * Jump to the first mblk_t that will be used to store the digest. 538 */ 539 for (mp = digest->cd_mp; mp != NULL && offset >= MBLKL(mp); 540 offset -= MBLKL(mp), mp = mp->b_cont); 541 if (mp == NULL) { 542 /* 543 * The caller specified an offset that is larger than the 544 * total size of the buffers it provided. 545 */ 546 return (CRYPTO_DATA_LEN_RANGE); 547 } 548 549 if (offset + digest_len <= MBLKL(mp)) { 550 /* 551 * The computed MD5 digest will fit in the current mblk. 552 * Do the MD5Final() in-place. 553 */ 554 if (digest_len != MD5_DIGEST_LENGTH) { 555 /* 556 * The caller requested a short digest. Digest 557 * into a scratch buffer and return to 558 * the user only what was requested. 559 */ 560 MD5Final(digest_scratch, md5_ctx); 561 bcopy(digest_scratch, mp->b_rptr + offset, digest_len); 562 } else { 563 MD5Final(mp->b_rptr + offset, md5_ctx); 564 } 565 } else { 566 /* 567 * The computed digest will be crossing one or more mblk's. 568 * This is bad performance-wise but we need to support it. 569 * Allocate a small scratch buffer on the stack and 570 * copy it piece meal to the specified digest iovec's. 571 */ 572 uchar_t digest_tmp[MD5_DIGEST_LENGTH]; 573 off_t scratch_offset = 0; 574 size_t length = digest_len; 575 size_t cur_len; 576 577 MD5Final(digest_tmp, md5_ctx); 578 579 while (mp != NULL && length > 0) { 580 cur_len = MIN(MBLKL(mp) - offset, length); 581 bcopy(digest_tmp + scratch_offset, 582 mp->b_rptr + offset, cur_len); 583 584 length -= cur_len; 585 mp = mp->b_cont; 586 scratch_offset += cur_len; 587 offset = 0; 588 } 589 590 if (mp == NULL && length > 0) { 591 /* 592 * The end of the specified mblk was reached but 593 * the length requested could not be processed, i.e. 594 * The caller requested to digest more data than it 595 * provided. 596 */ 597 return (CRYPTO_DATA_LEN_RANGE); 598 } 599 } 600 601 return (CRYPTO_SUCCESS); 602 } 603 604 /* ARGSUSED */ 605 static int 606 md5_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest, 607 crypto_req_handle_t req) 608 { 609 int ret = CRYPTO_SUCCESS; 610 611 ASSERT(ctx->cc_provider_private != NULL); 612 613 /* 614 * We need to just return the length needed to store the output. 615 * We should not destroy the context for the following cases. 616 */ 617 if ((digest->cd_length == 0) || 618 (digest->cd_length < MD5_DIGEST_LENGTH)) { 619 digest->cd_length = MD5_DIGEST_LENGTH; 620 return (CRYPTO_BUFFER_TOO_SMALL); 621 } 622 623 /* 624 * Do the MD5 update on the specified input data. 625 */ 626 switch (data->cd_format) { 627 case CRYPTO_DATA_RAW: 628 MD5Update(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 629 data->cd_raw.iov_base + data->cd_offset, 630 data->cd_length); 631 break; 632 case CRYPTO_DATA_UIO: 633 ret = md5_digest_update_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 634 data); 635 break; 636 case CRYPTO_DATA_MBLK: 637 ret = md5_digest_update_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 638 data); 639 break; 640 default: 641 ret = CRYPTO_ARGUMENTS_BAD; 642 } 643 644 if (ret != CRYPTO_SUCCESS) { 645 /* the update failed, free context and bail */ 646 kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t)); 647 ctx->cc_provider_private = NULL; 648 digest->cd_length = 0; 649 return (ret); 650 } 651 652 /* 653 * Do an MD5 final, must be done separately since the digest 654 * type can be different than the input data type. 655 */ 656 switch (digest->cd_format) { 657 case CRYPTO_DATA_RAW: 658 MD5Final((unsigned char *)digest->cd_raw.iov_base + 659 digest->cd_offset, &PROV_MD5_CTX(ctx)->mc_md5_ctx); 660 break; 661 case CRYPTO_DATA_UIO: 662 ret = md5_digest_final_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 663 digest, MD5_DIGEST_LENGTH, NULL); 664 break; 665 case CRYPTO_DATA_MBLK: 666 ret = md5_digest_final_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 667 digest, MD5_DIGEST_LENGTH, NULL); 668 break; 669 default: 670 ret = CRYPTO_ARGUMENTS_BAD; 671 } 672 673 /* all done, free context and return */ 674 675 if (ret == CRYPTO_SUCCESS) { 676 digest->cd_length = MD5_DIGEST_LENGTH; 677 } else { 678 digest->cd_length = 0; 679 } 680 681 kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t)); 682 ctx->cc_provider_private = NULL; 683 return (ret); 684 } 685 686 /* ARGSUSED */ 687 static int 688 md5_digest_update(crypto_ctx_t *ctx, crypto_data_t *data, 689 crypto_req_handle_t req) 690 { 691 int ret = CRYPTO_SUCCESS; 692 693 ASSERT(ctx->cc_provider_private != NULL); 694 695 /* 696 * Do the MD5 update on the specified input data. 697 */ 698 switch (data->cd_format) { 699 case CRYPTO_DATA_RAW: 700 MD5Update(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 701 data->cd_raw.iov_base + data->cd_offset, 702 data->cd_length); 703 break; 704 case CRYPTO_DATA_UIO: 705 ret = md5_digest_update_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 706 data); 707 break; 708 case CRYPTO_DATA_MBLK: 709 ret = md5_digest_update_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 710 data); 711 break; 712 default: 713 ret = CRYPTO_ARGUMENTS_BAD; 714 } 715 716 return (ret); 717 } 718 719 /* ARGSUSED */ 720 static int 721 md5_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest, 722 crypto_req_handle_t req) 723 { 724 int ret = CRYPTO_SUCCESS; 725 726 ASSERT(ctx->cc_provider_private != NULL); 727 728 /* 729 * We need to just return the length needed to store the output. 730 * We should not destroy the context for the following cases. 731 */ 732 if ((digest->cd_length == 0) || 733 (digest->cd_length < MD5_DIGEST_LENGTH)) { 734 digest->cd_length = MD5_DIGEST_LENGTH; 735 return (CRYPTO_BUFFER_TOO_SMALL); 736 } 737 738 /* 739 * Do an MD5 final. 740 */ 741 switch (digest->cd_format) { 742 case CRYPTO_DATA_RAW: 743 MD5Final((unsigned char *)digest->cd_raw.iov_base + 744 digest->cd_offset, &PROV_MD5_CTX(ctx)->mc_md5_ctx); 745 break; 746 case CRYPTO_DATA_UIO: 747 ret = md5_digest_final_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 748 digest, MD5_DIGEST_LENGTH, NULL); 749 break; 750 case CRYPTO_DATA_MBLK: 751 ret = md5_digest_final_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 752 digest, MD5_DIGEST_LENGTH, NULL); 753 break; 754 default: 755 ret = CRYPTO_ARGUMENTS_BAD; 756 } 757 758 /* all done, free context and return */ 759 760 if (ret == CRYPTO_SUCCESS) { 761 digest->cd_length = MD5_DIGEST_LENGTH; 762 } else { 763 digest->cd_length = 0; 764 } 765 766 kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t)); 767 ctx->cc_provider_private = NULL; 768 769 return (ret); 770 } 771 772 /* ARGSUSED */ 773 static int 774 md5_digest_atomic(crypto_provider_handle_t provider, 775 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 776 crypto_data_t *data, crypto_data_t *digest, 777 crypto_req_handle_t req) 778 { 779 int ret = CRYPTO_SUCCESS; 780 MD5_CTX md5_ctx; 781 782 if (mechanism->cm_type != MD5_MECH_INFO_TYPE) 783 return (CRYPTO_MECHANISM_INVALID); 784 785 /* 786 * Do the MD5 init. 787 */ 788 MD5Init(&md5_ctx); 789 790 /* 791 * Do the MD5 update on the specified input data. 792 */ 793 switch (data->cd_format) { 794 case CRYPTO_DATA_RAW: 795 MD5Update(&md5_ctx, data->cd_raw.iov_base + data->cd_offset, 796 data->cd_length); 797 break; 798 case CRYPTO_DATA_UIO: 799 ret = md5_digest_update_uio(&md5_ctx, data); 800 break; 801 case CRYPTO_DATA_MBLK: 802 ret = md5_digest_update_mblk(&md5_ctx, data); 803 break; 804 default: 805 ret = CRYPTO_ARGUMENTS_BAD; 806 } 807 808 if (ret != CRYPTO_SUCCESS) { 809 /* the update failed, bail */ 810 digest->cd_length = 0; 811 return (ret); 812 } 813 814 /* 815 * Do an MD5 final, must be done separately since the digest 816 * type can be different than the input data type. 817 */ 818 switch (digest->cd_format) { 819 case CRYPTO_DATA_RAW: 820 MD5Final((unsigned char *)digest->cd_raw.iov_base + 821 digest->cd_offset, &md5_ctx); 822 break; 823 case CRYPTO_DATA_UIO: 824 ret = md5_digest_final_uio(&md5_ctx, digest, 825 MD5_DIGEST_LENGTH, NULL); 826 break; 827 case CRYPTO_DATA_MBLK: 828 ret = md5_digest_final_mblk(&md5_ctx, digest, 829 MD5_DIGEST_LENGTH, NULL); 830 break; 831 default: 832 ret = CRYPTO_ARGUMENTS_BAD; 833 } 834 835 if (ret == CRYPTO_SUCCESS) { 836 digest->cd_length = MD5_DIGEST_LENGTH; 837 } else { 838 digest->cd_length = 0; 839 } 840 841 return (ret); 842 } 843 844 /* 845 * KCF software provider mac entry points. 846 * 847 * MD5 HMAC is: MD5(key XOR opad, MD5(key XOR ipad, text)) 848 * 849 * Init: 850 * The initialization routine initializes what we denote 851 * as the inner and outer contexts by doing 852 * - for inner context: MD5(key XOR ipad) 853 * - for outer context: MD5(key XOR opad) 854 * 855 * Update: 856 * Each subsequent MD5 HMAC update will result in an 857 * update of the inner context with the specified data. 858 * 859 * Final: 860 * The MD5 HMAC final will do a MD5 final operation on the 861 * inner context, and the resulting digest will be used 862 * as the data for an update on the outer context. Last 863 * but not least, an MD5 final on the outer context will 864 * be performed to obtain the MD5 HMAC digest to return 865 * to the user. 866 */ 867 868 /* 869 * Initialize a MD5-HMAC context. 870 */ 871 static void 872 md5_mac_init_ctx(md5_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes) 873 { 874 uint32_t ipad[MD5_HMAC_INTS_PER_BLOCK]; 875 uint32_t opad[MD5_HMAC_INTS_PER_BLOCK]; 876 uint_t i; 877 878 bzero(ipad, MD5_HMAC_BLOCK_SIZE); 879 bzero(opad, MD5_HMAC_BLOCK_SIZE); 880 881 bcopy(keyval, ipad, length_in_bytes); 882 bcopy(keyval, opad, length_in_bytes); 883 884 /* XOR key with ipad (0x36) and opad (0x5c) */ 885 for (i = 0; i < MD5_HMAC_INTS_PER_BLOCK; i++) { 886 ipad[i] ^= 0x36363636; 887 opad[i] ^= 0x5c5c5c5c; 888 } 889 890 /* perform MD5 on ipad */ 891 MD5Init(&ctx->hc_icontext); 892 MD5Update(&ctx->hc_icontext, ipad, MD5_HMAC_BLOCK_SIZE); 893 894 /* perform MD5 on opad */ 895 MD5Init(&ctx->hc_ocontext); 896 MD5Update(&ctx->hc_ocontext, opad, MD5_HMAC_BLOCK_SIZE); 897 } 898 899 /* 900 * Initializes a multi-part MAC operation. 901 */ 902 static int 903 md5_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 904 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 905 crypto_req_handle_t req) 906 { 907 int ret = CRYPTO_SUCCESS; 908 uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 909 910 if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE && 911 mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE) 912 return (CRYPTO_MECHANISM_INVALID); 913 914 /* Add support for key by attributes (RFE 4706552) */ 915 if (key->ck_format != CRYPTO_KEY_RAW) 916 return (CRYPTO_ARGUMENTS_BAD); 917 918 ctx->cc_provider_private = kmem_alloc(sizeof (md5_hmac_ctx_t), 919 crypto_kmflag(req)); 920 if (ctx->cc_provider_private == NULL) 921 return (CRYPTO_HOST_MEMORY); 922 923 if (ctx_template != NULL) { 924 /* reuse context template */ 925 bcopy(ctx_template, PROV_MD5_HMAC_CTX(ctx), 926 sizeof (md5_hmac_ctx_t)); 927 } else { 928 /* no context template, compute context */ 929 if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) { 930 uchar_t digested_key[MD5_DIGEST_LENGTH]; 931 md5_hmac_ctx_t *hmac_ctx = ctx->cc_provider_private; 932 933 /* 934 * Hash the passed-in key to get a smaller key. 935 * The inner context is used since it hasn't been 936 * initialized yet. 937 */ 938 PROV_MD5_DIGEST_KEY(&hmac_ctx->hc_icontext, 939 key->ck_data, keylen_in_bytes, digested_key); 940 md5_mac_init_ctx(PROV_MD5_HMAC_CTX(ctx), 941 digested_key, MD5_DIGEST_LENGTH); 942 } else { 943 md5_mac_init_ctx(PROV_MD5_HMAC_CTX(ctx), 944 key->ck_data, keylen_in_bytes); 945 } 946 } 947 948 /* 949 * Get the mechanism parameters, if applicable. 950 */ 951 PROV_MD5_HMAC_CTX(ctx)->hc_mech_type = mechanism->cm_type; 952 if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) { 953 if (mechanism->cm_param == NULL || 954 mechanism->cm_param_len != sizeof (ulong_t)) 955 ret = CRYPTO_MECHANISM_PARAM_INVALID; 956 PROV_MD5_GET_DIGEST_LEN(mechanism, 957 PROV_MD5_HMAC_CTX(ctx)->hc_digest_len); 958 if (PROV_MD5_HMAC_CTX(ctx)->hc_digest_len > 959 MD5_DIGEST_LENGTH) 960 ret = CRYPTO_MECHANISM_PARAM_INVALID; 961 } 962 963 if (ret != CRYPTO_SUCCESS) { 964 bzero(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t)); 965 kmem_free(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t)); 966 ctx->cc_provider_private = NULL; 967 } 968 969 return (ret); 970 } 971 972 973 /* ARGSUSED */ 974 static int 975 md5_mac_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req) 976 { 977 int ret = CRYPTO_SUCCESS; 978 979 ASSERT(ctx->cc_provider_private != NULL); 980 981 /* 982 * Do an MD5 update of the inner context using the specified 983 * data. 984 */ 985 switch (data->cd_format) { 986 case CRYPTO_DATA_RAW: 987 MD5Update(&PROV_MD5_HMAC_CTX(ctx)->hc_icontext, 988 data->cd_raw.iov_base + data->cd_offset, 989 data->cd_length); 990 break; 991 case CRYPTO_DATA_UIO: 992 ret = md5_digest_update_uio( 993 &PROV_MD5_HMAC_CTX(ctx)->hc_icontext, data); 994 break; 995 case CRYPTO_DATA_MBLK: 996 ret = md5_digest_update_mblk( 997 &PROV_MD5_HMAC_CTX(ctx)->hc_icontext, data); 998 break; 999 default: 1000 ret = CRYPTO_ARGUMENTS_BAD; 1001 } 1002 1003 return (ret); 1004 } 1005 1006 /* ARGSUSED */ 1007 static int 1008 md5_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac, crypto_req_handle_t req) 1009 { 1010 int ret = CRYPTO_SUCCESS; 1011 uchar_t digest[MD5_DIGEST_LENGTH]; 1012 uint32_t digest_len = MD5_DIGEST_LENGTH; 1013 1014 ASSERT(ctx->cc_provider_private != NULL); 1015 1016 if (PROV_MD5_HMAC_CTX(ctx)->hc_mech_type == MD5_HMAC_GEN_MECH_INFO_TYPE) 1017 digest_len = PROV_MD5_HMAC_CTX(ctx)->hc_digest_len; 1018 1019 /* 1020 * We need to just return the length needed to store the output. 1021 * We should not destroy the context for the following cases. 1022 */ 1023 if ((mac->cd_length == 0) || (mac->cd_length < digest_len)) { 1024 mac->cd_length = digest_len; 1025 return (CRYPTO_BUFFER_TOO_SMALL); 1026 } 1027 1028 /* 1029 * Do an MD5 final on the inner context. 1030 */ 1031 MD5Final(digest, &PROV_MD5_HMAC_CTX(ctx)->hc_icontext); 1032 1033 /* 1034 * Do an MD5 update on the outer context, feeding the inner 1035 * digest as data. 1036 */ 1037 MD5Update(&PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, digest, 1038 MD5_DIGEST_LENGTH); 1039 1040 /* 1041 * Do an MD5 final on the outer context, storing the computing 1042 * digest in the users buffer. 1043 */ 1044 switch (mac->cd_format) { 1045 case CRYPTO_DATA_RAW: 1046 if (digest_len != MD5_DIGEST_LENGTH) { 1047 /* 1048 * The caller requested a short digest. Digest 1049 * into a scratch buffer and return to 1050 * the user only what was requested. 1051 */ 1052 MD5Final(digest, 1053 &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext); 1054 bcopy(digest, (unsigned char *)mac->cd_raw.iov_base + 1055 mac->cd_offset, digest_len); 1056 } else { 1057 MD5Final((unsigned char *)mac->cd_raw.iov_base + 1058 mac->cd_offset, 1059 &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext); 1060 } 1061 break; 1062 case CRYPTO_DATA_UIO: 1063 ret = md5_digest_final_uio( 1064 &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, mac, 1065 digest_len, digest); 1066 break; 1067 case CRYPTO_DATA_MBLK: 1068 ret = md5_digest_final_mblk( 1069 &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, mac, 1070 digest_len, digest); 1071 break; 1072 default: 1073 ret = CRYPTO_ARGUMENTS_BAD; 1074 } 1075 1076 if (ret == CRYPTO_SUCCESS) { 1077 mac->cd_length = digest_len; 1078 } else { 1079 mac->cd_length = 0; 1080 } 1081 1082 bzero(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t)); 1083 kmem_free(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t)); 1084 ctx->cc_provider_private = NULL; 1085 1086 return (ret); 1087 } 1088 1089 #define MD5_MAC_UPDATE(data, ctx, ret) { \ 1090 switch (data->cd_format) { \ 1091 case CRYPTO_DATA_RAW: \ 1092 MD5Update(&(ctx).hc_icontext, \ 1093 data->cd_raw.iov_base + data->cd_offset, \ 1094 data->cd_length); \ 1095 break; \ 1096 case CRYPTO_DATA_UIO: \ 1097 ret = md5_digest_update_uio(&(ctx).hc_icontext, data); \ 1098 break; \ 1099 case CRYPTO_DATA_MBLK: \ 1100 ret = md5_digest_update_mblk(&(ctx).hc_icontext, \ 1101 data); \ 1102 break; \ 1103 default: \ 1104 ret = CRYPTO_ARGUMENTS_BAD; \ 1105 } \ 1106 } 1107 1108 1109 /* ARGSUSED */ 1110 static int 1111 md5_mac_atomic(crypto_provider_handle_t provider, 1112 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 1113 crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, 1114 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 1115 { 1116 int ret = CRYPTO_SUCCESS; 1117 uchar_t digest[MD5_DIGEST_LENGTH]; 1118 md5_hmac_ctx_t md5_hmac_ctx; 1119 uint32_t digest_len = MD5_DIGEST_LENGTH; 1120 uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 1121 1122 if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE && 1123 mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE) 1124 return (CRYPTO_MECHANISM_INVALID); 1125 1126 /* Add support for key by attributes (RFE 4706552) */ 1127 if (key->ck_format != CRYPTO_KEY_RAW) 1128 return (CRYPTO_ARGUMENTS_BAD); 1129 1130 if (ctx_template != NULL) { 1131 /* reuse context template */ 1132 bcopy(ctx_template, &md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1133 } else { 1134 /* no context template, compute context */ 1135 if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) { 1136 /* 1137 * Hash the passed-in key to get a smaller key. 1138 * The inner context is used since it hasn't been 1139 * initialized yet. 1140 */ 1141 PROV_MD5_DIGEST_KEY(&md5_hmac_ctx.hc_icontext, 1142 key->ck_data, keylen_in_bytes, digest); 1143 md5_mac_init_ctx(&md5_hmac_ctx, digest, 1144 MD5_DIGEST_LENGTH); 1145 } else { 1146 md5_mac_init_ctx(&md5_hmac_ctx, key->ck_data, 1147 keylen_in_bytes); 1148 } 1149 } 1150 1151 /* 1152 * Get the mechanism parameters, if applicable. 1153 */ 1154 if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) { 1155 if (mechanism->cm_param == NULL || 1156 mechanism->cm_param_len != sizeof (ulong_t)) { 1157 ret = CRYPTO_MECHANISM_PARAM_INVALID; 1158 goto bail; 1159 } 1160 PROV_MD5_GET_DIGEST_LEN(mechanism, digest_len); 1161 if (digest_len > MD5_DIGEST_LENGTH) { 1162 ret = CRYPTO_MECHANISM_PARAM_INVALID; 1163 goto bail; 1164 } 1165 } 1166 1167 /* do an MD5 update of the inner context using the specified data */ 1168 MD5_MAC_UPDATE(data, md5_hmac_ctx, ret); 1169 if (ret != CRYPTO_SUCCESS) 1170 /* the update failed, free context and bail */ 1171 goto bail; 1172 1173 /* do an MD5 final on the inner context */ 1174 MD5Final(digest, &md5_hmac_ctx.hc_icontext); 1175 1176 /* 1177 * Do an MD5 update on the outer context, feeding the inner 1178 * digest as data. 1179 */ 1180 MD5Update(&md5_hmac_ctx.hc_ocontext, digest, MD5_DIGEST_LENGTH); 1181 1182 /* 1183 * Do an MD5 final on the outer context, storing the computed 1184 * digest in the users buffer. 1185 */ 1186 switch (mac->cd_format) { 1187 case CRYPTO_DATA_RAW: 1188 if (digest_len != MD5_DIGEST_LENGTH) { 1189 /* 1190 * The caller requested a short digest. Digest 1191 * into a scratch buffer and return to 1192 * the user only what was requested. 1193 */ 1194 MD5Final(digest, &md5_hmac_ctx.hc_ocontext); 1195 bcopy(digest, (unsigned char *)mac->cd_raw.iov_base + 1196 mac->cd_offset, digest_len); 1197 } else { 1198 MD5Final((unsigned char *)mac->cd_raw.iov_base + 1199 mac->cd_offset, &md5_hmac_ctx.hc_ocontext); 1200 } 1201 break; 1202 case CRYPTO_DATA_UIO: 1203 ret = md5_digest_final_uio(&md5_hmac_ctx.hc_ocontext, mac, 1204 digest_len, digest); 1205 break; 1206 case CRYPTO_DATA_MBLK: 1207 ret = md5_digest_final_mblk(&md5_hmac_ctx.hc_ocontext, mac, 1208 digest_len, digest); 1209 break; 1210 default: 1211 ret = CRYPTO_ARGUMENTS_BAD; 1212 } 1213 1214 if (ret == CRYPTO_SUCCESS) { 1215 mac->cd_length = digest_len; 1216 } else { 1217 mac->cd_length = 0; 1218 } 1219 /* Extra paranoia: zeroizing the local context on the stack */ 1220 bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1221 1222 return (ret); 1223 bail: 1224 bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1225 mac->cd_length = 0; 1226 return (ret); 1227 } 1228 1229 /* ARGSUSED */ 1230 static int 1231 md5_mac_verify_atomic(crypto_provider_handle_t provider, 1232 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 1233 crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, 1234 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 1235 { 1236 int ret = CRYPTO_SUCCESS; 1237 uchar_t digest[MD5_DIGEST_LENGTH]; 1238 md5_hmac_ctx_t md5_hmac_ctx; 1239 uint32_t digest_len = MD5_DIGEST_LENGTH; 1240 uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 1241 1242 if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE && 1243 mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE) 1244 return (CRYPTO_MECHANISM_INVALID); 1245 1246 /* Add support for key by attributes (RFE 4706552) */ 1247 if (key->ck_format != CRYPTO_KEY_RAW) 1248 return (CRYPTO_ARGUMENTS_BAD); 1249 1250 if (ctx_template != NULL) { 1251 /* reuse context template */ 1252 bcopy(ctx_template, &md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1253 } else { 1254 /* no context template, compute context */ 1255 if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) { 1256 /* 1257 * Hash the passed-in key to get a smaller key. 1258 * The inner context is used since it hasn't been 1259 * initialized yet. 1260 */ 1261 PROV_MD5_DIGEST_KEY(&md5_hmac_ctx.hc_icontext, 1262 key->ck_data, keylen_in_bytes, digest); 1263 md5_mac_init_ctx(&md5_hmac_ctx, digest, 1264 MD5_DIGEST_LENGTH); 1265 } else { 1266 md5_mac_init_ctx(&md5_hmac_ctx, key->ck_data, 1267 keylen_in_bytes); 1268 } 1269 } 1270 1271 /* 1272 * Get the mechanism parameters, if applicable. 1273 */ 1274 if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) { 1275 if (mechanism->cm_param == NULL || 1276 mechanism->cm_param_len != sizeof (ulong_t)) { 1277 ret = CRYPTO_MECHANISM_PARAM_INVALID; 1278 goto bail; 1279 } 1280 PROV_MD5_GET_DIGEST_LEN(mechanism, digest_len); 1281 if (digest_len > MD5_DIGEST_LENGTH) { 1282 ret = CRYPTO_MECHANISM_PARAM_INVALID; 1283 goto bail; 1284 } 1285 } 1286 1287 if (mac->cd_length != digest_len) { 1288 ret = CRYPTO_INVALID_MAC; 1289 goto bail; 1290 } 1291 1292 /* do an MD5 update of the inner context using the specified data */ 1293 MD5_MAC_UPDATE(data, md5_hmac_ctx, ret); 1294 if (ret != CRYPTO_SUCCESS) 1295 /* the update failed, free context and bail */ 1296 goto bail; 1297 1298 /* do an MD5 final on the inner context */ 1299 MD5Final(digest, &md5_hmac_ctx.hc_icontext); 1300 1301 /* 1302 * Do an MD5 update on the outer context, feeding the inner 1303 * digest as data. 1304 */ 1305 MD5Update(&md5_hmac_ctx.hc_ocontext, digest, MD5_DIGEST_LENGTH); 1306 1307 /* 1308 * Do an MD5 final on the outer context, storing the computed 1309 * digest in the local digest buffer. 1310 */ 1311 MD5Final(digest, &md5_hmac_ctx.hc_ocontext); 1312 1313 /* 1314 * Compare the computed digest against the expected digest passed 1315 * as argument. 1316 */ 1317 switch (mac->cd_format) { 1318 1319 case CRYPTO_DATA_RAW: 1320 if (bcmp(digest, (unsigned char *)mac->cd_raw.iov_base + 1321 mac->cd_offset, digest_len) != 0) 1322 ret = CRYPTO_INVALID_MAC; 1323 break; 1324 1325 case CRYPTO_DATA_UIO: { 1326 off_t offset = mac->cd_offset; 1327 uint_t vec_idx; 1328 off_t scratch_offset = 0; 1329 size_t length = digest_len; 1330 size_t cur_len; 1331 1332 /* we support only kernel buffer */ 1333 if (mac->cd_uio->uio_segflg != UIO_SYSSPACE) 1334 return (CRYPTO_ARGUMENTS_BAD); 1335 1336 /* jump to the first iovec containing the expected digest */ 1337 for (vec_idx = 0; 1338 offset >= mac->cd_uio->uio_iov[vec_idx].iov_len && 1339 vec_idx < mac->cd_uio->uio_iovcnt; 1340 offset -= mac->cd_uio->uio_iov[vec_idx++].iov_len); 1341 if (vec_idx == mac->cd_uio->uio_iovcnt) { 1342 /* 1343 * The caller specified an offset that is 1344 * larger than the total size of the buffers 1345 * it provided. 1346 */ 1347 ret = CRYPTO_DATA_LEN_RANGE; 1348 break; 1349 } 1350 1351 /* do the comparison of computed digest vs specified one */ 1352 while (vec_idx < mac->cd_uio->uio_iovcnt && length > 0) { 1353 cur_len = MIN(mac->cd_uio->uio_iov[vec_idx].iov_len - 1354 offset, length); 1355 1356 if (bcmp(digest + scratch_offset, 1357 mac->cd_uio->uio_iov[vec_idx].iov_base + offset, 1358 cur_len) != 0) { 1359 ret = CRYPTO_INVALID_MAC; 1360 break; 1361 } 1362 1363 length -= cur_len; 1364 vec_idx++; 1365 scratch_offset += cur_len; 1366 offset = 0; 1367 } 1368 break; 1369 } 1370 1371 case CRYPTO_DATA_MBLK: { 1372 off_t offset = mac->cd_offset; 1373 mblk_t *mp; 1374 off_t scratch_offset = 0; 1375 size_t length = digest_len; 1376 size_t cur_len; 1377 1378 /* jump to the first mblk_t containing the expected digest */ 1379 for (mp = mac->cd_mp; mp != NULL && offset >= MBLKL(mp); 1380 offset -= MBLKL(mp), mp = mp->b_cont); 1381 if (mp == NULL) { 1382 /* 1383 * The caller specified an offset that is larger than 1384 * the total size of the buffers it provided. 1385 */ 1386 ret = CRYPTO_DATA_LEN_RANGE; 1387 break; 1388 } 1389 1390 while (mp != NULL && length > 0) { 1391 cur_len = MIN(MBLKL(mp) - offset, length); 1392 if (bcmp(digest + scratch_offset, 1393 mp->b_rptr + offset, cur_len) != 0) { 1394 ret = CRYPTO_INVALID_MAC; 1395 break; 1396 } 1397 1398 length -= cur_len; 1399 mp = mp->b_cont; 1400 scratch_offset += cur_len; 1401 offset = 0; 1402 } 1403 break; 1404 } 1405 1406 default: 1407 ret = CRYPTO_ARGUMENTS_BAD; 1408 } 1409 1410 bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1411 return (ret); 1412 bail: 1413 bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1414 mac->cd_length = 0; 1415 return (ret); 1416 } 1417 1418 /* 1419 * KCF software provider context management entry points. 1420 */ 1421 1422 /* ARGSUSED */ 1423 static int 1424 md5_create_ctx_template(crypto_provider_handle_t provider, 1425 crypto_mechanism_t *mechanism, crypto_key_t *key, 1426 crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size, 1427 crypto_req_handle_t req) 1428 { 1429 md5_hmac_ctx_t *md5_hmac_ctx_tmpl; 1430 uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 1431 1432 if ((mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE) && 1433 (mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE)) 1434 return (CRYPTO_MECHANISM_INVALID); 1435 1436 /* Add support for key by attributes (RFE 4706552) */ 1437 if (key->ck_format != CRYPTO_KEY_RAW) 1438 return (CRYPTO_ARGUMENTS_BAD); 1439 1440 /* 1441 * Allocate and initialize MD5 context. 1442 */ 1443 md5_hmac_ctx_tmpl = kmem_alloc(sizeof (md5_hmac_ctx_t), 1444 crypto_kmflag(req)); 1445 if (md5_hmac_ctx_tmpl == NULL) 1446 return (CRYPTO_HOST_MEMORY); 1447 1448 if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) { 1449 uchar_t digested_key[MD5_DIGEST_LENGTH]; 1450 1451 /* 1452 * Hash the passed-in key to get a smaller key. 1453 * The inner context is used since it hasn't been 1454 * initialized yet. 1455 */ 1456 PROV_MD5_DIGEST_KEY(&md5_hmac_ctx_tmpl->hc_icontext, 1457 key->ck_data, keylen_in_bytes, digested_key); 1458 md5_mac_init_ctx(md5_hmac_ctx_tmpl, digested_key, 1459 MD5_DIGEST_LENGTH); 1460 } else { 1461 md5_mac_init_ctx(md5_hmac_ctx_tmpl, key->ck_data, 1462 keylen_in_bytes); 1463 } 1464 1465 md5_hmac_ctx_tmpl->hc_mech_type = mechanism->cm_type; 1466 *ctx_template = (crypto_spi_ctx_template_t)md5_hmac_ctx_tmpl; 1467 *ctx_template_size = sizeof (md5_hmac_ctx_t); 1468 1469 return (CRYPTO_SUCCESS); 1470 } 1471 1472 static int 1473 md5_free_context(crypto_ctx_t *ctx) 1474 { 1475 uint_t ctx_len; 1476 md5_mech_type_t mech_type; 1477 1478 if (ctx->cc_provider_private == NULL) 1479 return (CRYPTO_SUCCESS); 1480 1481 /* 1482 * We have to free either MD5 or MD5-HMAC contexts, which 1483 * have different lengths. 1484 */ 1485 1486 mech_type = PROV_MD5_CTX(ctx)->mc_mech_type; 1487 if (mech_type == MD5_MECH_INFO_TYPE) 1488 ctx_len = sizeof (md5_ctx_t); 1489 else { 1490 ASSERT(mech_type == MD5_HMAC_MECH_INFO_TYPE || 1491 mech_type == MD5_HMAC_GEN_MECH_INFO_TYPE); 1492 ctx_len = sizeof (md5_hmac_ctx_t); 1493 } 1494 1495 bzero(ctx->cc_provider_private, ctx_len); 1496 kmem_free(ctx->cc_provider_private, ctx_len); 1497 ctx->cc_provider_private = NULL; 1498 1499 return (CRYPTO_SUCCESS); 1500 } 1501