# HG changeset patch # User Matt Johnston # Date 1383924733 -28800 # Node ID 754d7bee10686c045417b9139377617bd14a668d # Parent 6c69e7df3621c36a7859cad568edf0faccace09c# Parent f4bb964c86783a701294f927a0b2235b778043df Merge diff -r 6c69e7df3621 -r 754d7bee1068 Makefile.in --- 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 diff -r 6c69e7df3621 -r 754d7bee1068 cli-kex.c --- 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 */ diff -r 6c69e7df3621 -r 754d7bee1068 debug.h --- 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 diff -r 6c69e7df3621 -r 754d7bee1068 dropbearkey.c --- 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); -} diff -r 6c69e7df3621 -r 754d7bee1068 ecdsa.c --- 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) { diff -r 6c69e7df3621 -r 754d7bee1068 ecdsa.h --- 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 diff -r 6c69e7df3621 -r 754d7bee1068 gensignkey.c --- /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; +} diff -r 6c69e7df3621 -r 754d7bee1068 gensignkey.h --- /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 diff -r 6c69e7df3621 -r 754d7bee1068 keyimport.c --- 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; diff -r 6c69e7df3621 -r 754d7bee1068 options.h --- 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 diff -r 6c69e7df3621 -r 754d7bee1068 runopts.h --- 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; diff -r 6c69e7df3621 -r 754d7bee1068 signkey.c --- 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); diff -r 6c69e7df3621 -r 754d7bee1068 svr-kex.c --- 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); diff -r 6c69e7df3621 -r 754d7bee1068 svr-runopts.c --- 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 */ + } diff -r 6c69e7df3621 -r 754d7bee1068 sysoptions.h --- 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