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 }