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 md4 module is created with one modlinkage,
  29  * this is different to md5 and sha1 modules which have a legacy misc
  30  * variant for direct calls to the Init/Update/Final routines.
  31  *
  32  * - a modlcrypto that allows the module to register with the Kernel
  33  *   Cryptographic Framework (KCF) as a software provider for the MD4
  34  *   mechanisms.
  35  */
  36 
  37 #include <sys/types.h>
  38 #include <sys/systm.h>
  39 #include <sys/modctl.h>
  40 #include <sys/cmn_err.h>
  41 #include <sys/ddi.h>
  42 #include <sys/crypto/common.h>
  43 #include <sys/crypto/spi.h>
  44 #include <sys/sysmacros.h>
  45 #include <sys/strsun.h>
  46 #include <sys/note.h>
  47 #include <sys/md4.h>
  48 
  49 extern struct mod_ops mod_miscops;
  50 extern struct mod_ops mod_cryptoops;
  51 
  52 /*
  53  * Module linkage information for the kernel.
  54  */
  55 
  56 static struct modlcrypto modlcrypto = {
  57         &mod_cryptoops,
  58         "MD4 Kernel SW Provider"
  59 };
  60 
  61 static struct modlinkage modlinkage = {
  62         MODREV_1,
  63         (void *)&modlcrypto,
  64         NULL
  65 };
  66 
  67 /*
  68  * CSPI information (entry points, provider info, etc.)
  69  */
  70 
  71 typedef enum md4_mech_type {
  72         MD4_MECH_INFO_TYPE,             /* SUN_CKM_MD4 */
  73 } md4_mech_type_t;
  74 
  75 #define MD4_DIGEST_LENGTH       16      /* MD4 digest length in bytes */
  76 
  77 /*
  78  * Context for MD4 mechanism.
  79  */
  80 typedef struct md4_ctx {
  81         md4_mech_type_t         mc_mech_type;   /* type of context */
  82         MD4_CTX                 mc_md4_ctx;     /* MD4 context */
  83 } md4_ctx_t;
  84 
  85 /*
  86  * Macros to access the MD4 contexts from a context passed
  87  * by KCF to one of the entry points.
  88  */
  89 
  90 #define PROV_MD4_CTX(ctx)       ((md4_ctx_t *)(ctx)->cc_provider_private)
  91 
  92 /*
  93  * Mechanism info structure passed to KCF during registration.
  94  */
  95 static crypto_mech_info_t md4_mech_info_tab[] = {
  96         /* MD4 */
  97         {SUN_CKM_MD4, MD4_MECH_INFO_TYPE,
  98             CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
  99             0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
 100 };
 101 
 102 static void md4_provider_status(crypto_provider_handle_t, uint_t *);
 103 
 104 static crypto_control_ops_t md4_control_ops = {
 105         md4_provider_status
 106 };
 107 
 108 static int md4_digest_init(crypto_ctx_t *, crypto_mechanism_t *,
 109     crypto_req_handle_t);
 110 static int md4_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
 111     crypto_req_handle_t);
 112 static int md4_digest_update(crypto_ctx_t *, crypto_data_t *,
 113     crypto_req_handle_t);
 114 static int md4_digest_final(crypto_ctx_t *, crypto_data_t *,
 115     crypto_req_handle_t);
 116 static int md4_digest_atomic(crypto_provider_handle_t, crypto_session_id_t,
 117     crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
 118     crypto_req_handle_t);
 119 
 120 static crypto_digest_ops_t md4_digest_ops = {
 121         md4_digest_init,
 122         md4_digest,
 123         md4_digest_update,
 124         NULL,
 125         md4_digest_final,
 126         md4_digest_atomic
 127 };
 128 
 129 static crypto_ops_t md4_crypto_ops = {
 130         &md4_control_ops,
 131         &md4_digest_ops,
 132         NULL,
 133         NULL,
 134         NULL,
 135         NULL,
 136         NULL,
 137         NULL,
 138         NULL,
 139         NULL,
 140         NULL,
 141         NULL,
 142         NULL,
 143         NULL,
 144 };
 145 
 146 static crypto_provider_info_t md4_prov_info = {
 147         CRYPTO_SPI_VERSION_1,
 148         "MD4 Software Provider",
 149         CRYPTO_SW_PROVIDER,
 150         {&modlinkage},
 151         NULL,
 152         &md4_crypto_ops,
 153         sizeof (md4_mech_info_tab)/sizeof (crypto_mech_info_t),
 154         md4_mech_info_tab
 155 };
 156 
 157 static crypto_kcf_provider_handle_t md4_prov_handle = NULL;
 158 
 159 int
 160 _init(void)
 161 {
 162         int ret;
 163 
 164         if ((ret = mod_install(&modlinkage)) != 0)
 165                 return (ret);
 166 
 167         /* Register with KCF.  If the registration fails, remove the module. */
 168         if (crypto_register_provider(&md4_prov_info, &md4_prov_handle)) {
 169                 (void) mod_remove(&modlinkage);
 170                 return (EACCES);
 171         }
 172 
 173         return (0);
 174 }
 175 
 176 int
 177 _fini(void)
 178 {
 179         /* Unregister from KCF if module is registered */
 180         if (md4_prov_handle != NULL) {
 181                 if (crypto_unregister_provider(md4_prov_handle))
 182                         return (EBUSY);
 183 
 184                 md4_prov_handle = NULL;
 185         }
 186 
 187         return (mod_remove(&modlinkage));
 188 }
 189 
 190 int
 191 _info(struct modinfo *modinfop)
 192 {
 193         return (mod_info(&modlinkage, modinfop));
 194 }
 195 
 196 /*
 197  * KCF software provider control entry points.
 198  */
 199 /* ARGSUSED */
 200 static void
 201 md4_provider_status(crypto_provider_handle_t provider, uint_t *status)
 202 {
 203         *status = CRYPTO_PROVIDER_READY;
 204 }
 205 
 206 /*
 207  * KCF software provider digest entry points.
 208  */
 209 
 210 static int
 211 md4_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
 212     crypto_req_handle_t req)
 213 {
 214         if (mechanism->cm_type != MD4_MECH_INFO_TYPE)
 215                 return (CRYPTO_MECHANISM_INVALID);
 216 
 217         /*
 218          * Allocate and initialize MD4 context.
 219          */
 220         ctx->cc_provider_private = kmem_alloc(sizeof (md4_ctx_t),
 221             crypto_kmflag(req));
 222         if (ctx->cc_provider_private == NULL)
 223                 return (CRYPTO_HOST_MEMORY);
 224 
 225         PROV_MD4_CTX(ctx)->mc_mech_type = MD4_MECH_INFO_TYPE;
 226         MD4Init(&PROV_MD4_CTX(ctx)->mc_md4_ctx);
 227 
 228         return (CRYPTO_SUCCESS);
 229 }
 230 
 231 /*
 232  * Helper MD4 digest update function for uio data.
 233  */
 234 static int
 235 md4_digest_update_uio(MD4_CTX *md4_ctx, crypto_data_t *data)
 236 {
 237         off_t offset = data->cd_offset;
 238         size_t length = data->cd_length;
 239         uint_t vec_idx;
 240         size_t cur_len;
 241 
 242         /* we support only kernel buffer */
 243         if (data->cd_uio->uio_segflg != UIO_SYSSPACE)
 244                 return (CRYPTO_ARGUMENTS_BAD);
 245 
 246         /*
 247          * Jump to the first iovec containing data to be
 248          * digested.
 249          */
 250         for (vec_idx = 0; vec_idx < data->cd_uio->uio_iovcnt &&
 251             offset >= data->cd_uio->uio_iov[vec_idx].iov_len;
 252             offset -= data->cd_uio->uio_iov[vec_idx++].iov_len)
 253                 ;
 254         if (vec_idx == data->cd_uio->uio_iovcnt) {
 255                 /*
 256                  * The caller specified an offset that is larger than the
 257                  * total size of the buffers it provided.
 258                  */
 259                 return (CRYPTO_DATA_LEN_RANGE);
 260         }
 261 
 262         /*
 263          * Now do the digesting on the iovecs.
 264          */
 265         while (vec_idx < data->cd_uio->uio_iovcnt && length > 0) {
 266                 cur_len = MIN(data->cd_uio->uio_iov[vec_idx].iov_len -
 267                     offset, length);
 268 
 269                 MD4Update(md4_ctx, data->cd_uio->uio_iov[vec_idx].iov_base +
 270                     offset, cur_len);
 271 
 272                 length -= cur_len;
 273                 vec_idx++;
 274                 offset = 0;
 275         }
 276 
 277         if (vec_idx == data->cd_uio->uio_iovcnt && length > 0) {
 278                 /*
 279                  * The end of the specified iovec's was reached but
 280                  * the length requested could not be processed, i.e.
 281                  * The caller requested to digest more data than it provided.
 282                  */
 283                 return (CRYPTO_DATA_LEN_RANGE);
 284         }
 285 
 286         return (CRYPTO_SUCCESS);
 287 }
 288 
 289 /*
 290  * Helper MD4 digest final function for uio data.
 291  * digest_len is the length of the desired digest. If digest_len
 292  * is smaller than the default MD4 digest length, the caller
 293  * must pass a scratch buffer, digest_scratch, which must
 294  * be at least MD4_DIGEST_LENGTH bytes.
 295  */
 296 static int
 297 md4_digest_final_uio(MD4_CTX *md4_ctx, crypto_data_t *digest,
 298     ulong_t digest_len, uchar_t *digest_scratch)
 299 {
 300         off_t offset = digest->cd_offset;
 301         uint_t vec_idx;
 302 
 303         /* we support only kernel buffer */
 304         if (digest->cd_uio->uio_segflg != UIO_SYSSPACE)
 305                 return (CRYPTO_ARGUMENTS_BAD);
 306 
 307         /*
 308          * Jump to the first iovec containing ptr to the digest to
 309          * be returned.
 310          */
 311         for (vec_idx = 0; offset >= digest->cd_uio->uio_iov[vec_idx].iov_len &&
 312             vec_idx < digest->cd_uio->uio_iovcnt;
 313             offset -= digest->cd_uio->uio_iov[vec_idx++].iov_len)
 314                 ;
 315         if (vec_idx == digest->cd_uio->uio_iovcnt) {
 316                 /*
 317                  * The caller specified an offset that is
 318                  * larger than the total size of the buffers
 319                  * it provided.
 320                  */
 321                 return (CRYPTO_DATA_LEN_RANGE);
 322         }
 323 
 324         if (offset + digest_len <=
 325             digest->cd_uio->uio_iov[vec_idx].iov_len) {
 326                 /*
 327                  * The computed MD4 digest will fit in the current
 328                  * iovec.
 329                  */
 330                 if (digest_len != MD4_DIGEST_LENGTH) {
 331                         /*
 332                          * The caller requested a short digest. Digest
 333                          * into a scratch buffer and return to
 334                          * the user only what was requested.
 335                          */
 336                         MD4Final(digest_scratch, md4_ctx);
 337                         bcopy(digest_scratch, (uchar_t *)digest->
 338                             cd_uio->uio_iov[vec_idx].iov_base + offset,
 339                             digest_len);
 340                 } else {
 341                         MD4Final((uchar_t *)digest->
 342                             cd_uio->uio_iov[vec_idx].iov_base + offset,
 343                             md4_ctx);
 344                 }
 345         } else {
 346                 /*
 347                  * The computed digest will be crossing one or more iovec's.
 348                  * This is bad performance-wise but we need to support it.
 349                  * Allocate a small scratch buffer on the stack and
 350                  * copy it piece meal to the specified digest iovec's.
 351                  */
 352                 uchar_t digest_tmp[MD4_DIGEST_LENGTH];
 353                 off_t scratch_offset = 0;
 354                 size_t length = digest_len;
 355                 size_t cur_len;
 356 
 357                 MD4Final(digest_tmp, md4_ctx);
 358 
 359                 while (vec_idx < digest->cd_uio->uio_iovcnt && length > 0) {
 360                         cur_len = MIN(digest->cd_uio->uio_iov[vec_idx].iov_len -
 361                             offset, length);
 362                         bcopy(digest_tmp + scratch_offset,
 363                             digest->cd_uio->uio_iov[vec_idx].iov_base + offset,
 364                             cur_len);
 365 
 366                         length -= cur_len;
 367                         vec_idx++;
 368                         scratch_offset += cur_len;
 369                         offset = 0;
 370                 }
 371 
 372                 if (vec_idx == digest->cd_uio->uio_iovcnt && length > 0) {
 373                         /*
 374                          * The end of the specified iovec's was reached but
 375                          * the length requested could not be processed, i.e.
 376                          * The caller requested to digest more data than it
 377                          * provided.
 378                          */
 379                         return (CRYPTO_DATA_LEN_RANGE);
 380                 }
 381         }
 382 
 383         return (CRYPTO_SUCCESS);
 384 }
 385 
 386 /*
 387  * Helper MD4 digest update for mblk's.
 388  */
 389 static int
 390 md4_digest_update_mblk(MD4_CTX *md4_ctx, crypto_data_t *data)
 391 {
 392         off_t offset = data->cd_offset;
 393         size_t length = data->cd_length;
 394         mblk_t *mp;
 395         size_t cur_len;
 396 
 397         /*
 398          * Jump to the first mblk_t containing data to be digested.
 399          */
 400         for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp);
 401             offset -= MBLKL(mp), mp = mp->b_cont)
 402                 ;
 403         if (mp == NULL) {
 404                 /*
 405                  * The caller specified an offset that is larger than the
 406                  * total size of the buffers it provided.
 407                  */
 408                 return (CRYPTO_DATA_LEN_RANGE);
 409         }
 410 
 411         /*
 412          * Now do the digesting on the mblk chain.
 413          */
 414         while (mp != NULL && length > 0) {
 415                 cur_len = MIN(MBLKL(mp) - offset, length);
 416                 MD4Update(md4_ctx, mp->b_rptr + offset, cur_len);
 417                 length -= cur_len;
 418                 offset = 0;
 419                 mp = mp->b_cont;
 420         }
 421 
 422         if (mp == NULL && length > 0) {
 423                 /*
 424                  * The end of the mblk was reached but the length requested
 425                  * could not be processed, i.e. The caller requested
 426                  * to digest more data than it provided.
 427                  */
 428                 return (CRYPTO_DATA_LEN_RANGE);
 429         }
 430 
 431         return (CRYPTO_SUCCESS);
 432 }
 433 
 434 /*
 435  * Helper MD4 digest final for mblk's.
 436  * digest_len is the length of the desired digest. If digest_len
 437  * is smaller than the default MD4 digest length, the caller
 438  * must pass a scratch buffer, digest_scratch, which must
 439  * be at least MD4_DIGEST_LENGTH bytes.
 440  */
 441 static int
 442 md4_digest_final_mblk(MD4_CTX *md4_ctx, crypto_data_t *digest,
 443     ulong_t digest_len, uchar_t *digest_scratch)
 444 {
 445         off_t offset = digest->cd_offset;
 446         mblk_t *mp;
 447 
 448         /*
 449          * Jump to the first mblk_t that will be used to store the digest.
 450          */
 451         for (mp = digest->cd_mp; mp != NULL && offset >= MBLKL(mp);
 452             offset -= MBLKL(mp), mp = mp->b_cont)
 453                 ;
 454         if (mp == NULL) {
 455                 /*
 456                  * The caller specified an offset that is larger than the
 457                  * total size of the buffers it provided.
 458                  */
 459                 return (CRYPTO_DATA_LEN_RANGE);
 460         }
 461 
 462         if (offset + digest_len <= MBLKL(mp)) {
 463                 /*
 464                  * The computed MD4 digest will fit in the current mblk.
 465                  * Do the MD4Final() in-place.
 466                  */
 467                 if (digest_len != MD4_DIGEST_LENGTH) {
 468                         /*
 469                          * The caller requested a short digest. Digest
 470                          * into a scratch buffer and return to
 471                          * the user only what was requested.
 472                          */
 473                         MD4Final(digest_scratch, md4_ctx);
 474                         bcopy(digest_scratch, mp->b_rptr + offset, digest_len);
 475                 } else {
 476                         MD4Final(mp->b_rptr + offset, md4_ctx);
 477                 }
 478         } else {
 479                 /*
 480                  * The computed digest will be crossing one or more mblk's.
 481                  * This is bad performance-wise but we need to support it.
 482                  * Allocate a small scratch buffer on the stack and
 483                  * copy it piece meal to the specified digest iovec's.
 484                  */
 485                 uchar_t digest_tmp[MD4_DIGEST_LENGTH];
 486                 off_t scratch_offset = 0;
 487                 size_t length = digest_len;
 488                 size_t cur_len;
 489 
 490                 MD4Final(digest_tmp, md4_ctx);
 491 
 492                 while (mp != NULL && length > 0) {
 493                         cur_len = MIN(MBLKL(mp) - offset, length);
 494                         bcopy(digest_tmp + scratch_offset,
 495                             mp->b_rptr + offset, cur_len);
 496 
 497                         length -= cur_len;
 498                         mp = mp->b_cont;
 499                         scratch_offset += cur_len;
 500                         offset = 0;
 501                 }
 502 
 503                 if (mp == NULL && length > 0) {
 504                         /*
 505                          * The end of the specified mblk was reached but
 506                          * the length requested could not be processed, i.e.
 507                          * The caller requested to digest more data than it
 508                          * provided.
 509                          */
 510                         return (CRYPTO_DATA_LEN_RANGE);
 511                 }
 512         }
 513 
 514         return (CRYPTO_SUCCESS);
 515 }
 516 
 517 /* ARGSUSED */
 518 static int
 519 md4_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
 520     crypto_req_handle_t req)
 521 {
 522         int ret = CRYPTO_SUCCESS;
 523 
 524         ASSERT(ctx->cc_provider_private != NULL);
 525 
 526         /*
 527          * We need to just return the length needed to store the output.
 528          * We should not destroy the context for the following cases.
 529          */
 530         if ((digest->cd_length == 0) ||
 531             (digest->cd_length < MD4_DIGEST_LENGTH)) {
 532                 digest->cd_length = MD4_DIGEST_LENGTH;
 533                 return (CRYPTO_BUFFER_TOO_SMALL);
 534         }
 535 
 536         /*
 537          * Do the MD4 update on the specified input data.
 538          */
 539         switch (data->cd_format) {
 540         case CRYPTO_DATA_RAW:
 541                 MD4Update(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
 542                     data->cd_raw.iov_base + data->cd_offset,
 543                     data->cd_length);
 544                 break;
 545         case CRYPTO_DATA_UIO:
 546                 ret = md4_digest_update_uio(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
 547                     data);
 548                 break;
 549         case CRYPTO_DATA_MBLK:
 550                 ret = md4_digest_update_mblk(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
 551                     data);
 552                 break;
 553         default:
 554                 ret = CRYPTO_ARGUMENTS_BAD;
 555         }
 556 
 557         if (ret != CRYPTO_SUCCESS) {
 558                 /* the update failed, free context and bail */
 559                 kmem_free(ctx->cc_provider_private, sizeof (md4_ctx_t));
 560                 ctx->cc_provider_private = NULL;
 561                 digest->cd_length = 0;
 562                 return (ret);
 563         }
 564 
 565         /*
 566          * Do an MD4 final, must be done separately since the digest
 567          * type can be different than the input data type.
 568          */
 569         switch (digest->cd_format) {
 570         case CRYPTO_DATA_RAW:
 571                 MD4Final((unsigned char *)digest->cd_raw.iov_base +
 572                     digest->cd_offset, &PROV_MD4_CTX(ctx)->mc_md4_ctx);
 573                 break;
 574         case CRYPTO_DATA_UIO:
 575                 ret = md4_digest_final_uio(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
 576                     digest, MD4_DIGEST_LENGTH, NULL);
 577                 break;
 578         case CRYPTO_DATA_MBLK:
 579                 ret = md4_digest_final_mblk(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
 580                     digest, MD4_DIGEST_LENGTH, NULL);
 581                 break;
 582         default:
 583                 ret = CRYPTO_ARGUMENTS_BAD;
 584         }
 585 
 586         /* all done, free context and return */
 587 
 588         if (ret == CRYPTO_SUCCESS) {
 589                 digest->cd_length = MD4_DIGEST_LENGTH;
 590         } else {
 591                 digest->cd_length = 0;
 592         }
 593 
 594         kmem_free(ctx->cc_provider_private, sizeof (md4_ctx_t));
 595         ctx->cc_provider_private = NULL;
 596         return (ret);
 597 }
 598 
 599 /* ARGSUSED */
 600 static int
 601 md4_digest_update(crypto_ctx_t *ctx, crypto_data_t *data,
 602     crypto_req_handle_t req)
 603 {
 604         int ret = CRYPTO_SUCCESS;
 605 
 606         ASSERT(ctx->cc_provider_private != NULL);
 607 
 608         /*
 609          * Do the MD4 update on the specified input data.
 610          */
 611         switch (data->cd_format) {
 612         case CRYPTO_DATA_RAW:
 613                 MD4Update(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
 614                     data->cd_raw.iov_base + data->cd_offset,
 615                     data->cd_length);
 616                 break;
 617         case CRYPTO_DATA_UIO:
 618                 ret = md4_digest_update_uio(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
 619                     data);
 620                 break;
 621         case CRYPTO_DATA_MBLK:
 622                 ret = md4_digest_update_mblk(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
 623                     data);
 624                 break;
 625         default:
 626                 ret = CRYPTO_ARGUMENTS_BAD;
 627         }
 628 
 629         return (ret);
 630 }
 631 
 632 /* ARGSUSED */
 633 static int
 634 md4_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest,
 635     crypto_req_handle_t req)
 636 {
 637         int ret = CRYPTO_SUCCESS;
 638 
 639         ASSERT(ctx->cc_provider_private != NULL);
 640 
 641         /*
 642          * We need to just return the length needed to store the output.
 643          * We should not destroy the context for the following cases.
 644          */
 645         if ((digest->cd_length == 0) ||
 646             (digest->cd_length < MD4_DIGEST_LENGTH)) {
 647                 digest->cd_length = MD4_DIGEST_LENGTH;
 648                 return (CRYPTO_BUFFER_TOO_SMALL);
 649         }
 650 
 651         /*
 652          * Do an MD4 final.
 653          */
 654         switch (digest->cd_format) {
 655         case CRYPTO_DATA_RAW:
 656                 MD4Final((unsigned char *)digest->cd_raw.iov_base +
 657                     digest->cd_offset, &PROV_MD4_CTX(ctx)->mc_md4_ctx);
 658                 break;
 659         case CRYPTO_DATA_UIO:
 660                 ret = md4_digest_final_uio(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
 661                     digest, MD4_DIGEST_LENGTH, NULL);
 662                 break;
 663         case CRYPTO_DATA_MBLK:
 664                 ret = md4_digest_final_mblk(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
 665                     digest, MD4_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 = MD4_DIGEST_LENGTH;
 675         } else {
 676                 digest->cd_length = 0;
 677         }
 678 
 679         kmem_free(ctx->cc_provider_private, sizeof (md4_ctx_t));
 680         ctx->cc_provider_private = NULL;
 681 
 682         return (ret);
 683 }
 684 
 685 /* ARGSUSED */
 686 static int
 687 md4_digest_atomic(crypto_provider_handle_t provider,
 688     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
 689     crypto_data_t *data, crypto_data_t *digest,
 690     crypto_req_handle_t req)
 691 {
 692         int ret = CRYPTO_SUCCESS;
 693         MD4_CTX md4_ctx;
 694 
 695         if (mechanism->cm_type != MD4_MECH_INFO_TYPE)
 696                 return (CRYPTO_MECHANISM_INVALID);
 697 
 698         /*
 699          * Do the MD4 init.
 700          */
 701         MD4Init(&md4_ctx);
 702 
 703         /*
 704          * Do the MD4 update on the specified input data.
 705          */
 706         switch (data->cd_format) {
 707         case CRYPTO_DATA_RAW:
 708                 MD4Update(&md4_ctx, data->cd_raw.iov_base + data->cd_offset,
 709                     data->cd_length);
 710                 break;
 711         case CRYPTO_DATA_UIO:
 712                 ret = md4_digest_update_uio(&md4_ctx, data);
 713                 break;
 714         case CRYPTO_DATA_MBLK:
 715                 ret = md4_digest_update_mblk(&md4_ctx, data);
 716                 break;
 717         default:
 718                 ret = CRYPTO_ARGUMENTS_BAD;
 719         }
 720 
 721         if (ret != CRYPTO_SUCCESS) {
 722                 /* the update failed, bail */
 723                 digest->cd_length = 0;
 724                 return (ret);
 725         }
 726 
 727         /*
 728          * Do an MD4 final, must be done separately since the digest
 729          * type can be different than the input data type.
 730          */
 731         switch (digest->cd_format) {
 732         case CRYPTO_DATA_RAW:
 733                 MD4Final((unsigned char *)digest->cd_raw.iov_base +
 734                     digest->cd_offset, &md4_ctx);
 735                 break;
 736         case CRYPTO_DATA_UIO:
 737                 ret = md4_digest_final_uio(&md4_ctx, digest,
 738                     MD4_DIGEST_LENGTH, NULL);
 739                 break;
 740         case CRYPTO_DATA_MBLK:
 741                 ret = md4_digest_final_mblk(&md4_ctx, digest,
 742                     MD4_DIGEST_LENGTH, NULL);
 743                 break;
 744         default:
 745                 ret = CRYPTO_ARGUMENTS_BAD;
 746         }
 747 
 748         if (ret == CRYPTO_SUCCESS) {
 749                 digest->cd_length = MD4_DIGEST_LENGTH;
 750         } else {
 751                 digest->cd_length = 0;
 752         }
 753 
 754         return (ret);
 755 }