diff options
author | Matt Johnston <matt@ucc.asn.au> | 2013-05-03 23:07:48 +0800 |
---|---|---|
committer | Matt Johnston <matt@ucc.asn.au> | 2013-05-03 23:07:48 +0800 |
commit | 95a21c8fd796c570e8660db983b3032af96ec5cb (patch) | |
tree | 05347fa8c369407065cccb05806a06593f8a6bc4 | |
parent | 79660f2eb1c64bcac9ba0084f9d3822ee88dbd5c (diff) |
ecdsa is working
--HG--
branch : ecc
-rw-r--r-- | cli-main.c | 5 | ||||
-rw-r--r-- | cli-session.c | 4 | ||||
-rw-r--r-- | common-algo.c | 11 | ||||
-rw-r--r-- | dropbearkey.c | 9 | ||||
-rw-r--r-- | ecdsa.c | 20 | ||||
-rw-r--r-- | ecdsa.h | 2 | ||||
-rw-r--r-- | options.h | 5 | ||||
-rw-r--r-- | runopts.h | 7 | ||||
-rw-r--r-- | signkey.c | 51 | ||||
-rw-r--r-- | signkey.h | 20 | ||||
-rw-r--r-- | svr-main.c | 5 | ||||
-rw-r--r-- | svr-runopts.c | 154 | ||||
-rw-r--r-- | svr-session.c | 1 | ||||
-rw-r--r-- | sysoptions.h | 2 |
14 files changed, 203 insertions, 93 deletions
@@ -28,6 +28,8 @@ #include "dbutil.h" #include "runopts.h" #include "session.h" +#include "random.h" +#include "crypto_desc.h" static void cli_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN; static void cli_dropbear_log(int priority, const char* format, va_list param); @@ -51,6 +53,9 @@ int main(int argc, char ** argv) { disallow_core(); + seedrandom(); + crypto_init(); + cli_getopts(argc, argv); TRACE(("user='%s' host='%s' port='%s'", cli_opts.username, diff --git a/cli-session.c b/cli-session.c index 2905389..55040af 100644 --- a/cli-session.c +++ b/cli-session.c @@ -85,10 +85,6 @@ static const struct ChanType *cli_chantypes[] = { void cli_session(int sock_in, int sock_out) { - seedrandom(); - - crypto_init(); - common_session_init(sock_in, sock_out); chaninitialise(cli_chantypes); diff --git a/common-algo.c b/common-algo.c index 9915ce6..5d5de01 100644 --- a/common-algo.c +++ b/common-algo.c @@ -207,6 +207,17 @@ algo_type ssh_nocompress[] = { }; algo_type sshhostkey[] = { +#ifdef DROPBEAR_ECDSA +#ifdef DROPBEAR_ECC_256 + {"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL}, +#endif +#ifdef DROPBEAR_ECC_384 + {"ecdsa-sha2-nistp384", DROPBEAR_SIGNKEY_ECDSA_NISTP384, NULL, 1, NULL}, +#endif +#ifdef DROPBEAR_ECC_521 + {"ecdsa-sha2-nistp521", DROPBEAR_SIGNKEY_ECDSA_NISTP521, NULL, 1, NULL}, +#endif +#endif #ifdef DROPBEAR_RSA {"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL}, #endif diff --git a/dropbearkey.c b/dropbearkey.c index fb8461e..8bc114c 100644 --- a/dropbearkey.c +++ b/dropbearkey.c @@ -53,6 +53,7 @@ #include "gendss.h" #include "ecdsa.h" #include "crypto_desc.h" +#include "random.h" static void printhelp(char * progname); @@ -120,6 +121,9 @@ int main(int argc, char ** argv) { unsigned int bits; int printpub = 0; + crypto_init(); + seedrandom(); + /* get the commandline options */ for (i = 1; i < argc; i++) { if (argv[i] == NULL) { @@ -223,10 +227,6 @@ int main(int argc, char ** argv) { /* don't want the file readable by others */ umask(077); - crypto_init(); - seedrandom(); - - /* now we can generate the key */ key = new_sign_key(); @@ -245,6 +245,7 @@ int main(int argc, char ** argv) { #ifdef DROPBEAR_ECDSA case DROPBEAR_SIGNKEY_ECDSA_KEYGEN: key->ecckey = gen_ecdsa_priv_key(bits); + keytype = ecdsa_signkey_type(key->ecckey); break; #endif default: @@ -4,9 +4,29 @@ #include "crypto_desc.h" #include "ecc.h" #include "ecdsa.h" +#include "signkey.h" #ifdef DROPBEAR_ECDSA +enum signkey_type ecdsa_signkey_type(ecc_key * key) { +#ifdef DROPBEAR_ECC_256 + if (key->dp == ecc_curve_nistp256.dp) { + return DROPBEAR_SIGNKEY_ECDSA_NISTP256; + } +#endif +#ifdef DROPBEAR_ECC_384 + if (key->dp == ecc_curve_nistp384.dp) { + return DROPBEAR_SIGNKEY_ECDSA_NISTP384; + } +#endif +#ifdef DROPBEAR_ECC_521 + if (key->dp == ecc_curve_nistp521.dp) { + return DROPBEAR_SIGNKEY_ECDSA_NISTP521; + } +#endif + return DROPBEAR_SIGNKEY_NONE; +} + ecc_key *gen_ecdsa_priv_key(unsigned int bit_size) { const ltc_ecc_set_type *dp = NULL; // curve domain parameters switch (bit_size) { @@ -3,6 +3,7 @@ #include "includes.h" #include "buffer.h" +#include "signkey.h" #ifdef DROPBEAR_ECC_256 #define ECDSA_DEFAULT_SIZE 256 @@ -19,6 +20,7 @@ ecc_key *buf_get_ecdsa_pub_key(buffer* buf); ecc_key *buf_get_ecdsa_priv_key(buffer *buf); void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key); void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key); +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); @@ -8,7 +8,7 @@ /* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif" * parts are to allow for commandline -DDROPBEAR_XXX options etc. */ -// XXX XXX You should probably run "make clean" after changing most options */ +/* Important: Many options will require "make clean" after changes */ #ifndef DROPBEAR_DEFPORT #define DROPBEAR_DEFPORT "22" @@ -26,6 +26,9 @@ #ifndef RSA_PRIV_FILENAME #define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key" #endif +#ifndef ECDSA_PRIV_FILENAME +#define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key" +#endif /* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens * on chosen ports and keeps accepting connections. This is the default. @@ -57,11 +57,10 @@ typedef struct runopts { extern runopts opts; int readhostkey(const char * filename, sign_key * hostkey, int *type); +void load_all_hostkeys(); typedef struct svr_runopts { - char * rsakeyfile; - char * dsskeyfile; char * bannerfile; int forkbg; @@ -99,6 +98,10 @@ typedef struct svr_runopts { #endif sign_key *hostkey; + + char *hostkey_files[MAX_HOSTKEYS]; + int num_hostkey_files; + buffer * banner; char * pidfile; @@ -37,15 +37,9 @@ static const char *signkey_names[DROPBEAR_SIGNKEY_NUM_NAMED] = { "ssh-dss", #endif #ifdef DROPBEAR_ECDSA -#ifdef DROPBEAR_ECC_256 "ecdsa-sha2-nistp256", -#endif -#ifdef DROPBEAR_ECC_384 "ecdsa-sha2-nistp384", -#endif -#ifdef DROPBEAR_ECC_521 "ecdsa-sha2-nistp521", -#endif "ecdsa" // for keygen #endif // DROPBEAR_ECDSA }; @@ -81,6 +75,25 @@ enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen) const char *fixed_name = signkey_names[i]; if (namelen == strlen(fixed_name) && memcmp(fixed_name, name, namelen) == 0) { + +#ifdef DROPBEAR_ECDSA + /* Some of the ECDSA key sizes are defined even if they're not compiled in */ + if (0 +#ifndef DROPBEAR_ECC_256 + || i == DROPBEAR_SIGNKEY_ECDSA_NISTP256 +#endif +#ifndef DROPBEAR_ECC_384 + || i == DROPBEAR_SIGNKEY_ECDSA_NISTP384 +#endif +#ifndef DROPBEAR_ECC_521 + || i == DROPBEAR_SIGNKEY_ECDSA_NISTP521 +#endif + ) { + TRACE(("attempt to use ecdsa type %d not compiled in", i)) + return DROPBEAR_SIGNKEY_NONE; + } +#endif + return i; } } @@ -139,9 +152,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) { } #endif #ifdef DROPBEAR_ECDSA - if (keytype == DROPBEAR_SIGNKEY_ECDSA_NISTP256 - || keytype == DROPBEAR_SIGNKEY_ECDSA_NISTP384 - || keytype == DROPBEAR_SIGNKEY_ECDSA_NISTP521) { + if (IS_ECDSA_KEY(keytype)) { if (key->ecckey) { ecc_free(key->ecckey); } @@ -205,9 +216,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) { } #endif #ifdef DROPBEAR_ECDSA - if (keytype == DROPBEAR_SIGNKEY_ECDSA_NISTP256 - || keytype == DROPBEAR_SIGNKEY_ECDSA_NISTP384 - || keytype == DROPBEAR_SIGNKEY_ECDSA_NISTP521) { + if (IS_ECDSA_KEY(keytype)) { if (key->ecckey) { ecc_free(key->ecckey); } @@ -243,9 +252,7 @@ void buf_put_pub_key(buffer* buf, sign_key *key, int type) { } #endif #ifdef DROPBEAR_ECDSA - if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256 - || type == DROPBEAR_SIGNKEY_ECDSA_NISTP384 - || type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) { + if (IS_ECDSA_KEY(type)) { buf_put_ecdsa_pub_key(pubkeys, key->ecckey); } #endif @@ -279,10 +286,8 @@ void buf_put_priv_key(buffer* buf, sign_key *key, int type) { } #endif #ifdef DROPBEAR_ECDSA - if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256 - || type == DROPBEAR_SIGNKEY_ECDSA_NISTP384 - || type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) { - buf_put_ecdsa_pub_key(buf, key->ecckey); + if (IS_ECDSA_KEY(type)) { + buf_put_ecdsa_priv_key(buf, key->ecckey); return; } #endif @@ -424,9 +429,7 @@ void buf_put_sign(buffer* buf, sign_key *key, int type, } #endif #ifdef DROPBEAR_ECDSA - if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256 - || type == DROPBEAR_SIGNKEY_ECDSA_NISTP384 - || type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) { + if (IS_ECDSA_KEY(type)) { buf_put_ecdsa_sign(sigblob, key->ecckey, data_buf); } #endif @@ -474,9 +477,7 @@ int buf_verify(buffer * buf, sign_key *key, buffer *data_buf) { } #endif #ifdef DROPBEAR_ECDSA - if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256 - || type == DROPBEAR_SIGNKEY_ECDSA_NISTP384 - || type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) { + if (IS_ECDSA_KEY(type)) { return buf_ecdsa_verify(buf, key->ecckey, data_buf); } #endif @@ -37,15 +37,9 @@ enum signkey_type { DROPBEAR_SIGNKEY_DSS, #endif #ifdef DROPBEAR_ECDSA -#ifdef DROPBEAR_ECC_256 DROPBEAR_SIGNKEY_ECDSA_NISTP256, -#endif -#ifdef DROPBEAR_ECC_384 DROPBEAR_SIGNKEY_ECDSA_NISTP384, -#endif -#ifdef DROPBEAR_ECC_521 DROPBEAR_SIGNKEY_ECDSA_NISTP521, -#endif DROPBEAR_SIGNKEY_ECDSA_KEYGEN, // just "ecdsa" for keygen #endif // DROPBEAR_ECDSA DROPBEAR_SIGNKEY_NUM_NAMED, @@ -63,11 +57,9 @@ typedef enum { struct SIGN_key { - int type; /* The type of key (dss or rsa) */ + enum signkey_type type; signkey_source source; char *filename; - /* the buffer? for encrypted keys, so we can later get - * the private key portion */ #ifdef DROPBEAR_DSS dropbear_dss_key * dsskey; @@ -76,7 +68,7 @@ struct SIGN_key { dropbear_rsa_key * rsakey; #endif #ifdef DROPBEAR_ECDSA - ecc_key *ecckey; + ecc_key * ecckey; #endif }; @@ -99,4 +91,12 @@ int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen, const unsigned char* algoname, unsigned int algolen, buffer * line, char ** fingerprint); +#ifdef DROPBEAR_ECDSA +#define IS_ECDSA_KEY(type) \ + ((type) == DROPBEAR_SIGNKEY_ECDSA_NISTP256 \ + || (type) == DROPBEAR_SIGNKEY_ECDSA_NISTP384 \ + || (type) == DROPBEAR_SIGNKEY_ECDSA_NISTP521 \ + || (type) == DROPBEAR_SIGNKEY_ECDSA_KEYGEN) +#endif + #endif /* _SIGNKEY_H_ */ @@ -29,6 +29,7 @@ #include "signkey.h" #include "runopts.h" #include "random.h" +#include "crypto_desc.h" static size_t listensockets(int *sock, size_t sockcount, int *maxfd); static void sigchld_handler(int dummy); @@ -383,9 +384,11 @@ static void commonsetup() { dropbear_exit("signal() error"); } + crypto_init(); + /* Now we can setup the hostkeys - needs to be after logging is on, * otherwise we might end up blatting error messages to the socket */ - loadhostkeys(); + load_all_hostkeys(); seedrandom(); } diff --git a/svr-runopts.c b/svr-runopts.c index f6ce86c..a775ea3 100644 --- a/svr-runopts.c +++ b/svr-runopts.c @@ -28,11 +28,14 @@ #include "buffer.h" #include "dbutil.h" #include "algo.h" +#include "ecdsa.h" svr_runopts svr_opts; /* GLOBAL */ static void printhelp(const char * progname); static void addportandaddress(char* spec); +static void loadhostkey(const char *keyfile, int fatal_duplicate); +static void addhostkey(const char *keyfile); static void printhelp(const char * progname) { @@ -105,10 +108,10 @@ void svr_getopts(int argc, char ** argv) { char* recv_window_arg = NULL; char* keepalive_arg = NULL; char* idle_timeout_arg = NULL; + char* keyfile = NULL; + /* see printhelp() for options */ - svr_opts.rsakeyfile = NULL; - svr_opts.dsskeyfile = NULL; svr_opts.bannerfile = NULL; svr_opts.banner = NULL; svr_opts.forkbg = 1; @@ -160,6 +163,11 @@ void svr_getopts(int argc, char ** argv) { dropbear_exit("Invalid null argument"); } next = 0x00; + + if (keyfile) { + addhostkey(keyfile); + keyfile = NULL; + } continue; } @@ -168,16 +176,10 @@ void svr_getopts(int argc, char ** argv) { case 'b': next = &svr_opts.bannerfile; break; -#ifdef DROPBEAR_DSS case 'd': - next = &svr_opts.dsskeyfile; - break; -#endif -#ifdef DROPBEAR_RSA case 'r': - next = &svr_opts.rsakeyfile; + next = &keyfile; break; -#endif case 'F': svr_opts.forkbg = 0; break; @@ -267,13 +269,6 @@ void svr_getopts(int argc, char ** argv) { svr_opts.portcount = 1; } - if (svr_opts.dsskeyfile == NULL) { - svr_opts.dsskeyfile = DSS_PRIV_FILENAME; - } - if (svr_opts.rsakeyfile == NULL) { - svr_opts.rsakeyfile = RSA_PRIV_FILENAME; - } - if (svr_opts.bannerfile) { struct stat buf; if (stat(svr_opts.bannerfile, &buf) != 0) { @@ -292,7 +287,6 @@ void svr_getopts(int argc, char ** argv) { svr_opts.bannerfile); } buf_setpos(svr_opts.banner, 0); - } if (recv_window_arg) { @@ -370,55 +364,125 @@ static void addportandaddress(char* spec) { } } -static void disablekey(int type, const char* filename) { - +static void disablekey(int type) { int i; - for (i = 0; sshhostkey[i].name != NULL; i++) { if (sshhostkey[i].val == type) { - sshhostkey[i].usable = 0; + sshhostkey[i].usable = 1; break; } } - dropbear_log(LOG_WARNING, "Failed reading '%s', disabling %s", filename, - type == DROPBEAR_SIGNKEY_DSS ? "DSS" : "RSA"); } /* Must be called after syslog/etc is working */ -void loadhostkeys() { +static void loadhostkey(const char *keyfile, int fatal_duplicate) { + sign_key * read_key = new_sign_key(); + int type = DROPBEAR_SIGNKEY_ANY; + if (readhostkey(keyfile, read_key, &type) == DROPBEAR_FAILURE) { + dropbear_log(LOG_WARNING, "Failed loading %s", keyfile); + } - int ret; - int type; +#ifdef DROPBEAR_RSA + if (type == DROPBEAR_SIGNKEY_RSA) { + if (svr_opts.hostkey->rsakey) { + if (fatal_duplicate) { + dropbear_exit("Only one RSA key can be specified"); + } + } else { + svr_opts.hostkey->rsakey = read_key->rsakey; + read_key->rsakey = NULL; + } + } +#endif - TRACE(("enter loadhostkeys")) +#ifdef DROPBEAR_DSS + if (type == DROPBEAR_SIGNKEY_DSS) { + if (svr_opts.hostkey->dsskey) { + if (fatal_duplicate) { + dropbear_exit("Only one DSS key can be specified"); + } + } else { + svr_opts.hostkey->dsskey = read_key->dsskey; + read_key->dsskey = NULL; + } + } +#endif + +#ifdef DROPBEAR_ECDSA + if (IS_ECDSA_KEY(type)) { + if (svr_opts.hostkey->ecckey) { + if (fatal_duplicate) { + dropbear_exit("Only one ECDSA key can be specified"); + } + } else { + svr_opts.hostkey->ecckey = read_key->ecckey; + read_key->ecckey = NULL; + } + } +#endif + sign_key_free(read_key); + TRACE(("leave loadhostkey")) +} + +static void addhostkey(const char *keyfile) { + if (svr_opts.num_hostkey_files >= MAX_HOSTKEYS) { + dropbear_exit("Too many hostkeys"); + } + svr_opts.hostkey_files[svr_opts.num_hostkey_files] = m_strdup(keyfile); + svr_opts.num_hostkey_files++; +} + +void load_all_hostkeys() { + int i; svr_opts.hostkey = new_sign_key(); -#ifdef DROPBEAR_RSA - type = DROPBEAR_SIGNKEY_RSA; - ret = readhostkey(svr_opts.rsakeyfile, svr_opts.hostkey, &type); - if (ret == DROPBEAR_FAILURE) { - disablekey(DROPBEAR_SIGNKEY_RSA, svr_opts.rsakeyfile); + for (i = 0; i < svr_opts.num_hostkey_files; i++) { + char *hostkey_file = svr_opts.hostkey_files[i]; + loadhostkey(hostkey_file, 1); + m_free(hostkey_file); } + +#ifdef DROPBEAR_RSA + loadhostkey(RSA_PRIV_FILENAME, 0); #endif + #ifdef DROPBEAR_DSS - type = DROPBEAR_SIGNKEY_DSS; - ret = readhostkey(svr_opts.dsskeyfile, svr_opts.hostkey, &type); - if (ret == DROPBEAR_FAILURE) { - disablekey(DROPBEAR_SIGNKEY_DSS, svr_opts.dsskeyfile); - } + loadhostkey(DSS_PRIV_FILENAME, 0); #endif - if ( 1 -#ifdef DROPBEAR_DSS - && svr_opts.hostkey->dsskey == NULL +#ifdef DROPBEAR_ECDSA + loadhostkey(ECDSA_PRIV_FILENAME, 0); #endif + #ifdef DROPBEAR_RSA - && svr_opts.hostkey->rsakey == NULL + if (!svr_opts.hostkey->rsakey) { + disablekey(DROPBEAR_SIGNKEY_RSA); + } #endif - ) { - dropbear_exit("No hostkeys available"); +#ifdef DROPBEAR_DSS + if (!svr_opts.hostkey->dsskey) { + disablekey(DROPBEAR_SIGNKEY_RSA); } - - TRACE(("leave loadhostkeys")) +#endif +#ifdef DROPBEAR_ECDSA +#ifdef DROPBEAR_ECC_256 + if (!svr_opts.hostkey->ecckey + || ecdsa_signkey_type(svr_opts.hostkey->ecckey) != DROPBEAR_SIGNKEY_ECDSA_NISTP256) { + disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256); + } +#endif +#ifdef DROPBEAR_ECC_384 + if (!svr_opts.hostkey->ecckey + || ecdsa_signkey_type(svr_opts.hostkey->ecckey) != DROPBEAR_SIGNKEY_ECDSA_NISTP384) { + disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384); + } +#endif +#ifdef DROPBEAR_ECC_521 + if (!svr_opts.hostkey->ecckey + || ecdsa_signkey_type(svr_opts.hostkey->ecckey) != DROPBEAR_SIGNKEY_ECDSA_NISTP521) { + disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521); + } +#endif +#endif } diff --git a/svr-session.c b/svr-session.c index b3b8d5e..a207d78 100644 --- a/svr-session.c +++ b/svr-session.c @@ -77,7 +77,6 @@ void svr_session(int sock, int childpipe) { char *host, *port; size_t len; - crypto_init(); common_session_init(sock, sock); /* Initialise server specific parts of the session */ diff --git a/sysoptions.h b/sysoptions.h index 0619cf1..d2ef0ab 100644 --- a/sysoptions.h +++ b/sysoptions.h @@ -141,6 +141,8 @@ /* For a 4096 bit DSS key, empirically determined */ #define MAX_PRIVKEY_SIZE 1700 +#define MAX_HOSTKEYS 3 + /* The maximum size of the bignum portion of the kexhash buffer */ /* Sect. 8 of the transport rfc 4253, K_S + e + f + K */ #define KEXHASHBUF_MAX_INTS (1700 + 130 + 130 + 130) |