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