changeset 4002:d12f36b7c388

PSARC/2007/139 Kernel Crypto support for MD4 6354305 Kernel Crypto support for MD4 6533491 libmd's MD4 produces invalid message digests in 64-bit mode 6539262 MD4/MD5/SHA1/SHA2 Final functions not consistent
author darrenm
date Tue, 10 Apr 2007 11:12:59 -0700
parents 4d632d6bcf85
children 70e1c9a81b40
files usr/src/cmd/cmd-crypto/etc/kcf.conf usr/src/common/crypto/md4/md4.c usr/src/common/crypto/md5/md5.c usr/src/common/crypto/sha1/sha1.c usr/src/common/crypto/sha2/sha2.c usr/src/lib/libmd/common/md4.h usr/src/pkgdefs/SUNWckr/prototype_i386 usr/src/pkgdefs/SUNWckr/prototype_sparc usr/src/pkgdefs/SUNWhea/prototype_com usr/src/pkgdefs/common_files/i.kcfconfbase usr/src/uts/common/Makefile.files usr/src/uts/common/Makefile.rules usr/src/uts/common/crypto/io/dprov.c usr/src/uts/common/crypto/io/md4_mod.c usr/src/uts/common/sys/Makefile usr/src/uts/common/sys/crypto/common.h usr/src/uts/common/sys/md4.h usr/src/uts/common/sys/md5.h usr/src/uts/intel/Makefile.intel.shared usr/src/uts/intel/md4/Makefile usr/src/uts/intel/md4/inc.flg usr/src/uts/sparc/Makefile.sparc.shared usr/src/uts/sparc/md4/Makefile usr/src/uts/sparc/md4/inc.flg
diffstat 24 files changed, 1188 insertions(+), 91 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/cmd-crypto/etc/kcf.conf	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/cmd/cmd-crypto/etc/kcf.conf	Tue Apr 10 11:12:59 2007 -0700
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -47,6 +46,7 @@
 blowfish:supportedlist=CKM_BLOWFISH_ECB,CKM_BLOWFISH_CBC
 sha1:supportedlist=CKM_SHA_1,CKM_SHA_1_HMAC_GENERAL,CKM_SHA_1_HMAC
 sha2:supportedlist=CKM_SHA256,CKM_SHA256_HMAC,CKM_SHA256_HMAC_GENERAL,CKM_SHA384,CKM_SHA384_HMAC,CKM_SHA384_HMAC_GENERAL,CKM_SHA512,CKM_SHA512_HMAC,CKM_SHA512_HMAC_GENERAL
+md4:supportedlist=CKM_MD4
 md5:supportedlist=CKM_MD5,CKM_MD5_HMAC_GENERAL,CKM_MD5_HMAC
 rsa:supportedlist=CKM_RSA_PKCS,CKM_RSA_X_509,CKM_MD5_RSA_PKCS,CKM_SHA1_RSA_PKCS,CKM_SHA256_RSA_PKCS,CKM_SHA384_RSA_PKCS,CKM_SHA512_RSA_PKCS
 swrand:supportedlist=random
--- a/usr/src/common/crypto/md4/md4.c	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/common/crypto/md4/md4.c	Tue Apr 10 11:12:59 2007 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -31,10 +31,14 @@
  * documentation and/or software.
  */
 
-#include	<strings.h>
-#include	<sys/types.h>
+#include <sys/types.h>
+#ifdef _KERNEL
+#include <sys/sunddi.h>
+#else
+#include <strings.h>
+#endif /* _KERNEL */
 
-#include	"md4.h"
+#include <sys/md4.h>
 
 /*
  * Constants for MD4Transform routine.
@@ -52,9 +56,9 @@
 #define	S33 11
 #define	S34 15
 
-static void MD4Transform(ulong_t [4], unsigned char [64]);
-static void Encode(unsigned char *, ulong_t *, unsigned int);
-static void Decode(ulong_t *, unsigned char *, unsigned int);
+static void MD4Transform(uint32_t [4], unsigned char [64]);
+static void Encode(unsigned char *, uint32_t *, unsigned int);
+static void Decode(uint32_t *, unsigned char *, unsigned int);
 
 static unsigned char PADDING[64] = {
 	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -82,11 +86,11 @@
 		(a) = ROTATE_LEFT((a), (s)); \
 	}
 #define	GG(a, b, c, d, x, s) { \
-		(a) += G((b), (c), (d)) + (x) + (ulong_t)0x5a827999; \
+		(a) += G((b), (c), (d)) + (x) + (uint32_t)0x5a827999; \
 		(a) = ROTATE_LEFT((a), (s)); \
 	}
 #define	HH(a, b, c, d, x, s) { \
-		(a) += H((b), (c), (d)) + (x) + (ulong_t)0x6ed9eba1; \
+		(a) += H((b), (c), (d)) + (x) + (uint32_t)0x6ed9eba1; \
 		(a) = ROTATE_LEFT((a), (s)); \
 	}
 
@@ -94,8 +98,7 @@
  * MD4 initialization. Begins an MD4 operation, writing a new context.
  */
 void
-MD4Init(context)
-	MD4_CTX *context;			/* context */
+MD4Init(MD4_CTX *context)
 {
 	context->count[0] = context->count[1] = 0;
 
@@ -123,10 +126,10 @@
 	/* Compute number of bytes mod 64 */
 	index = (unsigned int)((context->count[0] >> 3) & 0x3F);
 	/* Update number of bits */
-	if ((context->count[0] += ((ulong_t)inputLen << 3))
-	    < ((ulong_t)inputLen << 3))
+	if ((context->count[0] += ((uint32_t)inputLen << 3))
+	    < ((uint32_t)inputLen << 3))
 		context->count[1]++;
-	context->count[1] += ((ulong_t)inputLen >> 29);
+	context->count[1] += ((uint32_t)inputLen >> 29);
 
 	partLen = 64 - index;
 
@@ -183,9 +186,9 @@
  * MD4 basic transformation. Transforms state based on block.
  */
 static void
-MD4Transform(ulong_t state[4], unsigned char block[64])
+MD4Transform(uint32_t state[4], unsigned char block[64])
 {
-	ulong_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+	uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
 
 
 	Decode(x, block, 64);
@@ -255,13 +258,13 @@
 }
 
 /*
- * Encodes input (ulong_t) into output (unsigned char). Assumes len is
+ * Encodes input (uint32_t) into output (unsigned char). Assumes len is
  * a multiple of 4.
  */
 static void
 Encode(output, input, len)
 	unsigned char *output;
-	ulong_t *input;
+	uint32_t *input;
 	unsigned int len;
 {
 	unsigned int i, j;
@@ -275,20 +278,20 @@
 }
 
 /*
- * Decodes input (unsigned char) into output (ulong_t). Assumes len is
+ * Decodes input (unsigned char) into output (uint32_t). Assumes len is
  * a multiple of 4.
  */
 static void
 Decode(output, input, len)
-	ulong_t *output;
+	uint32_t *output;
 	unsigned char *input;
 	unsigned int len;
 {
 	unsigned int i, j;
 
 	for (i = 0, j = 0; j < len; i++, j += 4)
-		output[i] = ((ulong_t)input[j]) |
-			(((ulong_t)input[j+1]) << 8) |
-			(((ulong_t)input[j+2]) << 16) |
-			(((ulong_t)input[j+3]) << 24);
+		output[i] = ((uint32_t)input[j]) |
+			(((uint32_t)input[j+1]) << 8) |
+			(((uint32_t)input[j+2]) << 16) |
+			(((uint32_t)input[j+3]) << 24);
 }
--- a/usr/src/common/crypto/md5/md5.c	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/common/crypto/md5/md5.c	Tue Apr 10 11:12:59 2007 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -324,13 +324,15 @@
  *
  * purpose: ends an md5 digest operation, finalizing the message digest and
  *          zeroing the context.
- *   input: uint8_t *	: a buffer to store the digest in
+ *   input: uchar_t *	: a buffer to store the digest in
+ *			: The function actually uses void* because many
+ *			: callers pass things other than uchar_t here.
  *          MD5_CTX *   : the context to finalize, save, and zero
  *  output: void
  */
 
 void
-MD5Final(unsigned char *digest, MD5_CTX *ctx)
+MD5Final(void *digest, MD5_CTX *ctx)
 {
 	uint8_t		bitcount_le[sizeof (ctx->count)];
 	uint32_t	index = (ctx->count[0] >> 3) & 0x3f;
--- a/usr/src/common/crypto/sha1/sha1.c	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/common/crypto/sha1/sha1.c	Tue Apr 10 11:12:59 2007 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -391,7 +391,9 @@
  *
  * purpose: ends an sha1 digest operation, finalizing the message digest and
  *          zeroing the context.
- *   input: uint8_t *	: a buffer to store the digest in
+ *   input: uchar_t *	: a buffer to store the digest in
+ *			: The function actually uses void* because many
+ *			: callers pass things other than uchar_t here.
  *          SHA1_CTX *  : the context to finalize, save, and zero
  *  output: void
  */
--- a/usr/src/common/crypto/sha2/sha2.c	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/common/crypto/sha2/sha2.c	Tue Apr 10 11:12:59 2007 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -845,7 +845,9 @@
  *
  * purpose: ends an sha2 digest operation, finalizing the message digest and
  *          zeroing the context.
- *   input: uint8_t *	: a buffer to store the digest in
+ *   input: uchar_t *	: a buffer to store the digest in
+ *			: The function actually uses void* because many
+ *			: callers pass things other than uchar_t here.
  *          SHA2_CTX *  : the context to finalize, save, and zero
  *  output: void
  */
--- a/usr/src/lib/libmd/common/md4.h	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/lib/libmd/common/md4.h	Tue Apr 10 11:12:59 2007 -0700
@@ -1,57 +1,34 @@
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef	__MD4_H
-#define	__MD4_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-
-/*
- * MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
  */
 
 /*
- * Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
- *
- * License to copy and use this software is granted provided that it
- * is identified as the "RSA Data Security, Inc. MD4 Message-Digest
- * Algorithm" in all material mentioning or referencing this software
- * or this function.
- *
- * License is also granted to make and use derivative works provided
- * that such works are identified as "derived from the RSA Data
- * Security, Inc. MD4 Message-Digest Algorithm" in all material
- * mentioning or referencing the derived work.
- *
- * RSA Data Security, Inc. makes no representations concerning either
- * the merchantability of this software or the suitability of this
- * software for any particular purpose. It is provided "as is"
- * without express or implied warranty of any kind.
- *
- * These notices must be retained in any copies of any part of this
- * documentation and/or software.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 
-#ifdef	__cplusplus
-extern "C" {
-#endif
+#ifndef _MD4_H
+#define	_MD4_H
 
-/* MD4 context. */
-typedef struct {
-	ulong_t state[4];	/* state (ABCD) */
-	ulong_t count[2];	/* number of bits, modulo 2^64 (lsb first) */
-	unsigned char buffer[64];	/* input buffer */
-} MD4_CTX;
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
 
-void MD4Init(MD4_CTX *);
-void MD4Update(MD4_CTX *, const void *_RESTRICT_KYWD, size_t);
-void MD4Final(void *, MD4_CTX *);
+#include <sys/md4.h>
 
-#ifdef	__cplusplus
-}
-#endif
-
-#endif	/* __MD4_H */
+#endif	/* _MD4_H */
--- a/usr/src/pkgdefs/SUNWckr/prototype_i386	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/pkgdefs/SUNWckr/prototype_i386	Tue Apr 10 11:12:59 2007 -0700
@@ -51,6 +51,7 @@
 f none kernel/crypto/arcfour 755 root sys
 f none kernel/crypto/blowfish 755 root sys
 f none kernel/crypto/des 755 root sys
+f none kernel/crypto/md4 755 root sys
 f none kernel/crypto/md5 755 root sys
 f none kernel/crypto/rsa 755 root sys
 f none kernel/crypto/sha1 755 root sys
@@ -247,6 +248,7 @@
 f none kernel/crypto/amd64/arcfour 755 root sys
 f none kernel/crypto/amd64/blowfish 755 root sys
 f none kernel/crypto/amd64/des 755 root sys
+f none kernel/crypto/amd64/md4 755 root sys
 f none kernel/crypto/amd64/md5 755 root sys
 f none kernel/crypto/amd64/rsa 755 root sys
 f none kernel/crypto/amd64/sha1 755 root sys
--- a/usr/src/pkgdefs/SUNWckr/prototype_sparc	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/pkgdefs/SUNWckr/prototype_sparc	Tue Apr 10 11:12:59 2007 -0700
@@ -54,6 +54,7 @@
 f none kernel/crypto/sparcv9/arcfour 755 root sys
 f none kernel/crypto/sparcv9/blowfish 755 root sys
 f none kernel/crypto/sparcv9/des 755 root sys
+f none kernel/crypto/sparcv9/md4 755 root sys
 f none kernel/crypto/sparcv9/md5 755 root sys
 f none kernel/crypto/sparcv9/rsa 755 root sys
 f none kernel/crypto/sparcv9/sha1 755 root sys
--- a/usr/src/pkgdefs/SUNWhea/prototype_com	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/pkgdefs/SUNWhea/prototype_com	Tue Apr 10 11:12:59 2007 -0700
@@ -885,6 +885,7 @@
 f none usr/include/sys/mem.h 644 root bin
 f none usr/include/sys/mem_config.h 644 root bin
 f none usr/include/sys/memlist.h 644 root bin
+f none usr/include/sys/md4.h 644 root bin
 f none usr/include/sys/md5.h 644 root bin
 f none usr/include/sys/md5_consts.h 644 root bin
 f none usr/include/sys/mkdev.h 644 root bin
--- a/usr/src/pkgdefs/common_files/i.kcfconfbase	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/pkgdefs/common_files/i.kcfconfbase	Tue Apr 10 11:12:59 2007 -0700
@@ -3,9 +3,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -48,15 +47,21 @@
 		if [ $? != 0 ]; then
 			swrand=`egrep '^swrand' $src`
 		fi
+		egrep '^md4' $dest > /dev/null 2>&1
+		if [ $? != 0 ]; then
+			md4=`egrep '^md4' $src`
+		fi
 		export rsa
 		export rc4
 		export sha2
 		export swrand
+		export md4
 		nawk '/^# End SUNWcsr/ { \
 			if (ENVIRON["rc4"] != "") {print ENVIRON["rc4"]} \
 			if (ENVIRON["rsa"] != "") {print ENVIRON["rsa"]} \
 			if (ENVIRON["sha2"] != "") {print ENVIRON["sha2"]} \
 			if (ENVIRON["swrand"] != "") {print ENVIRON["swrand"]} \
+			if (ENVIRON["md4"] != "") {print ENVIRON["md4"]} \
 		     } \
 		     { print } \
 		' $dest > $dest.$$
--- a/usr/src/uts/common/Makefile.files	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/uts/common/Makefile.files	Tue Apr 10 11:12:59 2007 -0700
@@ -429,6 +429,8 @@
 
 SAD_OBJS +=	sad.o
 
+MD4_OBJS +=	md4.o md4_mod.o
+
 MD5_OBJS +=	md5.o md5_mod.o
 
 SHA1_OBJS +=	sha1.o sha1_mod.o
--- a/usr/src/uts/common/Makefile.rules	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/uts/common/Makefile.rules	Tue Apr 10 11:12:59 2007 -0700
@@ -842,6 +842,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(COMMONBASE)/crypto/md4/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(COMMONBASE)/crypto/md5/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -1545,6 +1549,9 @@
 $(LINTS_DIR)/%.ln:       	$(COMMONBASE)/lvm/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(COMMONBASE)/crypto/md4/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(COMMONBASE)/crypto/md5/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- a/usr/src/uts/common/crypto/io/dprov.c	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/uts/common/crypto/io/dprov.c	Tue Apr 10 11:12:59 2007 -0700
@@ -194,6 +194,8 @@
  */
 
 typedef enum dprov_mech_type {
+	MD4_MECH_INFO_TYPE,		/* SUN_CKM_MD4 */
+
 	MD5_MECH_INFO_TYPE,		/* SUN_CKM_MD5 */
 	MD5_HMAC_MECH_INFO_TYPE,	/* SUN_CKM_MD5_HMAC */
 	MD5_HMAC_GEN_MECH_INFO_TYPE,	/* SUN_CKM_MD5_HMAC_GENERAL */
@@ -287,6 +289,10 @@
 #define	DPROV_CKM_RSA_PKCS_KEY_PAIR_GEN	"CKM_RSA_PKCS_KEY_PAIR_GEN"
 
 static crypto_mech_info_t dprov_mech_info_tab[] = {
+	/* MD4 */
+	{SUN_CKM_MD4, MD4_MECH_INFO_TYPE,
+	    CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC, 0, 0,
+	    CRYPTO_KEYSIZE_UNIT_IN_BITS},
 	/* MD5 */
 	{SUN_CKM_MD5, MD5_MECH_INFO_TYPE,
 	    CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC, 0, 0,
@@ -1746,7 +1752,8 @@
 	DPROV_DEBUG(D_DIGEST, ("(%d) dprov_digest_init: started\n", instance));
 
 	/* check mechanism */
-	if (mechanism->cm_type != MD5_MECH_INFO_TYPE &&
+	if (mechanism->cm_type != MD4_MECH_INFO_TYPE &&
+	    mechanism->cm_type != MD5_MECH_INFO_TYPE &&
 	    mechanism->cm_type != SHA1_MECH_INFO_TYPE &&
 	    mechanism->cm_type != SHA256_MECH_INFO_TYPE &&
 	    mechanism->cm_type != SHA384_MECH_INFO_TYPE &&
@@ -1875,7 +1882,8 @@
 	    instance));
 
 	/* check mechanism */
-	if (mechanism->cm_type != MD5_MECH_INFO_TYPE &&
+	if (mechanism->cm_type != MD4_MECH_INFO_TYPE &&
+	    mechanism->cm_type != MD5_MECH_INFO_TYPE &&
 	    mechanism->cm_type != SHA1_MECH_INFO_TYPE &&
 	    mechanism->cm_type != SHA256_MECH_INFO_TYPE &&
 	    mechanism->cm_type != SHA384_MECH_INFO_TYPE &&
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/crypto/io/md4_mod.c	Tue Apr 10 11:12:59 2007 -0700
@@ -0,0 +1,765 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * In kernel module, the md4 module is created with one modlinkage,
+ * this is different to md5 and sha1 modules which have a legacy misc
+ * variant for direct calls to the Init/Update/Final routines.
+ *
+ * - a modlcrypto that allows the module to register with the Kernel
+ *   Cryptographic Framework (KCF) as a software provider for the MD4
+ *   mechanisms.
+ */
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/modctl.h>
+#include <sys/cmn_err.h>
+#include <sys/ddi.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/spi.h>
+#include <sys/sysmacros.h>
+#include <sys/strsun.h>
+#include <sys/note.h>
+#include <sys/md4.h>
+
+extern struct mod_ops mod_miscops;
+extern struct mod_ops mod_cryptoops;
+
+/*
+ * Module linkage information for the kernel.
+ */
+
+static struct modlcrypto modlcrypto = {
+	&mod_cryptoops,
+	"MD4 Kernel SW Provider %I%"
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1,
+	(void *)&modlcrypto,
+	NULL
+};
+
+/*
+ * CSPI information (entry points, provider info, etc.)
+ */
+
+typedef enum md4_mech_type {
+	MD4_MECH_INFO_TYPE,		/* SUN_CKM_MD4 */
+} md4_mech_type_t;
+
+#define	MD4_DIGEST_LENGTH	16	/* MD4 digest length in bytes */
+
+/*
+ * Context for MD4 mechanism.
+ */
+typedef struct md4_ctx {
+	md4_mech_type_t		mc_mech_type;	/* type of context */
+	MD4_CTX			mc_md4_ctx;	/* MD4 context */
+} md4_ctx_t;
+
+/*
+ * Macros to access the MD4 contexts from a context passed
+ * by KCF to one of the entry points.
+ */
+
+#define	PROV_MD4_CTX(ctx)	((md4_ctx_t *)(ctx)->cc_provider_private)
+
+/*
+ * Mechanism info structure passed to KCF during registration.
+ */
+static crypto_mech_info_t md4_mech_info_tab[] = {
+	/* MD4 */
+	{SUN_CKM_MD4, MD4_MECH_INFO_TYPE,
+	    CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
+	    0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
+};
+
+static void md4_provider_status(crypto_provider_handle_t, uint_t *);
+
+static crypto_control_ops_t md4_control_ops = {
+	md4_provider_status
+};
+
+static int md4_digest_init(crypto_ctx_t *, crypto_mechanism_t *,
+    crypto_req_handle_t);
+static int md4_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
+    crypto_req_handle_t);
+static int md4_digest_update(crypto_ctx_t *, crypto_data_t *,
+    crypto_req_handle_t);
+static int md4_digest_final(crypto_ctx_t *, crypto_data_t *,
+    crypto_req_handle_t);
+static int md4_digest_atomic(crypto_provider_handle_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
+    crypto_req_handle_t);
+
+static crypto_digest_ops_t md4_digest_ops = {
+	md4_digest_init,
+	md4_digest,
+	md4_digest_update,
+	NULL,
+	md4_digest_final,
+	md4_digest_atomic
+};
+
+static crypto_ops_t md4_crypto_ops = {
+	&md4_control_ops,
+	&md4_digest_ops,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+};
+
+static crypto_provider_info_t md4_prov_info = {
+	CRYPTO_SPI_VERSION_1,
+	"MD4 Software Provider",
+	CRYPTO_SW_PROVIDER,
+	{&modlinkage},
+	NULL,
+	&md4_crypto_ops,
+	sizeof (md4_mech_info_tab)/sizeof (crypto_mech_info_t),
+	md4_mech_info_tab
+};
+
+static crypto_kcf_provider_handle_t md4_prov_handle = NULL;
+
+int
+_init(void)
+{
+	int ret;
+
+	if ((ret = mod_install(&modlinkage)) != 0)
+		return (ret);
+
+	/*
+	 * Register with KCF. If the registration fails, log an
+	 * error and uninstall the module.
+	 */
+	if ((ret = crypto_register_provider(&md4_prov_info,
+	    &md4_prov_handle)) != CRYPTO_SUCCESS) {
+		cmn_err(CE_WARN, "md4 _init: "
+		    "crypto_register_provider() failed (0x%x)", ret);
+		(void) mod_remove(&modlinkage);
+		return (ret);
+	}
+
+	return (0);
+}
+
+int
+_fini(void)
+{
+	int ret;
+
+	/*
+	 * Unregister from KCF if previous registration succeeded.
+	 */
+	if (md4_prov_handle != NULL) {
+		if ((ret = crypto_unregister_provider(md4_prov_handle)) !=
+		    CRYPTO_SUCCESS) {
+			cmn_err(CE_WARN, "md4 _fini: "
+			    "crypto_unregister_provider() failed (0x%x)", ret);
+			return (EBUSY);
+		}
+		md4_prov_handle = NULL;
+	}
+
+	return (mod_remove(&modlinkage));
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+/*
+ * KCF software provider control entry points.
+ */
+/* ARGSUSED */
+static void
+md4_provider_status(crypto_provider_handle_t provider, uint_t *status)
+{
+	*status = CRYPTO_PROVIDER_READY;
+}
+
+/*
+ * KCF software provider digest entry points.
+ */
+
+static int
+md4_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
+    crypto_req_handle_t req)
+{
+	if (mechanism->cm_type != MD4_MECH_INFO_TYPE)
+		return (CRYPTO_MECHANISM_INVALID);
+
+	/*
+	 * Allocate and initialize MD4 context.
+	 */
+	ctx->cc_provider_private = kmem_alloc(sizeof (md4_ctx_t),
+	    crypto_kmflag(req));
+	if (ctx->cc_provider_private == NULL)
+		return (CRYPTO_HOST_MEMORY);
+
+	PROV_MD4_CTX(ctx)->mc_mech_type = MD4_MECH_INFO_TYPE;
+	MD4Init(&PROV_MD4_CTX(ctx)->mc_md4_ctx);
+
+	return (CRYPTO_SUCCESS);
+}
+
+/*
+ * Helper MD4 digest update function for uio data.
+ */
+static int
+md4_digest_update_uio(MD4_CTX *md4_ctx, crypto_data_t *data)
+{
+	off_t offset = data->cd_offset;
+	size_t length = data->cd_length;
+	uint_t vec_idx;
+	size_t cur_len;
+
+	/* we support only kernel buffer */
+	if (data->cd_uio->uio_segflg != UIO_SYSSPACE)
+		return (CRYPTO_ARGUMENTS_BAD);
+
+	/*
+	 * Jump to the first iovec containing data to be
+	 * digested.
+	 */
+	for (vec_idx = 0; vec_idx < data->cd_uio->uio_iovcnt &&
+	    offset >= data->cd_uio->uio_iov[vec_idx].iov_len;
+	    offset -= data->cd_uio->uio_iov[vec_idx++].iov_len);
+	if (vec_idx == data->cd_uio->uio_iovcnt) {
+		/*
+		 * The caller specified an offset that is larger than the
+		 * total size of the buffers it provided.
+		 */
+		return (CRYPTO_DATA_LEN_RANGE);
+	}
+
+	/*
+	 * Now do the digesting on the iovecs.
+	 */
+	while (vec_idx < data->cd_uio->uio_iovcnt && length > 0) {
+		cur_len = MIN(data->cd_uio->uio_iov[vec_idx].iov_len -
+		    offset, length);
+
+		MD4Update(md4_ctx, data->cd_uio->uio_iov[vec_idx].iov_base +
+		    offset, cur_len);
+
+		length -= cur_len;
+		vec_idx++;
+		offset = 0;
+	}
+
+	if (vec_idx == data->cd_uio->uio_iovcnt && length > 0) {
+		/*
+		 * The end of the specified iovec's was reached but
+		 * the length requested could not be processed, i.e.
+		 * The caller requested to digest more data than it provided.
+		 */
+		return (CRYPTO_DATA_LEN_RANGE);
+	}
+
+	return (CRYPTO_SUCCESS);
+}
+
+/*
+ * Helper MD4 digest final function for uio data.
+ * digest_len is the length of the desired digest. If digest_len
+ * is smaller than the default MD4 digest length, the caller
+ * must pass a scratch buffer, digest_scratch, which must
+ * be at least MD4_DIGEST_LENGTH bytes.
+ */
+static int
+md4_digest_final_uio(MD4_CTX *md4_ctx, crypto_data_t *digest,
+    ulong_t digest_len, uchar_t *digest_scratch)
+{
+	off_t offset = digest->cd_offset;
+	uint_t vec_idx;
+
+	/* we support only kernel buffer */
+	if (digest->cd_uio->uio_segflg != UIO_SYSSPACE)
+		return (CRYPTO_ARGUMENTS_BAD);
+
+	/*
+	 * Jump to the first iovec containing ptr to the digest to
+	 * be returned.
+	 */
+	for (vec_idx = 0; offset >= digest->cd_uio->uio_iov[vec_idx].iov_len &&
+	    vec_idx < digest->cd_uio->uio_iovcnt;
+	    offset -= digest->cd_uio->uio_iov[vec_idx++].iov_len);
+	if (vec_idx == digest->cd_uio->uio_iovcnt) {
+		/*
+		 * The caller specified an offset that is
+		 * larger than the total size of the buffers
+		 * it provided.
+		 */
+		return (CRYPTO_DATA_LEN_RANGE);
+	}
+
+	if (offset + digest_len <=
+	    digest->cd_uio->uio_iov[vec_idx].iov_len) {
+		/*
+		 * The computed MD4 digest will fit in the current
+		 * iovec.
+		 */
+		if (digest_len != MD4_DIGEST_LENGTH) {
+			/*
+			 * The caller requested a short digest. Digest
+			 * into a scratch buffer and return to
+			 * the user only what was requested.
+			 */
+			MD4Final(digest_scratch, md4_ctx);
+			bcopy(digest_scratch, (uchar_t *)digest->
+			    cd_uio->uio_iov[vec_idx].iov_base + offset,
+			    digest_len);
+		} else {
+			MD4Final((uchar_t *)digest->
+			    cd_uio->uio_iov[vec_idx].iov_base + offset,
+			    md4_ctx);
+		}
+	} else {
+		/*
+		 * The computed digest will be crossing one or more iovec's.
+		 * This is bad performance-wise but we need to support it.
+		 * Allocate a small scratch buffer on the stack and
+		 * copy it piece meal to the specified digest iovec's.
+		 */
+		uchar_t digest_tmp[MD4_DIGEST_LENGTH];
+		off_t scratch_offset = 0;
+		size_t length = digest_len;
+		size_t cur_len;
+
+		MD4Final(digest_tmp, md4_ctx);
+
+		while (vec_idx < digest->cd_uio->uio_iovcnt && length > 0) {
+			cur_len = MIN(digest->cd_uio->uio_iov[vec_idx].iov_len -
+			    offset, length);
+			bcopy(digest_tmp + scratch_offset,
+			    digest->cd_uio->uio_iov[vec_idx].iov_base + offset,
+			    cur_len);
+
+			length -= cur_len;
+			vec_idx++;
+			scratch_offset += cur_len;
+			offset = 0;
+		}
+
+		if (vec_idx == digest->cd_uio->uio_iovcnt && length > 0) {
+			/*
+			 * The end of the specified iovec's was reached but
+			 * the length requested could not be processed, i.e.
+			 * The caller requested to digest more data than it
+			 * provided.
+			 */
+			return (CRYPTO_DATA_LEN_RANGE);
+		}
+	}
+
+	return (CRYPTO_SUCCESS);
+}
+
+/*
+ * Helper MD4 digest update for mblk's.
+ */
+static int
+md4_digest_update_mblk(MD4_CTX *md4_ctx, crypto_data_t *data)
+{
+	off_t offset = data->cd_offset;
+	size_t length = data->cd_length;
+	mblk_t *mp;
+	size_t cur_len;
+
+	/*
+	 * Jump to the first mblk_t containing data to be digested.
+	 */
+	for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp);
+	    offset -= MBLKL(mp), mp = mp->b_cont);
+	if (mp == NULL) {
+		/*
+		 * The caller specified an offset that is larger than the
+		 * total size of the buffers it provided.
+		 */
+		return (CRYPTO_DATA_LEN_RANGE);
+	}
+
+	/*
+	 * Now do the digesting on the mblk chain.
+	 */
+	while (mp != NULL && length > 0) {
+		cur_len = MIN(MBLKL(mp) - offset, length);
+		MD4Update(md4_ctx, mp->b_rptr + offset, cur_len);
+		length -= cur_len;
+		offset = 0;
+		mp = mp->b_cont;
+	}
+
+	if (mp == NULL && length > 0) {
+		/*
+		 * The end of the mblk was reached but the length requested
+		 * could not be processed, i.e. The caller requested
+		 * to digest more data than it provided.
+		 */
+		return (CRYPTO_DATA_LEN_RANGE);
+	}
+
+	return (CRYPTO_SUCCESS);
+}
+
+/*
+ * Helper MD4 digest final for mblk's.
+ * digest_len is the length of the desired digest. If digest_len
+ * is smaller than the default MD4 digest length, the caller
+ * must pass a scratch buffer, digest_scratch, which must
+ * be at least MD4_DIGEST_LENGTH bytes.
+ */
+static int
+md4_digest_final_mblk(MD4_CTX *md4_ctx, crypto_data_t *digest,
+    ulong_t digest_len, uchar_t *digest_scratch)
+{
+	off_t offset = digest->cd_offset;
+	mblk_t *mp;
+
+	/*
+	 * Jump to the first mblk_t that will be used to store the digest.
+	 */
+	for (mp = digest->cd_mp; mp != NULL && offset >= MBLKL(mp);
+	    offset -= MBLKL(mp), mp = mp->b_cont);
+	if (mp == NULL) {
+		/*
+		 * The caller specified an offset that is larger than the
+		 * total size of the buffers it provided.
+		 */
+		return (CRYPTO_DATA_LEN_RANGE);
+	}
+
+	if (offset + digest_len <= MBLKL(mp)) {
+		/*
+		 * The computed MD4 digest will fit in the current mblk.
+		 * Do the MD4Final() in-place.
+		 */
+		if (digest_len != MD4_DIGEST_LENGTH) {
+			/*
+			 * The caller requested a short digest. Digest
+			 * into a scratch buffer and return to
+			 * the user only what was requested.
+			 */
+			MD4Final(digest_scratch, md4_ctx);
+			bcopy(digest_scratch, mp->b_rptr + offset, digest_len);
+		} else {
+			MD4Final(mp->b_rptr + offset, md4_ctx);
+		}
+	} else {
+		/*
+		 * The computed digest will be crossing one or more mblk's.
+		 * This is bad performance-wise but we need to support it.
+		 * Allocate a small scratch buffer on the stack and
+		 * copy it piece meal to the specified digest iovec's.
+		 */
+		uchar_t digest_tmp[MD4_DIGEST_LENGTH];
+		off_t scratch_offset = 0;
+		size_t length = digest_len;
+		size_t cur_len;
+
+		MD4Final(digest_tmp, md4_ctx);
+
+		while (mp != NULL && length > 0) {
+			cur_len = MIN(MBLKL(mp) - offset, length);
+			bcopy(digest_tmp + scratch_offset,
+			    mp->b_rptr + offset, cur_len);
+
+			length -= cur_len;
+			mp = mp->b_cont;
+			scratch_offset += cur_len;
+			offset = 0;
+		}
+
+		if (mp == NULL && length > 0) {
+			/*
+			 * The end of the specified mblk was reached but
+			 * the length requested could not be processed, i.e.
+			 * The caller requested to digest more data than it
+			 * provided.
+			 */
+			return (CRYPTO_DATA_LEN_RANGE);
+		}
+	}
+
+	return (CRYPTO_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+md4_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
+    crypto_req_handle_t req)
+{
+	int ret = CRYPTO_SUCCESS;
+
+	ASSERT(ctx->cc_provider_private != NULL);
+
+	/*
+	 * We need to just return the length needed to store the output.
+	 * We should not destroy the context for the following cases.
+	 */
+	if ((digest->cd_length == 0) ||
+	    (digest->cd_length < MD4_DIGEST_LENGTH)) {
+		digest->cd_length = MD4_DIGEST_LENGTH;
+		return (CRYPTO_BUFFER_TOO_SMALL);
+	}
+
+	/*
+	 * Do the MD4 update on the specified input data.
+	 */
+	switch (data->cd_format) {
+	case CRYPTO_DATA_RAW:
+		MD4Update(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
+		    data->cd_raw.iov_base + data->cd_offset,
+		    data->cd_length);
+		break;
+	case CRYPTO_DATA_UIO:
+		ret = md4_digest_update_uio(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
+		    data);
+		break;
+	case CRYPTO_DATA_MBLK:
+		ret = md4_digest_update_mblk(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
+		    data);
+		break;
+	default:
+		ret = CRYPTO_ARGUMENTS_BAD;
+	}
+
+	if (ret != CRYPTO_SUCCESS) {
+		/* the update failed, free context and bail */
+		kmem_free(ctx->cc_provider_private, sizeof (md4_ctx_t));
+		ctx->cc_provider_private = NULL;
+		digest->cd_length = 0;
+		return (ret);
+	}
+
+	/*
+	 * Do an MD4 final, must be done separately since the digest
+	 * type can be different than the input data type.
+	 */
+	switch (digest->cd_format) {
+	case CRYPTO_DATA_RAW:
+		MD4Final((unsigned char *)digest->cd_raw.iov_base +
+		    digest->cd_offset, &PROV_MD4_CTX(ctx)->mc_md4_ctx);
+		break;
+	case CRYPTO_DATA_UIO:
+		ret = md4_digest_final_uio(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
+		    digest, MD4_DIGEST_LENGTH, NULL);
+		break;
+	case CRYPTO_DATA_MBLK:
+		ret = md4_digest_final_mblk(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
+		    digest, MD4_DIGEST_LENGTH, NULL);
+		break;
+	default:
+		ret = CRYPTO_ARGUMENTS_BAD;
+	}
+
+	/* all done, free context and return */
+
+	if (ret == CRYPTO_SUCCESS) {
+		digest->cd_length = MD4_DIGEST_LENGTH;
+	} else {
+		digest->cd_length = 0;
+	}
+
+	kmem_free(ctx->cc_provider_private, sizeof (md4_ctx_t));
+	ctx->cc_provider_private = NULL;
+	return (ret);
+}
+
+/* ARGSUSED */
+static int
+md4_digest_update(crypto_ctx_t *ctx, crypto_data_t *data,
+    crypto_req_handle_t req)
+{
+	int ret = CRYPTO_SUCCESS;
+
+	ASSERT(ctx->cc_provider_private != NULL);
+
+	/*
+	 * Do the MD4 update on the specified input data.
+	 */
+	switch (data->cd_format) {
+	case CRYPTO_DATA_RAW:
+		MD4Update(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
+		    data->cd_raw.iov_base + data->cd_offset,
+		    data->cd_length);
+		break;
+	case CRYPTO_DATA_UIO:
+		ret = md4_digest_update_uio(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
+		    data);
+		break;
+	case CRYPTO_DATA_MBLK:
+		ret = md4_digest_update_mblk(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
+		    data);
+		break;
+	default:
+		ret = CRYPTO_ARGUMENTS_BAD;
+	}
+
+	return (ret);
+}
+
+/* ARGSUSED */
+static int
+md4_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest,
+    crypto_req_handle_t req)
+{
+	int ret = CRYPTO_SUCCESS;
+
+	ASSERT(ctx->cc_provider_private != NULL);
+
+	/*
+	 * We need to just return the length needed to store the output.
+	 * We should not destroy the context for the following cases.
+	 */
+	if ((digest->cd_length == 0) ||
+	    (digest->cd_length < MD4_DIGEST_LENGTH)) {
+		digest->cd_length = MD4_DIGEST_LENGTH;
+		return (CRYPTO_BUFFER_TOO_SMALL);
+	}
+
+	/*
+	 * Do an MD4 final.
+	 */
+	switch (digest->cd_format) {
+	case CRYPTO_DATA_RAW:
+		MD4Final((unsigned char *)digest->cd_raw.iov_base +
+		    digest->cd_offset, &PROV_MD4_CTX(ctx)->mc_md4_ctx);
+		break;
+	case CRYPTO_DATA_UIO:
+		ret = md4_digest_final_uio(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
+		    digest, MD4_DIGEST_LENGTH, NULL);
+		break;
+	case CRYPTO_DATA_MBLK:
+		ret = md4_digest_final_mblk(&PROV_MD4_CTX(ctx)->mc_md4_ctx,
+		    digest, MD4_DIGEST_LENGTH, NULL);
+		break;
+	default:
+		ret = CRYPTO_ARGUMENTS_BAD;
+	}
+
+	/* all done, free context and return */
+
+	if (ret == CRYPTO_SUCCESS) {
+		digest->cd_length = MD4_DIGEST_LENGTH;
+	} else {
+		digest->cd_length = 0;
+	}
+
+	kmem_free(ctx->cc_provider_private, sizeof (md4_ctx_t));
+	ctx->cc_provider_private = NULL;
+
+	return (ret);
+}
+
+/* ARGSUSED */
+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)
+{
+	int ret = CRYPTO_SUCCESS;
+	MD4_CTX md4_ctx;
+
+	if (mechanism->cm_type != MD4_MECH_INFO_TYPE)
+		return (CRYPTO_MECHANISM_INVALID);
+
+	/*
+	 * Do the MD4 init.
+	 */
+	MD4Init(&md4_ctx);
+
+	/*
+	 * Do the MD4 update on the specified input data.
+	 */
+	switch (data->cd_format) {
+	case CRYPTO_DATA_RAW:
+		MD4Update(&md4_ctx, data->cd_raw.iov_base + data->cd_offset,
+		    data->cd_length);
+		break;
+	case CRYPTO_DATA_UIO:
+		ret = md4_digest_update_uio(&md4_ctx, data);
+		break;
+	case CRYPTO_DATA_MBLK:
+		ret = md4_digest_update_mblk(&md4_ctx, data);
+		break;
+	default:
+		ret = CRYPTO_ARGUMENTS_BAD;
+	}
+
+	if (ret != CRYPTO_SUCCESS) {
+		/* the update failed, bail */
+		digest->cd_length = 0;
+		return (ret);
+	}
+
+	/*
+	 * Do an MD4 final, must be done separately since the digest
+	 * type can be different than the input data type.
+	 */
+	switch (digest->cd_format) {
+	case CRYPTO_DATA_RAW:
+		MD4Final((unsigned char *)digest->cd_raw.iov_base +
+		    digest->cd_offset, &md4_ctx);
+		break;
+	case CRYPTO_DATA_UIO:
+		ret = md4_digest_final_uio(&md4_ctx, digest,
+		    MD4_DIGEST_LENGTH, NULL);
+		break;
+	case CRYPTO_DATA_MBLK:
+		ret = md4_digest_final_mblk(&md4_ctx, digest,
+		    MD4_DIGEST_LENGTH, NULL);
+		break;
+	default:
+		ret = CRYPTO_ARGUMENTS_BAD;
+	}
+
+	if (ret == CRYPTO_SUCCESS) {
+		digest->cd_length = MD4_DIGEST_LENGTH;
+	} else {
+		digest->cd_length = 0;
+	}
+
+	return (ret);
+}
--- a/usr/src/uts/common/sys/Makefile	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/uts/common/sys/Makefile	Tue Apr 10 11:12:59 2007 -0700
@@ -313,6 +313,7 @@
 	mac.h			\
 	mac_impl.h		\
 	map.h			\
+	md4.h			\
 	md5.h			\
 	md5_consts.h		\
 	mdi_impldefs.h		\
--- a/usr/src/uts/common/sys/crypto/common.h	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/uts/common/sys/crypto/common.h	Tue Apr 10 11:12:59 2007 -0700
@@ -85,6 +85,7 @@
 
 
 /* Mechanisms supported out-of-the-box */
+#define	SUN_CKM_MD4			"CKM_MD4"
 #define	SUN_CKM_MD5			"CKM_MD5"
 #define	SUN_CKM_MD5_HMAC		"CKM_MD5_HMAC"
 #define	SUN_CKM_MD5_HMAC_GENERAL	"CKM_MD5_HMAC_GENERAL"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/md4.h	Tue Apr 10 11:12:59 2007 -0700
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	__MD4_H
+#define	__MD4_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+
+/*
+ * MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm
+ */
+
+/*
+ * Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD4 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD4 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+#define	MD4_DIGEST_LENGTH	16
+
+/* MD4 context. */
+typedef struct {
+	uint32_t state[4];	/* state (ABCD) */
+	uint32_t count[2];	/* number of bits, modulo 2^64 (lsb first) */
+	unsigned char buffer[64];	/* input buffer */
+} MD4_CTX;
+
+void MD4Init(MD4_CTX *);
+void MD4Update(MD4_CTX *, const void *_RESTRICT_KYWD, size_t);
+void MD4Final(void *, MD4_CTX *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* __MD4_H */
--- a/usr/src/uts/common/sys/md5.h	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/uts/common/sys/md5.h	Tue Apr 10 11:12:59 2007 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -63,7 +63,7 @@
 
 void MD5Init(MD5_CTX *);
 void MD5Update(MD5_CTX *, const void *, unsigned int);
-void MD5Final(unsigned char [MD5_DIGEST_LENGTH], MD5_CTX *);
+void MD5Final(void *, MD5_CTX *);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/uts/intel/Makefile.intel.shared	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/uts/intel/Makefile.intel.shared	Tue Apr 10 11:12:59 2007 -0700
@@ -565,6 +565,7 @@
 $(CLOSED_BUILD)CRYPTO_KMODS	+= arcfour
 $(CLOSED_BUILD)CRYPTO_KMODS	+= blowfish
 $(CLOSED_BUILD)CRYPTO_KMODS	+= des
+CRYPTO_KMODS	+= md4
 CRYPTO_KMODS	+= md5
 CRYPTO_KMODS	+= rsa
 CRYPTO_KMODS	+= sha1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/md4/Makefile	Tue Apr 10 11:12:59 2007 -0700
@@ -0,0 +1,97 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# uts/intel/md4/Makefile
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of the md4 crypto kernel module.
+#
+#	intel architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= md4
+OBJECTS		= $(MD4_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(MD4_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_CRYPTO_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+#
+#	Override defaults
+#
+
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+LDFLAGS		+= -dy
+
+#
+# For now, disable these lint checks; maintainers should endeavor
+# to investigate and remove these for maximum lint coverage.
+# Please do not carry these forward to new Makefiles.
+#
+LINTTAGS	+= -erroff=E_PTRDIFF_OVERFLOW
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/md4/inc.flg	Tue Apr 10 11:12:59 2007 -0700
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+echo_file usr/src/common/crypto/md4/md4.c
--- a/usr/src/uts/sparc/Makefile.sparc.shared	Tue Apr 10 09:59:05 2007 -0700
+++ b/usr/src/uts/sparc/Makefile.sparc.shared	Tue Apr 10 11:12:59 2007 -0700
@@ -398,6 +398,7 @@
 $(CLOSED_BUILD)CRYPTO_KMODS	+= arcfour
 $(CLOSED_BUILD)CRYPTO_KMODS	+= blowfish
 $(CLOSED_BUILD)CRYPTO_KMODS	+= des
+CRYPTO_KMODS	+= md4
 CRYPTO_KMODS	+= md5
 CRYPTO_KMODS	+= rsa
 CRYPTO_KMODS	+= sha1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/md4/Makefile	Tue Apr 10 11:12:59 2007 -0700
@@ -0,0 +1,102 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# uts/sparc/md4/Makefile
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of the md4 crypto kernel module.
+#
+#	sparc architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= md4
+OBJECTS		= $(MD4_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(MD4_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_CRYPTO_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sparc/Makefile.sparc
+
+#
+#	Override defaults
+#
+
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+# lint pass one enforcement
+#
+CFLAGS += $(CCVERBOSE)
+
+LDFLAGS		+= -dy
+
+#
+# For now, disable these lint checks; maintainers should endeavor
+# to investigate and remove these for maximum lint coverage.
+# Please do not carry these forward to new Makefiles.
+#
+LINTTAGS	+= -erroff=E_PTRDIFF_OVERFLOW
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/sparc/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/md4/inc.flg	Tue Apr 10 11:12:59 2007 -0700
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+
+echo_file usr/src/common/crypto/md4/md4.c