# HG changeset patch # User Matt Johnston # Date 1364315883 -28800 # Node ID bf9dc2d9c2b1f644f4e29c32e84e62efcb7339c9 # Parent b07eb3dc23ecc05f2283aa1978f80c32749550dc more bits on ecc branch diff -r b07eb3dc23ec -r bf9dc2d9c2b1 Makefile.in --- a/Makefile.in Tue Mar 26 01:35:22 2013 +0800 +++ b/Makefile.in Wed Mar 27 00:38:03 2013 +0800 @@ -26,7 +26,7 @@ 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 -r b07eb3dc23ec -r bf9dc2d9c2b1 algo.h --- a/algo.h Tue Mar 26 01:35:22 2013 +0800 +++ b/algo.h Wed Mar 27 00:38:03 2013 +0800 @@ -79,6 +79,20 @@ 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 @@ 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 -r b07eb3dc23ec -r bf9dc2d9c2b1 cli-kex.c --- a/cli-kex.c Tue Mar 26 01:35:22 2013 +0800 +++ b/cli-kex.c Wed Mar 27 00:38:03 2013 +0800 @@ -49,7 +49,7 @@ 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 -r b07eb3dc23ec -r bf9dc2d9c2b1 common-algo.c --- a/common-algo.c Tue Mar 26 01:35:22 2013 +0800 +++ b/common-algo.c Wed Mar 27 00:38:03 2013 +0800 @@ -212,10 +212,36 @@ {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 -r b07eb3dc23ec -r bf9dc2d9c2b1 common-kex.c --- a/common-kex.c Tue Mar 26 01:35:22 2013 +0800 +++ b/common-kex.c Wed Mar 27 00:38:03 2013 +0800 @@ -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 @@ 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 @@ 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 @@ #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 @@ 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 -r b07eb3dc23ec -r bf9dc2d9c2b1 ecc.c --- a/ecc.c Tue Mar 26 01:35:22 2013 +0800 +++ b/ecc.c Wed Mar 27 00:38:03 2013 +0800 @@ -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 @@ 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 -r b07eb3dc23ec -r bf9dc2d9c2b1 ecc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ecc.h Wed Mar 27 00:38:03 2013 +0800 @@ -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 -r b07eb3dc23ec -r bf9dc2d9c2b1 kex.h --- a/kex.h Tue Mar 26 01:35:22 2013 +0800 +++ b/kex.h Wed Mar 27 00:38:03 2013 +0800 @@ -73,6 +73,11 @@ }; +#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 -r b07eb3dc23ec -r bf9dc2d9c2b1 libtomcrypt/src/headers/tomcrypt_custom.h --- a/libtomcrypt/src/headers/tomcrypt_custom.h Tue Mar 26 01:35:22 2013 +0800 +++ b/libtomcrypt/src/headers/tomcrypt_custom.h Wed Mar 27 00:38:03 2013 +0800 @@ -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 -r b07eb3dc23ec -r bf9dc2d9c2b1 session.h --- a/session.h Tue Mar 26 01:35:22 2013 +0800 +++ b/session.h Wed Mar 27 00:38:03 2013 +0800 @@ -86,7 +86,7 @@ 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 -r b07eb3dc23ec -r bf9dc2d9c2b1 sysoptions.h --- a/sysoptions.h Tue Mar 26 01:35:22 2013 +0800 +++ b/sysoptions.h Wed Mar 27 00:38:03 2013 +0800 @@ -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