changeset 795:7f604f9b3756 ecc

ecdsa is working
author Matt Johnston <matt@ucc.asn.au>
date Fri, 03 May 2013 23:07:48 +0800
parents d386defb5376
children 069b875031f5 45f1bc96f357
files cli-main.c cli-session.c common-algo.c dropbearkey.c ecdsa.c ecdsa.h options.h runopts.h signkey.c signkey.h svr-main.c svr-runopts.c svr-session.c sysoptions.h
diffstat 14 files changed, 205 insertions(+), 95 deletions(-) [+]
line wrap: on
line diff
--- a/cli-main.c	Sun Apr 28 23:17:43 2013 +0800
+++ b/cli-main.c	Fri May 03 23:07:48 2013 +0800
@@ -28,6 +28,8 @@
 #include "dbutil.h"
 #include "runopts.h"
 #include "session.h"
+#include "random.h"
+#include "crypto_desc.h"
 
 static void cli_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
 static void cli_dropbear_log(int priority, const char* format, va_list param);
@@ -51,6 +53,9 @@
 
 	disallow_core();
 
+	seedrandom();
+	crypto_init();
+
 	cli_getopts(argc, argv);
 
 	TRACE(("user='%s' host='%s' port='%s'", cli_opts.username,
--- a/cli-session.c	Sun Apr 28 23:17:43 2013 +0800
+++ b/cli-session.c	Fri May 03 23:07:48 2013 +0800
@@ -85,10 +85,6 @@
 
 void cli_session(int sock_in, int sock_out) {
 
-	seedrandom();
-
-	crypto_init();
-
 	common_session_init(sock_in, sock_out);
 
 	chaninitialise(cli_chantypes);
--- a/common-algo.c	Sun Apr 28 23:17:43 2013 +0800
+++ b/common-algo.c	Fri May 03 23:07:48 2013 +0800
@@ -207,6 +207,17 @@
 };
 
 algo_type sshhostkey[] = {
+#ifdef DROPBEAR_ECDSA
+#ifdef DROPBEAR_ECC_256
+	{"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL},
+#endif
+#ifdef DROPBEAR_ECC_384
+	{"ecdsa-sha2-nistp384", DROPBEAR_SIGNKEY_ECDSA_NISTP384, NULL, 1, NULL},
+#endif
+#ifdef DROPBEAR_ECC_521
+	{"ecdsa-sha2-nistp521", DROPBEAR_SIGNKEY_ECDSA_NISTP521, NULL, 1, NULL},
+#endif
+#endif
 #ifdef DROPBEAR_RSA
 	{"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL},
 #endif
--- a/dropbearkey.c	Sun Apr 28 23:17:43 2013 +0800
+++ b/dropbearkey.c	Fri May 03 23:07:48 2013 +0800
@@ -53,6 +53,7 @@
 #include "gendss.h"
 #include "ecdsa.h"
 #include "crypto_desc.h"
+#include "random.h"
 
 static void printhelp(char * progname);
 
@@ -120,6 +121,9 @@
 	unsigned int bits;
 	int printpub = 0;
 
+	crypto_init();
+	seedrandom();
+
 	/* get the commandline options */
 	for (i = 1; i < argc; i++) {
 		if (argv[i] == NULL) {
@@ -223,10 +227,6 @@
 	/* don't want the file readable by others */
 	umask(077);
 
-	crypto_init();
-	seedrandom();
-
-
 	/* now we can generate the key */
 	key = new_sign_key();
 	
@@ -245,6 +245,7 @@
 #ifdef DROPBEAR_ECDSA
 		case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
 			key->ecckey = gen_ecdsa_priv_key(bits);
+			keytype = ecdsa_signkey_type(key->ecckey);
 			break;
 #endif
 		default:
--- a/ecdsa.c	Sun Apr 28 23:17:43 2013 +0800
+++ b/ecdsa.c	Fri May 03 23:07:48 2013 +0800
@@ -4,9 +4,29 @@
 #include "crypto_desc.h"
 #include "ecc.h"
 #include "ecdsa.h"
+#include "signkey.h"
 
 #ifdef DROPBEAR_ECDSA
 
+enum signkey_type ecdsa_signkey_type(ecc_key * key) {
+#ifdef DROPBEAR_ECC_256
+	if (key->dp == ecc_curve_nistp256.dp) {
+		return DROPBEAR_SIGNKEY_ECDSA_NISTP256;
+	}
+#endif
+#ifdef DROPBEAR_ECC_384
+	if (key->dp == ecc_curve_nistp384.dp) {
+		return DROPBEAR_SIGNKEY_ECDSA_NISTP384;
+	}
+#endif
+#ifdef DROPBEAR_ECC_521
+	if (key->dp == ecc_curve_nistp521.dp) {
+		return DROPBEAR_SIGNKEY_ECDSA_NISTP521;
+	}
+#endif
+	return DROPBEAR_SIGNKEY_NONE;
+}
+
 ecc_key *gen_ecdsa_priv_key(unsigned int bit_size) {
 	const ltc_ecc_set_type *dp = NULL; // curve domain parameters
 	switch (bit_size) {
--- a/ecdsa.h	Sun Apr 28 23:17:43 2013 +0800
+++ b/ecdsa.h	Fri May 03 23:07:48 2013 +0800
@@ -3,6 +3,7 @@
 
 #include "includes.h"
 #include "buffer.h"
+#include "signkey.h"
 
 #ifdef DROPBEAR_ECC_256
 #define ECDSA_DEFAULT_SIZE 256
@@ -19,6 +20,7 @@
 ecc_key *buf_get_ecdsa_priv_key(buffer *buf);
 void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key);
 void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key);
+enum signkey_type ecdsa_signkey_type(ecc_key * key);
 
 void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf);
 int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf);
--- a/options.h	Sun Apr 28 23:17:43 2013 +0800
+++ b/options.h	Fri May 03 23:07:48 2013 +0800
@@ -8,7 +8,7 @@
 /* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
  * parts are to allow for commandline -DDROPBEAR_XXX options etc. */
 
-// XXX XXX You should probably run "make clean" after changing most options */
+/* Important: Many options will require "make clean" after changes */
 
 #ifndef DROPBEAR_DEFPORT
 #define DROPBEAR_DEFPORT "22"
@@ -26,6 +26,9 @@
 #ifndef RSA_PRIV_FILENAME
 #define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key"
 #endif
+#ifndef ECDSA_PRIV_FILENAME
+#define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key"
+#endif
 
 /* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens
  * on chosen ports and keeps accepting connections. This is the default.
--- a/runopts.h	Sun Apr 28 23:17:43 2013 +0800
+++ b/runopts.h	Fri May 03 23:07:48 2013 +0800
@@ -57,11 +57,10 @@
 extern runopts opts;
 
 int readhostkey(const char * filename, sign_key * hostkey, int *type);
+void load_all_hostkeys();
 
 typedef struct svr_runopts {
 
-	char * rsakeyfile;
-	char * dsskeyfile;
 	char * bannerfile;
 
 	int forkbg;
@@ -99,6 +98,10 @@
 #endif
 
 	sign_key *hostkey;
+
+	char *hostkey_files[MAX_HOSTKEYS];
+	int num_hostkey_files;
+
 	buffer * banner;
 	char * pidfile;
 
--- a/signkey.c	Sun Apr 28 23:17:43 2013 +0800
+++ b/signkey.c	Fri May 03 23:07:48 2013 +0800
@@ -37,15 +37,9 @@
 	"ssh-dss",
 #endif
 #ifdef DROPBEAR_ECDSA
-#ifdef DROPBEAR_ECC_256
 	"ecdsa-sha2-nistp256",
-#endif
-#ifdef DROPBEAR_ECC_384
 	"ecdsa-sha2-nistp384",
-#endif
-#ifdef DROPBEAR_ECC_521
 	"ecdsa-sha2-nistp521",
-#endif
 	"ecdsa" // for keygen
 #endif // DROPBEAR_ECDSA
 };
@@ -81,6 +75,25 @@
 		const char *fixed_name = signkey_names[i];
 		if (namelen == strlen(fixed_name)
 			&& memcmp(fixed_name, name, namelen) == 0) {
+
+#ifdef DROPBEAR_ECDSA
+			/* Some of the ECDSA key sizes are defined even if they're not compiled in */
+			if (0
+#ifndef DROPBEAR_ECC_256
+				|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP256
+#endif
+#ifndef DROPBEAR_ECC_384
+				|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP384
+#endif
+#ifndef DROPBEAR_ECC_521
+				|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP521
+#endif
+				) {
+				TRACE(("attempt to use ecdsa type %d not compiled in", i))
+				return DROPBEAR_SIGNKEY_NONE;
+			}
+#endif
+
 			return i;
 		}
 	}
@@ -139,9 +152,7 @@
 	}
 #endif
 #ifdef DROPBEAR_ECDSA
-	if (keytype == DROPBEAR_SIGNKEY_ECDSA_NISTP256
-		|| keytype == DROPBEAR_SIGNKEY_ECDSA_NISTP384
-		|| keytype == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
+	if (IS_ECDSA_KEY(keytype)) {
 		if (key->ecckey) {
 			ecc_free(key->ecckey);
 		}
@@ -205,9 +216,7 @@
 	}
 #endif
 #ifdef DROPBEAR_ECDSA
-	if (keytype == DROPBEAR_SIGNKEY_ECDSA_NISTP256
-		|| keytype == DROPBEAR_SIGNKEY_ECDSA_NISTP384
-		|| keytype == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
+	if (IS_ECDSA_KEY(keytype)) {
 		if (key->ecckey) {
 			ecc_free(key->ecckey);
 		}
@@ -243,9 +252,7 @@
 	}
 #endif
 #ifdef DROPBEAR_ECDSA
-	if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
-		|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
-		|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
+	if (IS_ECDSA_KEY(type)) {
 		buf_put_ecdsa_pub_key(pubkeys, key->ecckey);
 	}
 #endif
@@ -279,10 +286,8 @@
 	}
 #endif
 #ifdef DROPBEAR_ECDSA
-	if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
-		|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
-		|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
-		buf_put_ecdsa_pub_key(buf, key->ecckey);
+	if (IS_ECDSA_KEY(type)) {
+		buf_put_ecdsa_priv_key(buf, key->ecckey);
 		return;
 	}
 #endif
@@ -424,9 +429,7 @@
 	}
 #endif
 #ifdef DROPBEAR_ECDSA
-	if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
-		|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
-		|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
+	if (IS_ECDSA_KEY(type)) {
 		buf_put_ecdsa_sign(sigblob, key->ecckey, data_buf);
 	}
 #endif
@@ -474,9 +477,7 @@
 	}
 #endif
 #ifdef DROPBEAR_ECDSA
-	if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
-		|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
-		|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
+	if (IS_ECDSA_KEY(type)) {
 		return buf_ecdsa_verify(buf, key->ecckey, data_buf);
 	}
 #endif
--- a/signkey.h	Sun Apr 28 23:17:43 2013 +0800
+++ b/signkey.h	Fri May 03 23:07:48 2013 +0800
@@ -37,15 +37,9 @@
 	DROPBEAR_SIGNKEY_DSS,
 #endif
 #ifdef DROPBEAR_ECDSA
-#ifdef DROPBEAR_ECC_256
 	DROPBEAR_SIGNKEY_ECDSA_NISTP256,
-#endif
-#ifdef DROPBEAR_ECC_384
 	DROPBEAR_SIGNKEY_ECDSA_NISTP384,
-#endif
-#ifdef DROPBEAR_ECC_521
 	DROPBEAR_SIGNKEY_ECDSA_NISTP521,
-#endif
 	DROPBEAR_SIGNKEY_ECDSA_KEYGEN, // just "ecdsa" for keygen
 #endif // DROPBEAR_ECDSA
 	DROPBEAR_SIGNKEY_NUM_NAMED,
@@ -63,11 +57,9 @@
 
 struct SIGN_key {
 
-	int type; /* The type of key (dss or rsa) */
+	enum signkey_type type;
 	signkey_source source;
 	char *filename;
-	/* the buffer? for encrypted keys, so we can later get
-	 * the private key portion */
 
 #ifdef DROPBEAR_DSS
 	dropbear_dss_key * dsskey;
@@ -76,7 +68,7 @@
 	dropbear_rsa_key * rsakey;
 #endif
 #ifdef DROPBEAR_ECDSA
-	ecc_key *ecckey;
+	ecc_key * ecckey;
 #endif
 };
 
@@ -99,4 +91,12 @@
 					const unsigned char* algoname, unsigned int algolen, 
 					buffer * line, char ** fingerprint);
 
+#ifdef DROPBEAR_ECDSA
+#define IS_ECDSA_KEY(type) \
+	((type) == DROPBEAR_SIGNKEY_ECDSA_NISTP256 \
+		|| (type) == DROPBEAR_SIGNKEY_ECDSA_NISTP384 \
+		|| (type) == DROPBEAR_SIGNKEY_ECDSA_NISTP521 \
+		|| (type) == DROPBEAR_SIGNKEY_ECDSA_KEYGEN)
+#endif
+
 #endif /* _SIGNKEY_H_ */
--- a/svr-main.c	Sun Apr 28 23:17:43 2013 +0800
+++ b/svr-main.c	Fri May 03 23:07:48 2013 +0800
@@ -29,6 +29,7 @@
 #include "signkey.h"
 #include "runopts.h"
 #include "random.h"
+#include "crypto_desc.h"
 
 static size_t listensockets(int *sock, size_t sockcount, int *maxfd);
 static void sigchld_handler(int dummy);
@@ -383,9 +384,11 @@
 		dropbear_exit("signal() error");
 	}
 
+	crypto_init();
+
 	/* Now we can setup the hostkeys - needs to be after logging is on,
 	 * otherwise we might end up blatting error messages to the socket */
-	loadhostkeys();
+	load_all_hostkeys();
 
     seedrandom();
 }
--- a/svr-runopts.c	Sun Apr 28 23:17:43 2013 +0800
+++ b/svr-runopts.c	Fri May 03 23:07:48 2013 +0800
@@ -28,11 +28,14 @@
 #include "buffer.h"
 #include "dbutil.h"
 #include "algo.h"
+#include "ecdsa.h"
 
 svr_runopts svr_opts; /* GLOBAL */
 
 static void printhelp(const char * progname);
 static void addportandaddress(char* spec);
+static void loadhostkey(const char *keyfile, int fatal_duplicate);
+static void addhostkey(const char *keyfile);
 
 static void printhelp(const char * progname) {
 
@@ -105,10 +108,10 @@
 	char* recv_window_arg = NULL;
 	char* keepalive_arg = NULL;
 	char* idle_timeout_arg = NULL;
+	char* keyfile = NULL;
+
 
 	/* see printhelp() for options */
-	svr_opts.rsakeyfile = NULL;
-	svr_opts.dsskeyfile = NULL;
 	svr_opts.bannerfile = NULL;
 	svr_opts.banner = NULL;
 	svr_opts.forkbg = 1;
@@ -160,6 +163,11 @@
 				dropbear_exit("Invalid null argument");
 			}
 			next = 0x00;
+
+			if (keyfile) {
+				addhostkey(keyfile);
+				keyfile = NULL;
+			}
 			continue;
 		}
 
@@ -168,16 +176,10 @@
 				case 'b':
 					next = &svr_opts.bannerfile;
 					break;
-#ifdef DROPBEAR_DSS
 				case 'd':
-					next = &svr_opts.dsskeyfile;
+				case 'r':
+					next = &keyfile;
 					break;
-#endif
-#ifdef DROPBEAR_RSA
-				case 'r':
-					next = &svr_opts.rsakeyfile;
-					break;
-#endif
 				case 'F':
 					svr_opts.forkbg = 0;
 					break;
@@ -267,13 +269,6 @@
 		svr_opts.portcount = 1;
 	}
 
-	if (svr_opts.dsskeyfile == NULL) {
-		svr_opts.dsskeyfile = DSS_PRIV_FILENAME;
-	}
-	if (svr_opts.rsakeyfile == NULL) {
-		svr_opts.rsakeyfile = RSA_PRIV_FILENAME;
-	}
-
 	if (svr_opts.bannerfile) {
 		struct stat buf;
 		if (stat(svr_opts.bannerfile, &buf) != 0) {
@@ -292,7 +287,6 @@
 					svr_opts.bannerfile);
 		}
 		buf_setpos(svr_opts.banner, 0);
-
 	}
 	
 	if (recv_window_arg) {
@@ -370,55 +364,125 @@
 	}
 }
 
-static void disablekey(int type, const char* filename) {
-
+static void disablekey(int type) {
 	int i;
-
 	for (i = 0; sshhostkey[i].name != NULL; i++) {
 		if (sshhostkey[i].val == type) {
-			sshhostkey[i].usable = 0;
+			sshhostkey[i].usable = 1;
 			break;
 		}
 	}
-	dropbear_log(LOG_WARNING, "Failed reading '%s', disabling %s", filename,
-			type == DROPBEAR_SIGNKEY_DSS ? "DSS" : "RSA");
 }
 
 /* Must be called after syslog/etc is working */
-void loadhostkeys() {
+static void loadhostkey(const char *keyfile, int fatal_duplicate) {
+	sign_key * read_key = new_sign_key();
+	int type = DROPBEAR_SIGNKEY_ANY;
+	if (readhostkey(keyfile, read_key, &type) == DROPBEAR_FAILURE) {
+		dropbear_log(LOG_WARNING, "Failed loading %s", keyfile);
+	}
+
+#ifdef DROPBEAR_RSA
+	if (type == DROPBEAR_SIGNKEY_RSA) {
+		if (svr_opts.hostkey->rsakey) {
+			if (fatal_duplicate) {
+				dropbear_exit("Only one RSA key can be specified");
+			}
+		} else {
+			svr_opts.hostkey->rsakey = read_key->rsakey;
+			read_key->rsakey = NULL;
+		}
+	}
+#endif
 
-	int ret;
-	int type;
+#ifdef DROPBEAR_DSS
+	if (type == DROPBEAR_SIGNKEY_DSS) {
+		if (svr_opts.hostkey->dsskey) {
+			if (fatal_duplicate) {
+				dropbear_exit("Only one DSS key can be specified");
+			}
+		} else {
+			svr_opts.hostkey->dsskey = read_key->dsskey;
+			read_key->dsskey = NULL;
+		}
+	}
+#endif
 
-	TRACE(("enter loadhostkeys"))
+#ifdef DROPBEAR_ECDSA
+	if (IS_ECDSA_KEY(type)) {
+		if (svr_opts.hostkey->ecckey) {
+			if (fatal_duplicate) {
+				dropbear_exit("Only one ECDSA key can be specified");
+			}
+		} else {
+			svr_opts.hostkey->ecckey = read_key->ecckey;
+			read_key->ecckey = NULL;
+		}
+	}
+#endif
+	sign_key_free(read_key);
+	TRACE(("leave loadhostkey"))
+}
+
+static void addhostkey(const char *keyfile) {
+	if (svr_opts.num_hostkey_files >= MAX_HOSTKEYS) {
+		dropbear_exit("Too many hostkeys");
+	}
+	svr_opts.hostkey_files[svr_opts.num_hostkey_files] = m_strdup(keyfile);
+	svr_opts.num_hostkey_files++;
+}
+
+void load_all_hostkeys() {
+	int i;
 
 	svr_opts.hostkey = new_sign_key();
 
+	for (i = 0; i < svr_opts.num_hostkey_files; i++) {
+		char *hostkey_file = svr_opts.hostkey_files[i];
+		loadhostkey(hostkey_file, 1);
+		m_free(hostkey_file);
+	}
+
 #ifdef DROPBEAR_RSA
-	type = DROPBEAR_SIGNKEY_RSA;
-	ret = readhostkey(svr_opts.rsakeyfile, svr_opts.hostkey, &type);
-	if (ret == DROPBEAR_FAILURE) {
-		disablekey(DROPBEAR_SIGNKEY_RSA, svr_opts.rsakeyfile);
+	loadhostkey(RSA_PRIV_FILENAME, 0);
+#endif
+
+#ifdef DROPBEAR_DSS
+	loadhostkey(DSS_PRIV_FILENAME, 0);
+#endif
+
+#ifdef DROPBEAR_ECDSA
+	loadhostkey(ECDSA_PRIV_FILENAME, 0);
+#endif
+
+#ifdef DROPBEAR_RSA
+	if (!svr_opts.hostkey->rsakey) {
+		disablekey(DROPBEAR_SIGNKEY_RSA);
 	}
 #endif
 #ifdef DROPBEAR_DSS
-	type = DROPBEAR_SIGNKEY_DSS;
-	ret = readhostkey(svr_opts.dsskeyfile, svr_opts.hostkey, &type);
-	if (ret == DROPBEAR_FAILURE) {
-		disablekey(DROPBEAR_SIGNKEY_DSS, svr_opts.dsskeyfile);
+	if (!svr_opts.hostkey->dsskey) {
+		disablekey(DROPBEAR_SIGNKEY_RSA);
+	}
+#endif
+#ifdef DROPBEAR_ECDSA
+#ifdef DROPBEAR_ECC_256
+	if (!svr_opts.hostkey->ecckey 
+		|| ecdsa_signkey_type(svr_opts.hostkey->ecckey) != DROPBEAR_SIGNKEY_ECDSA_NISTP256) {
+		disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256);
 	}
 #endif
-
-	if ( 1
-#ifdef DROPBEAR_DSS
-		&& svr_opts.hostkey->dsskey == NULL
+#ifdef DROPBEAR_ECC_384
+	if (!svr_opts.hostkey->ecckey 
+		|| ecdsa_signkey_type(svr_opts.hostkey->ecckey) != DROPBEAR_SIGNKEY_ECDSA_NISTP384) {
+		disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384);
+	}
 #endif
-#ifdef DROPBEAR_RSA
-		&& svr_opts.hostkey->rsakey == NULL
+#ifdef DROPBEAR_ECC_521
+	if (!svr_opts.hostkey->ecckey 
+		|| ecdsa_signkey_type(svr_opts.hostkey->ecckey) != DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
+		disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521);
+	}
 #endif
-		) {
-		dropbear_exit("No hostkeys available");
-	}
-
-	TRACE(("leave loadhostkeys"))
+#endif
 }
--- a/svr-session.c	Sun Apr 28 23:17:43 2013 +0800
+++ b/svr-session.c	Fri May 03 23:07:48 2013 +0800
@@ -77,7 +77,6 @@
 	char *host, *port;
 	size_t len;
 
-	crypto_init();
 	common_session_init(sock, sock);
 
 	/* Initialise server specific parts of the session */
--- a/sysoptions.h	Sun Apr 28 23:17:43 2013 +0800
+++ b/sysoptions.h	Fri May 03 23:07:48 2013 +0800
@@ -141,6 +141,8 @@
 /* For a 4096 bit DSS key, empirically determined */
 #define MAX_PRIVKEY_SIZE 1700
 
+#define MAX_HOSTKEYS 3
+
 /* The maximum size of the bignum portion of the kexhash buffer */
 /* Sect. 8 of the transport rfc 4253, K_S + e + f + K */
 #define KEXHASHBUF_MAX_INTS (1700 + 130 + 130 + 130)