summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2013-11-08 23:32:13 +0800
committerMatt Johnston <matt@ucc.asn.au>2013-11-08 23:32:13 +0800
commit29b1455f362d3f40a7c328cbd202333a73149092 (patch)
treee88fd8f67951c1ffcf668ecc085bc6f843bf47fc
parent0162c116da2ce2d546cb6b6523b659d10f460d33 (diff)
parent58fe1c2d2a48cd51e1bafeee8e1e20f7201f31df (diff)
Merge
--HG-- branch : ecc
-rw-r--r--Makefile.in5
-rw-r--r--cli-kex.c19
-rw-r--r--debug.h1
-rw-r--r--dropbearkey.c172
-rw-r--r--ecdsa.c7
-rw-r--r--ecdsa.h2
-rw-r--r--gensignkey.c127
-rw-r--r--gensignkey.h8
-rw-r--r--keyimport.c26
-rw-r--r--options.h17
-rw-r--r--runopts.h2
-rw-r--r--signkey.c21
-rw-r--r--svr-kex.c89
-rw-r--r--svr-runopts.c52
-rw-r--r--sysoptions.h7
15 files changed, 375 insertions, 180 deletions
diff --git a/Makefile.in b/Makefile.in
index e3827cb..a644719 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -27,7 +27,8 @@ COMMONOBJS=dbutil.o buffer.o \
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 @@ CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
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 --git a/cli-kex.c b/cli-kex.c
index 7d94b0e..0ab4edc 100644
--- a/cli-kex.c
+++ b/cli-kex.c
@@ -184,7 +184,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;
@@ -192,14 +193,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);
@@ -294,16 +297,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) {
@@ -356,17 +360,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/debug.h b/debug.h
index a761c2e..022ad36 100644
--- a/debug.h
+++ b/debug.h
@@ -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 --git a/dropbearkey.c b/dropbearkey.c
index 57db3af..01385a1 100644
--- a/dropbearkey.c
+++ b/dropbearkey.c
@@ -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 @@ static void printhelp(char * progname) {
,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 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;
char * sizetext = NULL;
- unsigned int bits;
+ unsigned int bits = 0;
int printpub = 0;
crypto_init();
@@ -174,8 +194,8 @@ int main(int argc, char ** argv) {
}
if (printpub) {
- justprintpub(filename);
- /* Not reached */
+ int ret = printpubfile(filename);
+ exit(ret);
}
/* check/parse args */
@@ -216,106 +236,22 @@ int main(int argc, char ** argv) {
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 */
- }
- }
-
-
- 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);
+ check_signkey_bits(keytype, bits);;
+ }
- /* 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);
- }
+ if (signkey_generate(keytype, bits, filename) == DROPBEAR_FAILURE)
+ {
+ dropbear_exit("Failed to generate key.\n");
+ }
- 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 @@ out:
sign_key_free(key);
key = NULL;
}
- exit(err);
+ return err;
}
static void printpubkey(sign_key * key, int keytype) {
@@ -402,35 +338,3 @@ static void printpubkey(sign_key * key, int keytype) {
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 --git a/ecdsa.c b/ecdsa.c
index 66612e4..fc8ea1f 100644
--- a/ecdsa.c
+++ b/ecdsa.c
@@ -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 --git a/ecdsa.h b/ecdsa.h
index 316235f..c871e9f 100644
--- a/ecdsa.h
+++ b/ecdsa.h
@@ -26,6 +26,8 @@ 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);
+/* Returns 1 on success */
+int signkey_is_ecdsa(enum signkey_type type);
#endif
diff --git a/gensignkey.c b/gensignkey.c
new file mode 100644
index 0000000..5726249
--- /dev/null
+++ b/gensignkey.c
@@ -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 --git a/gensignkey.h b/gensignkey.h
new file mode 100644
index 0000000..b463a42
--- /dev/null
+++ b/gensignkey.h
@@ -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 --git a/keyimport.c b/keyimport.c
index 660739e..7098ae7 100644
--- a/keyimport.c
+++ b/keyimport.c
@@ -112,7 +112,7 @@ static sign_key *dropbear_read(const char* filename) {
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 @@ static int openssh_encrypted(const char *filename)
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 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
char *errmsg;
char *modptr = NULL;
int modlen = -9999;
- int type;
+ enum signkey_type type;
sign_key *retkey;
buffer * blobbuf = NULL;
@@ -709,19 +709,29 @@ static sign_key *openssh_read(const char *filename, char *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;
}
@@ -1019,7 +1029,7 @@ static int openssh_write(const char *filename, sign_key *key,
*/
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 --git a/options.h b/options.h
index 8a0bb8b..ccdd303 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,10 +138,14 @@ 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
+
#define DROPBEAR_CURVE25519
/* RSA can be vulnerable to timing attacks which use the time required for
@@ -149,6 +153,9 @@ much traffic. */
* 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 @@ much traffic. */
#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 0d08f10..a7f45d4 100644
--- a/signkey.c
+++ b/signkey.c
@@ -181,7 +181,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
}
#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 @@ int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) {
}
#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 @@ void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type) {
}
#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 @@ void buf_put_priv_key(buffer* buf, sign_key *key, enum signkey_type type) {
}
#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 @@ 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);
@@ -484,7 +487,7 @@ void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type type,
}
#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 @@ int buf_verify(buffer * buf, sign_key *key, buffer *data_buf) {
}
#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 --git a/svr-kex.c b/svr-kex.c
index 9ecbb41..4764e38 100644
--- a/svr-kex.c
+++ b/svr-kex.c
@@ -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 @@ void recv_msg_kexdh_init() {
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 @@ static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) {
/* 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 @@ static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) {
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 --git a/svr-runopts.c b/svr-runopts.c
index 2db88c2..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
@@ -96,6 +102,9 @@ static void printhelp(const char * progname) {
#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) {
+ 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