From 73e22c115c7aa5604c6a2135a5d2c1bc38161cb1 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 26 Mar 2013 01:35:22 +0800 Subject: refactor kexdh code a bit, start working on ecdh etc --HG-- branch : ecc --- common-algo.c | 1 + 1 file changed, 1 insertion(+) (limited to 'common-algo.c') diff --git a/common-algo.c b/common-algo.c index 4a14651..91d27b2 100644 --- a/common-algo.c +++ b/common-algo.c @@ -213,6 +213,7 @@ algo_type sshhostkey[] = { }; algo_type sshkex[] = { +// {"ecdh-sha2-secp256r1", DROPBEAR_KEX_ECDH_SECP256R1, NULL, 1, NULL}, {"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL}, {"diffie-hellman-group14-sha1", DROPBEAR_KEX_DH_GROUP14, NULL, 1, NULL}, {NULL, 0, NULL, 0, NULL} -- cgit v1.2.3 From 74cad1612f577fd067ca900ab06517c2a260bbe8 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 27 Mar 2013 00:38:03 +0800 Subject: more bits on ecc branch --HG-- branch : ecc --- Makefile.in | 2 +- algo.h | 20 ++++++- cli-kex.c | 2 +- common-algo.c | 32 +++++++++- common-kex.c | 97 ++++++++++++++++++++++++++----- ecc.c | 97 +++++++++++++++++++++++++++++++ ecc.h | 34 +++++++++++ kex.h | 5 ++ libtomcrypt/src/headers/tomcrypt_custom.h | 8 ++- session.h | 2 +- sysoptions.h | 7 +++ 11 files changed, 281 insertions(+), 25 deletions(-) create mode 100644 ecc.h (limited to 'common-algo.c') diff --git a/Makefile.in b/Makefile.in index 4eabd20..eef6fbe 100644 --- a/Makefile.in +++ b/Makefile.in @@ -26,7 +26,7 @@ COMMONOBJS=dbutil.o buffer.o \ dss.o bignum.o \ signkey.o rsa.o random.o \ queue.o \ - atomicio.o compat.o fake-rfc2553.o ltc_prng.o ecc.o + atomicio.o compat.o fake-rfc2553.o ltc_prng.o ecc.o SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \ diff --git a/algo.h b/algo.h index 89d05e3..aeb5641 100644 --- a/algo.h +++ b/algo.h @@ -79,6 +79,20 @@ struct dropbear_hash { unsigned char hashsize; }; +struct dropbear_kex { + // "normal" DH KEX + unsigned char *dh_p_bytes; + int dh_p_len; + + // elliptic curve DH KEX +#ifdef DROPBEAR_ECDH + const struct dropbear_ecc_curve *ecc_curve; +#endif + + // both + const struct ltc_hash_descriptor *hashdesc; +}; + void crypto_init(); int have_algo(char* algo, size_t algolen, algo_type algos[]); void buf_put_algolist(buffer * buf, algo_type localalgos[]); @@ -94,14 +108,16 @@ int check_user_algos(const char* user_algo_list, algo_type * algos, char * algolist_string(algo_type algos[]); #endif -enum { +enum kex_type { DROPBEAR_KEX_DH_GROUP1, DROPBEAR_KEX_DH_GROUP14, DROPBEAR_KEX_ECDH_SECP256R1, + DROPBEAR_KEX_ECDH_SECP384R1, + DROPBEAR_KEX_ECDH_SECP521R1, }; #ifdef DROPBEAR_ECDH -#define IS_NORMAL_DH(algo) ((algo) == DROPBEAR_KEX_DH_GROUP1 || (algo) == DROPBEAR_KEX_DH_GROUP14) +#define IS_NORMAL_DH(algo) ((algo)->dh_p_bytes != NULL) #else #define IS_NORMAL_DH(algo) 1 #endif diff --git a/cli-kex.c b/cli-kex.c index ddd2efc..8090756 100644 --- a/cli-kex.c +++ b/cli-kex.c @@ -49,7 +49,7 @@ void send_msg_kexdh_init() { buf_putmpint(ses.writepayload, &cli_ses.dh_param->pub); } else { #ifdef DROPBEAR_ECDH - cli_ses.ecdh_param = + cli_ses.ecdh_param = gen_kexecdh_param(); #endif } encrypt_packet(); diff --git a/common-algo.c b/common-algo.c index 91d27b2..87592e1 100644 --- a/common-algo.c +++ b/common-algo.c @@ -212,10 +212,36 @@ algo_type sshhostkey[] = { {NULL, 0, NULL, 0, NULL} }; +static struct dropbear_kex kex_dh_group1 {dh_p_1, DH_P_1_LEN, NULL, sha1_desc }; +static struct dropbear_kex kex_dh_group14 {dh_p_14, DH_P_14_LEN, NULL, sha1_desc }; + +#ifdef DROPBEAR_ECC_DH +#ifdef DROPBEAR_ECC_256 +static struct dropbear_kex kex_ecdh_secp256r1 {NULL, 0, &ecc_curve_secp256r1, sha256_desc }; +#endif +#ifdef DROPBEAR_ECC_384 +static struct dropbear_kex kex_ecdh_secp384r1 {NULL, 0, &ecc_curve_secp384r1, sha384_desc }; +#endif +#ifdef DROPBEAR_ECC_521 +static struct dropbear_kex kex_ecdh_secp521r1 {NULL, 0, &ecc_curve_secp521r1, sha512_desc }; +#endif +#endif // DROPBEAR_ECC_DH + + algo_type sshkex[] = { -// {"ecdh-sha2-secp256r1", DROPBEAR_KEX_ECDH_SECP256R1, NULL, 1, NULL}, - {"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL}, - {"diffie-hellman-group14-sha1", DROPBEAR_KEX_DH_GROUP14, NULL, 1, NULL}, +#ifdef DROPBEAR_ECC_DH +#ifdef DROPBEAR_ECC_256 + {"ecdh-sha2-secp256r1", 0, &kex_ecdh_descp256r1, 1, NULL}, +#endif +#ifdef DROPBEAR_ECC_384 + {"ecdh-sha2-secp384r1", 0, &kex_ecdh_descp384r1, 1, NULL}, +#endif +#ifdef DROPBEAR_ECC_521 + {"ecdh-sha2-secp521r1", 0, &kex_ecdh_descp521r1, 1, NULL}, +#endif +#endif + {"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL}, + {"diffie-hellman-group14-sha1", 0, &kex_dh_group14, 1, NULL}, {NULL, 0, NULL, 0, NULL} }; diff --git a/common-kex.c b/common-kex.c index c153c8f..5d46f79 100644 --- a/common-kex.c +++ b/common-kex.c @@ -36,8 +36,7 @@ #include "runopts.h" /* diffie-hellman-group1-sha1 value for p */ -#define DH_P_1_LEN 128 -static const unsigned char dh_p_1[DH_P_1_LEN] = { +const unsigned char dh_p_1[DH_P_1_LEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, @@ -51,8 +50,7 @@ static const unsigned char dh_p_1[DH_P_1_LEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; /* diffie-hellman-group14-sha1 value for p */ -#define DH_P_14_LEN 256 -static const unsigned char dh_p_14[DH_P_14_LEN] = { +const unsigned char dh_p_14[DH_P_14_LEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, @@ -536,14 +534,8 @@ void recv_msg_kexinit() { static void load_dh_p(mp_int * dh_p) { - switch (ses.newkeys->algo_kex) { - case DROPBEAR_KEX_DH_GROUP1: - bytes_to_mp(dh_p, dh_p_1, DH_P_1_LEN); - break; - case DROPBEAR_KEX_DH_GROUP14: - bytes_to_mp(dh_p, dh_p_14, DH_P_14_LEN); - break; - } + bytes_to_mp(dh_p, ses.newkeys->algo_kex->dh_p_bytes, + ses.newkeys->algo_kex->dh_p_len); } /* Initialises and generate one side of the diffie-hellman key exchange values. @@ -667,11 +659,84 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them, #ifdef DROPBEAR_ECDH struct kex_ecdh_param *gen_kexecdh_param() { struct kex_ecdh_param *param = m_malloc(sizeof(*param)); - if (ecc_make_key_ex(NULL, dropbear_ltc_prng, ¶m->key + if (ecc_make_key_ex(NULL, dropbear_ltc_prng, + ¶m->key, ses.newkeys->algo_kex->ecc_curve) != CRYPT_OK) { + dropbear_exit("ECC error") + } + return param; +} + +void free_kexecdh_param(struct kex_ecdh_param *param) { + ecc_free(¶m->key); + m_free(param); + } -void free_kexecdh_param(struct kex_ecdh_param *param); void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them, - sign_key *hostkey); + sign_key *hostkey) { + + hash_state hs; + // public keys from client and server + ecc_key *Q_C, *Q_S, *Q_them; + + // XXX load Q_them + + ses.dh_K = dropbear_ecc_shared_secret() + + /* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */ + if (mp_cmp(dh_pub_them, &dh_p) != MP_LT + || mp_cmp_d(dh_pub_them, 0) != MP_GT) { + dropbear_exit("Diffie-Hellman error"); + } + + /* K = e^y mod p = f^x mod p */ + ses.dh_K = (mp_int*)m_malloc(sizeof(mp_int)); + m_mp_init(ses.dh_K); + if (mp_exptmod(dh_pub_them, ¶m->priv, &dh_p, ses.dh_K) != MP_OKAY) { + dropbear_exit("Diffie-Hellman error"); + } + + /* clear no longer needed vars */ + mp_clear_multi(&dh_p, NULL); + + /* From here on, the code needs to work with the _same_ vars on each side, + * not vice-versaing for client/server */ + if (IS_DROPBEAR_CLIENT) { + dh_e = ¶m->pub; + dh_f = dh_pub_them; + } else { + dh_e = dh_pub_them; + dh_f = ¶m->pub; + } + + /* Create the remainder of the hash buffer, to generate the exchange hash */ + /* K_S, the host key */ + buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey); + /* e, exchange value sent by the client */ + buf_putmpint(ses.kexhashbuf, dh_e); + /* f, exchange value sent by the server */ + buf_putmpint(ses.kexhashbuf, dh_f); + /* K, the shared secret */ + buf_putmpint(ses.kexhashbuf, ses.dh_K); + + /* calculate the hash H to sign */ + sha1_init(&hs); + buf_setpos(ses.kexhashbuf, 0); + sha1_process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len), + ses.kexhashbuf->len); + sha1_done(&hs, ses.hash); + + buf_burn(ses.kexhashbuf); + buf_free(ses.kexhashbuf); + ses.kexhashbuf = NULL; + + /* first time around, we set the session_id to H */ + if (ses.session_id == NULL) { + /* create the session_id, this never needs freeing */ + ses.session_id = (unsigned char*)m_malloc(SHA1_HASH_SIZE); + memcpy(ses.session_id, ses.hash, SHA1_HASH_SIZE); + } + +} #endif /* read the other side's algo list. buf_match_algo is a callback to match @@ -707,7 +772,7 @@ static void read_kex_algos() { goto error; } TRACE(("kex algo %s", algo->name)) - ses.newkeys->algo_kex = algo->val; + ses.newkeys->algo_kex = algo->data; /* server_host_key_algorithms */ algo = ses.buf_match_algo(ses.payload, sshhostkey, &goodguess); diff --git a/ecc.c b/ecc.c index cf67ec0..873a92a 100644 --- a/ecc.c +++ b/ecc.c @@ -1,6 +1,37 @@ +#include "includes.h" +#include "options.h" +#include "ecc.h" + #ifdef DROPBEAR_ECC +#ifdef DROPBEAR_ECC_256 +const struct ecc_curve_secp256r1 { + .ltc_set = <c_ecc_sets[0], + .hash_desc = sha256_desc, + .name = "secp256r1" +}; +#endif + + +#ifdef DROPBEAR_ECC_384 +const struct ecc_curve_secp384r1 { + .ltc_set = <c_ecc_sets[1], + .hash_desc = sha384_desc, + .name = "secp384r1" +}; +#endif + +#ifdef DROPBEAR_ECC_256 +const struct ecc_curve_secp256r1 { + .ltc_set = <c_ecc_sets[0], + .hash_desc = sha256_desc, + .name = "secp256r1" +}; +#endif + + void buf_put_ecc_key_string(buffer *buf, ecc_key *key) { + // XXX point compression int len = key->dp->size*2 + 1; buf_putint(len); int err = ecc_ansi_x963_export(key, buf_getwriteptr(buf, len), &len); @@ -13,5 +44,71 @@ void buf_put_ecc_key_string(buffer *buf, ecc_key *key) { int buf_get_ecc_key_string(buffer *buf, ecc_key *key) { } +// a modified version of libtomcrypt's "ecc_shared_secret" to output +// a mp_int instead. +mp_int * dropbear_ecc_shared_secret(ecc_key *public_key, ecc_key *private_key) +{ + ecc_point *result = NULL + mp_int *prime = NULL, *shared_secret = NULL; + int ret = DROPBEAR_FAILURE; + + /* type valid? */ + if (private_key->type != PK_PRIVATE) { + goto done; + } + + if (private_key->dp != public_key->dp) { + goto done; + } + +#if 0 + // XXX - possibly not neccessary tests? + if (ltc_ecc_is_valid_idx(private_key->idx) == 0 || ltc_ecc_is_valid_idx(public_key->idx) == 0) { + goto done; + } + + if (XSTRCMP(private_key->dp->name, public_key->dp->name) != 0) { + goto done; + } +#endif + + /* make new point */ + result = ltc_ecc_new_point(); + if (result == NULL) { + goto done; + } + + prime = m_malloc(sizeof(*prime)); + m_mp_init(prime); + + if (mp_read_radix(prime, (char *)private_key->dp->prime, 16) != CRYPT_OK) { + goto done; + } + if (ltc_mp.ecc_ptmul(private_key->k, &public_key->pubkey, result, prime, 1) != CRYPT_OK) { + goto done; + } + + err = DROPBEAR_SUCCESS; +done: + if (err == DROPBEAR_SUCCESS) { + shared_secret = prime; + prime = NULL; + } + + if (prime) { + mp_clear(prime); + m_free(prime); + } + ltc_ecc_del_point(result); + + if (err == DROPBEAR_FAILURE) { + dropbear_exit("ECC error"); + } + + return shared_secret; + return err; +} + +} #endif diff --git a/ecc.h b/ecc.h new file mode 100644 index 0000000..426f698 --- /dev/null +++ b/ecc.h @@ -0,0 +1,34 @@ +#ifndef _DROPBEAR_ECC_H +#define _DROPBEAR_ECC_H + +#include "includes.h" +#include "options.h" + +#include "buffer.h" + +#ifdef DROPBEAR_ECC + +struct dropbear_ecc_curve { + const ltc_ecc_set_type* ltc_set; + const struct ltc_hash_descriptor *hash_desc; + const char *name; +}; + +extern const struct dropbear_ecc_curve ecc_curve_secp256r1; +extern const struct dropbear_ecc_curve ecc_curve_secp384r1; +extern const struct dropbear_ecc_curve ecc_curve_secp521r1; + +// "pubkey" refers to a point, but LTC uses ecc_key structure for both public +// and private keys +void buf_put_ecc_pubkey_string(buffer *buf, ecc_key *key); +int buf_get_ecc_pubkey_string(buffer *buf, ecc_key *key); +int buf_get_ecc_privkey_string(buffer *buf, ecc_key *key); + +mp_int * dropbear_ecc_shared_secret(ecc_key *pub_key, ecc_key *priv_key); + + +const ltc_ecc_set_type* get_ecc_curve(enum kex_type type); + +#endif + +#endif // _DROPBEAR_ECC_H \ No newline at end of file diff --git a/kex.h b/kex.h index f9d70b8..57019ff 100644 --- a/kex.h +++ b/kex.h @@ -73,6 +73,11 @@ struct KEXState { }; +#define DH_P_1_LEN 128 +extern const const unsigned char dh_p_1[DH_P_1_LEN]; +#define DH_P_14_LEN 256 +const unsigned char dh_p_14[DH_P_14_LEN] = { + struct kex_dh_param { mp_int pub; mp_int priv; diff --git a/libtomcrypt/src/headers/tomcrypt_custom.h b/libtomcrypt/src/headers/tomcrypt_custom.h index 1304ce7..344835f 100644 --- a/libtomcrypt/src/headers/tomcrypt_custom.h +++ b/libtomcrypt/src/headers/tomcrypt_custom.h @@ -134,12 +134,18 @@ #define LTC_HMAC -#ifdef DROPBEAR_ECDH +#ifdef DROPBEAR_ECC #define MECC +#ifdef DROPBEAR_ECC_256 #define ECC256 +#endif +#ifdef DROPBEAR_ECC_384 #define ECC384 +#endif +#ifdef DROPBEAR_ECC_521 #define ECC521 #endif +#endif /* Various tidbits of modern neatoness */ #define BASE64 diff --git a/session.h b/session.h index 145f695..6939536 100644 --- a/session.h +++ b/session.h @@ -86,7 +86,7 @@ struct key_context { struct key_context_directional recv; struct key_context_directional trans; - int algo_kex; + const struct dropbear_kex *algo_kex; int algo_hostkey; int allow_compress; /* whether compression has started (useful in diff --git a/sysoptions.h b/sysoptions.h index 20c2e57..8fa3ff0 100644 --- a/sysoptions.h +++ b/sysoptions.h @@ -93,6 +93,13 @@ #define DROPBEAR_ECC #endif + +#ifdef DROPBEAR_ECC +#define DROPBEAR_ECC_256 +#define DROPBEAR_ECC_384 +#define DROPBEAR_ECC_521 +#endif + // roughly 2x 521 bits #define MAX_ECC_SIZE 140 -- cgit v1.2.3 From b4bcc606576dab755441da1bc2fbe28041d54b06 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 29 Mar 2013 00:28:09 +0800 Subject: More changes for KEX and ECDH. Set up hash descriptors, make ECC code work, ses.hash and ses.session_id are now buffers (doesn't compile) --HG-- branch : ecc --- algo.h | 24 ++---- cli-kex.c | 7 +- common-algo.c | 18 +++-- common-kex.c | 61 +++++++-------- ecc.c | 119 ++++++++++++++++++++++-------- ecc.h | 5 +- kex.h | 5 +- libtomcrypt/src/headers/tomcrypt_custom.h | 4 +- ltc_prng.c | 1 + ltc_prng.h | 13 ++++ random.c | 2 + session.h | 6 +- svr-kex.c | 1 + sysoptions.h | 28 +++---- 14 files changed, 180 insertions(+), 114 deletions(-) create mode 100644 ltc_prng.h (limited to 'common-algo.c') diff --git a/algo.h b/algo.h index aeb5641..bda03dc 100644 --- a/algo.h +++ b/algo.h @@ -35,8 +35,8 @@ struct Algo_Type { - unsigned char *name; /* identifying name */ - char val; /* a value for this cipher, or -1 for invalid */ + const unsigned char *name; /* identifying name */ + const char val; /* a value for this cipher, or -1 for invalid */ const void *data; /* algorithm specific data */ char usable; /* whether we can use this algorithm */ const void *mode; /* the mode, currently only used for ciphers, @@ -59,8 +59,8 @@ extern const struct dropbear_hash dropbear_nohash; struct dropbear_cipher { const struct ltc_cipher_descriptor *cipherdesc; - unsigned long keysize; - unsigned char blocksize; + const unsigned long keysize; + const unsigned char blocksize; }; struct dropbear_cipher_mode { @@ -75,14 +75,14 @@ struct dropbear_cipher_mode { struct dropbear_hash { const struct ltc_hash_descriptor *hashdesc; - unsigned long keysize; - unsigned char hashsize; + const unsigned long keysize; + const unsigned char hashsize; }; struct dropbear_kex { // "normal" DH KEX - unsigned char *dh_p_bytes; - int dh_p_len; + const unsigned char *dh_p_bytes; + const int dh_p_len; // elliptic curve DH KEX #ifdef DROPBEAR_ECDH @@ -108,14 +108,6 @@ int check_user_algos(const char* user_algo_list, algo_type * algos, char * algolist_string(algo_type algos[]); #endif -enum kex_type { - DROPBEAR_KEX_DH_GROUP1, - DROPBEAR_KEX_DH_GROUP14, - DROPBEAR_KEX_ECDH_SECP256R1, - DROPBEAR_KEX_ECDH_SECP384R1, - DROPBEAR_KEX_ECDH_SECP521R1, -}; - #ifdef DROPBEAR_ECDH #define IS_NORMAL_DH(algo) ((algo)->dh_p_bytes != NULL) #else diff --git a/cli-kex.c b/cli-kex.c index 8090756..d6ebaf9 100644 --- a/cli-kex.c +++ b/cli-kex.c @@ -96,12 +96,15 @@ void recv_msg_kexdh_reply() { kexdh_comb_key(cli_ses.dh_param, &dh_f, hostkey); mp_clear(&dh_f); - free_kexdh_param(cli_ses.dh_param); - cli_ses.dh_param = NULL; } else { #ifdef DROPBEAR_ECDH + buffer *ecdh_qs = buf_getstringbuf(ses.payload); + kexecdh_comb_key(cli_ses.dh_param, ecdh_qs, hostkey); + buf_free(ecdh_qs); #endif } + free_kexdh_param(cli_ses.dh_param); + cli_ses.dh_param = NULL; if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE) != DROPBEAR_SUCCESS) { diff --git a/common-algo.c b/common-algo.c index 87592e1..7fb1503 100644 --- a/common-algo.c +++ b/common-algo.c @@ -25,6 +25,7 @@ #include "algo.h" #include "dbutil.h" +#include "kex.h" /* This file (algo.c) organises the ciphers which can be used, and is used to * decide which ciphers/hashes/compression/signing to use during key exchange*/ @@ -212,18 +213,18 @@ algo_type sshhostkey[] = { {NULL, 0, NULL, 0, NULL} }; -static struct dropbear_kex kex_dh_group1 {dh_p_1, DH_P_1_LEN, NULL, sha1_desc }; -static struct dropbear_kex kex_dh_group14 {dh_p_14, DH_P_14_LEN, NULL, sha1_desc }; +static struct dropbear_kex kex_dh_group1 = {dh_p_1, DH_P_1_LEN, NULL, &sha1_desc }; +static struct dropbear_kex kex_dh_group14 = {dh_p_14, DH_P_14_LEN, NULL, &sha1_desc }; #ifdef DROPBEAR_ECC_DH #ifdef DROPBEAR_ECC_256 -static struct dropbear_kex kex_ecdh_secp256r1 {NULL, 0, &ecc_curve_secp256r1, sha256_desc }; +static struct dropbear_kex kex_ecdh_secp256r1 = {NULL, 0, &ecc_curve_secp256r1, &sha256_desc }; #endif #ifdef DROPBEAR_ECC_384 -static struct dropbear_kex kex_ecdh_secp384r1 {NULL, 0, &ecc_curve_secp384r1, sha384_desc }; +static struct dropbear_kex kex_ecdh_secp384r1 = {NULL, 0, &ecc_curve_secp384r1, &sha384_desc }; #endif #ifdef DROPBEAR_ECC_521 -static struct dropbear_kex kex_ecdh_secp521r1 {NULL, 0, &ecc_curve_secp521r1, sha512_desc }; +static struct dropbear_kex kex_ecdh_secp521r1 = {NULL, 0, &ecc_curve_secp521r1, &sha512_desc }; #endif #endif // DROPBEAR_ECC_DH @@ -272,10 +273,13 @@ void crypto_init() { #ifdef DROPBEAR_MD5_HMAC &md5_desc, #endif -#ifdef DROPBEAR_SHA2_256_HMAC +#ifdef DROPBEAR_SHA256 &sha256_desc, #endif -#ifdef DROPBEAR_SHA2_512_HMAC +#ifdef DROPBEAR_SHA384 + &sha384_desc, +#endif +#ifdef DROPBEAR_SHA512 &sha512_desc, #endif NULL diff --git a/common-kex.c b/common-kex.c index aa4c3a4..e241101 100644 --- a/common-kex.c +++ b/common-kex.c @@ -34,6 +34,7 @@ #include "bignum.h" #include "random.h" #include "runopts.h" +#include "ecc.h" /* diffie-hellman-group1-sha1 value for p */ const unsigned char dh_p_1[DH_P_1_LEN] = { @@ -642,6 +643,9 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them, buf_setpos(ses.kexhashbuf, 0); sha1_process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len), ses.kexhashbuf->len); + + ses.hash = m_malloc(SHA1_HASH_SIZE); + } sha1_done(&hs, ses.hash); buf_burn(ses.kexhashbuf); @@ -660,8 +664,8 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them, struct kex_ecdh_param *gen_kexecdh_param() { struct kex_ecdh_param *param = m_malloc(sizeof(*param)); if (ecc_make_key_ex(NULL, dropbear_ltc_prng, - ¶m->key, ses.newkeys->algo_kex->ecc_curve) != CRYPT_OK) { - dropbear_exit("ECC error") + ¶m->key, ses.newkeys->algo_kex->ecc_curve->dp) != CRYPT_OK) { + dropbear_exit("ECC error"); } return param; } @@ -673,58 +677,45 @@ void free_kexecdh_param(struct kex_ecdh_param *param) { } void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them, sign_key *hostkey) { - + const struct dropbear_kex *algo_kex = ses.newkeys->algo_kex; hash_state hs; // public keys from client and server ecc_key *Q_C, *Q_S, *Q_them; -oj // XXX load Q_them - Q_them = buf_get_ecc_key_string() + // XXX load Q_them + Q_them = buf_get_ecc_pubkey(pub_them, algo_kex->ecc_curve); - ses.dh_K = dropbear_ecc_shared_secret(); - - /* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */ - if (mp_cmp(dh_pub_them, &dh_p) != MP_LT - || mp_cmp_d(dh_pub_them, 0) != MP_GT) { - dropbear_exit("Diffie-Hellman error"); - } - - /* K = e^y mod p = f^x mod p */ - ses.dh_K = (mp_int*)m_malloc(sizeof(mp_int)); - m_mp_init(ses.dh_K); - if (mp_exptmod(dh_pub_them, ¶m->priv, &dh_p, ses.dh_K) != MP_OKAY) { - dropbear_exit("Diffie-Hellman error"); - } - - /* clear no longer needed vars */ - mp_clear_multi(&dh_p, NULL); + ses.dh_K = dropbear_ecc_shared_secret(Q_them, param->key); /* From here on, the code needs to work with the _same_ vars on each side, * not vice-versaing for client/server */ if (IS_DROPBEAR_CLIENT) { - dh_e = ¶m->pub; - dh_f = dh_pub_them; + Q_C = param->key; + Q_S = Q_them; } else { - dh_e = dh_pub_them; - dh_f = ¶m->pub; + Q_C = Q_them; + Q_S = param->key; } /* Create the remainder of the hash buffer, to generate the exchange hash */ /* K_S, the host key */ buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey); - /* e, exchange value sent by the client */ - buf_putmpint(ses.kexhashbuf, dh_e); - /* f, exchange value sent by the server */ - buf_putmpint(ses.kexhashbuf, dh_f); + /* Q_C, client's ephemeral public key octet string */ + buf_put_ecc_pubkey_string(Q_C); + /* Q_S, server's ephemeral public key octet string */ + buf_put_ecc_pubkey_string(Q_S); /* K, the shared secret */ buf_putmpint(ses.kexhashbuf, ses.dh_K); /* calculate the hash H to sign */ - sha1_init(&hs); + algo_kex->hashdesc->init(&hs); buf_setpos(ses.kexhashbuf, 0); - sha1_process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len), + algo_kex->hashdesc->process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len), ses.kexhashbuf->len); - sha1_done(&hs, ses.hash); + if (!ses.hash) { + ses.hash = m_malloc(algo_kex->hashdesc->hashsize); + } + algo_kex->hashdesc->done(&hs, ses.hash); buf_burn(ses.kexhashbuf); buf_free(ses.kexhashbuf); @@ -733,8 +724,8 @@ oj // XXX load Q_them /* first time around, we set the session_id to H */ if (ses.session_id == NULL) { /* create the session_id, this never needs freeing */ - ses.session_id = (unsigned char*)m_malloc(SHA1_HASH_SIZE); - memcpy(ses.session_id, ses.hash, SHA1_HASH_SIZE); + ses.session_id = m_malloc(algo_kex->hashdesc->hashsize); + memcpy(ses.session_id, ses.hash, algo_kex->hashdesc->hashsize); } } diff --git a/ecc.c b/ecc.c index 0172516..8b3422c 100644 --- a/ecc.c +++ b/ecc.c @@ -1,41 +1,48 @@ #include "includes.h" #include "options.h" #include "ecc.h" +#include "dbutil.h" +#include "bignum.h" #ifdef DROPBEAR_ECC // TODO: use raw bytes for the dp rather than the hex strings in libtomcrypt's ecc.c #ifdef DROPBEAR_ECC_256 -const struct dropbear_ecc_curve ecc_curve_secp256r1 { +const struct dropbear_ecc_curve ecc_curve_secp256r1 = { .dp = <c_ecc_sets[0], - .hash_desc = sha256_desc, + .hash_desc = &sha256_desc, .name = "secp256r1" }; #endif - - #ifdef DROPBEAR_ECC_384 -const struct dropbear_ecc_curve ecc_curve_secp384r1 { +const struct dropbear_ecc_curve ecc_curve_secp384r1 = { .dp = <c_ecc_sets[1], - .hash_desc = sha384_desc, + .hash_desc = &sha384_desc, .name = "secp384r1" }; #endif - #ifdef DROPBEAR_ECC_521 -const struct dropbear_ecc_curve ecc_curve_secp521r1 { +const struct dropbear_ecc_curve ecc_curve_secp521r1 = { .dp = <c_ecc_sets[2], - .hash_desc = sha521_desc, + .hash_desc = &sha512_desc, .name = "secp521r1" }; #endif +static ecc_key * new_ecc_key(void) { + ecc_key *key = m_malloc(sizeof(*key)); + key->pubkey.x = m_malloc(sizeof(mp_int)); + key->pubkey.y = m_malloc(sizeof(mp_int)); + key->pubkey.z = m_malloc(sizeof(mp_int)); + key->k = m_malloc(sizeof(mp_init)); + m_mp_init_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL); + return key; +} void buf_put_ecc_pubkey_string(buffer *buf, ecc_key *key) { - // XXX point compression - int len = key->dp->size*2 + 1; - buf_putint(len); + unsigned long len = key->dp->size*2 + 1; + buf_putint(buf, len); int err = ecc_ansi_x963_export(key, buf_getwriteptr(buf, len), &len); if (err != CRYPT_OK) { dropbear_exit("ECC error"); @@ -43,38 +50,93 @@ void buf_put_ecc_pubkey_string(buffer *buf, ecc_key *key) { buf_incrwritepos(buf, len); } -ecc_key * buf_get_ecc_key_string(buffer *buf, const struct dropbear_ecc_curve *curve) { +// Copied from libtomcrypt ecc_import.c (version there is static), modified +// for different mp_int pointer without LTC_SOURCE +static int ecc_is_point(ecc_key *key) +{ + mp_int *prime, *b, *t1, *t2; + int err; + + prime = m_malloc(sizeof(mp_int)); + b = m_malloc(sizeof(mp_int)); + t1 = m_malloc(sizeof(mp_int)); + t2 = m_malloc(sizeof(mp_int)); + + m_mp_init_multi(prime, b, t1, t2, NULL); + + /* load prime and b */ + if ((err = mp_read_radix(prime, key->dp->prime, 16)) != CRYPT_OK) { goto error; } + if ((err = mp_read_radix(b, key->dp->B, 16)) != CRYPT_OK) { goto error; } + + /* compute y^2 */ + if ((err = mp_sqr(key->pubkey.y, t1)) != CRYPT_OK) { goto error; } + + /* compute x^3 */ + if ((err = mp_sqr(key->pubkey.x, t2)) != CRYPT_OK) { goto error; } + if ((err = mp_mod(t2, prime, t2)) != CRYPT_OK) { goto error; } + if ((err = mp_mul(key->pubkey.x, t2, t2)) != CRYPT_OK) { goto error; } + + /* compute y^2 - x^3 */ + if ((err = mp_sub(t1, t2, t1)) != CRYPT_OK) { goto error; } + + /* compute y^2 - x^3 + 3x */ + if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; } + if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; } + if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; } + if ((err = mp_mod(t1, prime, t1)) != CRYPT_OK) { goto error; } + while (mp_cmp_d(t1, 0) == LTC_MP_LT) { + if ((err = mp_add(t1, prime, t1)) != CRYPT_OK) { goto error; } + } + while (mp_cmp(t1, prime) != LTC_MP_LT) { + if ((err = mp_sub(t1, prime, t1)) != CRYPT_OK) { goto error; } + } + + /* compare to b */ + if (mp_cmp(t1, b) != LTC_MP_EQ) { + err = CRYPT_INVALID_PACKET; + } else { + err = CRYPT_OK; + } + +error: + mp_clear_multi(prime, b, t1, t2, NULL); + m_free(prime); + m_free(b); + m_free(t1); + m_free(t2); + return err; +} + +ecc_key * buf_get_ecc_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve) { ecc_key *key = NULL; int ret = DROPBEAR_FAILURE; const int size = curve->dp->size; - unsigned int len = buf_get_string(buf); - unsigned char first = buf_get_char(buf); + buf_setpos(buf, 0); + unsigned int len = buf->len; + unsigned char first = buf_getbyte(buf); if (first == 2 || first == 3) { - dropbear_log("Dropbear doesn't support ECC point compression"); + dropbear_log(LOG_WARNING, "Dropbear doesn't support ECC point compression"); return NULL; } if (first != 4 || len != 1+2*size) { return NULL; } - key = m_malloc(sizeof(*key)); - m_mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, NULL); + key = new_ecc_key(); - if (mp_read_unsigned_bin(&key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) { + if (mp_read_unsigned_bin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) { goto out; } buf_incrpos(buf, size); - if (mp_read_unsigned_bin(&key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) { + if (mp_read_unsigned_bin(key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) { goto out; } buf_incrpos(buf, size); - if (mp_set(key->pubkey.z, 1) != MP_OKAY) { - goto out; - } + mp_set(key->pubkey.z, 1); - if (is_point(key) != CRYPT_OK) { + if (ecc_is_point(key) != CRYPT_OK) { goto out; } @@ -91,7 +153,7 @@ ecc_key * buf_get_ecc_key_string(buffer *buf, const struct dropbear_ecc_curve *c out: if (ret == DROPBEAR_FAILURE) { if (key) { - mp_free_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, NULL); + ecc_free(key); m_free(key); key = NULL; } @@ -105,9 +167,9 @@ out: // a mp_int instead. mp_int * dropbear_ecc_shared_secret(ecc_key *public_key, ecc_key *private_key) { - ecc_point *result = NULL + ecc_point *result = NULL; mp_int *prime = NULL, *shared_secret = NULL; - int ret = DROPBEAR_FAILURE; + int err = DROPBEAR_FAILURE; /* type valid? */ if (private_key->type != PK_PRIVATE) { @@ -163,9 +225,6 @@ done: } return shared_secret; - return err; -} - } #endif diff --git a/ecc.h b/ecc.h index 019282d..d72fbb1 100644 --- a/ecc.h +++ b/ecc.h @@ -21,14 +21,11 @@ extern const struct dropbear_ecc_curve ecc_curve_secp521r1; // "pubkey" refers to a point, but LTC uses ecc_key structure for both public // and private keys void buf_put_ecc_pubkey_string(buffer *buf, ecc_key *key); -int buf_get_ecc_pubkey_string(buffer *buf, ecc_key *key); +ecc_key * buf_get_ecc_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve); int buf_get_ecc_privkey_string(buffer *buf, ecc_key *key); mp_int * dropbear_ecc_shared_secret(ecc_key *pub_key, ecc_key *priv_key); - -const ltc_ecc_set_type* get_ecc_curve(enum kex_type type); - #endif #endif // _DROPBEAR_ECC_H \ No newline at end of file diff --git a/kex.h b/kex.h index 57019ff..10b31c8 100644 --- a/kex.h +++ b/kex.h @@ -27,6 +27,7 @@ #include "includes.h" #include "algo.h" +#include "signkey.h" void send_msg_kexinit(); void recv_msg_kexinit(); @@ -74,9 +75,9 @@ struct KEXState { }; #define DH_P_1_LEN 128 -extern const const unsigned char dh_p_1[DH_P_1_LEN]; +extern const unsigned char dh_p_1[DH_P_1_LEN]; #define DH_P_14_LEN 256 -const unsigned char dh_p_14[DH_P_14_LEN] = { +extern const unsigned char dh_p_14[DH_P_14_LEN]; struct kex_dh_param { mp_int pub; diff --git a/libtomcrypt/src/headers/tomcrypt_custom.h b/libtomcrypt/src/headers/tomcrypt_custom.h index 344835f..d1d86c6 100644 --- a/libtomcrypt/src/headers/tomcrypt_custom.h +++ b/libtomcrypt/src/headers/tomcrypt_custom.h @@ -127,7 +127,9 @@ #ifdef DROPBEAR_SHA256 #define SHA256 #endif - +#ifdef DROPBEAR_SHA384 +#define SHA384 +#endif #ifdef DROPBEAR_SHA512 #define SHA512 #endif diff --git a/ltc_prng.c b/ltc_prng.c index cfd98fc..31a0658 100644 --- a/ltc_prng.c +++ b/ltc_prng.c @@ -14,6 +14,7 @@ #include "options.h" #include "includes.h" #include "random.h" +#include "ltc_prng.h" /** @file sprng.c diff --git a/ltc_prng.h b/ltc_prng.h new file mode 100644 index 0000000..d7ec904 --- /dev/null +++ b/ltc_prng.h @@ -0,0 +1,13 @@ +#ifndef _LTC_PRNG_H_DROPBEAR +#define _LTC_PRNG_H_DROPBEAR + +#include "options.h" +#include "includes.h" + +#ifdef DROPBEAR_LTC_PRNG + +extern const struct ltc_prng_descriptor dropbear_prng_desc; + +#endif // DROPBEAR_LTC_PRNG + +#endif // _LTC_PRNG_H_DROPBEAR \ No newline at end of file diff --git a/random.c b/random.c index 20095aa..8907644 100644 --- a/random.c +++ b/random.c @@ -27,6 +27,8 @@ #include "dbutil.h" #include "bignum.h" #include "random.h" +#include "ltc_prng.h" + /* this is used to generate unique output from the same hashpool */ static uint32_t counter = 0; diff --git a/session.h b/session.h index 6939536..91af1a3 100644 --- a/session.h +++ b/session.h @@ -154,10 +154,10 @@ struct sshsession { struct KEXState kexstate; struct key_context *keys; struct key_context *newkeys; - unsigned char *session_id; /* this is the hash from the first kex */ - /* The below are used temorarily during kex, are freed after use */ + buffer *session_id; /* this is the hash from the first kex */ + /* The below are used temporarily during kex, are freed after use */ mp_int * dh_K; /* SSH_MSG_KEXDH_REPLY and sending SSH_MSH_NEWKEYS */ - unsigned char hash[SHA1_HASH_SIZE]; /* the hash*/ + buffer *hash/* the session hash */ buffer* kexhashbuf; /* session hash buffer calculated from various packets*/ buffer* transkexinit; /* the kexinit packet we send should be kept so we can add it to the hash when generating keys */ diff --git a/svr-kex.c b/svr-kex.c index e30a2d4..d9106a9 100644 --- a/svr-kex.c +++ b/svr-kex.c @@ -59,6 +59,7 @@ void recv_msg_kexdh_init() { } } else { #ifdef DROPBEAR_ECDH + buffer *ecdh_qs = buf_getstringbuf(ses.payload); #endif } diff --git a/sysoptions.h b/sysoptions.h index 8fa3ff0..9b7c15a 100644 --- a/sysoptions.h +++ b/sysoptions.h @@ -93,13 +93,26 @@ #define DROPBEAR_ECC #endif - #ifdef DROPBEAR_ECC #define DROPBEAR_ECC_256 #define DROPBEAR_ECC_384 #define DROPBEAR_ECC_521 #endif +// 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) +#define DROPBEAR_SHA512 +#endif +#if defined(DROPBEAR_MD5_HMAC) +#define DROPBEAR_MD5 +#endif + // roughly 2x 521 bits #define MAX_ECC_SIZE 140 @@ -155,19 +168,6 @@ #define DROPBEAR_TWOFISH #endif -#ifdef DROPBEAR_MD5_HMAC -#define DROPBEAR_MD5 -#endif - -#ifdef DROPBEAR_SHA2_256_HMAC -#define DROPBEAR_SHA256 -#endif - -#if (defined(DROPBEAR_DSS) && defined(DSS_PROTOK)) \ - || defined(DROPBEAR_SHA2_512_HMAC) -#define DROPBEAR_SHA512 -#endif - #ifndef ENABLE_X11FWD #define DISABLE_X11FWD #endif -- cgit v1.2.3 From c6bdc810abab5b58aba26a7618c49f3dac58ebd6 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 7 Apr 2013 01:36:42 +0800 Subject: ecc kind of works, needs fixing/testing --HG-- branch : ecc --- Makefile.in | 8 +-- algo.h | 3 +- buffer.h | 2 +- cli-agentfwd.c | 2 +- cli-authpubkey.c | 2 +- cli-chansession.c | 2 +- cli-kex.c | 6 +- common-algo.c | 40 +++++++++---- common-kex.c | 66 ++++++++++------------ common-session.c | 13 ++++- debug.h | 4 +- ecc.c | 3 +- libtomcrypt/Makefile.in | 50 +++++++++++++++- libtomcrypt/src/headers/tomcrypt.h | 2 +- libtomcrypt/src/headers/tomcrypt_custom.h | 2 + libtomcrypt/src/headers/tomcrypt_math.h | 6 -- .../src/misc/crypt/crypt_ltc_mp_descriptor.c | 2 +- libtomcrypt/src/pk/ecc/ecc_decrypt_key.c | 2 +- libtomcrypt/src/pk/ecc/ecc_encrypt_key.c | 2 +- libtomcrypt/src/pk/ecc/ecc_export.c | 2 +- libtomcrypt/src/pk/ecc/ecc_import.c | 2 +- libtomcrypt/src/pk/ecc/ecc_sign_hash.c | 2 +- libtomcrypt/src/pk/ecc/ecc_verify_hash.c | 2 +- ltc_prng.c | 16 +++--- options.h | 8 +-- random.c | 10 ---- random.h | 2 - session.h | 2 +- svr-auth.c | 10 ++-- svr-authpubkey.c | 5 +- svr-kex.c | 8 +-- sysoptions.h | 8 +-- 32 files changed, 174 insertions(+), 120 deletions(-) (limited to 'common-algo.c') diff --git a/Makefile.in b/Makefile.in index eef6fbe..f456a72 100644 --- a/Makefile.in +++ b/Makefile.in @@ -17,9 +17,9 @@ LTC=libtomcrypt/libtomcrypt.a LTM=libtommath/libtommath.a ifeq (@BUNDLED_LIBTOM@, 1) -LIBTOM_DEPS=$(LTC) $(LTM) -CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/ -LIBS+=$(LTC) $(LTM) +LIBTOM_DEPS=$(LTM) $(LTC) +CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/ +LIBS+=$(LTM) $(LTC) endif COMMONOBJS=dbutil.o buffer.o \ @@ -185,7 +185,7 @@ link%: -ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT) $(LTC): options.h - cd libtomcrypt && $(MAKE) clean && $(MAKE) + cd libtomcrypt && $(MAKE) $(LTM): options.h cd libtommath && $(MAKE) diff --git a/algo.h b/algo.h index bda03dc..500c449 100644 --- a/algo.h +++ b/algo.h @@ -36,7 +36,7 @@ struct Algo_Type { const unsigned char *name; /* identifying name */ - const char val; /* a value for this cipher, or -1 for invalid */ + char val; /* a value for this cipher, or -1 for invalid */ const void *data; /* algorithm specific data */ char usable; /* whether we can use this algorithm */ const void *mode; /* the mode, currently only used for ciphers, @@ -120,5 +120,6 @@ enum { DROPBEAR_COMP_ZLIB_DELAY, }; +extern int dropbear_ltc_prng; #endif /* _ALGO_H_ */ diff --git a/buffer.h b/buffer.h index b18ccaa..1d83f8e 100644 --- a/buffer.h +++ b/buffer.h @@ -59,7 +59,7 @@ buffer * buf_getstringbuf(buffer *buf); void buf_eatstring(buffer *buf); void buf_putint(buffer* buf, unsigned int val); void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len); -void buf_putstringbuf(buffer *buf, const buffer* buf_str); +void buf_putbufstring(buffer *buf, const buffer* buf_str); void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len); void buf_putmpint(buffer* buf, mp_int * mp); int buf_getmpint(buffer* buf, mp_int* mp); diff --git a/cli-agentfwd.c b/cli-agentfwd.c index b7b8da3..ba07f54 100644 --- a/cli-agentfwd.c +++ b/cli-agentfwd.c @@ -266,7 +266,7 @@ void agent_buf_sign(buffer *sigblob, sign_key *key, string data uint32 flags */ - request_data = buf_new(MAX_PUBKEY_SIZE + data_buf>-len + 12); + request_data = buf_new(MAX_PUBKEY_SIZE + data_buf->len + 12); buf_put_pub_key(request_data, key, key->type); buf_putbufstring(request_data, data_buf); diff --git a/cli-authpubkey.c b/cli-authpubkey.c index adcf2a8..96eee05 100644 --- a/cli-authpubkey.c +++ b/cli-authpubkey.c @@ -172,7 +172,7 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) { sigbuf = buf_new(4 + SHA1_HASH_SIZE + ses.writepayload->len); buf_putbufstring(sigbuf, ses.session_id); buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len); - cli_buf_put_sign(ses.writepayload, key, type, sigbuf->data, sigbuf->len); + cli_buf_put_sign(ses.writepayload, key, type, sigbuf); buf_free(sigbuf); /* Nothing confidential in the buffer */ } diff --git a/cli-chansession.c b/cli-chansession.c index 65d1f4f..d3b14bb 100644 --- a/cli-chansession.c +++ b/cli-chansession.c @@ -455,7 +455,7 @@ do_escape(unsigned char c) { } static -void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len) { +void cli_escape_handler(struct Channel* UNUSED(channel), unsigned char* buf, int *len) { char c; int skip_char = 0; diff --git a/cli-kex.c b/cli-kex.c index d6ebaf9..23b7308 100644 --- a/cli-kex.c +++ b/cli-kex.c @@ -36,6 +36,7 @@ #include "random.h" #include "runopts.h" #include "signkey.h" +#include "ecc.h" static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen); @@ -50,6 +51,7 @@ void send_msg_kexdh_init() { } else { #ifdef DROPBEAR_ECDH cli_ses.ecdh_param = gen_kexecdh_param(); + buf_put_ecc_pubkey_string(ses.writepayload, &cli_ses.ecdh_param->key); #endif } encrypt_packet(); @@ -99,14 +101,14 @@ void recv_msg_kexdh_reply() { } else { #ifdef DROPBEAR_ECDH buffer *ecdh_qs = buf_getstringbuf(ses.payload); - kexecdh_comb_key(cli_ses.dh_param, ecdh_qs, hostkey); + kexecdh_comb_key(cli_ses.ecdh_param, ecdh_qs, hostkey); buf_free(ecdh_qs); #endif } free_kexdh_param(cli_ses.dh_param); cli_ses.dh_param = NULL; - if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE) + if (buf_verify(ses.payload, hostkey, ses.hash) != DROPBEAR_SUCCESS) { dropbear_exit("Bad hostkey signature"); } diff --git a/common-algo.c b/common-algo.c index 7fb1503..04bbd51 100644 --- a/common-algo.c +++ b/common-algo.c @@ -23,24 +23,33 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include "includes.h" #include "algo.h" #include "dbutil.h" #include "kex.h" +#include "ltc_prng.h" +#include "ecc.h" /* This file (algo.c) organises the ciphers which can be used, and is used to * decide which ciphers/hashes/compression/signing to use during key exchange*/ +#ifdef DROPBEAR_LTC_PRNG + int dropbear_ltc_prng = -1; +#endif + + + static int void_cipher(const unsigned char* in, unsigned char* out, - unsigned long len, void *cipher_state) { + unsigned long len, void* UNUSED(cipher_state)) { if (in != out) { memmove(out, in, len); } return CRYPT_OK; } -static int void_start(int cipher, const unsigned char *IV, - const unsigned char *key, - int keylen, int num_rounds, void *cipher_state) { +static int void_start(int UNUSED(cipher), const unsigned char* UNUSED(IV), + const unsigned char* UNUSED(key), + int UNUSED(keylen), int UNUSED(num_rounds), void* UNUSED(cipher_state)) { return CRYPT_OK; } @@ -216,7 +225,7 @@ algo_type sshhostkey[] = { static struct dropbear_kex kex_dh_group1 = {dh_p_1, DH_P_1_LEN, NULL, &sha1_desc }; static struct dropbear_kex kex_dh_group14 = {dh_p_14, DH_P_14_LEN, NULL, &sha1_desc }; -#ifdef DROPBEAR_ECC_DH +#ifdef DROPBEAR_ECDH #ifdef DROPBEAR_ECC_256 static struct dropbear_kex kex_ecdh_secp256r1 = {NULL, 0, &ecc_curve_secp256r1, &sha256_desc }; #endif @@ -226,19 +235,19 @@ static struct dropbear_kex kex_ecdh_secp384r1 = {NULL, 0, &ecc_curve_secp384r1, #ifdef DROPBEAR_ECC_521 static struct dropbear_kex kex_ecdh_secp521r1 = {NULL, 0, &ecc_curve_secp521r1, &sha512_desc }; #endif -#endif // DROPBEAR_ECC_DH +#endif // DROPBEAR_ECDH algo_type sshkex[] = { -#ifdef DROPBEAR_ECC_DH +#ifdef DROPBEAR_ECDH #ifdef DROPBEAR_ECC_256 - {"ecdh-sha2-secp256r1", 0, &kex_ecdh_descp256r1, 1, NULL}, + {"ecdh-sha2-secp256r1", 0, &kex_ecdh_secp256r1, 1, NULL}, #endif #ifdef DROPBEAR_ECC_384 - {"ecdh-sha2-secp384r1", 0, &kex_ecdh_descp384r1, 1, NULL}, + {"ecdh-sha2-secp384r1", 0, &kex_ecdh_secp384r1, 1, NULL}, #endif #ifdef DROPBEAR_ECC_521 - {"ecdh-sha2-secp521r1", 0, &kex_ecdh_descp521r1, 1, NULL}, + {"ecdh-sha2-secp521r1", 0, &kex_ecdh_secp521r1, 1, NULL}, #endif #endif {"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL}, @@ -297,6 +306,17 @@ void crypto_init() { dropbear_exit("Error registering crypto"); } } + +#ifdef DROPBEAR_LTC_PRNG + dropbear_ltc_prng = register_prng(&dropbear_prng_desc); + if (dropbear_ltc_prng == -1) { + dropbear_exit("Error registering crypto"); + } +#endif + +#ifdef DROPBEAR_ECC + ltc_mp = ltm_desc; +#endif } /* algolen specifies the length of algo, algos is our local list to match diff --git a/common-kex.c b/common-kex.c index e241101..48569fe 100644 --- a/common-kex.c +++ b/common-kex.c @@ -87,6 +87,7 @@ static void read_kex_algos(); /* helper function for gen_new_keys */ static void hashkeys(unsigned char *out, int outlen, const hash_state * hs, unsigned const char X); +static void finish_kexhashbuf(void); /* Send our list of algorithms we can use */ @@ -258,7 +259,7 @@ static void hashkeys(unsigned char *out, int outlen, memcpy(&hs2, hs, sizeof(hash_state)); sha1_process(&hs2, &X, 1); - sha1_process(&hs2, ses.session_id, SHA1_HASH_SIZE); + sha1_process(&hs2, ses.session_id->data, ses.session_id->len); sha1_done(&hs2, out); for (offset = SHA1_HASH_SIZE; offset < outlen; @@ -301,8 +302,10 @@ void gen_new_keys() { sha1_process_mp(&hs, ses.dh_K); mp_clear(ses.dh_K); m_free(ses.dh_K); - sha1_process(&hs, ses.hash, SHA1_HASH_SIZE); - m_burn(ses.hash, SHA1_HASH_SIZE); + sha1_process(&hs, ses.hash->data, ses.hash->len); + buf_burn(ses.hash); + buf_free(ses.hash); + ses.hash = NULL; if (IS_DROPBEAR_CLIENT) { trans_IV = C2S_IV; @@ -596,8 +599,6 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them, mp_int dh_p; mp_int *dh_e = NULL, *dh_f = NULL; - hash_state hs; - /* read the prime and generator*/ m_mp_init(&dh_p); load_dh_p(&dh_p); @@ -639,25 +640,7 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them, buf_putmpint(ses.kexhashbuf, ses.dh_K); /* calculate the hash H to sign */ - sha1_init(&hs); - buf_setpos(ses.kexhashbuf, 0); - sha1_process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len), - ses.kexhashbuf->len); - - ses.hash = m_malloc(SHA1_HASH_SIZE); - } - sha1_done(&hs, ses.hash); - - buf_burn(ses.kexhashbuf); - buf_free(ses.kexhashbuf); - ses.kexhashbuf = NULL; - - /* first time around, we set the session_id to H */ - if (ses.session_id == NULL) { - /* create the session_id, this never needs freeing */ - ses.session_id = (unsigned char*)m_malloc(SHA1_HASH_SIZE); - memcpy(ses.session_id, ses.hash, SHA1_HASH_SIZE); - } + finish_kexhashbuf(); } #ifdef DROPBEAR_ECDH @@ -685,25 +668,25 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them, // XXX load Q_them Q_them = buf_get_ecc_pubkey(pub_them, algo_kex->ecc_curve); - ses.dh_K = dropbear_ecc_shared_secret(Q_them, param->key); + ses.dh_K = dropbear_ecc_shared_secret(Q_them, ¶m->key); /* From here on, the code needs to work with the _same_ vars on each side, * not vice-versaing for client/server */ if (IS_DROPBEAR_CLIENT) { - Q_C = param->key; + Q_C = ¶m->key; Q_S = Q_them; } else { Q_C = Q_them; - Q_S = param->key; + Q_S = ¶m->key; } /* Create the remainder of the hash buffer, to generate the exchange hash */ /* K_S, the host key */ buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey); /* Q_C, client's ephemeral public key octet string */ - buf_put_ecc_pubkey_string(Q_C); + buf_put_ecc_pubkey_string(ses.kexhashbuf, Q_C); /* Q_S, server's ephemeral public key octet string */ - buf_put_ecc_pubkey_string(Q_S); + buf_put_ecc_pubkey_string(ses.kexhashbuf, Q_S); /* K, the shared secret */ buf_putmpint(ses.kexhashbuf, ses.dh_K); @@ -712,10 +695,23 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them, buf_setpos(ses.kexhashbuf, 0); algo_kex->hashdesc->process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len), ses.kexhashbuf->len); - if (!ses.hash) { - ses.hash = m_malloc(algo_kex->hashdesc->hashsize); - } - algo_kex->hashdesc->done(&hs, ses.hash); + + /* calculate the hash H to sign */ + finish_kexhashbuf(); +} +#endif + +static void finish_kexhashbuf(void) { + hash_state hs; + const struct ltc_hash_descriptor *hashdesc = ses.newkeys->algo_kex->hashdesc; + + hashdesc->init(&hs); + buf_setpos(ses.kexhashbuf, 0); + hashdesc->process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len), + ses.kexhashbuf->len); + ses.hash = buf_new(hashdesc->hashsize); + hashdesc->done(&hs, buf_getwriteptr(ses.hash, hashdesc->hashsize)); + buf_setlen(ses.hash, hashdesc->hashsize); buf_burn(ses.kexhashbuf); buf_free(ses.kexhashbuf); @@ -724,12 +720,10 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them, /* first time around, we set the session_id to H */ if (ses.session_id == NULL) { /* create the session_id, this never needs freeing */ - ses.session_id = m_malloc(algo_kex->hashdesc->hashsize); - memcpy(ses.session_id, ses.hash, algo_kex->hashdesc->hashsize); + ses.session_id = buf_newcopy(ses.hash); } } -#endif /* read the other side's algo list. buf_match_algo is a callback to match * algos for the client or server. */ diff --git a/common-session.c b/common-session.c index f4fa579..ef8e6fa 100644 --- a/common-session.c +++ b/common-session.c @@ -103,7 +103,7 @@ void common_session_init(int sock_in, int sock_out) { ses.keys->recv.algo_mac = &dropbear_nohash; ses.keys->trans.algo_mac = &dropbear_nohash; - ses.keys->algo_kex = -1; + ses.keys->algo_kex = NULL; ses.keys->algo_hostkey = -1; ses.keys->recv.algo_comp = DROPBEAR_COMP_NONE; ses.keys->trans.algo_comp = DROPBEAR_COMP_NONE; @@ -235,7 +235,16 @@ void common_session_cleanup() { return; } - m_free(ses.session_id); + if (ses.session_id) { + buf_burn(ses.session_id); + buf_free(ses.session_id); + ses.session_id = NULL; + } + if (ses.hash) { + buf_burn(ses.hash); + buf_free(ses.hash); + ses.hash = NULL; + } m_burn(ses.keys, sizeof(struct key_context)); m_free(ses.keys); diff --git a/debug.h b/debug.h index b20e685..02c100f 100644 --- a/debug.h +++ b/debug.h @@ -39,7 +39,7 @@ * Caution: Don't use this in an unfriendly environment (ie unfirewalled), * since the printing may not sanitise strings etc. This will add a reasonable * amount to your executable size. */ -/*#define DEBUG_TRACE */ +#define DEBUG_TRACE /* All functions writing to the cleartext payload buffer call * CHECKCLEARTOWRITE() before writing. This is only really useful if you're @@ -69,7 +69,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 /* For testing as non-root on shadowed systems, include the crypt of a password diff --git a/ecc.c b/ecc.c index 8b3422c..0f988ac 100644 --- a/ecc.c +++ b/ecc.c @@ -110,7 +110,7 @@ error: ecc_key * buf_get_ecc_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve) { ecc_key *key = NULL; int ret = DROPBEAR_FAILURE; - const int size = curve->dp->size; + const unsigned int size = curve->dp->size; buf_setpos(buf, 0); unsigned int len = buf->len; unsigned char first = buf_getbyte(buf); @@ -123,6 +123,7 @@ ecc_key * buf_get_ecc_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve } key = new_ecc_key(); + key->dp = curve->dp; if (mp_read_unsigned_bin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) { goto out; diff --git a/libtomcrypt/Makefile.in b/libtomcrypt/Makefile.in index 14bce99..3056ef0 100644 --- a/libtomcrypt/Makefile.in +++ b/libtomcrypt/Makefile.in @@ -19,7 +19,7 @@ srcdir=@srcdir@ # Compilation flags. Note the += does not write over the user's CFLAGS! # The rest of the flags come from the parent Dropbear makefile -CFLAGS += -c -I$(srcdir)/src/headers/ -I$(srcdir)/../ -DLTC_SOURCE +CFLAGS += -c -I$(srcdir)/src/headers/ -I$(srcdir)/../ -DLTC_SOURCE -I$(srcdir)/../libtommath/ # additional warnings (newer GCC 3.4 and higher) ifdef GCC_34 @@ -157,7 +157,53 @@ src/modes/lrw/lrw_decrypt.o src/modes/lrw/lrw_done.o src/modes/lrw/lrw_encrypt.o src/modes/lrw/lrw_getiv.o src/modes/lrw/lrw_process.o src/modes/lrw/lrw_setiv.o \ src/modes/lrw/lrw_start.o src/modes/lrw/lrw_test.o src/modes/ofb/ofb_decrypt.o src/modes/ofb/ofb_done.o \ src/modes/ofb/ofb_encrypt.o src/modes/ofb/ofb_getiv.o src/modes/ofb/ofb_setiv.o \ -src/modes/ofb/ofb_start.o +src/modes/ofb/ofb_start.o src/pk/asn1/der/bit/der_decode_bit_string.o \ +src/pk/asn1/der/bit/der_encode_bit_string.o src/pk/asn1/der/bit/der_length_bit_string.o \ +src/pk/asn1/der/boolean/der_decode_boolean.o src/pk/asn1/der/boolean/der_encode_boolean.o \ +src/pk/asn1/der/boolean/der_length_boolean.o src/pk/asn1/der/choice/der_decode_choice.o \ +src/pk/asn1/der/ia5/der_decode_ia5_string.o src/pk/asn1/der/ia5/der_encode_ia5_string.o \ +src/pk/asn1/der/ia5/der_length_ia5_string.o src/pk/asn1/der/integer/der_decode_integer.o \ +src/pk/asn1/der/integer/der_encode_integer.o src/pk/asn1/der/integer/der_length_integer.o \ +src/pk/asn1/der/object_identifier/der_decode_object_identifier.o \ +src/pk/asn1/der/object_identifier/der_encode_object_identifier.o \ +src/pk/asn1/der/object_identifier/der_length_object_identifier.o \ +src/pk/asn1/der/octet/der_decode_octet_string.o src/pk/asn1/der/octet/der_encode_octet_string.o \ +src/pk/asn1/der/octet/der_length_octet_string.o \ +src/pk/asn1/der/printable_string/der_decode_printable_string.o \ +src/pk/asn1/der/printable_string/der_encode_printable_string.o \ +src/pk/asn1/der/printable_string/der_length_printable_string.o \ +src/pk/asn1/der/sequence/der_decode_sequence_ex.o \ +src/pk/asn1/der/sequence/der_decode_sequence_flexi.o \ +src/pk/asn1/der/sequence/der_decode_sequence_multi.o \ +src/pk/asn1/der/sequence/der_encode_sequence_ex.o \ +src/pk/asn1/der/sequence/der_encode_sequence_multi.o src/pk/asn1/der/sequence/der_length_sequence.o \ +src/pk/asn1/der/sequence/der_sequence_free.o src/pk/asn1/der/set/der_encode_set.o \ +src/pk/asn1/der/set/der_encode_setof.o src/pk/asn1/der/short_integer/der_decode_short_integer.o \ +src/pk/asn1/der/short_integer/der_encode_short_integer.o \ +src/pk/asn1/der/short_integer/der_length_short_integer.o src/pk/asn1/der/utctime/der_decode_utctime.o \ +src/pk/asn1/der/utctime/der_encode_utctime.o src/pk/asn1/der/utctime/der_length_utctime.o \ +src/pk/asn1/der/utf8/der_decode_utf8_string.o src/pk/asn1/der/utf8/der_encode_utf8_string.o \ +src/pk/asn1/der/utf8/der_length_utf8_string.o src/pk/dsa/dsa_decrypt_key.o \ +src/pk/dsa/dsa_encrypt_key.o src/pk/dsa/dsa_export.o src/pk/dsa/dsa_free.o src/pk/dsa/dsa_import.o \ +src/pk/dsa/dsa_make_key.o src/pk/dsa/dsa_shared_secret.o src/pk/dsa/dsa_sign_hash.o \ +src/pk/dsa/dsa_verify_hash.o src/pk/dsa/dsa_verify_key.o src/pk/ecc/ecc.o \ +src/pk/ecc/ecc_ansi_x963_export.o src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o \ +src/pk/ecc/ecc_encrypt_key.o src/pk/ecc/ecc_export.o src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_size.o \ +src/pk/ecc/ecc_import.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_shared_secret.o \ +src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \ +src/pk/ecc/ltc_ecc_is_valid_idx.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \ +src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \ +src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \ +src/pk/katja/katja_decrypt_key.o src/pk/katja/katja_encrypt_key.o src/pk/katja/katja_export.o \ +src/pk/katja/katja_exptmod.o src/pk/katja/katja_free.o src/pk/katja/katja_import.o \ +src/pk/katja/katja_make_key.o src/pk/pkcs1/pkcs_1_i2osp.o src/pk/pkcs1/pkcs_1_mgf1.o \ +src/pk/pkcs1/pkcs_1_oaep_decode.o src/pk/pkcs1/pkcs_1_oaep_encode.o src/pk/pkcs1/pkcs_1_os2ip.o \ +src/pk/pkcs1/pkcs_1_pss_decode.o src/pk/pkcs1/pkcs_1_pss_encode.o src/pk/pkcs1/pkcs_1_v1_5_decode.o \ +src/pk/pkcs1/pkcs_1_v1_5_encode.o src/pk/rsa/rsa_decrypt_key.o src/pk/rsa/rsa_encrypt_key.o \ +src/pk/rsa/rsa_export.o src/pk/rsa/rsa_exptmod.o src/pk/rsa/rsa_free.o src/pk/rsa/rsa_import.o \ +src/pk/rsa/rsa_make_key.o src/pk/rsa/rsa_sign_hash.o src/pk/rsa/rsa_verify_hash.o src/prngs/fortuna.o \ +src/prngs/rc4.o src/prngs/rng_get_bytes.o src/prngs/rng_make_prng.o src/prngs/sober128.o \ +src/prngs/sprng.o src/prngs/yarrow.o HEADERS=src/headers/tomcrypt_cfg.h src/headers/tomcrypt_mac.h src/headers/tomcrypt_macros.h \ src/headers/tomcrypt_custom.h src/headers/tomcrypt_argchk.h src/headers/tomcrypt_cipher.h \ diff --git a/libtomcrypt/src/headers/tomcrypt.h b/libtomcrypt/src/headers/tomcrypt.h index 15ccd04..ba9f181 100644 --- a/libtomcrypt/src/headers/tomcrypt.h +++ b/libtomcrypt/src/headers/tomcrypt.h @@ -24,7 +24,7 @@ extern "C" { /* descriptor table size */ /* Dropbear change - this should be smaller, saves some size */ -#define TAB_SIZE 4 +#define TAB_SIZE 5 /* error codes [will be expanded in future releases] */ enum { diff --git a/libtomcrypt/src/headers/tomcrypt_custom.h b/libtomcrypt/src/headers/tomcrypt_custom.h index d1d86c6..91a2ccb 100644 --- a/libtomcrypt/src/headers/tomcrypt_custom.h +++ b/libtomcrypt/src/headers/tomcrypt_custom.h @@ -138,6 +138,8 @@ #ifdef DROPBEAR_ECC #define MECC +#define MPI +#define LTM_DESC #ifdef DROPBEAR_ECC_256 #define ECC256 #endif diff --git a/libtomcrypt/src/headers/tomcrypt_math.h b/libtomcrypt/src/headers/tomcrypt_math.h index 8bf544f..c996e41 100644 --- a/libtomcrypt/src/headers/tomcrypt_math.h +++ b/libtomcrypt/src/headers/tomcrypt_math.h @@ -11,12 +11,9 @@ typedef void ecc_point; #endif -/* Dropbear has its own rsa_key. We just comment this out. */ -#if 0 #ifndef MRSA typedef void rsa_key; #endif -#endif /** math descriptor */ typedef struct { @@ -389,8 +386,6 @@ typedef struct { ecc_point *C, void *modulus); -/* Dropbear has its own rsa code */ -#if 0 /* ---- (optional) rsa optimized math (for internal CRT) ---- */ /** RSA Key Generation @@ -416,7 +411,6 @@ typedef struct { int (*rsa_me)(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, int which, rsa_key *key); -#endif } ltc_math_descriptor; extern ltc_math_descriptor ltc_mp; diff --git a/libtomcrypt/src/misc/crypt/crypt_ltc_mp_descriptor.c b/libtomcrypt/src/misc/crypt/crypt_ltc_mp_descriptor.c index 907862f..e042910 100644 --- a/libtomcrypt/src/misc/crypt/crypt_ltc_mp_descriptor.c +++ b/libtomcrypt/src/misc/crypt/crypt_ltc_mp_descriptor.c @@ -10,4 +10,4 @@ */ #include "tomcrypt.h" -ltc_math_descriptor ltc_mp; +ltc_math_descriptor ltc_mp = {0}; diff --git a/libtomcrypt/src/pk/ecc/ecc_decrypt_key.c b/libtomcrypt/src/pk/ecc/ecc_decrypt_key.c index bb56208..97039d0 100644 --- a/libtomcrypt/src/pk/ecc/ecc_decrypt_key.c +++ b/libtomcrypt/src/pk/ecc/ecc_decrypt_key.c @@ -21,7 +21,7 @@ ECC Crypto, Tom St Denis */ -#ifdef MECC +#if defined(MECC) && defined(LTC_DER) /** Decrypt an ECC encrypted key diff --git a/libtomcrypt/src/pk/ecc/ecc_encrypt_key.c b/libtomcrypt/src/pk/ecc/ecc_encrypt_key.c index dd9bab0..d11ffe4 100644 --- a/libtomcrypt/src/pk/ecc/ecc_encrypt_key.c +++ b/libtomcrypt/src/pk/ecc/ecc_encrypt_key.c @@ -21,7 +21,7 @@ ECC Crypto, Tom St Denis */ -#ifdef MECC +#if defined(MECC) && defined(LTC_DER) /** Encrypt a symmetric key with ECC diff --git a/libtomcrypt/src/pk/ecc/ecc_export.c b/libtomcrypt/src/pk/ecc/ecc_export.c index 1919849..08c8d31 100644 --- a/libtomcrypt/src/pk/ecc/ecc_export.c +++ b/libtomcrypt/src/pk/ecc/ecc_export.c @@ -21,7 +21,7 @@ ECC Crypto, Tom St Denis */ -#ifdef MECC +#if defined(MECC) && defined(LTC_DER) /** Export an ECC key as a binary packet diff --git a/libtomcrypt/src/pk/ecc/ecc_import.c b/libtomcrypt/src/pk/ecc/ecc_import.c index 4adb28e..97eaa7d 100644 --- a/libtomcrypt/src/pk/ecc/ecc_import.c +++ b/libtomcrypt/src/pk/ecc/ecc_import.c @@ -21,7 +21,7 @@ ECC Crypto, Tom St Denis */ -#ifdef MECC +#if defined(MECC) && defined(LTC_DER) static int is_point(ecc_key *key) { diff --git a/libtomcrypt/src/pk/ecc/ecc_sign_hash.c b/libtomcrypt/src/pk/ecc/ecc_sign_hash.c index 44f949e..34c5893 100644 --- a/libtomcrypt/src/pk/ecc/ecc_sign_hash.c +++ b/libtomcrypt/src/pk/ecc/ecc_sign_hash.c @@ -21,7 +21,7 @@ ECC Crypto, Tom St Denis */ -#ifdef MECC +#if defined(MECC) && defined(LTC_DER) /** Sign a message digest diff --git a/libtomcrypt/src/pk/ecc/ecc_verify_hash.c b/libtomcrypt/src/pk/ecc/ecc_verify_hash.c index bd8a840..65a96e6 100644 --- a/libtomcrypt/src/pk/ecc/ecc_verify_hash.c +++ b/libtomcrypt/src/pk/ecc/ecc_verify_hash.c @@ -21,7 +21,7 @@ ECC Crypto, Tom St Denis */ -#ifdef MECC +#if defined(MECC) && defined(LTC_DER) /* verify * diff --git a/ltc_prng.c b/ltc_prng.c index 31a0658..11e95d6 100644 --- a/ltc_prng.c +++ b/ltc_prng.c @@ -33,7 +33,7 @@ @param prng [out] The PRNG state to initialize @return CRYPT_OK if successful */ -int dropbear_prng_start(prng_state *prng) +int dropbear_prng_start(prng_state* UNUSED(prng)) { return CRYPT_OK; } @@ -45,7 +45,7 @@ int dropbear_prng_start(prng_state *prng) @param prng PRNG state to update @return CRYPT_OK if successful */ -int dropbear_prng_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng) +int dropbear_prng_add_entropy(const unsigned char* UNUSED(in), unsigned long UNUSED(inlen), prng_state* UNUSED(prng)) { return CRYPT_OK; } @@ -55,7 +55,7 @@ int dropbear_prng_add_entropy(const unsigned char *in, unsigned long inlen, prng @param prng The PRNG to make active @return CRYPT_OK if successful */ -int dropbear_prng_ready(prng_state *prng) +int dropbear_prng_ready(prng_state* UNUSED(prng)) { return CRYPT_OK; } @@ -67,11 +67,11 @@ int dropbear_prng_ready(prng_state *prng) @param prng The active PRNG to read from @return Number of octets read */ -unsigned long dropbear_prng_read(unsigned char *out, unsigned long outlen, prng_state *prng) +unsigned long dropbear_prng_read(unsigned char* out, unsigned long outlen, prng_state* UNUSED(prng)) { LTC_ARGCHK(out != NULL); genrandom(out, outlen); - return CRYPT_OK; + return outlen; } /** @@ -79,7 +79,7 @@ unsigned long dropbear_prng_read(unsigned char *out, unsigned long outlen, prng_ @param prng The PRNG to terminate @return CRYPT_OK if successful */ -int dropbear_prng_done(prng_state *prng) +int dropbear_prng_done(prng_state* UNUSED(prng)) { return CRYPT_OK; } @@ -91,7 +91,7 @@ int dropbear_prng_done(prng_state *prng) @param prng The PRNG to export @return CRYPT_OK if successful */ -int dropbear_prng_export(unsigned char *out, unsigned long *outlen, prng_state *prng) +int dropbear_prng_export(unsigned char* UNUSED(out), unsigned long* outlen, prng_state* UNUSED(prng)) { LTC_ARGCHK(outlen != NULL); @@ -106,7 +106,7 @@ int dropbear_prng_export(unsigned char *out, unsigned long *outlen, prng_state * @param prng The PRNG to import @return CRYPT_OK if successful */ -int dropbear_prng_import(const unsigned char *in, unsigned long inlen, prng_state *prng) +int dropbear_prng_import(const unsigned char* UNUSED(in), unsigned long UNUSED(inlen), prng_state* UNUSED(prng)) { return CRYPT_OK; } diff --git a/options.h b/options.h index 4c42c02..4f0dc12 100644 --- a/options.h +++ b/options.h @@ -5,10 +5,10 @@ #ifndef _OPTIONS_H_ #define _OPTIONS_H_ -/****************************************************************** - * Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif" - * parts are to allow for commandline -DDROPBEAR_XXX options etc. - ******************************************************************/ +/* 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 */ #ifndef DROPBEAR_DEFPORT #define DROPBEAR_DEFPORT "22" diff --git a/random.c b/random.c index 8907644..c5a522e 100644 --- a/random.c +++ b/random.c @@ -27,7 +27,6 @@ #include "dbutil.h" #include "bignum.h" #include "random.h" -#include "ltc_prng.h" /* this is used to generate unique output from the same hashpool */ @@ -38,8 +37,6 @@ static uint32_t counter = 0; static unsigned char hashpool[SHA1_HASH_SIZE] = {0}; static int donerandinit = 0; -int dropbear_ltc_prng = -1; - #define INIT_SEED_SIZE 32 /* 256 bits */ /* The basic setup is we read some data from /dev/(u)random or prngd and hash it @@ -235,13 +232,6 @@ void seedrandom() { sha1_done(&hs, hashpool); -#ifdef DROPBEAR_LTC_PRNG - if (dropbear_ltc_prng == -1) { - dropbear_ltc_prng = register_prng(&dropbear_prng_desc); - dropbear_assert(dropbear_ltc_prng != -1); - } -#endif - counter = 0; donerandinit = 1; diff --git a/random.h b/random.h index 4042757..544e77e 100644 --- a/random.h +++ b/random.h @@ -32,6 +32,4 @@ void genrandom(unsigned char* buf, unsigned int len); void addrandom(char * buf, unsigned int len); void gen_random_mpint(mp_int *max, mp_int *rand); -extern int dropbear_ltc_prng; - #endif /* _RANDOM_H_ */ diff --git a/session.h b/session.h index 91af1a3..be789b3 100644 --- a/session.h +++ b/session.h @@ -157,7 +157,7 @@ struct sshsession { buffer *session_id; /* this is the hash from the first kex */ /* The below are used temporarily during kex, are freed after use */ mp_int * dh_K; /* SSH_MSG_KEXDH_REPLY and sending SSH_MSH_NEWKEYS */ - buffer *hash/* the session hash */ + buffer *hash; /* the session hash */ buffer* kexhashbuf; /* session hash buffer calculated from various packets*/ buffer* transkexinit; /* the kexinit packet we send should be kept so we can add it to the hash when generating keys */ diff --git a/svr-auth.c b/svr-auth.c index 404232e..dca95f5 100644 --- a/svr-auth.c +++ b/svr-auth.c @@ -93,8 +93,7 @@ static void send_msg_userauth_banner() { CHECKCLEARTOWRITE(); buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_BANNER); - buf_putstring(ses.writepayload, buf_getptr(svr_opts.banner, - svr_opts.banner->len), svr_opts.banner->len); + buf_putbufstring(ses.writepayload, svr_opts.banner); buf_putstring(ses.writepayload, "en", 2); encrypt_packet(); @@ -330,11 +329,10 @@ void send_msg_userauth_failure(int partial, int incrfail) { buf_putbytes(typebuf, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN); } - buf_setpos(typebuf, 0); - buf_putstring(ses.writepayload, buf_getptr(typebuf, typebuf->len), - typebuf->len); + buf_putbufstring(ses.writepayload, typebuf); - TRACE(("auth fail: methods %d, '%s'", ses.authstate.authtypes, + TRACE(("auth fail: methods %d, '%.*s'", ses.authstate.authtypes, + typebuf->len, buf_getptr(typebuf, typebuf->len))); buf_free(typebuf); diff --git a/svr-authpubkey.c b/svr-authpubkey.c index d483e9d..1c5f9d6 100644 --- a/svr-authpubkey.c +++ b/svr-authpubkey.c @@ -126,14 +126,13 @@ void svr_auth_pubkey() { /* create the data which has been signed - this a string containing * session_id, concatenated with the payload packet up to the signature */ signbuf = buf_new(ses.payload->pos + 4 + SHA1_HASH_SIZE); - buf_putstring(signbuf, ses.session_id, SHA1_HASH_SIZE); + buf_putbufstring(signbuf, ses.session_id); buf_putbytes(signbuf, ses.payload->data, ses.payload->pos); buf_setpos(signbuf, 0); /* ... and finally verify the signature */ fp = sign_key_fingerprint(keyblob, keybloblen); - if (buf_verify(ses.payload, key, buf_getptr(signbuf, signbuf->len), - signbuf->len) == DROPBEAR_SUCCESS) { + if (buf_verify(ses.payload, key, signbuf) == DROPBEAR_SUCCESS) { dropbear_log(LOG_NOTICE, "Pubkey auth succeeded for '%s' with key %s from %s", ses.authstate.pw_name, fp, svr_ses.addrstring); diff --git a/svr-kex.c b/svr-kex.c index d9106a9..a4376df 100644 --- a/svr-kex.c +++ b/svr-kex.c @@ -34,7 +34,7 @@ #include "bignum.h" #include "random.h" #include "runopts.h" - +#include "ecc.h" static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs); @@ -59,7 +59,7 @@ void recv_msg_kexdh_init() { } } else { #ifdef DROPBEAR_ECDH - buffer *ecdh_qs = buf_getstringbuf(ses.payload); + ecdh_qs = buf_getstringbuf(ses.payload); #endif } @@ -104,14 +104,14 @@ static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) { struct kex_ecdh_param *ecdh_param = gen_kexecdh_param(); kexecdh_comb_key(ecdh_param, ecdh_qs, svr_opts.hostkey); - buf_put_ecc_pub(ses.writepayload, &ecdh_param->key); + buf_put_ecc_pubkey_string(ses.writepayload, &ecdh_param->key); free_kexecdh_param(ecdh_param); #endif } /* calc the signature */ buf_put_sign(ses.writepayload, svr_opts.hostkey, - ses.newkeys->algo_hostkey, ses.hash, SHA1_HASH_SIZE); + ses.newkeys->algo_hostkey, ses.hash); /* the SSH_MSG_KEXDH_REPLY is done */ encrypt_packet(); diff --git a/sysoptions.h b/sysoptions.h index 9b7c15a..d31b56f 100644 --- a/sysoptions.h +++ b/sysoptions.h @@ -70,10 +70,6 @@ #define DROPBEAR_SIGNKEY_VERIFY #endif -#ifdef DROPBEAR_ECDH -#define DROPBEAR_LTC_PRNG -#endif - #define SHA1_HASH_SIZE 20 #define MD5_HASH_SIZE 16 @@ -99,6 +95,10 @@ #define DROPBEAR_ECC_521 #endif +#ifdef DROPBEAR_ECC +#define DROPBEAR_LTC_PRNG +#endif + // hashes which will be linked and registered #if defined(DROPBEAR_SHA2_256_HMAC) || defined(DROPBEAR_ECC_256) #define DROPBEAR_SHA256 -- cgit v1.2.3 From c797c1750c46d2e111874e31adf5627b24e97462 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Mon, 8 Apr 2013 00:10:57 +0800 Subject: - Fix various hardcoded uses of SHA1 - rename curves to nistp256 etc - fix svr-auth.c TRACE problem --HG-- branch : ecc --- bignum.c | 7 +++---- bignum.h | 3 ++- cli-authpubkey.c | 2 +- common-algo.c | 12 ++++++------ common-kex.c | 46 ++++++++++++++++++++++------------------------ ecc.c | 14 +++++++------- ecc.h | 6 +++--- svr-auth.c | 3 +-- svr-authpubkey.c | 2 +- sysoptions.h | 3 +-- 10 files changed, 47 insertions(+), 51 deletions(-) (limited to 'common-algo.c') diff --git a/bignum.c b/bignum.c index cf50ddc..886568d 100644 --- a/bignum.c +++ b/bignum.c @@ -60,7 +60,8 @@ void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) { } /* hash the ssh representation of the mp_int mp */ -void sha1_process_mp(hash_state *hs, mp_int *mp) { +void hash_process_mp(const struct ltc_hash_descriptor *hash_desc, + hash_state *hs, mp_int *mp) { int i; buffer * buf; @@ -68,8 +69,6 @@ void sha1_process_mp(hash_state *hs, mp_int *mp) { buf = buf_new(512 + 20); /* max buffer is a 4096 bit key, plus header + some leeway*/ buf_putmpint(buf, mp); - i = buf->pos; - buf_setpos(buf, 0); - sha1_process(hs, buf_getptr(buf, i), i); + hash_desc->process(hs, buf->data, buf->len); buf_free(buf); } diff --git a/bignum.h b/bignum.h index 042f811..f7abc7d 100644 --- a/bignum.h +++ b/bignum.h @@ -30,6 +30,7 @@ void m_mp_init(mp_int *mp); void m_mp_init_multi(mp_int *mp, ...); void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len); -void sha1_process_mp(hash_state *hs, mp_int *mp); +void hash_process_mp(const struct ltc_hash_descriptor *hash_desc, + hash_state *hs, mp_int *mp); #endif /* _BIGNUM_H_ */ diff --git a/cli-authpubkey.c b/cli-authpubkey.c index 96eee05..9fcc256 100644 --- a/cli-authpubkey.c +++ b/cli-authpubkey.c @@ -169,7 +169,7 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) { TRACE(("realsign")) /* We put the signature as well - this contains string(session id), then * the contents of the write payload to this point */ - sigbuf = buf_new(4 + SHA1_HASH_SIZE + ses.writepayload->len); + sigbuf = buf_new(4 + ses.session_id->len + ses.writepayload->len); buf_putbufstring(sigbuf, ses.session_id); buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len); cli_buf_put_sign(ses.writepayload, key, type, sigbuf); diff --git a/common-algo.c b/common-algo.c index 04bbd51..025faae 100644 --- a/common-algo.c +++ b/common-algo.c @@ -227,13 +227,13 @@ static struct dropbear_kex kex_dh_group14 = {dh_p_14, DH_P_14_LEN, NULL, &sha1_d #ifdef DROPBEAR_ECDH #ifdef DROPBEAR_ECC_256 -static struct dropbear_kex kex_ecdh_secp256r1 = {NULL, 0, &ecc_curve_secp256r1, &sha256_desc }; +static struct dropbear_kex kex_ecdh_nistp256 = {NULL, 0, &ecc_curve_nistp256, &sha256_desc }; #endif #ifdef DROPBEAR_ECC_384 -static struct dropbear_kex kex_ecdh_secp384r1 = {NULL, 0, &ecc_curve_secp384r1, &sha384_desc }; +static struct dropbear_kex kex_ecdh_nistp384 = {NULL, 0, &ecc_curve_nistp384, &sha384_desc }; #endif #ifdef DROPBEAR_ECC_521 -static struct dropbear_kex kex_ecdh_secp521r1 = {NULL, 0, &ecc_curve_secp521r1, &sha512_desc }; +static struct dropbear_kex kex_ecdh_nistp521 = {NULL, 0, &ecc_curve_nistp521, &sha512_desc }; #endif #endif // DROPBEAR_ECDH @@ -241,13 +241,13 @@ static struct dropbear_kex kex_ecdh_secp521r1 = {NULL, 0, &ecc_curve_secp521r1, algo_type sshkex[] = { #ifdef DROPBEAR_ECDH #ifdef DROPBEAR_ECC_256 - {"ecdh-sha2-secp256r1", 0, &kex_ecdh_secp256r1, 1, NULL}, + {"ecdh-sha2-nistp256", 0, &kex_ecdh_nistp256, 1, NULL}, #endif #ifdef DROPBEAR_ECC_384 - {"ecdh-sha2-secp384r1", 0, &kex_ecdh_secp384r1, 1, NULL}, + {"ecdh-sha2-nistp384", 0, &kex_ecdh_nistp384, 1, NULL}, #endif #ifdef DROPBEAR_ECC_521 - {"ecdh-sha2-secp521r1", 0, &kex_ecdh_secp521r1, 1, NULL}, + {"ecdh-sha2-nistp521", 0, &kex_ecdh_nistp521, 1, NULL}, #endif #endif {"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL}, diff --git a/common-kex.c b/common-kex.c index 48569fe..1543fb8 100644 --- a/common-kex.c +++ b/common-kex.c @@ -85,8 +85,8 @@ static void gen_new_zstreams(); #endif static void read_kex_algos(); /* helper function for gen_new_keys */ -static void hashkeys(unsigned char *out, int outlen, - const hash_state * hs, unsigned const char X); +static void hashkeys(unsigned char *out, unsigned int outlen, + const hash_state * hs, const unsigned char X); static void finish_kexhashbuf(void); @@ -251,26 +251,28 @@ static void kexinitialise() { * out must have at least min(SHA1_HASH_SIZE, outlen) bytes allocated. * * See Section 7.2 of rfc4253 (ssh transport) for details */ -static void hashkeys(unsigned char *out, int outlen, +static void hashkeys(unsigned char *out, unsigned int outlen, const hash_state * hs, const unsigned char X) { + const struct ltc_hash_descriptor *hashdesc = ses.newkeys->algo_kex->hashdesc; hash_state hs2; - int offset; + unsigned int offset; + unsigned char tmpout[hashdesc->hashsize]; memcpy(&hs2, hs, sizeof(hash_state)); - sha1_process(&hs2, &X, 1); - sha1_process(&hs2, ses.session_id->data, ses.session_id->len); - sha1_done(&hs2, out); - for (offset = SHA1_HASH_SIZE; + hashdesc->process(&hs2, &X, 1); + hashdesc->process(&hs2, ses.session_id->data, ses.session_id->len); + hashdesc->done(&hs2, tmpout); + memcpy(out, tmpout, MIN(hashdesc->hashsize, outlen)); + for (offset = hashdesc->hashsize; offset < outlen; - offset += SHA1_HASH_SIZE) + offset += hashdesc->hashsize) { /* need to extend */ - unsigned char k2[SHA1_HASH_SIZE]; memcpy(&hs2, hs, sizeof(hash_state)); - sha1_process(&hs2, out, offset); - sha1_done(&hs2, k2); - memcpy(&out[offset], k2, MIN(outlen - offset, SHA1_HASH_SIZE)); + hashdesc->process(&hs2, out, offset); + hashdesc->done(&hs2, tmpout); + memcpy(&out[offset], tmpout, MIN(outlen - offset, hashdesc->hashsize)); } } @@ -292,14 +294,14 @@ void gen_new_keys() { unsigned char *trans_IV, *trans_key, *recv_IV, *recv_key; hash_state hs; - unsigned int C2S_keysize, S2C_keysize; + const struct ltc_hash_descriptor *hashdesc = ses.newkeys->algo_kex->hashdesc; char mactransletter, macrecvletter; /* Client or server specific */ TRACE(("enter gen_new_keys")) /* the dh_K and hash are the start of all hashes, we make use of that */ - sha1_init(&hs); - sha1_process_mp(&hs, ses.dh_K); + hashdesc->init(&hs); + hash_process_mp(hashdesc, &hs, ses.dh_K); mp_clear(ses.dh_K); m_free(ses.dh_K); sha1_process(&hs, ses.hash->data, ses.hash->len); @@ -312,8 +314,6 @@ void gen_new_keys() { recv_IV = S2C_IV; trans_key = C2S_key; recv_key = S2C_key; - C2S_keysize = ses.newkeys->trans.algo_crypt->keysize; - S2C_keysize = ses.newkeys->recv.algo_crypt->keysize; mactransletter = 'E'; macrecvletter = 'F'; } else { @@ -321,16 +321,14 @@ void gen_new_keys() { recv_IV = C2S_IV; trans_key = S2C_key; recv_key = C2S_key; - C2S_keysize = ses.newkeys->recv.algo_crypt->keysize; - S2C_keysize = ses.newkeys->trans.algo_crypt->keysize; mactransletter = 'F'; macrecvletter = 'E'; } - hashkeys(C2S_IV, SHA1_HASH_SIZE, &hs, 'A'); - hashkeys(S2C_IV, SHA1_HASH_SIZE, &hs, 'B'); - hashkeys(C2S_key, C2S_keysize, &hs, 'C'); - hashkeys(S2C_key, S2C_keysize, &hs, 'D'); + hashkeys(C2S_IV, sizeof(C2S_IV), &hs, 'A'); + hashkeys(S2C_IV, sizeof(S2C_IV), &hs, 'B'); + hashkeys(C2S_key, sizeof(C2S_key), &hs, 'C'); + hashkeys(S2C_key, sizeof(S2C_key), &hs, 'D'); if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) { int recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name); diff --git a/ecc.c b/ecc.c index 0f988ac..fc5ea9d 100644 --- a/ecc.c +++ b/ecc.c @@ -9,24 +9,24 @@ // TODO: use raw bytes for the dp rather than the hex strings in libtomcrypt's ecc.c #ifdef DROPBEAR_ECC_256 -const struct dropbear_ecc_curve ecc_curve_secp256r1 = { +const struct dropbear_ecc_curve ecc_curve_nistp256 = { .dp = <c_ecc_sets[0], .hash_desc = &sha256_desc, - .name = "secp256r1" + .name = "nistp256" }; #endif #ifdef DROPBEAR_ECC_384 -const struct dropbear_ecc_curve ecc_curve_secp384r1 = { +const struct dropbear_ecc_curve ecc_curve_nistp384 = { .dp = <c_ecc_sets[1], .hash_desc = &sha384_desc, - .name = "secp384r1" + .name = "nistp384" }; #endif #ifdef DROPBEAR_ECC_521 -const struct dropbear_ecc_curve ecc_curve_secp521r1 = { +const struct dropbear_ecc_curve ecc_curve_nistp521 = { .dp = <c_ecc_sets[2], .hash_desc = &sha512_desc, - .name = "secp521r1" + .name = "nistp521" }; #endif @@ -35,7 +35,7 @@ static ecc_key * new_ecc_key(void) { key->pubkey.x = m_malloc(sizeof(mp_int)); key->pubkey.y = m_malloc(sizeof(mp_int)); key->pubkey.z = m_malloc(sizeof(mp_int)); - key->k = m_malloc(sizeof(mp_init)); + key->k = m_malloc(sizeof(mp_int)); m_mp_init_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL); return key; } diff --git a/ecc.h b/ecc.h index d72fbb1..dcf190e 100644 --- a/ecc.h +++ b/ecc.h @@ -14,9 +14,9 @@ struct dropbear_ecc_curve { const char *name; }; -extern const struct dropbear_ecc_curve ecc_curve_secp256r1; -extern const struct dropbear_ecc_curve ecc_curve_secp384r1; -extern const struct dropbear_ecc_curve ecc_curve_secp521r1; +extern const struct dropbear_ecc_curve ecc_curve_nistp256; +extern const struct dropbear_ecc_curve ecc_curve_nistp384; +extern const struct dropbear_ecc_curve ecc_curve_nistp521; // "pubkey" refers to a point, but LTC uses ecc_key structure for both public // and private keys diff --git a/svr-auth.c b/svr-auth.c index dca95f5..eb518fc 100644 --- a/svr-auth.c +++ b/svr-auth.c @@ -332,8 +332,7 @@ void send_msg_userauth_failure(int partial, int incrfail) { buf_putbufstring(ses.writepayload, typebuf); TRACE(("auth fail: methods %d, '%.*s'", ses.authstate.authtypes, - typebuf->len, - buf_getptr(typebuf, typebuf->len))); + typebuf->len, typebuf->data)) buf_free(typebuf); diff --git a/svr-authpubkey.c b/svr-authpubkey.c index 1c5f9d6..e0727de 100644 --- a/svr-authpubkey.c +++ b/svr-authpubkey.c @@ -125,7 +125,7 @@ void svr_auth_pubkey() { /* create the data which has been signed - this a string containing * session_id, concatenated with the payload packet up to the signature */ - signbuf = buf_new(ses.payload->pos + 4 + SHA1_HASH_SIZE); + signbuf = buf_new(ses.payload->pos + 4 + ses.session_id->len); buf_putbufstring(signbuf, ses.session_id); buf_putbytes(signbuf, ses.payload->data, ses.payload->pos); buf_setpos(signbuf, 0); diff --git a/sysoptions.h b/sysoptions.h index d31b56f..a6b1364 100644 --- a/sysoptions.h +++ b/sysoptions.h @@ -74,8 +74,7 @@ #define MD5_HASH_SIZE 16 #define MAX_KEY_LEN 32 /* 256 bits for aes256 etc */ -#define MAX_IV_LEN 20 /* must be same as max blocksize, - and >= SHA1_HASH_SIZE */ +#define MAX_IV_LEN 20 /* must be same as max blocksize, */ #if defined(DROPBEAR_SHA2_512_HMAC) #define MAX_MAC_LEN 64 -- cgit v1.2.3 From 7f091e70196cdcfbf80d16d508e6bed0bce38022 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 9 Apr 2013 00:36:04 +0800 Subject: start on ecdsa keys --HG-- branch : ecc --- Makefile.in | 5 ++-- algo.h | 3 --- cli-session.c | 1 + common-algo.c | 70 -------------------------------------------------------- common-kex.c | 1 + crypto_desc.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ crypto_desc.h | 9 ++++++++ dropbearkey.c | 1 + ecc.c | 7 +++--- ecc.h | 2 +- ecdsa.c | 53 +++++++++++++++++++++++++++++++++++++++++++ ecdsa.h | 0 options.h | 1 + signkey.h | 3 +++ svr-session.c | 1 + sysoptions.h | 11 +++++---- 16 files changed, 157 insertions(+), 84 deletions(-) create mode 100644 crypto_desc.c create mode 100644 crypto_desc.h create mode 100644 ecdsa.c create mode 100644 ecdsa.h (limited to 'common-algo.c') diff --git a/Makefile.in b/Makefile.in index f456a72..13d8e83 100644 --- a/Makefile.in +++ b/Makefile.in @@ -26,7 +26,8 @@ COMMONOBJS=dbutil.o buffer.o \ dss.o bignum.o \ signkey.o rsa.o random.o \ queue.o \ - atomicio.o compat.o fake-rfc2553.o ltc_prng.o ecc.o + atomicio.o compat.o fake-rfc2553.o \ + ltc_prng.o ecc.o ecdsa.o crypto_desc.o SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \ @@ -54,7 +55,7 @@ HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \ debug.h channel.h chansession.h config.h queue.h sshpty.h \ termcodes.h gendss.h genrsa.h runopts.h includes.h \ loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \ - listener.h fake-rfc2553.h + listener.h fake-rfc2553.h ecc.h ecdsa.h dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) @CRYPTLIB@ dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS) diff --git a/algo.h b/algo.h index 500c449..4be7cf3 100644 --- a/algo.h +++ b/algo.h @@ -93,7 +93,6 @@ struct dropbear_kex { const struct ltc_hash_descriptor *hashdesc; }; -void crypto_init(); int have_algo(char* algo, size_t algolen, algo_type algos[]); void buf_put_algolist(buffer * buf, algo_type localalgos[]); @@ -120,6 +119,4 @@ enum { DROPBEAR_COMP_ZLIB_DELAY, }; -extern int dropbear_ltc_prng; - #endif /* _ALGO_H_ */ diff --git a/cli-session.c b/cli-session.c index e58fdbd..2905389 100644 --- a/cli-session.c +++ b/cli-session.c @@ -36,6 +36,7 @@ #include "runopts.h" #include "chansession.h" #include "agentfwd.h" +#include "crypto_desc.h" static void cli_remoteclosed(); static void cli_sessionloop(); diff --git a/common-algo.c b/common-algo.c index 025faae..9915ce6 100644 --- a/common-algo.c +++ b/common-algo.c @@ -33,12 +33,6 @@ /* This file (algo.c) organises the ciphers which can be used, and is used to * decide which ciphers/hashes/compression/signing to use during key exchange*/ -#ifdef DROPBEAR_LTC_PRNG - int dropbear_ltc_prng = -1; -#endif - - - static int void_cipher(const unsigned char* in, unsigned char* out, unsigned long len, void* UNUSED(cipher_state)) { if (in != out) { @@ -255,70 +249,6 @@ algo_type sshkex[] = { {NULL, 0, NULL, 0, NULL} }; - -/* Register the compiled in ciphers. - * This should be run before using any of the ciphers/hashes */ -void crypto_init() { - - const struct ltc_cipher_descriptor *regciphers[] = { -#ifdef DROPBEAR_AES - &aes_desc, -#endif -#ifdef DROPBEAR_BLOWFISH - &blowfish_desc, -#endif -#ifdef DROPBEAR_TWOFISH - &twofish_desc, -#endif -#ifdef DROPBEAR_3DES - &des3_desc, -#endif - NULL - }; - - const struct ltc_hash_descriptor *reghashes[] = { - /* we need sha1 for hostkey stuff regardless */ - &sha1_desc, -#ifdef DROPBEAR_MD5_HMAC - &md5_desc, -#endif -#ifdef DROPBEAR_SHA256 - &sha256_desc, -#endif -#ifdef DROPBEAR_SHA384 - &sha384_desc, -#endif -#ifdef DROPBEAR_SHA512 - &sha512_desc, -#endif - NULL - }; - int i; - - for (i = 0; regciphers[i] != NULL; i++) { - if (register_cipher(regciphers[i]) == -1) { - dropbear_exit("Error registering crypto"); - } - } - - for (i = 0; reghashes[i] != NULL; i++) { - if (register_hash(reghashes[i]) == -1) { - dropbear_exit("Error registering crypto"); - } - } - -#ifdef DROPBEAR_LTC_PRNG - dropbear_ltc_prng = register_prng(&dropbear_prng_desc); - if (dropbear_ltc_prng == -1) { - dropbear_exit("Error registering crypto"); - } -#endif - -#ifdef DROPBEAR_ECC - ltc_mp = ltm_desc; -#endif -} - /* algolen specifies the length of algo, algos is our local list to match * against. * Returns DROPBEAR_SUCCESS if we have a match for algo, DROPBEAR_FAILURE diff --git a/common-kex.c b/common-kex.c index 99d0859..c68b227 100644 --- a/common-kex.c +++ b/common-kex.c @@ -35,6 +35,7 @@ #include "random.h" #include "runopts.h" #include "ecc.h" +#include "crypto_desc.h" /* diffie-hellman-group1-sha1 value for p */ const unsigned char dh_p_1[DH_P_1_LEN] = { diff --git a/crypto_desc.c b/crypto_desc.c new file mode 100644 index 0000000..403e085 --- /dev/null +++ b/crypto_desc.c @@ -0,0 +1,73 @@ +#include "includes.h" +#include "dbutil.h" +#include "crypto_desc.h" +#include "ltc_prng.h" + +#ifdef DROPBEAR_LTC_PRNG + int dropbear_ltc_prng = -1; +#endif + + +/* Register the compiled in ciphers. + * This should be run before using any of the ciphers/hashes */ +void crypto_init() { + + const struct ltc_cipher_descriptor *regciphers[] = { +#ifdef DROPBEAR_AES + &aes_desc, +#endif +#ifdef DROPBEAR_BLOWFISH + &blowfish_desc, +#endif +#ifdef DROPBEAR_TWOFISH + &twofish_desc, +#endif +#ifdef DROPBEAR_3DES + &des3_desc, +#endif + NULL + }; + + const struct ltc_hash_descriptor *reghashes[] = { + /* we need sha1 for hostkey stuff regardless */ + &sha1_desc, +#ifdef DROPBEAR_MD5_HMAC + &md5_desc, +#endif +#ifdef DROPBEAR_SHA256 + &sha256_desc, +#endif +#ifdef DROPBEAR_SHA384 + &sha384_desc, +#endif +#ifdef DROPBEAR_SHA512 + &sha512_desc, +#endif + NULL + }; + int i; + + for (i = 0; regciphers[i] != NULL; i++) { + if (register_cipher(regciphers[i]) == -1) { + dropbear_exit("Error registering crypto"); + } + } + + for (i = 0; reghashes[i] != NULL; i++) { + if (register_hash(reghashes[i]) == -1) { + dropbear_exit("Error registering crypto"); + } + } + +#ifdef DROPBEAR_LTC_PRNG + dropbear_ltc_prng = register_prng(&dropbear_prng_desc); + if (dropbear_ltc_prng == -1) { + dropbear_exit("Error registering crypto"); + } +#endif + +#ifdef DROPBEAR_ECC + ltc_mp = ltm_desc; +#endif +} + diff --git a/crypto_desc.h b/crypto_desc.h new file mode 100644 index 0000000..ff04066 --- /dev/null +++ b/crypto_desc.h @@ -0,0 +1,9 @@ +#ifndef _CRYPTO_DESC_H +#define _CRYPTO_DESC_H + +void crypto_init(); + +extern int dropbear_ltc_prng; + +#endif // _CRYPTO_DESC_H + diff --git a/dropbearkey.c b/dropbearkey.c index 9b82a77..a9d80fd 100644 --- a/dropbearkey.c +++ b/dropbearkey.c @@ -188,6 +188,7 @@ int main(int argc, char ** argv) { exit(EXIT_FAILURE); } + // TODO: put RSA and DSS size checks into genrsa.c etc if (keytype == DROPBEAR_SIGNKEY_DSS && bits != 1024) { fprintf(stderr, "DSS keys have a fixed size of 1024 bits\n"); exit(EXIT_FAILURE); diff --git a/ecc.c b/ecc.c index 56ab47a..10ae322 100644 --- a/ecc.c +++ b/ecc.c @@ -7,25 +7,24 @@ #ifdef DROPBEAR_ECC // TODO: use raw bytes for the dp rather than the hex strings in libtomcrypt's ecc.c - #ifdef DROPBEAR_ECC_256 const struct dropbear_ecc_curve ecc_curve_nistp256 = { .dp = <c_ecc_sets[0], - .hash_desc = &sha256_desc, + .hashdesc = &sha256_desc, .name = "nistp256" }; #endif #ifdef DROPBEAR_ECC_384 const struct dropbear_ecc_curve ecc_curve_nistp384 = { .dp = <c_ecc_sets[1], - .hash_desc = &sha384_desc, + .hashdesc = &sha384_desc, .name = "nistp384" }; #endif #ifdef DROPBEAR_ECC_521 const struct dropbear_ecc_curve ecc_curve_nistp521 = { .dp = <c_ecc_sets[2], - .hash_desc = &sha512_desc, + .hashdesc = &sha512_desc, .name = "nistp521" }; #endif diff --git a/ecc.h b/ecc.h index 9457ebe..35775d8 100644 --- a/ecc.h +++ b/ecc.h @@ -10,7 +10,7 @@ struct dropbear_ecc_curve { const ltc_ecc_set_type *dp; // curve domain parameters - const struct ltc_hash_descriptor *hash_desc; + const struct ltc_hash_descriptor *hashdesc; const char *name; }; diff --git a/ecdsa.c b/ecdsa.c new file mode 100644 index 0000000..b29ef1f --- /dev/null +++ b/ecdsa.c @@ -0,0 +1,53 @@ +#include "includes.h" +#include "dbutil.h" +#include "crypto_desc.h" + +#ifdef DROPBEAR_ECDSA + +ecc_key *gen_ecdsa_priv_key(unsigned int bit_size) { + const ltc_ecc_set_type *dp = NULL; // curve domain parameters + // TODO: use raw bytes for the dp rather than the hex strings in libtomcrypt's ecc.c + switch (bit_size) { +#ifdef DROPBEAR_ECC_256 + case 256: + dp = <c_ecc_sets[0]; + break; +#endif +#ifdef DROPBEAR_ECC_384 + case 384: + dp = <c_ecc_sets[0]; + break; +#endif +#ifdef DROPBEAR_ECC_521 + case 521: + dp = <c_ecc_sets[0]; + break; +#endif + } + if (!dp) { + dropbear_exit("Key size %d isn't valid. Try " +#ifdef DROPBEAR_ECC_256 + "256 " +#endif +#ifdef DROPBEAR_ECC_384 + "384 " +#endif +#ifdef DROPBEAR_ECC_521 + "521 " +#endif + , bit_size); + } + + ecc_key *new_key = m_malloc(sizeof(*new_key)); + if (ecc_make_key_ex(NULL, dropbear_ltc_prng, new_key, dp) != CRYPT_OK) { + dropbear_exit("ECC error"); + } + return new_key; +} + +int buf_get_ecdsa_pub_key(buffer* buf, ecc_key *key) { + +} + + +#endif // DROPBEAR_ECDSA diff --git a/ecdsa.h b/ecdsa.h new file mode 100644 index 0000000..e69de29 diff --git a/options.h b/options.h index 4f0dc12..2547c99 100644 --- a/options.h +++ b/options.h @@ -137,6 +137,7 @@ much traffic. */ #define DROPBEAR_DSS #define DROPBEAR_ECDH +#define DROPBEAR_ECDSA /* RSA can be vulnerable to timing attacks which use the time required for * signing to guess the private key. Blinding avoids this attack, though makes diff --git a/signkey.h b/signkey.h index e4dd7ce..316ca49 100644 --- a/signkey.h +++ b/signkey.h @@ -51,6 +51,9 @@ struct SIGN_key { #ifdef DROPBEAR_RSA dropbear_rsa_key * rsakey; #endif +#ifdef DROPBEAR_ECDSA + ecc_key *ecckey; +#endif }; typedef struct SIGN_key sign_key; diff --git a/svr-session.c b/svr-session.c index cf82289..b3b8d5e 100644 --- a/svr-session.c +++ b/svr-session.c @@ -39,6 +39,7 @@ #include "service.h" #include "auth.h" #include "runopts.h" +#include "crypto_desc.h" static void svr_remoteclosed(); diff --git a/sysoptions.h b/sysoptions.h index a6b1364..af3efe4 100644 --- a/sysoptions.h +++ b/sysoptions.h @@ -60,10 +60,13 @@ #define DROPBEAR_SUCCESS 0 #define DROPBEAR_FAILURE -1 -#define DROPBEAR_SIGNKEY_ANY 0 -#define DROPBEAR_SIGNKEY_RSA 1 -#define DROPBEAR_SIGNKEY_DSS 2 -#define DROPBEAR_SIGNKEY_NONE 3 +enum { + DROPBEAR_SIGNKEY_ANY, + DROPBEAR_SIGNKEY_RSA, + DROPBEAR_SIGNKEY_DSS, + DROPBEAR_SIGNKEY_ECDSA, + DROPBEAR_SIGNKEY_NONE, +}; /* Required for pubkey auth */ #if defined(ENABLE_SVR_PUBKEY_AUTH) || defined(DROPBEAR_CLIENT) -- cgit v1.2.3 From 95a21c8fd796c570e8660db983b3032af96ec5cb Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 3 May 2013 23:07:48 +0800 Subject: ecdsa is working --HG-- branch : ecc --- cli-main.c | 5 ++ cli-session.c | 4 -- common-algo.c | 11 +++++ dropbearkey.c | 9 ++-- ecdsa.c | 20 ++++++++ ecdsa.h | 2 + options.h | 5 +- runopts.h | 7 ++- signkey.c | 51 +++++++++---------- signkey.h | 20 ++++---- svr-main.c | 5 +- svr-runopts.c | 154 +++++++++++++++++++++++++++++++++++++++++----------------- svr-session.c | 1 - sysoptions.h | 2 + 14 files changed, 203 insertions(+), 93 deletions(-) (limited to 'common-algo.c') diff --git a/cli-main.c b/cli-main.c index 5f72969..2d4905e 100644 --- a/cli-main.c +++ b/cli-main.c @@ -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: diff --git a/ecdsa.c b/ecdsa.c index 360f988..03b51a2 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -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) { diff --git a/ecdsa.h b/ecdsa.h index 312b7cf..db4ae18 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -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); diff --git a/options.h b/options.h index 2547c99..0d30282 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. */ -// 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. diff --git a/runopts.h b/runopts.h index 9cd84d0..d5dcc9d 100644 --- a/runopts.h +++ b/runopts.h @@ -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; diff --git a/signkey.c b/signkey.c index 40b5378..ef7556e 100644 --- a/signkey.c +++ b/signkey.c @@ -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 diff --git a/signkey.h b/signkey.h index 7758d45..61095c7 100644 --- a/signkey.h +++ b/signkey.h @@ -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_ */ diff --git a/svr-main.c b/svr-main.c index 461aeaf..5e4150a 100644 --- a/svr-main.c +++ b/svr-main.c @@ -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) -- cgit v1.2.3