changeset 847:f4bb964c8678 keyondemand

Add '-R' for delayed hostkey option
author Matt Johnston <matt@ucc.asn.au>
date Thu, 07 Nov 2013 23:49:37 +0800
parents b298bb438625
children 754d7bee1068
files cli-kex.c dropbearkey.c gensignkey.c keyimport.c options.h runopts.h signkey.c svr-kex.c svr-runopts.c sysoptions.h
diffstat 10 files changed, 104 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/cli-kex.c	Thu Nov 07 00:18:52 2013 +0800
+++ b/cli-kex.c	Thu Nov 07 23:49:37 2013 +0800
@@ -147,7 +147,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;
@@ -155,14 +156,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);
 
@@ -257,16 +260,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) {
@@ -319,17 +323,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/dropbearkey.c	Thu Nov 07 00:18:52 2013 +0800
+++ b/dropbearkey.c	Thu Nov 07 23:49:37 2013 +0800
@@ -54,6 +54,7 @@
 #include "ecdsa.h"
 #include "crypto_desc.h"
 #include "random.h"
+#include "gensignkey.h"
 
 static void printhelp(char * progname);
 
@@ -133,8 +134,6 @@
 
 	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;
--- a/gensignkey.c	Thu Nov 07 00:18:52 2013 +0800
+++ b/gensignkey.c	Thu Nov 07 23:49:37 2013 +0800
@@ -72,7 +72,6 @@
 		}
 }
 
-
 int signkey_generate(enum signkey_type keytype, int bits, const char* filename)
 {
 	sign_key * key = NULL;
--- a/keyimport.c	Thu Nov 07 00:18:52 2013 +0800
+++ b/keyimport.c	Thu Nov 07 23:49:37 2013 +0800
@@ -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;
 		}
--- a/options.h	Thu Nov 07 00:18:52 2013 +0800
+++ b/options.h	Thu Nov 07 23:49:37 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,15 +138,22 @@
  * 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
 
 /* RSA can be vulnerable to timing attacks which use the time required for
  * signing to guess the private key. Blinding avoids this attack, though makes
  * 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.
@@ -180,9 +187,9 @@
  * PAM challenge/response.
  * You can't enable both PASSWORD and PAM. */
 
-//#define ENABLE_SVR_PASSWORD_AUTH
+#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	Thu Nov 07 00:18:52 2013 +0800
+++ b/runopts.h	Thu Nov 07 23:49:37 2013 +0800
@@ -100,6 +100,8 @@
 
 	sign_key *hostkey;
 
+	int delay_hostkey;
+
 	char *hostkey_files[MAX_HOSTKEYS];
 	int num_hostkey_files;
 
--- a/signkey.c	Thu Nov 07 00:18:52 2013 +0800
+++ b/signkey.c	Thu Nov 07 23:49:37 2013 +0800
@@ -351,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);
 
--- a/svr-kex.c	Thu Nov 07 00:18:52 2013 +0800
+++ b/svr-kex.c	Thu Nov 07 23:49:37 2013 +0800
@@ -77,6 +77,7 @@
 	TRACE(("leave recv_msg_kexdh_init"))
 }
 
+#ifdef DROPBEAR_DELAY_HOSTKEY
 static void svr_ensure_hostkey() {
 
 	const char* fn = NULL;
@@ -141,7 +142,7 @@
 
 	if (ret == DROPBEAR_FAILURE)
 	{
-		dropbear_exit("Couldn't read or generate hostkey");
+		dropbear_exit("Couldn't read or generate hostkey %s", fn);
 	}
 
 	// directory for keys.
@@ -152,6 +153,7 @@
 	// 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
@@ -165,8 +167,13 @@
 
 	/* we can start creating the kexdh_reply packet */
 	CHECKCLEARTOWRITE();
-	
-	svr_ensure_hostkey();
+
+#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,
--- a/svr-runopts.c	Thu Nov 07 00:18:52 2013 +0800
+++ b/svr-runopts.c	Thu Nov 07 23:49:37 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) {
-		//disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521);
+	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	Thu Nov 07 00:18:52 2013 +0800
+++ b/sysoptions.h	Thu Nov 07 23:49:37 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