Index: kex.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/kex.h,v
retrieving revision 1.44
diff -u -p -r1.44 kex.h
--- kex.h	3 Aug 2006 03:34:42 -0000	1.44
+++ kex.h	24 Mar 2007 20:07:54 -0000
@@ -85,10 +85,11 @@ struct Enc {
 struct Mac {
 	char	*name;
 	int	enabled;
-	const EVP_MD	*md;
+	void	*md_state;
 	u_int	mac_len;
 	u_char	*key;
 	u_int	key_len;
+	int	type;	/* HMAC or UMAC */
 };
 struct Comp {
 	int	type;
Index: mac.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/mac.c,v
retrieving revision 1.12
diff -u -p -r1.12 mac.c
--- mac.c	3 Aug 2006 03:34:42 -0000	1.12
+++ mac.c	25 Mar 2007 20:45:08 -0000
@@ -39,35 +39,58 @@
 #include "mac.h"
 #include "misc.h"
 
+#include "umac.h"
+
+#define SSH_EVP	1	/* an EVP-based MAC */
+#define SSH_UMAC	2	/* special case UMAC (not integrated in OpenSSL) */
+
 struct {
 	char		*name;
+	int		type;
 	const EVP_MD *	(*mdfunc)(void);
 	int		truncatebits;	/* truncate digest if != 0 */
+	int		key_len;	/* just for UMAC */
+	int		len;		/* just for UMAC */
 } macs[] = {
-	{ "hmac-sha1",			EVP_sha1, 0, },
-	{ "hmac-sha1-96",		EVP_sha1, 96 },
-	{ "hmac-md5",			EVP_md5, 0 },
-	{ "hmac-md5-96",		EVP_md5, 96 },
-	{ "hmac-ripemd160",		EVP_ripemd160, 0 },
-	{ "hmac-ripemd160@openssh.com",	EVP_ripemd160, 0 },
-	{ NULL,				NULL, 0 }
+	{ "hmac-sha1",			SSH_EVP, EVP_sha1, 0, -1, -1 },
+	{ "hmac-sha1-96",		SSH_EVP, EVP_sha1, 96, -1, -1 },
+	{ "hmac-md5",			SSH_EVP, EVP_md5, 0, -1, -1 },
+	{ "hmac-md5-96",		SSH_EVP, EVP_md5, 96, -1, -1 },
+	{ "hmac-ripemd160",		SSH_EVP, EVP_ripemd160, 0, -1, -1 },
+	{ "hmac-ripemd160@openssh.com",	SSH_EVP, EVP_ripemd160, 0, -1, -1 },
+	{ "umac@openssh.com",		SSH_UMAC, NULL, 0, 128, 64 },
+	{ NULL,				0, NULL, 0 }
 };
 
+static void
+mac_init_by_id(Mac *mac, int which)
+{
+	int evp_len;
+
+	mac->type = macs[which].type;
+	if (mac->type == SSH_EVP) {
+		mac->md_state = (void *)(*macs[which].mdfunc)();
+		if ((evp_len = EVP_MD_size((const EVP_MD *)mac->md_state)) <= 0)
+			fatal("mac %s len %d", mac->name, evp_len);
+		mac->key_len = mac->mac_len = (u_int)evp_len;
+	} else {
+		mac->mac_len = macs[which].len / 8;
+		mac->key_len = macs[which].key_len / 8;
+		mac->md_state = NULL;
+	}
+	if (macs[which].truncatebits != 0)
+		mac->mac_len = macs[which].truncatebits / 8;
+}
+
 int
 mac_init(Mac *mac, char *name)
 {
-	int i, evp_len;
+	int i;
 
 	for (i = 0; macs[i].name; i++) {
 		if (strcmp(name, macs[i].name) == 0) {
-			if (mac != NULL) {
-				mac->md = (*macs[i].mdfunc)();
-				if ((evp_len = EVP_MD_size(mac->md)) <= 0)
-					fatal("mac %s len %d", name, evp_len);
-				mac->key_len = mac->mac_len = (u_int)evp_len;
-				if (macs[i].truncatebits != 0)
-					mac->mac_len = macs[i].truncatebits/8;
-			}
+			if (mac != NULL)
+				mac_init_by_id(mac, i);
 			debug2("mac_init: found %s", name);
 			return (0);
 		}
@@ -76,23 +99,60 @@ mac_init(Mac *mac, char *name)
 	return (-1);
 }
 
+int
+mac_cleanup(Mac *mac)
+{
+	if (mac->type == SSH_UMAC) {
+		umac_delete(mac->md_state);
+		mac->md_state = NULL;
+	}
+	return (0);
+}
+
+int
+mac_preinit(Mac *mac)
+{
+	switch (mac->type) {
+	case SSH_UMAC:
+		mac->md_state = umac_new(mac->key);
+		break;
+	case 0:
+		return (-1);
+	}
+	return (0);
+}
+
 u_char *
 mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen)
 {
 	HMAC_CTX c;
 	static u_char m[EVP_MAX_MD_SIZE];
-	u_char b[4];
+
+	umac_ctx_t uc;
+	u_char b[4], nonce[8];
 
 	if (mac->key == NULL)
 		fatal("mac_compute: no key");
 	if (mac->mac_len > sizeof(m))
-		fatal("mac_compute: mac too long");
-	HMAC_Init(&c, mac->key, mac->key_len, mac->md);
-	put_u32(b, seqno);
-	HMAC_Update(&c, b, sizeof(b));
-	HMAC_Update(&c, data, datalen);
-	HMAC_Final(&c, m, NULL);
-	HMAC_cleanup(&c);
+		fatal("mac_compute: mac too long %d %d", mac->mac_len, sizeof(m));
+
+	switch (mac->type) {
+	case SSH_EVP:
+		HMAC_Init(&c, mac->key, mac->key_len, mac->md_state);
+		put_u32(b, seqno);
+		HMAC_Update(&c, b, sizeof(b));
+		HMAC_Update(&c, data, datalen);
+		HMAC_Final(&c, m, NULL);
+		HMAC_cleanup(&c);
+		break;
+	case SSH_UMAC:
+		put_u64(nonce, (u_int64_t)seqno);
+		umac_update(mac->md_state, data, datalen);
+		umac_final(mac->md_state, m, nonce);
+		break;
+	default:
+		fatal("mac_compute: unknown MAC type");
+	}
 	return (m);
 }
 
Index: mac.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/mac.h,v
retrieving revision 1.4
diff -u -p -r1.4 mac.h
--- mac.h	25 Mar 2006 22:22:43 -0000	1.4
+++ mac.h	24 Mar 2007 20:41:03 -0000
@@ -25,4 +25,6 @@
 
 int	 mac_valid(const char *);
 int	 mac_init(Mac *, char *);
+int	 mac_preinit(Mac *);
+int	 mac_cleanup(Mac *);
 u_char	*mac_compute(Mac *, u_int32_t, u_char *, int);
Index: monitor_wrap.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/monitor_wrap.c,v
retrieving revision 1.55
diff -u -p -r1.55 monitor_wrap.c
--- monitor_wrap.c	19 Feb 2007 10:45:58 -0000	1.55
+++ monitor_wrap.c	24 Mar 2007 20:41:03 -0000
@@ -472,6 +472,7 @@ mm_newkeys_from_blob(u_char *blob, int b
 		fatal("%s: bad mac key length: %u > %d", __func__, len,
 		    mac->key_len);
 	mac->key_len = len;
+	mac_preinit(mac);
 
 	/* Comp structure */
 	comp->type = buffer_get_int(&b);
Index: myproposal.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/myproposal.h,v
retrieving revision 1.21
diff -u -p -r1.21 myproposal.h
--- myproposal.h	25 Mar 2006 22:22:43 -0000	1.21
+++ myproposal.h	24 Mar 2007 20:07:11 -0000
@@ -35,7 +35,7 @@
 	"aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se," \
 	"aes128-ctr,aes192-ctr,aes256-ctr"
 #define	KEX_DEFAULT_MAC \
-	"hmac-md5,hmac-sha1,hmac-ripemd160," \
+	"umac@openssh.com,hmac-md5,hmac-sha1,hmac-ripemd160," \
 	"hmac-ripemd160@openssh.com," \
 	"hmac-sha1-96,hmac-md5-96"
 #define	KEX_DEFAULT_COMP	"none,zlib@openssh.com,zlib"
Index: packet.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/packet.c,v
retrieving revision 1.145
diff -u -p -r1.145 packet.c
--- packet.c	19 Sep 2006 21:14:08 -0000	1.145
+++ packet.c	25 Mar 2007 20:17:25 -0000
@@ -620,6 +620,7 @@ set_newkeys(int mode)
 		enc  = &newkeys[mode]->enc;
 		mac  = &newkeys[mode]->mac;
 		comp = &newkeys[mode]->comp;
+		mac_cleanup(mac);
 		memset(mac->key, 0, mac->key_len);
 		xfree(enc->name);
 		xfree(enc->iv);
@@ -635,7 +636,7 @@ set_newkeys(int mode)
 	enc  = &newkeys[mode]->enc;
 	mac  = &newkeys[mode]->mac;
 	comp = &newkeys[mode]->comp;
-	if (mac->md != NULL)
+	if (mac_preinit(mac) == 0)
 		mac->enabled = 1;
 	DBG(debug("cipher_init_context: %d", mode));
 	cipher_init(cc, enc->cipher, enc->key, enc->key_len,
Index: lib/Makefile
===================================================================
RCS file: /cvs/src/usr.bin/ssh/lib/Makefile,v
retrieving revision 1.54
diff -u -p -r1.54 Makefile
--- lib/Makefile	28 May 2006 16:45:09 -0000	1.54
+++ lib/Makefile	24 Mar 2007 20:05:37 -0000
@@ -12,7 +12,7 @@ SRCS=	authfd.c authfile.c bufaux.c bufbn
 	key.c dispatch.c kex.c mac.c uidswap.c uuencode.c misc.c \
 	ssh-dss.c ssh-rsa.c dh.c kexdh.c kexgex.c \
 	kexdhc.c kexgexc.c scard.c msg.c progressmeter.c dns.c \
-	monitor_fdpass.c md-sha256.c
+	monitor_fdpass.c md-sha256.c umac.c
 
 DEBUGLIBS= no
 NOPROFILE= yes
