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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)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
md4_provider_status(crypto_provider_handle_t provider,uint_t * status)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
md4_digest_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_req_handle_t req)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
md4_digest_update_uio(MD4_CTX * md4_ctx,crypto_data_t * data)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
md4_digest_final_uio(MD4_CTX * md4_ctx,crypto_data_t * digest,ulong_t digest_len,uchar_t * digest_scratch)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
md4_digest_update_mblk(MD4_CTX * md4_ctx,crypto_data_t * data)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
md4_digest_final_mblk(MD4_CTX * md4_ctx,crypto_data_t * digest,ulong_t digest_len,uchar_t * digest_scratch)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
md4_digest(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * digest,crypto_req_handle_t req)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
md4_digest_update(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)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
md4_digest_final(crypto_ctx_t * ctx,crypto_data_t * digest,crypto_req_handle_t req)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
md4_digest_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_data_t * data,crypto_data_t * digest,crypto_req_handle_t req)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 }
756