- markus@cvs.openbsd.org 2013/01/08 18:49:04
     [PROTOCOL authfile.c cipher.c cipher.h kex.c kex.h monitor_wrap.c]
     [myproposal.h packet.c ssh_config.5 sshd_config.5]
     support AES-GCM as defined in RFC 5647 (but with simpler KEX handling)
     ok and feedback djm@
diff --git a/packet.c b/packet.c
index fe379aa..ae7b04c 100644
--- a/packet.c
+++ b/packet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.179 2012/12/12 16:45:52 markus Exp $ */
+/* $OpenBSD: packet.c,v 1.180 2013/01/08 18:49:04 markus Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -709,7 +709,7 @@
 	    buffer_len(&active_state->outgoing_packet));
 	cipher_crypt(&active_state->send_context, cp,
 	    buffer_ptr(&active_state->outgoing_packet),
-	    buffer_len(&active_state->outgoing_packet), 0);
+	    buffer_len(&active_state->outgoing_packet), 0, 0);
 
 #ifdef PACKET_DEBUG
 	fprintf(stderr, "encrypted: ");
@@ -757,7 +757,7 @@
 		mac  = &active_state->newkeys[mode]->mac;
 		comp = &active_state->newkeys[mode]->comp;
 		mac_clear(mac);
-		memset(enc->iv,  0, enc->block_size);
+		memset(enc->iv,  0, enc->iv_len);
 		memset(enc->key, 0, enc->key_len);
 		memset(mac->key, 0, mac->key_len);
 		xfree(enc->name);
@@ -774,11 +774,11 @@
 	enc  = &active_state->newkeys[mode]->enc;
 	mac  = &active_state->newkeys[mode]->mac;
 	comp = &active_state->newkeys[mode]->comp;
-	if (mac_init(mac) == 0)
+	if (cipher_authlen(enc->cipher) == 0 && mac_init(mac) == 0)
 		mac->enabled = 1;
 	DBG(debug("cipher_init_context: %d", mode));
 	cipher_init(cc, enc->cipher, enc->key, enc->key_len,
-	    enc->iv, enc->block_size, crypt_type);
+	    enc->iv, enc->iv_len, crypt_type);
 	/* Deleting the keys does not gain extra security */
 	/* memset(enc->iv,  0, enc->block_size);
 	   memset(enc->key, 0, enc->key_len);
@@ -846,7 +846,7 @@
 {
 	u_char type, *cp, *macbuf = NULL;
 	u_char padlen, pad = 0;
-	u_int i, len, aadlen = 0;
+	u_int i, len, authlen = 0, aadlen = 0;
 	u_int32_t rnd = 0;
 	Enc *enc   = NULL;
 	Mac *mac   = NULL;
@@ -857,9 +857,12 @@
 		enc  = &active_state->newkeys[MODE_OUT]->enc;
 		mac  = &active_state->newkeys[MODE_OUT]->mac;
 		comp = &active_state->newkeys[MODE_OUT]->comp;
+		/* disable mac for authenticated encryption */
+		if ((authlen = cipher_authlen(enc->cipher)) != 0)
+			mac = NULL;
 	}
 	block_size = enc ? enc->block_size : 8;
-	aadlen = mac && mac->enabled && mac->etm ? 4 : 0;
+	aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0;
 
 	cp = buffer_ptr(&active_state->outgoing_packet);
 	type = cp[5];
@@ -936,10 +939,10 @@
 		DBG(debug("done calc MAC out #%d", active_state->p_send.seqnr));
 	}
 	/* encrypt packet and append to output buffer. */
-	cp = buffer_append_space(&active_state->output, len);
+	cp = buffer_append_space(&active_state->output, len + authlen);
 	cipher_crypt(&active_state->send_context, cp,
 	    buffer_ptr(&active_state->outgoing_packet),
-	    len - aadlen, aadlen);
+	    len - aadlen, aadlen, authlen);
 	/* append unencrypted MAC */
 	if (mac && mac->enabled) {
 		if (mac->etm) {
@@ -1199,7 +1202,7 @@
 	buffer_clear(&active_state->incoming_packet);
 	cp = buffer_append_space(&active_state->incoming_packet, padded_len);
 	cipher_crypt(&active_state->receive_context, cp,
-	    buffer_ptr(&active_state->input), padded_len, 0);
+	    buffer_ptr(&active_state->input), padded_len, 0, 0);
 
 	buffer_consume(&active_state->input, padded_len);
 
@@ -1248,7 +1251,7 @@
 {
 	u_int padlen, need;
 	u_char *macbuf = NULL, *cp, type;
-	u_int maclen, aadlen = 0, block_size;
+	u_int maclen, authlen = 0, aadlen = 0, block_size;
 	Enc *enc   = NULL;
 	Mac *mac   = NULL;
 	Comp *comp = NULL;
@@ -1260,10 +1263,13 @@
 		enc  = &active_state->newkeys[MODE_IN]->enc;
 		mac  = &active_state->newkeys[MODE_IN]->mac;
 		comp = &active_state->newkeys[MODE_IN]->comp;
+		/* disable mac for authenticated encryption */
+		if ((authlen = cipher_authlen(enc->cipher)) != 0)
+			mac = NULL;
 	}
 	maclen = mac && mac->enabled ? mac->mac_len : 0;
 	block_size = enc ? enc->block_size : 8;
-	aadlen = mac && mac->enabled && mac->etm ? 4 : 0;
+	aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0;
 
 	if (aadlen && active_state->packlen == 0) {
 		if (buffer_len(&active_state->input) < 4)
@@ -1290,7 +1296,7 @@
 		cp = buffer_append_space(&active_state->incoming_packet,
 		    block_size);
 		cipher_crypt(&active_state->receive_context, cp,
-		    buffer_ptr(&active_state->input), block_size, 0);
+		    buffer_ptr(&active_state->input), block_size, 0, 0);
 		cp = buffer_ptr(&active_state->incoming_packet);
 		active_state->packlen = get_u32(cp);
 		if (active_state->packlen < 1 + 4 ||
@@ -1316,8 +1322,8 @@
 		 */
 		need = 4 + active_state->packlen - block_size;
 	}
-	DBG(debug("partial packet: block %d, need %d, maclen %d, aadlen %d",
-	    block_size, need, maclen, aadlen));
+	DBG(debug("partial packet: block %d, need %d, maclen %d, authlen %d,"
+	    " aadlen %d", block_size, need, maclen, authlen, aadlen));
 	if (need % block_size != 0) {
 		logit("padding error: need %d block %d mod %d",
 		    need, block_size, need % block_size);
@@ -1329,10 +1335,11 @@
 	 * check if the entire packet has been received and
 	 * decrypt into incoming_packet:
 	 * 'aadlen' bytes are unencrypted, but authenticated.
-	 * 'need' bytes are encrypted, followed by
+	 * 'need' bytes are encrypted, followed by either
+	 * 'authlen' bytes of authentication tag or
 	 * 'maclen' bytes of message authentication code.
 	 */
-	if (buffer_len(&active_state->input) < aadlen + need + maclen)
+	if (buffer_len(&active_state->input) < aadlen + need + authlen + maclen)
 		return SSH_MSG_NONE;
 #ifdef PACKET_DEBUG
 	fprintf(stderr, "read_poll enc/full: ");
@@ -1344,8 +1351,8 @@
 		    buffer_ptr(&active_state->input), aadlen + need);
 	cp = buffer_append_space(&active_state->incoming_packet, aadlen + need);
 	cipher_crypt(&active_state->receive_context, cp,
-	    buffer_ptr(&active_state->input), need, aadlen);
-	buffer_consume(&active_state->input, aadlen + need);
+	    buffer_ptr(&active_state->input), need, aadlen, authlen);
+	buffer_consume(&active_state->input, aadlen + need + authlen);
 	/*
 	 * compute MAC over seqnr and packet,
 	 * increment sequence number for incoming packet