changeset 849:754d7bee1068 ecc

Merge
author Matt Johnston <matt@ucc.asn.au>
date Fri, 08 Nov 2013 23:32:13 +0800
parents 6c69e7df3621 (current diff) f4bb964c8678 (diff)
children 7507b174bba0
files Makefile.in cli-kex.c debug.h keyimport.c options.h svr-kex.c
diffstat 15 files changed, 376 insertions(+), 181 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.in	Fri Nov 08 23:11:43 2013 +0800
+++ b/Makefile.in	Fri Nov 08 23:32:13 2013 +0800
@@ -27,7 +27,8 @@
 		signkey.o rsa.o random.o \
 		queue.o \
 		atomicio.o compat.o fake-rfc2553.o \
-		ltc_prng.o ecc.o ecdsa.o crypto_desc.o
+		ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
+		gensignkey.o gendss.o genrsa.o
 
 SVROBJS=svr-kex.o svr-auth.o sshpty.o \
 		svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
@@ -44,7 +45,7 @@
 			tcp-accept.o listener.o process-packet.o \
 			common-runopts.o circbuffer.o curve25519-donna.o
 
-KEYOBJS=dropbearkey.o gendss.o genrsa.o
+KEYOBJS=dropbearkey.o
 
 CONVERTOBJS=dropbearconvert.o keyimport.o
 
--- a/cli-kex.c	Fri Nov 08 23:11:43 2013 +0800
+++ b/cli-kex.c	Fri Nov 08 23:32:13 2013 +0800
@@ -184,7 +184,8 @@
 	TRACE(("leave recv_msg_kexdh_init"))
 }
 
-static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen) {
+static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen,
+	const char* algoname) {
 
 	char* fp = NULL;
 	FILE *tty = NULL;
@@ -192,14 +193,16 @@
 
 	fp = sign_key_fingerprint(keyblob, keybloblen);
 	if (cli_opts.always_accept_key) {
-		fprintf(stderr, "\nHost '%s' key accepted unconditionally.\n(fingerprint %s)\n",
+		fprintf(stderr, "\nHost '%s' key accepted unconditionally.\n(%s fingerprint %s)\n",
 				cli_opts.remotehost,
+				algoname,
 				fp);
 		m_free(fp);
 		return;
 	}
-	fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(fingerprint %s)\nDo you want to continue connecting? (y/n) ", 
+	fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(%s fingerprint %s)\nDo you want to continue connecting? (y/n) ", 
 			cli_opts.remotehost, 
+			algoname,
 			fp);
 	m_free(fp);
 
@@ -294,16 +297,17 @@
 		return;
 	}
 
+	algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen);
+
 	hostsfile = open_known_hosts_file(&readonly);
 	if (!hostsfile)	{
-		ask_to_confirm(keyblob, keybloblen);
+		ask_to_confirm(keyblob, keybloblen, algoname);
 		/* ask_to_confirm will exit upon failure */
 		return;
 	}
 	
 	line = buf_new(MAX_KNOWNHOSTS_LINE);
 	hostlen = strlen(cli_opts.remotehost);
-	algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen);
 
 	do {
 		if (buf_getline(line, hostsfile) == DROPBEAR_FAILURE) {
@@ -356,17 +360,18 @@
 
 		/* The keys didn't match. eep. Note that we're "leaking"
 		   the fingerprint strings here, but we're exiting anyway */
-		dropbear_exit("\n\nHost key mismatch for %s !\n"
+		dropbear_exit("\n\n%s host key mismatch for %s !\n"
 					"Fingerprint is %s\n"
 					"Expected %s\n"
 					"If you know that the host key is correct you can\nremove the bad entry from ~/.ssh/known_hosts", 
+					algoname,
 					cli_opts.remotehost,
 					sign_key_fingerprint(keyblob, keybloblen),
 					fingerprint ? fingerprint : "UNKNOWN");
 	} while (1); /* keep going 'til something happens */
 
 	/* Key doesn't exist yet */
-	ask_to_confirm(keyblob, keybloblen);
+	ask_to_confirm(keyblob, keybloblen, algoname);
 
 	/* If we get here, they said yes */
 
--- a/debug.h	Fri Nov 08 23:11:43 2013 +0800
+++ b/debug.h	Fri Nov 08 23:32:13 2013 +0800
@@ -72,6 +72,7 @@
 
 /* To debug with GDB it is easier to run with no forking of child processes.
    You will need to pass "-F" as well. */
+/* #define DEBUG_NOFORK */
 #define DEBUG_NOFORK
 
 
--- a/dropbearkey.c	Fri Nov 08 23:11:43 2013 +0800
+++ b/dropbearkey.c	Fri Nov 08 23:32:13 2013 +0800
@@ -54,15 +54,13 @@
 #include "ecdsa.h"
 #include "crypto_desc.h"
 #include "random.h"
+#include "gensignkey.h"
 
 static void printhelp(char * progname);
 
-#define RSA_DEFAULT_SIZE 2048
-#define DSS_DEFAULT_SIZE 1024
 
-static void buf_writefile(buffer * buf, const char * filename);
 static void printpubkey(sign_key * key, int keytype);
-static void justprintpub(const char* filename);
+static int printpubfile(const char* filename);
 
 /* Print a help message */
 static void printhelp(char * progname) {
@@ -103,6 +101,30 @@
 					,progname);
 }
 
+/* fails fatally */
+static void check_signkey_bits(enum signkey_type type, int bits)
+{
+        switch (type) {
+#ifdef DROPBEAR_RSA
+            case DROPBEAR_SIGNKEY_RSA:
+                if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
+                	dropbear_exit("Bits must satisfy 512 <= bits <= 4096, and be a"
+                            " multiple of 8\n");
+                }
+                break;
+#endif
+#ifdef DROPEAR_DSS
+            case DROPBEAR_SIGNKEY_DSS:
+                if (bits != 1024) {
+                    dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
+                    exit(EXIT_FAILURE);
+                }
+#endif
+			default:
+				(void)0; /* quiet, compiler. ecdsa handles checks itself */
+        }
+}
+
 #if defined(DBMULTI_dropbearkey) || !defined(DROPBEAR_MULTI)
 #if defined(DBMULTI_dropbearkey) && defined(DROPBEAR_MULTI)
 int dropbearkey_main(int argc, char ** argv) {
@@ -112,13 +134,11 @@
 
 	int i;
 	char ** next = 0;
-	sign_key *key = NULL;
-	buffer *buf = NULL;
 	char * filename = NULL;
 	enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE;
 	char * typetext = NULL;
 	char * sizetext = NULL;
-	unsigned int bits;
+	unsigned int bits = 0;
 	int printpub = 0;
 
 	crypto_init();
@@ -174,8 +194,8 @@
 	}
 
 	if (printpub) {
-		justprintpub(filename);
-		/* Not reached */
+		int ret = printpubfile(filename);
+		exit(ret);
 	}
 
 	/* check/parse args */
@@ -216,106 +236,22 @@
 			exit(EXIT_FAILURE);
 		}
 		
-		// TODO: put RSA and DSS size checks into genrsa.c etc
-        switch (keytype) {
-#ifdef DROPBEAR_RSA
-            case DROPBEAR_SIGNKEY_RSA:
-                if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
-                    fprintf(stderr, "Bits must satisfy 512 <= bits <= 4096, and be a"
-                            " multiple of 8\n");
-                    exit(EXIT_FAILURE);
-                }
-                break;
-#endif
-#ifdef DROPEAR_DSS
-            case DROPBEAR_SIGNKEY_DSS:
-                if (bits != 1024) {
-                    fprintf(stderr, "DSS keys have a fixed size of 1024 bits\n");
-                    exit(EXIT_FAILURE);			
-                }
-#endif
-			default:
-				(void)0; /* quiet, compiler. ecdsa handles checks itself */
-        }
-
-    } else {
-    	/* default key size */
-
-        switch (keytype) {
-#ifdef DROPBEAR_RSA
-            case DROPBEAR_SIGNKEY_RSA:
-				bits = RSA_DEFAULT_SIZE;
-                break;
-#endif
-#ifdef DROPBEAR_DSS
-            case DROPBEAR_SIGNKEY_DSS:
-                bits = DSS_DEFAULT_SIZE;
-                break;
-#endif
-#ifdef DROPBEAR_ECDSA
-            case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
-                bits = ECDSA_DEFAULT_SIZE;
-                break;
-#endif
-            default:
-                exit(EXIT_FAILURE); /* not reached */
-		}
-	}
-
+		check_signkey_bits(keytype, bits);;
+    }
 
-	fprintf(stderr, "Will output %d bit %s secret key to '%s'\n", bits,
-			typetext, filename);
-
-	/* don't want the file readable by others */
-	umask(077);
+	fprintf(stderr, "Generating key, this may take a while...\n");
+    if (signkey_generate(keytype, bits, filename) == DROPBEAR_FAILURE)
+    {
+    	dropbear_exit("Failed to generate key.\n");
+    }
 
-	/* now we can generate the key */
-	key = new_sign_key();
-	
-	fprintf(stderr, "Generating key, this may take a while...\n");
-	switch(keytype) {
-#ifdef DROPBEAR_RSA
-		case DROPBEAR_SIGNKEY_RSA:
-			key->rsakey = gen_rsa_priv_key(bits);
-			break;
-#endif
-#ifdef DROPBEAR_DSS
-		case DROPBEAR_SIGNKEY_DSS:
-			key->dsskey = gen_dss_priv_key(bits);
-			break;
-#endif
-#ifdef DROPBEAR_ECDSA
-		case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
-			{
-				ecc_key *ecckey = gen_ecdsa_priv_key(bits);
-				keytype = ecdsa_signkey_type(ecckey);
-				*signkey_key_ptr(key, keytype) = ecckey;
-			}
-			break;
-#endif
-		default:
-			fprintf(stderr, "Internal error, bad key type\n");
-			exit(EXIT_FAILURE);
-	}
-
-	buf = buf_new(MAX_PRIVKEY_SIZE); 
-
-	buf_put_priv_key(buf, key, keytype);
-	buf_setpos(buf, 0);
-	buf_writefile(buf, filename);
-
-	buf_burn(buf);
-	buf_free(buf);
-
-	printpubkey(key, keytype);
-
-	sign_key_free(key);
+	printpubfile(filename);
 
 	return EXIT_SUCCESS;
 }
 #endif
 
-static void justprintpub(const char* filename) {
+static int printpubfile(const char* filename) {
 
 	buffer *buf = NULL;
 	sign_key *key = NULL;
@@ -353,7 +289,7 @@
 		sign_key_free(key);
 		key = NULL;
 	}
-	exit(err);
+	return err;
 }
 
 static void printpubkey(sign_key * key, int keytype) {
@@ -402,35 +338,3 @@
 	m_free(fp);
 	buf_free(buf);
 }
-
-/* Write a buffer to a file specified, failing if the file exists */
-static void buf_writefile(buffer * buf, const char * filename) {
-
-	int fd;
-	int len;
-
-	fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
-	if (fd < 0) {
-		fprintf(stderr, "Couldn't create new file %s\n", filename);
-		perror("Reason");
-		buf_burn(buf);
-		exit(EXIT_FAILURE);
-	}
-
-	/* write the file now */
-	while (buf->pos != buf->len) {
-		len = write(fd, buf_getptr(buf, buf->len - buf->pos),
-				buf->len - buf->pos);
-		if (errno == EINTR) {
-			continue;
-		}
-		if (len <= 0) {
-			fprintf(stderr, "Failed writing file '%s'\n",filename);
-			perror("Reason");
-			exit(EXIT_FAILURE);
-		}
-		buf_incrpos(buf, len);
-	}
-
-	close(fd);
-}
--- a/ecdsa.c	Fri Nov 08 23:11:43 2013 +0800
+++ b/ecdsa.c	Fri Nov 08 23:32:13 2013 +0800
@@ -8,6 +8,13 @@
 
 #ifdef DROPBEAR_ECDSA
 
+int signkey_is_ecdsa(enum signkey_type type)
+{
+	return type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
+		|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
+		|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP521;
+}
+
 enum signkey_type ecdsa_signkey_type(ecc_key * key) {
 #ifdef DROPBEAR_ECC_256
 	if (key->dp == ecc_curve_nistp256.dp) {
--- a/ecdsa.h	Fri Nov 08 23:11:43 2013 +0800
+++ b/ecdsa.h	Fri Nov 08 23:32:13 2013 +0800
@@ -26,6 +26,8 @@
 
 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);
+/* Returns 1 on success */
+int signkey_is_ecdsa(enum signkey_type type);
 
 #endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gensignkey.c	Fri Nov 08 23:32:13 2013 +0800
@@ -0,0 +1,127 @@
+#include "includes.h"
+#include "dbutil.h"
+#include "buffer.h"
+#include "ecdsa.h"
+#include "genrsa.h"
+#include "gendss.h"
+#include "signkey.h"
+
+#define RSA_DEFAULT_SIZE 2048
+#define DSS_DEFAULT_SIZE 1024
+
+// Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE
+static int buf_writefile(buffer * buf, const char * filename) {
+	int ret = DROPBEAR_FAILURE;
+	int fd = -1;
+
+	fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+	if (fd < 0) {
+		dropbear_log(LOG_ERR, "Couldn't create new file %s: %s",
+			filename, strerror(errno));
+		goto out;
+	}
+
+	/* write the file now */
+	while (buf->pos != buf->len) {
+		int len = write(fd, buf_getptr(buf, buf->len - buf->pos),
+				buf->len - buf->pos);
+		if (errno == EINTR) {
+			continue;
+		}
+		if (len <= 0) {
+			dropbear_log(LOG_ERR, "Failed writing file %s: %s",
+				filename, strerror(errno));
+			goto out;
+		}
+		buf_incrpos(buf, len);
+	}
+
+	ret = DROPBEAR_SUCCESS;
+
+out:
+	if (fd >= 0) {
+		m_close(fd);
+	}
+	return ret;
+}
+
+/* returns 0 on failure */
+static int get_default_bits(enum signkey_type keytype)
+{
+        switch (keytype) {
+#ifdef DROPBEAR_RSA
+            case DROPBEAR_SIGNKEY_RSA:
+				return RSA_DEFAULT_SIZE;
+#endif
+#ifdef DROPBEAR_DSS
+            case DROPBEAR_SIGNKEY_DSS:
+                return DSS_DEFAULT_SIZE;
+#endif
+#ifdef DROPBEAR_ECDSA
+            case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
+                return ECDSA_DEFAULT_SIZE;
+            case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
+            	return 521;
+            case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
+            	return 384;
+            case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
+            	return 256;
+#endif
+            default:
+                return 0;
+		}
+}
+
+int signkey_generate(enum signkey_type keytype, int bits, const char* filename)
+{
+	sign_key * key = NULL;
+	buffer *buf = NULL;
+	int ret = DROPBEAR_FAILURE;
+	if (bits == 0)
+	{
+		bits = get_default_bits(keytype);
+	}
+
+	/* now we can generate the key */
+	key = new_sign_key();
+
+	switch(keytype) {
+#ifdef DROPBEAR_RSA
+		case DROPBEAR_SIGNKEY_RSA:
+			key->rsakey = gen_rsa_priv_key(bits);
+			break;
+#endif
+#ifdef DROPBEAR_DSS
+		case DROPBEAR_SIGNKEY_DSS:
+			key->dsskey = gen_dss_priv_key(bits);
+			break;
+#endif
+#ifdef DROPBEAR_ECDSA
+		case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
+		case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
+		case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
+		case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
+			{
+				ecc_key *ecckey = gen_ecdsa_priv_key(bits);
+				keytype = ecdsa_signkey_type(ecckey);
+				*signkey_key_ptr(key, keytype) = ecckey;
+			}
+			break;
+#endif
+		default:
+			dropbear_exit("Internal error");
+	}
+
+	buf = buf_new(MAX_PRIVKEY_SIZE); 
+
+	buf_put_priv_key(buf, key, keytype);
+	sign_key_free(key);
+	key = NULL;
+	buf_setpos(buf, 0);
+	ret = buf_writefile(buf, filename);
+
+	buf_burn(buf);
+	buf_free(buf);
+	buf = NULL;
+	return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gensignkey.h	Fri Nov 08 23:32:13 2013 +0800
@@ -0,0 +1,8 @@
+#ifndef _GENSIGNKEY_H
+#define _GENSIGNKEY_H
+
+#include "signkey.h"
+
+int signkey_generate(enum signkey_type type, int bits, const char* filename);
+
+#endif
--- a/keyimport.c	Fri Nov 08 23:11:43 2013 +0800
+++ b/keyimport.c	Fri Nov 08 23:32:13 2013 +0800
@@ -112,7 +112,7 @@
 
 	buffer * buf = NULL;
 	sign_key *ret = NULL;
-	int type;
+	enum signkey_type type;
 
 	buf = buf_new(MAX_PRIVKEY_SIZE);
 	if (buf_readfile(buf, filename) == DROPBEAR_FAILURE) {
@@ -501,7 +501,7 @@
 	return ret;
 }
 
-static sign_key *openssh_read(const char *filename, char *passphrase)
+static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
 {
 	struct openssh_key *key;
 	unsigned char *p;
@@ -511,7 +511,7 @@
 	char *errmsg;
 	char *modptr = NULL;
 	int modlen = -9999;
-	int type;
+	enum signkey_type type;
 
 	sign_key *retkey;
 	buffer * blobbuf = NULL;
@@ -709,19 +709,29 @@
 			goto error;
 		}
 
-		if (len == sizeof(OID_SEC256R1_BLOB) 
+		if (0) {}
+#ifdef DROPBEAR_ECC_256
+		else if (len == sizeof(OID_SEC256R1_BLOB) 
 			&& memcmp(p, OID_SEC256R1_BLOB, len) == 0) {
 			retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
 			curve = &ecc_curve_nistp256;
-		} else if (len == sizeof(OID_SEC384R1_BLOB)
+		} 
+#endif
+#ifdef DROPBEAR_ECC_384
+		else if (len == sizeof(OID_SEC384R1_BLOB)
 			&& memcmp(p, OID_SEC384R1_BLOB, len) == 0) {
 			retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP384;
 			curve = &ecc_curve_nistp384;
-		} else if (len == sizeof(OID_SEC521R1_BLOB)
+		} 
+#endif
+#ifdef DROPBEAR_ECC_521
+		else if (len == sizeof(OID_SEC521R1_BLOB)
 			&& memcmp(p, OID_SEC521R1_BLOB, len) == 0) {
 			retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP521;
 			curve = &ecc_curve_nistp521;
-		} else {
+		} 
+#endif
+		else {
 			errmsg = "Unknown ECC key type";
 			goto error;
 		}
@@ -1019,7 +1029,7 @@
 		*/
 		buffer *seq_buf = buf_new(400);
 		ecc_key **eck = (ecc_key**)signkey_key_ptr(key, key->type);
-		const unsigned long curve_size = (*eck)->dp->size;
+		const long curve_size = (*eck)->dp->size;
 		int curve_oid_len = 0;
 		const void* curve_oid = NULL;
 		unsigned long pubkey_size = 2*curve_size+1;
--- a/options.h	Fri Nov 08 23:11:43 2013 +0800
+++ b/options.h	Fri Nov 08 23:32:13 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. */
 
-/* Important: Many options will require "make clean" after changes */
+/* IMPORTANT: Many options will require "make clean" after changes */
 
 #ifndef DROPBEAR_DEFPORT
 #define DROPBEAR_DEFPORT "22"
@@ -129,7 +129,7 @@
 
 /* You can also disable integrity. Don't bother disabling this if you're
  * still using a cipher, it's relatively cheap. If you disable this it's dead
- * simple to run arbitrary commands on the remote host. Beware. */
+ * simple for an attacker to run arbitrary commands on the remote host. Beware. */
 /* #define DROPBEAR_NONE_INTEGRITY */
 
 /* Hostkey/public key algorithms - at least one required, these are used
@@ -138,9 +138,13 @@
  * SSH2 RFC Draft requires dss, recommends rsa */
 #define DROPBEAR_RSA
 #define DROPBEAR_DSS
+#define DROPBEAR_ECDSA
 
-#define DROPBEAR_ECDH
-#define DROPBEAR_ECDSA
+/* Generate hostkeys as-needed when the first connection using that key type occurs.
+   This avoids the need to otherwise run "dropbearkey" and avoids some problems
+   with badly seeded random devices when systems first boot.
+   This also requires a runtime flag "-R". */
+#define DROPBEAR_DELAY_HOSTKEY
 
 #define DROPBEAR_CURVE25519
 
@@ -149,6 +153,9 @@
  * signing operations slightly slower. */
 #define RSA_BLINDING
 
+/* Enable elliptic curve Diffie Hellman key exchange */
+#define DROPBEAR_ECDH
+
 /* Control the memory/performance/compression tradeoff for zlib.
  * Set windowBits=8 for least memory usage, see your system's
  * zlib.h for full details.
@@ -184,7 +191,7 @@
 
 #define ENABLE_SVR_PASSWORD_AUTH
 /* PAM requires ./configure --enable-pam */
-//#define ENABLE_SVR_PAM_AUTH
+/*#define ENABLE_SVR_PAM_AUTH */
 #define ENABLE_SVR_PUBKEY_AUTH
 
 /* Whether to take public key options in 
--- a/runopts.h	Fri Nov 08 23:11:43 2013 +0800
+++ b/runopts.h	Fri Nov 08 23:32:13 2013 +0800
@@ -100,6 +100,8 @@
 
 	sign_key *hostkey;
 
+	int delay_hostkey;
+
 	char *hostkey_files[MAX_HOSTKEYS];
 	int num_hostkey_files;
 
--- a/signkey.c	Fri Nov 08 23:11:43 2013 +0800
+++ b/signkey.c	Fri Nov 08 23:32:13 2013 +0800
@@ -181,7 +181,7 @@
 	}
 #endif
 #ifdef DROPBEAR_ECDSA
-	{
+	if (signkey_is_ecdsa(keytype)) {
 		ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
 		if (eck) {
 			if (*eck) {
@@ -249,7 +249,7 @@
 	}
 #endif
 #ifdef DROPBEAR_ECDSA
-	{
+	if (signkey_is_ecdsa(keytype)) {
 		ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
 		if (eck) {
 			if (*eck) {
@@ -289,10 +289,7 @@
 	}
 #endif
 #ifdef DROPBEAR_ECDSA
-	if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
-		|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
-		|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP521)
-	{
+	if (signkey_is_ecdsa(type)) {
 		ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
 		if (eck) {
 			buf_put_ecdsa_pub_key(pubkeys, *eck);
@@ -329,7 +326,7 @@
 	}
 #endif
 #ifdef DROPBEAR_ECDSA
-	{
+	if (signkey_is_ecdsa(type)) {
 		ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
 		if (eck) {
 			buf_put_ecdsa_priv_key(buf, *eck);
@@ -354,19 +351,25 @@
 	key->rsakey = NULL;
 #endif
 #ifdef DROPBEAR_ECDSA
+#ifdef DROPBEAR_ECC_256
 	if (key->ecckey256) {
 		ecc_free(key->ecckey256);
 		key->ecckey256 = NULL;
 	}
+#endif
+#ifdef DROPBEAR_ECC_384
 	if (key->ecckey384) {
 		ecc_free(key->ecckey384);
 		key->ecckey384 = NULL;
 	}
+#endif
+#ifdef DROPBEAR_ECC_521
 	if (key->ecckey521) {
 		ecc_free(key->ecckey521);
 		key->ecckey521 = NULL;
 	}
 #endif
+#endif
 
 	m_free(key->filename);
 
@@ -484,7 +487,7 @@
 	}
 #endif
 #ifdef DROPBEAR_ECDSA
-	{
+	if (signkey_is_ecdsa(type)) {
 		ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
 		if (eck) {
 			buf_put_ecdsa_sign(sigblob, *eck, data_buf);
@@ -535,7 +538,7 @@
 	}
 #endif
 #ifdef DROPBEAR_ECDSA
-	{
+	if (signkey_is_ecdsa(type)) {
 		ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
 		if (eck) {
 			return buf_ecdsa_verify(buf, *eck, data_buf);
--- a/svr-kex.c	Fri Nov 08 23:11:43 2013 +0800
+++ b/svr-kex.c	Fri Nov 08 23:32:13 2013 +0800
@@ -35,6 +35,7 @@
 #include "random.h"
 #include "runopts.h"
 #include "ecc.h"
+#include "gensignkey.h"
 
 static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs);
 
@@ -82,6 +83,84 @@
 	ses.requirenext[1] = 0;
 	TRACE(("leave recv_msg_kexdh_init"))
 }
+
+#ifdef DROPBEAR_DELAY_HOSTKEY
+static void svr_ensure_hostkey() {
+
+	const char* fn = NULL;
+	char *fn_temp = NULL;
+	enum signkey_type type = ses.newkeys->algo_hostkey;
+	void **hostkey = signkey_key_ptr(svr_opts.hostkey, type);
+	int ret = DROPBEAR_FAILURE;
+
+	if (hostkey && *hostkey) {
+		return;
+	}
+
+	switch (type)
+	{
+#ifdef DROPBEAR_RSA
+		case DROPBEAR_SIGNKEY_RSA:
+			fn = RSA_PRIV_FILENAME;
+			break;
+#endif
+#ifdef DROPBEAR_DSS
+		case DROPBEAR_SIGNKEY_DSS:
+			fn = DSS_PRIV_FILENAME;
+			break;
+#endif
+#ifdef DROPBEAR_ECDSA
+		case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
+		case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
+		case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
+			fn = ECDSA_PRIV_FILENAME;
+			break;
+#endif
+		default:
+			(void)0;
+	}
+
+	if (readhostkey(fn, svr_opts.hostkey, &type) == DROPBEAR_SUCCESS) {
+		return;
+	}
+
+	fn_temp = m_malloc(strlen(fn) + 20);
+	snprintf(fn_temp, strlen(fn)+20, "%s.tmp%d", fn, getpid());
+
+	if (signkey_generate(type, 0, fn_temp) == DROPBEAR_FAILURE) {
+		goto out;
+	}
+
+	if (link(fn_temp, fn) < 0) {
+		if (errno != EEXIST) {
+			dropbear_log(LOG_ERR, "Failed moving key file to %s", fn);
+			/* XXX fallback to non-atomic copy for some filesystems? */
+			goto out;
+		}
+	}
+
+	ret = readhostkey(fn, svr_opts.hostkey, &type);
+
+out:
+	if (fn_temp) {
+		unlink(fn_temp);
+		m_free(fn_temp);
+	}
+
+	if (ret == DROPBEAR_FAILURE)
+	{
+		dropbear_exit("Couldn't read or generate hostkey %s", fn);
+	}
+
+	// directory for keys.
+
+	// Create lockfile first, or wait if it exists. PID!
+	// Generate key
+	// write it, load to memory
+	// atomic rename, done.
+
+}
+#endif
 	
 /* Generate our side of the diffie-hellman key exchange value (dh_f), and
  * calculate the session key using the diffie-hellman algorithm. Following
@@ -95,6 +174,14 @@
 
 	/* we can start creating the kexdh_reply packet */
 	CHECKCLEARTOWRITE();
+
+#ifdef DROPBEAR_DELAY_HOSTKEY
+	if (svr_opts.delay_hostkey)
+	{
+		svr_ensure_hostkey();
+	}
+#endif
+
 	buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_REPLY);
 	buf_put_pub_key(ses.writepayload, svr_opts.hostkey,
 			ses.newkeys->algo_hostkey);
@@ -124,7 +211,7 @@
 		case DROPBEAR_KEX_CURVE25519:
 #ifdef DROPBEAR_CURVE25519
 			{
-			struct kex_curve25519_param *param = gen_kexecdh_param();
+			struct kex_curve25519_param *param = gen_kexcurve25519_param();
 			kexcurve25519_comb_key(param, ecdh_qs, svr_opts.hostkey);
 			buf_putstring(ses.writepayload, param->priv, CURVE25519_LEN);
 			free_kexcurve25519_param(param);
--- a/svr-runopts.c	Fri Nov 08 23:11:43 2013 +0800
+++ b/svr-runopts.c	Fri Nov 08 23:32:13 2013 +0800
@@ -44,13 +44,19 @@
 					"-b bannerfile	Display the contents of bannerfile"
 					" before user login\n"
 					"		(default: none)\n"
+					"-r keyfile  Specify hostkeys (repeatable)\n"
+					"		defaults: \n"
 #ifdef DROPBEAR_DSS
-					"-d dsskeyfile	Use dsskeyfile for the DSS host key\n"
-					"		(default: %s)\n"
+					"		dss %s\n"
 #endif
 #ifdef DROPBEAR_RSA
-					"-r rsakeyfile	Use rsakeyfile for the RSA host key\n"
-					"		(default: %s)\n"
+					"		rsa %s\n"
+#endif
+#ifdef DROPBEAR_ECDSA
+					"		ecdsa %s\n"
+#endif
+#ifdef DROPBEAR_DELAY_HOSTKEY
+					"-R		Create hostkeys as required\n" 
 #endif
 					"-F		Don't fork into background\n"
 #ifdef DISABLE_SYSLOG
@@ -96,6 +102,9 @@
 #ifdef DROPBEAR_RSA
 					RSA_PRIV_FILENAME,
 #endif
+#ifdef DROPBEAR_ECDSA
+					ECDSA_PRIV_FILENAME,
+#endif
 					DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE,
 					DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
 }
@@ -122,6 +131,7 @@
 	svr_opts.inetdmode = 0;
 	svr_opts.portcount = 0;
 	svr_opts.hostkey = NULL;
+	svr_opts.delay_hostkey = 0;
 	svr_opts.pidfile = DROPBEAR_PIDFILE;
 #ifdef ENABLE_SVR_LOCALTCPFWD
 	svr_opts.nolocaltcp = 0;
@@ -180,6 +190,9 @@
 				case 'r':
 					next = &keyfile;
 					break;
+				case 'R':
+					svr_opts.delay_hostkey = 1;
+					break;
 				case 'F':
 					svr_opts.forkbg = 0;
 					break;
@@ -390,7 +403,7 @@
 /* Must be called after syslog/etc is working */
 static void loadhostkey(const char *keyfile, int fatal_duplicate) {
 	sign_key * read_key = new_sign_key();
-	int type = DROPBEAR_SIGNKEY_ANY;
+	enum signkey_type type = DROPBEAR_SIGNKEY_ANY;
 	if (readhostkey(keyfile, read_key, &type) == DROPBEAR_FAILURE) {
 		dropbear_log(LOG_WARNING, "Failed loading %s", keyfile);
 	}
@@ -438,6 +451,7 @@
 
 void load_all_hostkeys() {
 	int i;
+	int disable_unset_keys = 1;
 
 	svr_opts.hostkey = new_sign_key();
 
@@ -459,31 +473,47 @@
 	loadhostkey(ECDSA_PRIV_FILENAME, 0);
 #endif
 
+#ifdef DROPBEAR_DELAY_HOSTKEY
+	if (svr_opts.delay_hostkey)
+	{
+		disable_unset_keys = 0;
+	}
+#endif
+
 #ifdef DROPBEAR_RSA
-	if (!svr_opts.hostkey->rsakey) {
+	if (disable_unset_keys && !svr_opts.hostkey->rsakey) {
 		disablekey(DROPBEAR_SIGNKEY_RSA);
 	}
 #endif
+
 #ifdef DROPBEAR_DSS
-	if (!svr_opts.hostkey->dsskey) {
+	if (disable_unset_keys && !svr_opts.hostkey->dsskey) {
 		disablekey(DROPBEAR_SIGNKEY_RSA);
 	}
 #endif
+
+
 #ifdef DROPBEAR_ECDSA
 #ifdef DROPBEAR_ECC_256
-	if (!svr_opts.hostkey->ecckey256) {
+	if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 256)
+		&& !svr_opts.hostkey->ecckey256) {
 		disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256);
 	}
 #endif
+
 #ifdef DROPBEAR_ECC_384
-	if (!svr_opts.hostkey->ecckey384) {
+	if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 384)
+		&& !svr_opts.hostkey->ecckey384) {
 		disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384);
 	}
 #endif
+
 #ifdef DROPBEAR_ECC_521
-	if (!svr_opts.hostkey->ecckey521) {
+	if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 521)
+		&& !svr_opts.hostkey->ecckey521) {
 		disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521);
 	}
 #endif
-#endif
+#endif /* DROPBEAR_ECDSA */
+
 }
--- a/sysoptions.h	Fri Nov 08 23:11:43 2013 +0800
+++ b/sysoptions.h	Fri Nov 08 23:32:13 2013 +0800
@@ -104,21 +104,22 @@
 #define DROPBEAR_LTC_PRNG
 #endif
 
-// hashes which will be linked and registered
+/* hashes which will be linked and registered */
 #if defined(DROPBEAR_SHA2_256_HMAC) || defined(DROPBEAR_ECC_256)
 #define DROPBEAR_SHA256
 #endif
 #if defined(DROPBEAR_ECC_384)
 #define DROPBEAR_SHA384
 #endif
-#if defined(DROPBEAR_SHA2_512_HMAC) || defined(DROPBEAR_ECC_521)
+/* LTC SHA384 depends on SHA512 */
+#if defined(DROPBEAR_SHA2_512_HMAC) || defined(DROPBEAR_ECC_521) || defined(DROPBEAR_ECC_384)
 #define DROPBEAR_SHA512
 #endif
 #if defined(DROPBEAR_MD5_HMAC)
 #define DROPBEAR_MD5
 #endif
 
-// roughly 2x 521 bits
+/* roughly 2x 521 bits */
 #define MAX_ECC_SIZE 140
 
 #define MAX_NAME_LEN 64 /* maximum length of a protocol name, isn't