Module Name:    src
Committed By:   snj
Date:           Mon Jun 29 23:01:24 UTC 2009

Modified Files:
        src/crypto/dist/ssh [netbsd-5-0]: cipher.c cipher.h packet.c

Log Message:
Pull up following revision(s) (requested by tonnerre in ticket #843):
        crypto/dist/ssh/cipher.c: revision 1.22
        crypto/dist/ssh/cipher.h: revision 1.3
        crypto/dist/ssh/packet.c: revision 1.32
Add special handling for CBC cipher modes to make them appear less favorable
than CTR modes. Also, in order to avoid creating oracles unnecessarily,
change behavior in various situations from "Drop connection" to "Ignore
packets up to 256kB". This affects CBC mode ciphers only.
Patch from OpenBSD.


To generate a diff of this commit:
cvs rdiff -u -r1.21 -r1.21.8.1 src/crypto/dist/ssh/cipher.c
cvs rdiff -u -r1.2 -r1.2.28.1 src/crypto/dist/ssh/cipher.h
cvs rdiff -u -r1.30 -r1.30.8.1 src/crypto/dist/ssh/packet.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/crypto/dist/ssh/cipher.c
diff -u src/crypto/dist/ssh/cipher.c:1.21 src/crypto/dist/ssh/cipher.c:1.21.8.1
--- src/crypto/dist/ssh/cipher.c:1.21	Mon Jun 23 14:51:31 2008
+++ src/crypto/dist/ssh/cipher.c	Mon Jun 29 23:01:24 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: cipher.c,v 1.21 2008/06/23 14:51:31 christos Exp $	*/
+/*	$NetBSD: cipher.c,v 1.21.8.1 2009/06/29 23:01:24 snj Exp $	*/
 /* $OpenBSD: cipher.c,v 1.81 2006/08/03 03:34:42 deraadt Exp $ */
 /*
  * Author: Tatu Ylonen <y...@cs.hut.fi>
@@ -37,7 +37,7 @@
  */
 
 #include "includes.h"
-__RCSID("$NetBSD: cipher.c,v 1.21 2008/06/23 14:51:31 christos Exp $");
+__RCSID("$NetBSD: cipher.c,v 1.21.8.1 2009/06/29 23:01:24 snj Exp $");
 #include <sys/types.h>
 
 #include <openssl/md5.h>
@@ -62,38 +62,39 @@
 	u_int	block_size;
 	u_int	key_len;
 	u_int	discard_len;
+	u_int	cbc_mode;
 	const EVP_CIPHER	*(*evptype)(void);
 } ciphers[] = {
-	{ "none",		SSH_CIPHER_NONE, 8, 0, 0, EVP_enc_null },
-	{ "des",		SSH_CIPHER_DES, 8, 8, 0, EVP_des_cbc },
-	{ "3des",		SSH_CIPHER_3DES, 8, 16, 0, evp_ssh1_3des },
-	{ "blowfish",		SSH_CIPHER_BLOWFISH, 8, 32, 0, evp_ssh1_bf },
-
-	{ "3des-cbc",		SSH_CIPHER_SSH2, 8, 24, 0, EVP_des_ede3_cbc },
-	{ "blowfish-cbc",	SSH_CIPHER_SSH2, 8, 16, 0, EVP_bf_cbc },
-	{ "cast128-cbc",	SSH_CIPHER_SSH2, 8, 16, 0, EVP_cast5_cbc },
-	{ "arcfour",		SSH_CIPHER_SSH2, 8, 16, 0, EVP_rc4 },
-	{ "arcfour128",		SSH_CIPHER_SSH2, 8, 16, 1536, EVP_rc4 },
-	{ "arcfour256",		SSH_CIPHER_SSH2, 8, 32, 1536, EVP_rc4 },
-	{ "aes128-cbc",		SSH_CIPHER_SSH2, 16, 16, 0, EVP_aes_128_cbc },
-	{ "aes192-cbc",		SSH_CIPHER_SSH2, 16, 24, 0, EVP_aes_192_cbc },
-	{ "aes256-cbc",		SSH_CIPHER_SSH2, 16, 32, 0, EVP_aes_256_cbc },
+	{ "none",		SSH_CIPHER_NONE, 8, 0, 0, 0, EVP_enc_null },
+	{ "des",		SSH_CIPHER_DES, 8, 8, 0, 1, EVP_des_cbc },
+	{ "3des",		SSH_CIPHER_3DES, 8, 16, 0, 1, evp_ssh1_3des },
+	{ "blowfish",		SSH_CIPHER_BLOWFISH, 8, 32, 0, 0, evp_ssh1_bf },
+
+	{ "3des-cbc",		SSH_CIPHER_SSH2, 8, 24, 0, 1, EVP_des_ede3_cbc },
+	{ "blowfish-cbc",	SSH_CIPHER_SSH2, 8, 16, 0, 1, EVP_bf_cbc },
+	{ "cast128-cbc",	SSH_CIPHER_SSH2, 8, 16, 0, 1, EVP_cast5_cbc },
+	{ "arcfour",		SSH_CIPHER_SSH2, 8, 16, 0, 0, EVP_rc4 },
+	{ "arcfour128",		SSH_CIPHER_SSH2, 8, 16, 1536, 0, EVP_rc4 },
+	{ "arcfour256",		SSH_CIPHER_SSH2, 8, 32, 1536, 0, EVP_rc4 },
+	{ "aes128-cbc",		SSH_CIPHER_SSH2, 16, 16, 0, 1, EVP_aes_128_cbc },
+	{ "aes192-cbc",		SSH_CIPHER_SSH2, 16, 24, 0, 1, EVP_aes_192_cbc },
+	{ "aes256-cbc",		SSH_CIPHER_SSH2, 16, 32, 0, 1, EVP_aes_256_cbc },
 	{ "rijndael-...@lysator.liu.se",
-				SSH_CIPHER_SSH2, 16, 32, 0, EVP_aes_256_cbc },
+				SSH_CIPHER_SSH2, 16, 32, 0, 1, EVP_aes_256_cbc },
 #ifdef AES_CTR_MT
-	{ "aes128-ctr",		SSH_CIPHER_SSH2, 16, 16, 0, evp_aes_ctr_mt },
-	{ "aes192-ctr",		SSH_CIPHER_SSH2, 16, 24, 0, evp_aes_ctr_mt },
-	{ "aes256-ctr",		SSH_CIPHER_SSH2, 16, 32, 0, evp_aes_ctr_mt },
+	{ "aes128-ctr",		SSH_CIPHER_SSH2, 16, 16, 0, 0, evp_aes_ctr_mt },
+	{ "aes192-ctr",		SSH_CIPHER_SSH2, 16, 24, 0, 0, evp_aes_ctr_mt },
+	{ "aes256-ctr",		SSH_CIPHER_SSH2, 16, 32, 0, 0, evp_aes_ctr_mt },
 #else
-	{ "aes128-ctr",		SSH_CIPHER_SSH2, 16, 16, 0, evp_aes_128_ctr },
-	{ "aes192-ctr",		SSH_CIPHER_SSH2, 16, 24, 0, evp_aes_128_ctr },
-	{ "aes256-ctr",		SSH_CIPHER_SSH2, 16, 32, 0, evp_aes_128_ctr },
+	{ "aes128-ctr",		SSH_CIPHER_SSH2, 16, 16, 0, 0, evp_aes_128_ctr },
+	{ "aes192-ctr",		SSH_CIPHER_SSH2, 16, 24, 0, 0, evp_aes_128_ctr },
+	{ "aes256-ctr",		SSH_CIPHER_SSH2, 16, 32, 0, 0, evp_aes_128_ctr },
 #endif
 #ifdef ACSS
-	{ "a...@openssh.org",	SSH_CIPHER_SSH2, 16, 5, 0, EVP_acss },
+	{ "a...@openssh.org",	SSH_CIPHER_SSH2, 16, 5, 0, 0, EVP_acss },
 #endif
 
-	{ NULL,			SSH_CIPHER_INVALID, 0, 0, 0, NULL }
+	{ NULL,			SSH_CIPHER_INVALID, 0, 0, 0, 0, NULL }
 };
 
 #ifndef ACSS
@@ -121,6 +122,12 @@
 }
 
 u_int
+cipher_is_cbc(const Cipher *c)
+{
+	return (c->cbc_mode);
+}
+
+u_int
 cipher_mask_ssh1(int client)
 {
 	u_int mask = 0;

Index: src/crypto/dist/ssh/cipher.h
diff -u src/crypto/dist/ssh/cipher.h:1.2 src/crypto/dist/ssh/cipher.h:1.2.28.1
--- src/crypto/dist/ssh/cipher.h:1.2	Thu Sep 28 21:22:14 2006
+++ src/crypto/dist/ssh/cipher.h	Mon Jun 29 23:01:24 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: cipher.h,v 1.2 2006/09/28 21:22:14 christos Exp $	*/
+/*	$NetBSD: cipher.h,v 1.2.28.1 2009/06/29 23:01:24 snj Exp $	*/
 /* $OpenBSD: cipher.h,v 1.36 2006/03/25 22:22:42 djm Exp $ */
 
 /*
@@ -82,6 +82,7 @@
 void	 cipher_set_key_string(CipherContext *, Cipher *, const char *, int);
 u_int	 cipher_blocksize(const Cipher *);
 u_int	 cipher_keylen(const Cipher *);
+u_int	 cipher_is_cbc(const Cipher *);
 
 u_int	 cipher_get_number(const Cipher *);
 void	 cipher_get_keyiv(CipherContext *, u_char *, u_int);

Index: src/crypto/dist/ssh/packet.c
diff -u src/crypto/dist/ssh/packet.c:1.30 src/crypto/dist/ssh/packet.c:1.30.8.1
--- src/crypto/dist/ssh/packet.c:1.30	Sun Jun 22 15:42:50 2008
+++ src/crypto/dist/ssh/packet.c	Mon Jun 29 23:01:24 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: packet.c,v 1.30 2008/06/22 15:42:50 christos Exp $	*/
+/*	$NetBSD: packet.c,v 1.30.8.1 2009/06/29 23:01:24 snj Exp $	*/
 /* $OpenBSD: packet.c,v 1.151 2008/02/22 20:44:02 dtucker Exp $ */
 /*
  * Author: Tatu Ylonen <y...@cs.hut.fi>
@@ -39,7 +39,7 @@
  */
 
 #include "includes.h"
-__RCSID("$NetBSD: packet.c,v 1.30 2008/06/22 15:42:50 christos Exp $");
+__RCSID("$NetBSD: packet.c,v 1.30.8.1 2009/06/29 23:01:24 snj Exp $");
 
 #include <sys/types.h>
 #include <sys/queue.h>
@@ -84,6 +84,8 @@
 #define DBG(x)
 #endif
 
+#define PACKET_MAX_SIZE (256 * 1024)
+
 /*
  * This variable contains the file descriptors used for communicating with
  * the other side.  connection_in is used for reading; connection_out for
@@ -156,6 +158,10 @@
 /* roundup current message to extra_pad bytes */
 static u_char extra_pad = 0;
 
+/* XXX discard incoming data after MAC error */
+static u_int packet_discard = 0;
+static Mac *packet_discard_mac = NULL;
+
 struct packet {
 	TAILQ_ENTRY(packet) next;
 	u_char type;
@@ -191,6 +197,36 @@
 	}
 }
 
+static void
+packet_stop_discard(void)
+{
+	if (packet_discard_mac) {
+		char buf[1024];
+		
+		memset(buf, 'a', sizeof(buf));
+		while (buffer_len(&incoming_packet) < PACKET_MAX_SIZE)
+			buffer_append(&incoming_packet, buf, sizeof(buf));
+		(void) mac_compute(packet_discard_mac,
+		    p_read.seqnr,
+		    buffer_ptr(&incoming_packet),
+		    PACKET_MAX_SIZE);
+	}
+	logit("Finished discarding for %.200s", get_remote_ipaddr());
+	cleanup_exit(255);
+}
+
+static void
+packet_start_discard(Enc *enc, Mac *mac, u_int packet_length, u_int discard)
+{
+	if (!cipher_is_cbc(enc->cipher))
+		packet_disconnect("Packet corrupt");
+	if (packet_length != PACKET_MAX_SIZE && mac && mac->enabled)
+		packet_discard_mac = mac;
+	if (buffer_len(&input) >= discard)
+		packet_stop_discard();
+	packet_discard = discard - buffer_len(&input);
+}
+
 /* Returns 1 if remote host is connected via socket, 0 if not. */
 
 int
@@ -1071,6 +1107,9 @@
 	Mac *mac   = NULL;
 	Comp *comp = NULL;
 
+	if (packet_discard)
+		return SSH_MSG_NONE;
+
 	if (newkeys[MODE_IN] != NULL) {
 		enc  = &newkeys[MODE_IN]->enc;
 		mac  = &newkeys[MODE_IN]->mac;
@@ -1092,11 +1131,15 @@
 		    block_size);
 		cp = buffer_ptr(&incoming_packet);
 		packet_length = get_u32(cp);
-		if (packet_length < 1 + 4 || packet_length > 256 * 1024) {
+		if (packet_length < 1 + 4 || packet_length > PACKET_MAX_SIZE) {
 #ifdef PACKET_DEBUG
 			buffer_dump(&incoming_packet);
 #endif
-			packet_disconnect("Bad packet length %u.", packet_length);
+			logit("Bad packet length %-10u.",
+			    packet_length);
+			packet_start_discard(enc, mac, packet_length,
+			    PACKET_MAX_SIZE);
+			return SSH_MSG_NONE;
 		}
 		DBG(debug("input: packet len %u", packet_length+4));
 		buffer_consume(&input, block_size);
@@ -1105,9 +1148,13 @@
 	need = 4 + packet_length - block_size;
 	DBG(debug("partial packet %d, need %d, maclen %d", block_size,
 	    need, maclen));
-	if (need % block_size != 0)
-		fatal("padding error: need %d block %d mod %d",
+	if (need % block_size != 0) {
+		logit("padding error: need %d block %d mod %d",
 		    need, block_size, need % block_size);
+		packet_start_discard(enc, mac, packet_length,
+		    PACKET_MAX_SIZE - block_size);
+		return SSH_MSG_NONE;
+	}
 	/*
 	 * check if the entire packet has been received and
 	 * decrypt into incoming_packet
@@ -1129,11 +1176,19 @@
 		macbuf = mac_compute(mac, p_read.seqnr,
 		    buffer_ptr(&incoming_packet),
 		    buffer_len(&incoming_packet));
-		if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0)
-			packet_disconnect("Corrupted MAC on input.");
+		if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) {
+			logit("Corrupted MAC on input.");
+			if (need > PACKET_MAX_SIZE)
+				fatal("internal error need %d", need);
+			packet_start_discard(enc, mac, packet_length,
+			    PACKET_MAX_SIZE - need);
+			return SSH_MSG_NONE;
+		}
+				
 		DBG(debug("MAC #%d ok", p_read.seqnr));
 		buffer_consume(&input, mac->mac_len);
 	}
+	/* XXX now it's safe to use fatal/packet_disconnect */
 	if (seqnr_p != NULL)
 		*seqnr_p = p_read.seqnr;
 	if (++p_read.seqnr == 0)
@@ -1264,6 +1319,13 @@
 void
 packet_process_incoming(const char *buf, u_int len)
 {
+	if (packet_discard) {
+		keep_alive_timeouts = 0; /* ?? */
+		if (len >= packet_discard)
+			packet_stop_discard();
+		packet_discard -= len;
+		return;
+	}
 	buffer_append(&input, buf, len);
 }
 

Reply via email to