--HG--
branch : ecc
This commit is contained in:
Matt Johnston 2013-11-08 23:32:13 +08:00
commit 29b1455f36
15 changed files with 375 additions and 180 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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 */
}
check_signkey_bits(keytype, bits);;
}
} 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);
/* 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);
}

View File

@ -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) {

View File

@ -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

127
gensignkey.c Normal file
View File

@ -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;
}

8
gensignkey.h Normal file
View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -100,6 +100,8 @@ typedef struct svr_runopts {
sign_key *hostkey;
int delay_hostkey;
char *hostkey_files[MAX_HOSTKEYS];
int num_hostkey_files;

View File

@ -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,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);
@ -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);

View File

@ -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);

View File

@ -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) {
if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 521)
&& !svr_opts.hostkey->ecckey521) {
disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521);
}
#endif
#endif
#endif /* DROPBEAR_ECDSA */
}

View File

@ -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