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