From be46b9e5feb342d5a10ee0e7609d7d1efc7e10b9 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 7 Nov 2013 23:49:37 +0800 Subject: Add '-R' for delayed hostkey option --- cli-kex.c | 19 ++++++++++++------- dropbearkey.c | 3 +-- gensignkey.c | 1 - keyimport.c | 18 ++++++++++++++---- options.h | 19 +++++++++++++------ runopts.h | 2 ++ signkey.c | 6 ++++++ svr-kex.c | 13 ++++++++++--- svr-runopts.c | 54 ++++++++++++++++++++++++++++++++++++++++++------------ sysoptions.h | 7 ++++--- 10 files changed, 104 insertions(+), 38 deletions(-) diff --git a/cli-kex.c b/cli-kex.c index 0cc730c..2677b0e 100644 --- a/cli-kex.c +++ b/cli-kex.c @@ -147,7 +147,8 @@ void recv_msg_kexdh_reply() { 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 @@ static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen) { 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 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) { 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 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) { /* 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 */ diff --git a/dropbearkey.c b/dropbearkey.c index 9e696b7..01385a1 100644 --- a/dropbearkey.c +++ b/dropbearkey.c @@ -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 main(int argc, char ** argv) { 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; diff --git a/gensignkey.c b/gensignkey.c index 10890f4..5726249 100644 --- a/gensignkey.c +++ b/gensignkey.c @@ -72,7 +72,6 @@ static int get_default_bits(enum signkey_type keytype) } } - int signkey_generate(enum signkey_type keytype, int bits, const char* filename) { sign_key * key = NULL; diff --git a/keyimport.c b/keyimport.c index 7595c1d..7098ae7 100644 --- a/keyimport.c +++ b/keyimport.c @@ -709,19 +709,29 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase)) 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; } diff --git a/options.h b/options.h index c5bc7fe..d345601 100644 --- a/options.h +++ b/options.h @@ -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 @@ much traffic. */ /* 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 @@ much traffic. */ * SSH2 RFC Draft requires dss, recommends rsa */ #define DROPBEAR_RSA #define DROPBEAR_DSS - -#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 @@ much traffic. */ * 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 diff --git a/runopts.h b/runopts.h index 59e968a..21fc8e5 100644 --- a/runopts.h +++ b/runopts.h @@ -100,6 +100,8 @@ typedef struct svr_runopts { sign_key *hostkey; + int delay_hostkey; + char *hostkey_files[MAX_HOSTKEYS]; int num_hostkey_files; diff --git a/signkey.c b/signkey.c index edb9400..a7f45d4 100644 --- a/signkey.c +++ b/signkey.c @@ -351,18 +351,24 @@ void sign_key_free(sign_key *key) { 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); diff --git a/svr-kex.c b/svr-kex.c index 3d131a1..ca87875 100644 --- a/svr-kex.c +++ b/svr-kex.c @@ -77,6 +77,7 @@ void recv_msg_kexdh_init() { TRACE(("leave recv_msg_kexdh_init")) } +#ifdef DROPBEAR_DELAY_HOSTKEY static void svr_ensure_hostkey() { const char* fn = NULL; @@ -141,7 +142,7 @@ out: 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 @@ out: // 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 @@ static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) { /* 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, diff --git a/svr-runopts.c b/svr-runopts.c index 53dd9fd..fd05bbe 100644 --- a/svr-runopts.c +++ b/svr-runopts.c @@ -44,13 +44,19 @@ static void printhelp(const char * progname) { "-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 @@ -95,6 +101,9 @@ static void printhelp(const char * progname) { #endif #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 @@ void svr_getopts(int argc, char ** argv) { 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 @@ void svr_getopts(int argc, char ** argv) { case 'r': next = &keyfile; break; + case 'R': + svr_opts.delay_hostkey = 1; + break; case 'F': svr_opts.forkbg = 0; break; @@ -390,7 +403,7 @@ static void loadhostkey_helper(const char *name, void** src, void** dst, int fat /* 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 @@ static void addhostkey(const char *keyfile) { void load_all_hostkeys() { int i; + int disable_unset_keys = 1; svr_opts.hostkey = new_sign_key(); @@ -459,31 +473,47 @@ void load_all_hostkeys() { 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 */ + } diff --git a/sysoptions.h b/sysoptions.h index 8d57375..6637ad5 100644 --- a/sysoptions.h +++ b/sysoptions.h @@ -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 -- cgit v1.2.1