From 7dc2f36c3e2d21455ae432da4d8f338e7dc0668c Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Mon, 6 Apr 2020 23:18:26 +0800 Subject: use sigtype where appropriate --- common-algo.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) (limited to 'common-algo.c') diff --git a/common-algo.c b/common-algo.c index 558aad2..28f6744 100644 --- a/common-algo.c +++ b/common-algo.c @@ -237,8 +237,13 @@ algo_type sshhostkey[] = { #endif #endif #if DROPBEAR_RSA +#if DROPBEAR_RSA_SHA256 + {"rsa-sha2-256", DROPBEAR_SIGNKEY_RSA_SHA256, NULL, 1, NULL}, +#endif +#if DROPBEAR_RSA_SHA1 {"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL}, #endif +#endif #if DROPBEAR_DSS {"ssh-dss", DROPBEAR_SIGNKEY_DSS, NULL, 1, NULL}, #endif @@ -311,24 +316,6 @@ algo_type sshkex[] = { {NULL, 0, NULL, 0, NULL} }; -/* 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 - * otherwise */ -int have_algo(const char* algo, size_t algolen, const algo_type algos[]) { - - int i; - - for (i = 0; algos[i].name != NULL; i++) { - if (strlen(algos[i].name) == algolen - && (strncmp(algos[i].name, algo, algolen) == 0)) { - return DROPBEAR_SUCCESS; - } - } - - return DROPBEAR_FAILURE; -} - /* Output a comma separated list of algorithms to a buffer */ void buf_put_algolist(buffer * buf, const algo_type localalgos[]) { -- cgit v1.2.3 From 972d723484d89c71e73ed63cc17bb2a6ce8cca5a Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 17 May 2020 23:58:31 +0800 Subject: split signkey_type and signature_type for RSA sha1 vs sha256 --- cli-authpubkey.c | 36 ++++++++++++++++++++------------ common-algo.c | 16 +++++++------- fuzzer-verify.c | 18 ++++++++++++---- rsa.c | 12 +++++------ rsa.h | 4 ++-- session.h | 12 +++++++++-- signkey.c | 63 ++++++++++++++++++++++++++++++++++++++++---------------- signkey.h | 36 +++++++++++++++++++++++++------- ssh.h | 2 +- svr-authpubkey.c | 17 ++++++++++----- 10 files changed, 148 insertions(+), 68 deletions(-) (limited to 'common-algo.c') diff --git a/cli-authpubkey.c b/cli-authpubkey.c index d1cc1f6..0ad80ea 100644 --- a/cli-authpubkey.c +++ b/cli-authpubkey.c @@ -33,7 +33,7 @@ #include "agentfwd.h" #if DROPBEAR_CLI_PUBKEY_AUTH -static void send_msg_userauth_pubkey(sign_key *key, enum signkey_type sigtype, int realsign); +static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype, int realsign); /* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request. * We use it to remove the key we tried from the list */ @@ -58,7 +58,8 @@ void recv_msg_userauth_pk_ok() { buffer* keybuf = NULL; char* algotype = NULL; unsigned int algolen; - enum signkey_type sigtype, keytype; + enum signkey_type keytype; + enum signature_type sigtype; unsigned int remotelen; TRACE(("enter recv_msg_userauth_pk_ok")) @@ -113,7 +114,7 @@ void recv_msg_userauth_pk_ok() { TRACE(("matching key")) /* XXX TODO: if it's an encrypted key, here we ask for their * password */ - send_msg_userauth_pubkey((sign_key*)iter->item, keytype, 1); + send_msg_userauth_pubkey((sign_key*)iter->item, sigtype, 1); } else { TRACE(("That was whacky. We got told that a key was valid, but it didn't match our list. Sounds like dodgy code on Dropbear's part")) } @@ -121,7 +122,7 @@ void recv_msg_userauth_pk_ok() { TRACE(("leave recv_msg_userauth_pk_ok")) } -static void cli_buf_put_sign(buffer* buf, sign_key *key, enum signkey_type sigtype, +static void cli_buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype, const buffer *data_buf) { #if DROPBEAR_CLI_AGENTFWD // TODO: rsa-sha256 agent @@ -139,14 +140,14 @@ static void cli_buf_put_sign(buffer* buf, sign_key *key, enum signkey_type sigty } } -static void send_msg_userauth_pubkey(sign_key *key, enum signkey_type sigtype, int realsign) { +static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype, int realsign) { const char *algoname = NULL; unsigned int algolen; buffer* sigbuf = NULL; enum signkey_type keytype = signkey_type_from_signature(sigtype); - TRACE(("enter send_msg_userauth_pubkey")) + TRACE(("enter send_msg_userauth_pubkey sigtype %d", sigtype)) CHECKCLEARTOWRITE(); buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST); @@ -183,7 +184,6 @@ static void send_msg_userauth_pubkey(sign_key *key, enum signkey_type sigtype, i /* Returns 1 if a key was tried */ int cli_auth_pubkey() { - TRACE(("enter cli_auth_pubkey")) #if DROPBEAR_CLI_AGENTFWD @@ -194,16 +194,26 @@ int cli_auth_pubkey() { } #endif + /* TODO iterate through privkeys to skip ones not in server-sig-algs */ + + /* TODO: testing */ +#if DROPBEAR_RSA_SHA256 + cli_ses.preferred_rsa_sigtype = DROPBEAR_SIGNATURE_RSA_SHA256; +#elif DROPBEAR_RSA_SHA1 + cli_ses.preferred_rsa_sigtype = DROPBEAR_SIGNATURE_RSA_SHA1; +#endif + if (cli_opts.privkeys->first) { sign_key * key = (sign_key*)cli_opts.privkeys->first->item; - enum signkey_type sigtype = key->type; - /* Send a trial request */ -#if DROPBEAR_RSA && DROPBEAR_RSA_SHA256 - // TODO: use ext-info to choose rsa kind - if (sigtype == DROPBEAR_SIGNKEY_RSA) { - sigtype = DROPBEAR_SIGNKEY_RSA_SHA256; + /* Determine the signature type to use */ + enum signature_type sigtype = (enum signature_type)key->type; +#if DROPBEAR_RSA + if (key->type == DROPBEAR_SIGNKEY_RSA) { + sigtype = cli_ses.preferred_rsa_sigtype; } #endif + + /* Send a trial request */ send_msg_userauth_pubkey(key, sigtype, 0); cli_ses.lastprivkey = key; TRACE(("leave cli_auth_pubkey-success")) diff --git a/common-algo.c b/common-algo.c index 28f6744..2a1047e 100644 --- a/common-algo.c +++ b/common-algo.c @@ -223,29 +223,29 @@ algo_type ssh_nocompress[] = { algo_type sshhostkey[] = { #if DROPBEAR_ED25519 - {"ssh-ed25519", DROPBEAR_SIGNKEY_ED25519, NULL, 1, NULL}, + {"ssh-ed25519", DROPBEAR_SIGNATURE_ED25519, NULL, 1, NULL}, #endif #if DROPBEAR_ECDSA #if DROPBEAR_ECC_256 - {"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL}, + {"ecdsa-sha2-nistp256", DROPBEAR_SIGNATURE_ECDSA_NISTP256, NULL, 1, NULL}, #endif #if DROPBEAR_ECC_384 - {"ecdsa-sha2-nistp384", DROPBEAR_SIGNKEY_ECDSA_NISTP384, NULL, 1, NULL}, + {"ecdsa-sha2-nistp384", DROPBEAR_SIGNATURE_ECDSA_NISTP384, NULL, 1, NULL}, #endif #if DROPBEAR_ECC_521 - {"ecdsa-sha2-nistp521", DROPBEAR_SIGNKEY_ECDSA_NISTP521, NULL, 1, NULL}, + {"ecdsa-sha2-nistp521", DROPBEAR_SIGNATURE_ECDSA_NISTP521, NULL, 1, NULL}, #endif #endif #if DROPBEAR_RSA #if DROPBEAR_RSA_SHA256 - {"rsa-sha2-256", DROPBEAR_SIGNKEY_RSA_SHA256, NULL, 1, NULL}, + {"rsa-sha2-256", DROPBEAR_SIGNATURE_RSA_SHA256, NULL, 1, NULL}, #endif #if DROPBEAR_RSA_SHA1 - {"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL}, + {"ssh-rsa", DROPBEAR_SIGNATURE_RSA_SHA1, NULL, 1, NULL}, #endif #endif #if DROPBEAR_DSS - {"ssh-dss", DROPBEAR_SIGNKEY_DSS, NULL, 1, NULL}, + {"ssh-dss", DROPBEAR_SIGNATURE_DSS, NULL, 1, NULL}, #endif {NULL, 0, NULL, 0, NULL} }; @@ -263,8 +263,6 @@ static const struct dropbear_kex kex_dh_group14_sha256 = {DROPBEAR_KEX_NORMAL_DH static const struct dropbear_kex kex_dh_group16_sha512 = {DROPBEAR_KEX_NORMAL_DH, dh_p_16, DH_P_16_LEN, NULL, &sha512_desc }; #endif -/* These can't be const since dropbear_ecc_fill_dp() fills out - ecc_curve at runtime */ #if DROPBEAR_ECDH #if DROPBEAR_ECC_256 static const struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc }; diff --git a/fuzzer-verify.c b/fuzzer-verify.c index 8ecbcdb..cda7723 100644 --- a/fuzzer-verify.c +++ b/fuzzer-verify.c @@ -27,15 +27,25 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { if (setjmp(fuzz.jmp) == 0) { sign_key *key = new_sign_key(); - enum signkey_type type = DROPBEAR_SIGNKEY_ANY; - if (buf_get_pub_key(fuzz.input, key, &type) == DROPBEAR_SUCCESS) { - if (buf_verify(fuzz.input, key, verifydata) == DROPBEAR_SUCCESS) { + enum signkey_type keytype = DROPBEAR_SIGNKEY_ANY; + if (buf_get_pub_key(fuzz.input, key, &keytype) == DROPBEAR_SUCCESS) { + enum signature_type sigtype = (enum signature_type)keytype; + if (keytype == DROPBEAR_SIGNKEY_RSA) { + /* Flip a coin to decide rsa signature type */ + int flag = buf_getbyte(fuzz_input); + if (flag & 0x01) { + sigtype = DROPBEAR_SIGNATURE_RSA_SHA256; + } else { + sigtype = DROPBEAR_SIGNATURE_RSA_SHA1; + } + } + if (buf_verify(fuzz.input, key, sigtype, verifydata) == DROPBEAR_SUCCESS) { /* The fuzzer is capable of generating keys with a signature to match. We don't want false positives if the key is bogus, since a client/server wouldn't be trusting a bogus key anyway */ int boguskey = 0; - if (type == DROPBEAR_SIGNKEY_DSS) { + if (keytype == DROPBEAR_SIGNKEY_DSS) { /* So far have seen dss keys with bad p/q/g domain parameters */ int pprime, qprime, trials; trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->p)); diff --git a/rsa.c b/rsa.c index ef737c8..39e2d46 100644 --- a/rsa.c +++ b/rsa.c @@ -44,7 +44,7 @@ #endif static void rsa_pad_em(const dropbear_rsa_key * key, - const buffer *data_buf, mp_int * rsa_em, enum signkey_type sigtype); + const buffer *data_buf, mp_int * rsa_em, enum signature_type sigtype); /* Load a public rsa key from a buffer, initialising the values. * The key will have the same format as buf_put_rsa_key. @@ -197,7 +197,7 @@ void buf_put_rsa_priv_key(buffer* buf, const dropbear_rsa_key *key) { /* Verify a signature in buf, made on data by the key given. * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ int buf_rsa_verify(buffer * buf, const dropbear_rsa_key *key, - enum signkey_type sigtype, const buffer *data_buf) { + enum signature_type sigtype, const buffer *data_buf) { unsigned int slen; DEF_MP_INT(rsa_s); DEF_MP_INT(rsa_mdash); @@ -253,7 +253,7 @@ out: /* Sign the data presented with key, writing the signature contents * to the buffer */ void buf_put_rsa_sign(buffer* buf, const dropbear_rsa_key *key, - enum signkey_type sigtype, const buffer *data_buf) { + enum signature_type sigtype, const buffer *data_buf) { const char *name = NULL; unsigned int nsize, ssize, namelen = 0; unsigned int i; @@ -352,7 +352,7 @@ void buf_put_rsa_sign(buffer* buf, const dropbear_rsa_key *key, /* Creates the message value as expected by PKCS, see rfc8017 section 9.2 */ static void rsa_pad_em(const dropbear_rsa_key * key, - const buffer *data_buf, mp_int * rsa_em, enum signkey_type sigtype) { + const buffer *data_buf, mp_int * rsa_em, enum signature_type sigtype) { /* EM = 0x00 || 0x01 || PS || 0x00 || T PS is padding of 0xff to make EM the size of key->n @@ -380,14 +380,14 @@ static void rsa_pad_em(const dropbear_rsa_key * key, switch (sigtype) { #if DROPBEAR_RSA_SHA1 - case DROPBEAR_SIGNKEY_RSA: + case DROPBEAR_SIGNATURE_RSA_SHA1: Tlen = sizeof(T_sha1); T = T_sha1; hash_desc = &sha1_desc; break; #endif #if DROPBEAR_RSA_SHA256 - case DROPBEAR_SIGNKEY_RSA_SHA256: + case DROPBEAR_SIGNATURE_RSA_SHA256: Tlen = sizeof(T_sha256); T = T_sha256; hash_desc = &sha256_desc; diff --git a/rsa.h b/rsa.h index 39e6004..a8bbf41 100644 --- a/rsa.h +++ b/rsa.h @@ -43,10 +43,10 @@ typedef struct dropbear_RSA_Key { } dropbear_rsa_key; void buf_put_rsa_sign(buffer* buf, const dropbear_rsa_key *key, - enum signkey_type sigtype, const buffer *data_buf); + enum signature_type sigtype, const buffer *data_buf); #if DROPBEAR_SIGNKEY_VERIFY int buf_rsa_verify(buffer * buf, const dropbear_rsa_key *key, - enum signkey_type sigtype, const buffer *data_buf); + enum signature_type sigtype, const buffer *data_buf); #endif int buf_get_rsa_pub_key(buffer* buf, dropbear_rsa_key *key); int buf_get_rsa_priv_key(buffer* buf, dropbear_rsa_key *key); diff --git a/session.h b/session.h index ebfc915..cbe9cb5 100644 --- a/session.h +++ b/session.h @@ -92,8 +92,8 @@ struct key_context { struct key_context_directional trans; const struct dropbear_kex *algo_kex; - int algo_hostkey; /* server key type */ - int algo_signature; /* server signature type */ + enum signkey_type algo_hostkey; /* server key type */ + enum signature_type algo_signature; /* server signature type */ int allow_compress; /* whether compression has started (useful in zlib@openssh.com delayed compression case) */ @@ -313,6 +313,14 @@ struct clientsession { #endif sign_key *lastprivkey; + enum signature_type server_sig_algs[DROPBEAR_SIGNKEY_NUM_NAMED+1]; + int server_sig_algs_count; +#if DROPBEAR_RSA + /* Set to DROPBEAR_SIGNATURE_RSA_SHA256 or DROPBEAR_SIGNATURE_RSA_SHA1 + if depending which the server accepts */ + enum signature_type preferred_rsa_sigtype; +#endif + int retval; /* What the command exit status was - we emulate it */ #if 0 TODO diff --git a/signkey.c b/signkey.c index 27b09a3..47c8c8e 100644 --- a/signkey.c +++ b/signkey.c @@ -111,34 +111,52 @@ enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen) /* Special case for rsa-sha2-256. This could be generalised if more signature names are added that aren't 1-1 with public key names */ -const char* signature_name_from_type(enum signkey_type type, unsigned int *namelen) { +const char* signature_name_from_type(enum signature_type type, unsigned int *namelen) { #if DROPBEAR_RSA_SHA256 - if (type == DROPBEAR_SIGNKEY_RSA_SHA256) { - *namelen = strlen(SSH_SIGNKEY_RSA_SHA256); - return SSH_SIGNKEY_RSA_SHA256; + if (type == DROPBEAR_SIGNATURE_RSA_SHA256) { + *namelen = strlen(SSH_SIGNATURE_RSA_SHA256); + return SSH_SIGNATURE_RSA_SHA256; } #endif - return signkey_name_from_type(type, namelen); +#if DROPBEAR_RSA_SHA1 + if (type == DROPBEAR_SIGNATURE_RSA_SHA1) { + *namelen = strlen(SSH_SIGNKEY_RSA); + return SSH_SIGNKEY_RSA; + } +#endif + return signkey_name_from_type((enum signkey_type)type, namelen); } -enum signkey_type signature_type_from_name(const char* name, unsigned int namelen) { +/* Returns DROPBEAR_SIGNATURE_NONE if none match */ +enum signature_type signature_type_from_name(const char* name, unsigned int namelen) { #if DROPBEAR_RSA_SHA256 - if (namelen == strlen(SSH_SIGNKEY_RSA_SHA256) - && memcmp(name, SSH_SIGNKEY_RSA_SHA256, namelen) == 0) { - return DROPBEAR_SIGNKEY_RSA_SHA256; + if (namelen == strlen(SSH_SIGNATURE_RSA_SHA256) + && memcmp(name, SSH_SIGNATURE_RSA_SHA256, namelen) == 0) { + return DROPBEAR_SIGNATURE_RSA_SHA256; } #endif - return signkey_type_from_name(name, namelen); +#if DROPBEAR_RSA_SHA256 + if (namelen == strlen(SSH_SIGNKEY_RSA) + && memcmp(name, SSH_SIGNKEY_RSA, namelen) == 0) { + return DROPBEAR_SIGNATURE_RSA_SHA1; + } +#endif + return (enum signature_type)signkey_type_from_name(name, namelen); } -enum signkey_type signkey_type_from_signature(enum signkey_type sigtype) { +enum signkey_type signkey_type_from_signature(enum signature_type sigtype) { #if DROPBEAR_RSA_SHA256 - if (sigtype == DROPBEAR_SIGNKEY_RSA_SHA256) { + if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) { + return DROPBEAR_SIGNKEY_RSA; + } +#endif +#if DROPBEAR_RSA_SHA1 + if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA1) { return DROPBEAR_SIGNKEY_RSA; } #endif assert(sigtype < DROPBEAR_SIGNKEY_NUM_NAMED); - return sigtype; + return (enum signkey_type)sigtype; } /* Returns a pointer to the key part specific to "type". @@ -562,11 +580,20 @@ char * sign_key_fingerprint(const unsigned char* keyblob, unsigned int keybloble #endif } -void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type sigtype, +void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype, const buffer *data_buf) { buffer *sigblob = buf_new(MAX_PUBKEY_SIZE); enum signkey_type keytype = signkey_type_from_signature(sigtype); +#if DEBUG_TRACE + { + int namelen; + const char* signame = signature_name_from_type(sigtype, &namelen); + TRACE(("buf_put_sign type %d %s", sigtype, signame)); + } +#endif + + #if DROPBEAR_DSS if (keytype == DROPBEAR_SIGNKEY_DSS) { buf_put_dss_sign(sigblob, key->dsskey, data_buf); @@ -603,11 +630,12 @@ void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type sigtype, * If FAILURE is returned, the position of * buf is undefined. If SUCCESS is returned, buf will be positioned after the * signature blob */ -int buf_verify(buffer * buf, sign_key *key, enum signkey_type expect_sigtype, const buffer *data_buf) { +int buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, const buffer *data_buf) { char *type_name = NULL; unsigned int type_name_len = 0; - enum signkey_type sigtype, keytype; + enum signature_type sigtype; + enum signkey_type keytype; TRACE(("enter buf_verify")) @@ -616,8 +644,7 @@ int buf_verify(buffer * buf, sign_key *key, enum signkey_type expect_sigtype, co sigtype = signature_type_from_name(type_name, type_name_len); m_free(type_name); - if (expect_sigtype != DROPBEAR_SIGNKEY_ANY - && expect_sigtype != sigtype) { + if (expect_sigtype != sigtype) { dropbear_exit("Non-matching signing type"); } diff --git a/signkey.h b/signkey.h index 78b237b..9468509 100644 --- a/signkey.h +++ b/signkey.h @@ -32,6 +32,7 @@ struct dropbear_DSS_Key; struct dropbear_RSA_Key; struct dropbear_ED25519_Key; +/* Must match with signature_type below */ enum signkey_type { #if DROPBEAR_RSA DROPBEAR_SIGNKEY_RSA, @@ -49,13 +50,32 @@ enum signkey_type { #endif DROPBEAR_SIGNKEY_NUM_NAMED, DROPBEAR_SIGNKEY_ECDSA_KEYGEN = 70, /* just "ecdsa" for keygen */ -#if DROPBEAR_RSA_SHA256 - DROPBEAR_SIGNKEY_RSA_SHA256, /* rsa-sha2-256 signature. has a ssh-rsa key */ -#endif DROPBEAR_SIGNKEY_ANY = 80, DROPBEAR_SIGNKEY_NONE = 90, }; +/* Must match with signkey_type above, apart from rsa */ +enum signature_type { +#if DROPBEAR_DSS + DROPBEAR_SIGNATURE_DSS = DROPBEAR_SIGNKEY_DSS, +#endif +#if DROPBEAR_ECDSA + DROPBEAR_SIGNATURE_ECDSA_NISTP256 = DROPBEAR_SIGNKEY_ECDSA_NISTP256, + DROPBEAR_SIGNATURE_ECDSA_NISTP384 = DROPBEAR_SIGNKEY_ECDSA_NISTP384, + DROPBEAR_SIGNATURE_ECDSA_NISTP521 = DROPBEAR_SIGNKEY_ECDSA_NISTP521, +#endif /* DROPBEAR_ECDSA */ +#if DROPBEAR_ED25519 + DROPBEAR_SIGNATURE_ED25519 = DROPBEAR_SIGNKEY_ED25519, +#endif +#if DROPBEAR_RSA_SHA1 + DROPBEAR_SIGNATURE_RSA_SHA1 = 100, /* ssh-rsa signature (sha1) */ +#endif +#if DROPBEAR_RSA_SHA256 + DROPBEAR_SIGNATURE_RSA_SHA256 = 101, /* rsa-sha2-256 signature. has a ssh-rsa key */ +#endif + DROPBEAR_SIGNATURE_NONE = DROPBEAR_SIGNKEY_NONE, +}; + /* Sources for signing keys */ typedef enum { @@ -97,17 +117,17 @@ typedef struct SIGN_key sign_key; sign_key * new_sign_key(void); const char* signkey_name_from_type(enum signkey_type type, unsigned int *namelen); enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen); -const char* signature_name_from_type(enum signkey_type type, unsigned int *namelen); -enum signkey_type signature_type_from_name(const char* name, unsigned int namelen); -enum signkey_type signkey_type_from_signature(enum signkey_type sigtype); +const char* signature_name_from_type(enum signature_type type, unsigned int *namelen); +enum signature_type signature_type_from_name(const char* name, unsigned int namelen); +enum signkey_type signkey_type_from_signature(enum signature_type sigtype); int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type); int buf_get_priv_key(buffer* buf, sign_key *key, enum signkey_type *type); void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type); void buf_put_priv_key(buffer* buf, sign_key *key, enum signkey_type type); void sign_key_free(sign_key *key); -void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type sigtype, const buffer *data_buf); +void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype, const buffer *data_buf); #if DROPBEAR_SIGNKEY_VERIFY -int buf_verify(buffer * buf, sign_key *key, enum signkey_type type, const buffer *data_buf); +int buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, const buffer *data_buf); char * sign_key_fingerprint(const unsigned char* keyblob, unsigned int keybloblen); #endif int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen, diff --git a/ssh.h b/ssh.h index fb7f9f2..5030fe9 100644 --- a/ssh.h +++ b/ssh.h @@ -108,7 +108,7 @@ #define SSH_SIGNKEY_ED25519 "ssh-ed25519" #define SSH_SIGNKEY_ED25519_LEN 11 /* signature type */ -#define SSH_SIGNKEY_RSA_SHA256 "rsa-sha2-256" +#define SSH_SIGNATURE_RSA_SHA256 "rsa-sha2-256" /* Agent commands. These aren't part of the spec, and are defined * only on the openssh implementation. */ diff --git a/svr-authpubkey.c b/svr-authpubkey.c index a52667c..46237b7 100644 --- a/svr-authpubkey.c +++ b/svr-authpubkey.c @@ -92,7 +92,8 @@ void svr_auth_pubkey(int valid_user) { buffer * signbuf = NULL; sign_key * key = NULL; char* fp = NULL; - enum signkey_type sigtype, keytype; + enum signature_type sigtype; + enum signkey_type keytype; int auth_failure = 1; TRACE(("enter pubkeyauth")) @@ -102,10 +103,6 @@ void svr_auth_pubkey(int valid_user) { testkey = (buf_getbool(ses.payload) == 0); sigalgo = buf_getstring(ses.payload, &sigalgolen); - sigtype = signature_type_from_name(sigalgo, sigalgolen); - keytype = signkey_type_from_signature(sigtype); - keyalgo = signkey_name_from_type(keytype, &keyalgolen); - keybloblen = buf_getint(ses.payload); keyblob = buf_getptr(ses.payload, keybloblen); @@ -117,6 +114,16 @@ void svr_auth_pubkey(int valid_user) { send_msg_userauth_failure(0, 0); goto out; } + + sigtype = signature_type_from_name(sigalgo, sigalgolen); + if (sigtype == DROPBEAR_SIGNATURE_NONE) { + send_msg_userauth_failure(0, 0); + goto out; + } + + keytype = signkey_type_from_signature(sigtype); + keyalgo = signkey_name_from_type(keytype, &keyalgolen); + #if DROPBEAR_PLUGIN if (svr_ses.plugin_instance != NULL) { char *options_buf; -- cgit v1.2.3 From 5acee497bf3e44d86bdecf5bfa35042c363ab753 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 19 May 2020 00:31:41 +0800 Subject: ext-info handling for server-sig-algs only client side is handled --- algo.h | 11 +---- buffer.c | 22 +++++++++- buffer.h | 1 + cli-authpubkey.c | 78 +++++++++++++++++++++++++++++------- cli-kex.c | 25 ++++++++++++ cli-main.c | 1 + cli-session.c | 5 ++- common-algo.c | 119 ++++++++++++++++++++++++++++++++++++------------------- common-kex.c | 30 +++++++++----- fuzzer-verify.c | 4 +- kex.h | 2 + session.h | 11 ++--- signkey.c | 21 ++++++++-- signkey.h | 2 + ssh.h | 6 +++ svr-session.c | 7 +++- 16 files changed, 255 insertions(+), 90 deletions(-) (limited to 'common-algo.c') diff --git a/algo.h b/algo.h index 1a6d384..1565665 100644 --- a/algo.h +++ b/algo.h @@ -114,18 +114,11 @@ struct dropbear_kex { void buf_put_algolist(buffer * buf, const algo_type localalgos[]); -enum kexguess2_used { - KEXGUESS2_LOOK, - KEXGUESS2_NO, - KEXGUESS2_YES, -}; - #define KEXGUESS2_ALGO_NAME "kexguess2@matt.ucc.asn.au" -#define KEXGUESS2_ALGO_ID 99 - +int buf_has_algo(buffer *buf, const char *algo); algo_type * buf_match_algo(buffer* buf, algo_type localalgos[], - enum kexguess2_used *kexguess2, int *goodguess); + int kexguess2, int *goodguess); #if DROPBEAR_USER_ALGO_LIST int check_user_algos(const char* user_algo_list, algo_type * algos, diff --git a/buffer.c b/buffer.c index e70ec29..dc8b909 100644 --- a/buffer.c +++ b/buffer.c @@ -228,19 +228,37 @@ char* buf_getstring(buffer* buf, unsigned int *retlen) { } /* Return a string as a newly allocated buffer */ -buffer * buf_getstringbuf(buffer *buf) { +static buffer * buf_getstringbuf_int(buffer *buf, int incllen) { buffer *ret = NULL; unsigned int len = buf_getint(buf); + int extra = 0; if (len > MAX_STRING_LEN) { dropbear_exit("String too long"); } - ret = buf_new(len); + if (incllen) { + extra = 4; + } + ret = buf_new(len+extra); + if (incllen) { + buf_putint(ret, len); + } memcpy(buf_getwriteptr(ret, len), buf_getptr(buf, len), len); buf_incrpos(buf, len); buf_incrlen(ret, len); + buf_setpos(ret, 0); return ret; } +/* Return a string as a newly allocated buffer */ +buffer * buf_getstringbuf(buffer *buf) { + return buf_getstringbuf_int(buf, 0); +} + +/* Returns a string in a new buffer, including the length */ +buffer * buf_getbuf(buffer *buf) { + return buf_getstringbuf_int(buf, 1); +} + /* Just increment the buffer position the same as if we'd used buf_getstring, * but don't bother copying/malloc()ing for it */ void buf_eatstring(buffer *buf) { diff --git a/buffer.h b/buffer.h index befe1c7..85f913d 100644 --- a/buffer.h +++ b/buffer.h @@ -58,6 +58,7 @@ unsigned char* buf_getptr(const buffer* buf, unsigned int len); unsigned char* buf_getwriteptr(const buffer* buf, unsigned int len); char* buf_getstring(buffer* buf, unsigned int *retlen); buffer * buf_getstringbuf(buffer *buf); +buffer * buf_getbuf(buffer *buf); void buf_eatstring(buffer *buf); void buf_putint(buffer* buf, unsigned int val); void buf_putstring(buffer* buf, const char* str, unsigned int len); diff --git a/cli-authpubkey.c b/cli-authpubkey.c index 0ad80ea..8426e84 100644 --- a/cli-authpubkey.c +++ b/cli-authpubkey.c @@ -184,6 +184,7 @@ static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype, /* Returns 1 if a key was tried */ int cli_auth_pubkey() { + enum signature_type sigtype; TRACE(("enter cli_auth_pubkey")) #if DROPBEAR_CLI_AGENTFWD @@ -191,28 +192,77 @@ int cli_auth_pubkey() { /* get the list of available keys from the agent */ cli_load_agent_keys(cli_opts.privkeys); cli_opts.agent_keys_loaded = 1; + TRACE(("cli_auth_pubkey: agent keys loaded")) } #endif - /* TODO iterate through privkeys to skip ones not in server-sig-algs */ - - /* TODO: testing */ + /* iterate through privkeys to remove ones not allowed in server-sig-algs */ + while (cli_opts.privkeys->first) { + sign_key * key = (sign_key*)cli_opts.privkeys->first->item; + if (cli_ses.server_sig_algs) { +#ifdef DROPBEAR_RSA + if (key->type == DROPBEAR_SIGNKEY_RSA) { #if DROPBEAR_RSA_SHA256 - cli_ses.preferred_rsa_sigtype = DROPBEAR_SIGNATURE_RSA_SHA256; -#elif DROPBEAR_RSA_SHA1 - cli_ses.preferred_rsa_sigtype = DROPBEAR_SIGNATURE_RSA_SHA1; + if (buf_has_algo(cli_ses.server_sig_algs, SSH_SIGNATURE_RSA_SHA256) + == DROPBEAR_SUCCESS) { + sigtype = DROPBEAR_SIGNATURE_RSA_SHA256; + TRACE(("server-sig-algs allows rsa sha256")) + break; + } +#endif /* DROPBEAR_RSA_SHA256 */ +#if DROPBEAR_RSA_SHA1 + if (buf_has_algo(cli_ses.server_sig_algs, SSH_SIGNKEY_RSA) + == DROPBEAR_SUCCESS) { + sigtype = DROPBEAR_SIGNATURE_RSA_SHA1; + TRACE(("server-sig-algs allows rsa sha1")) + break; + } +#endif /* DROPBEAR_RSA_SHA256 */ + } else +#endif /* DROPBEAR_RSA */ + { + /* Not RSA */ + const char *name = NULL; + sigtype = signature_type_from_signkey(key->type); + name = signature_name_from_type(sigtype, NULL); + if (buf_has_algo(cli_ses.server_sig_algs, name) + == DROPBEAR_SUCCESS) { + TRACE(("server-sig-algs allows %s", name)) + break; + } + } + + /* No match, skip this key */ + TRACE(("server-sig-algs no match keytype %d, skipping", key->type)) + key = list_remove(cli_opts.privkeys->first); + sign_key_free(key); + continue; + } else { + /* Server didn't provide a server-sig-algs list, we'll + assume all except rsa-sha256 are OK. */ +#if DROPBEAR_RSA + if (key->type == DROPBEAR_SIGNKEY_RSA) { +#ifdef DROPBEAR_RSA_SHA1 + sigtype = DROPBEAR_SIGNATURE_RSA_SHA1; + TRACE(("no server-sig-algs, using rsa sha1")) + break; +#else + /* only support rsa-sha256, skip this key */ + TRACE(("no server-sig-algs, skipping rsa sha256")) + key = list_remove(cli_opts.privkeys->first); + sign_key_free(key); + continue; #endif + } /* key->type == DROPBEAR_SIGNKEY_RSA */ +#endif /* DROPBEAR_RSA */ + sigtype = signature_type_from_signkey(key->type); + TRACE(("no server-sig-algs, using key")) + break; + } + } if (cli_opts.privkeys->first) { sign_key * key = (sign_key*)cli_opts.privkeys->first->item; - /* Determine the signature type to use */ - enum signature_type sigtype = (enum signature_type)key->type; -#if DROPBEAR_RSA - if (key->type == DROPBEAR_SIGNKEY_RSA) { - sigtype = cli_ses.preferred_rsa_sigtype; - } -#endif - /* Send a trial request */ send_msg_userauth_pubkey(key, sigtype, 0); cli_ses.lastprivkey = key; diff --git a/cli-kex.c b/cli-kex.c index 7337ffd..99370eb 100644 --- a/cli-kex.c +++ b/cli-kex.c @@ -411,3 +411,28 @@ out: } m_free(fingerprint); } + +void recv_msg_ext_info(void) { + /* This message is not client-specific in the protocol but Dropbear only handles + a server-sent message at present. */ + unsigned int num_ext; + unsigned int i; + + num_ext = buf_getint(ses.payload); + TRACE(("received SSH_MSG_EXT_INFO with %d items", num_ext)) + + for (i = 0; i < num_ext; i++) { + unsigned int name_len; + char *ext_name = buf_getstring(ses.payload, &name_len); + TRACE(("extension %d name '%s'", i, ext_name)) + if (cli_ses.server_sig_algs == NULL + && name_len == strlen(SSH_SERVER_SIG_ALGS) + && strcmp(ext_name, SSH_SERVER_SIG_ALGS) == 0) { + cli_ses.server_sig_algs = buf_getbuf(ses.payload); + } else { + /* valid extension values could be >MAX_STRING_LEN */ + buf_eatstring(ses.payload); + } + m_free(ext_name); + } +} diff --git a/cli-main.c b/cli-main.c index 713cb09..b43b1e2 100644 --- a/cli-main.c +++ b/cli-main.c @@ -106,6 +106,7 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) { /* Render the formatted exit message */ vsnprintf(exitmsg, sizeof(exitmsg), format, param); + TRACE(("Exited, cleaning up: %s", exitmsg)) /* Add the prefix depending on session/auth state */ if (!ses.init_done) { diff --git a/cli-session.c b/cli-session.c index 56dd4af..fc81e2d 100644 --- a/cli-session.c +++ b/cli-session.c @@ -81,6 +81,7 @@ static const packettype cli_packettypes[] = { {SSH_MSG_REQUEST_SUCCESS, ignore_recv_response}, {SSH_MSG_REQUEST_FAILURE, ignore_recv_response}, #endif + {SSH_MSG_EXT_INFO, recv_msg_ext_info}, {0, NULL} /* End */ }; @@ -352,7 +353,9 @@ static void cli_session_cleanup(void) { (void)fcntl(cli_ses.stderrcopy, F_SETFL, cli_ses.stderrflags); cli_tty_cleanup(); - + if (cli_ses.server_sig_algs) { + buf_free(cli_ses.server_sig_algs); + } } static void cli_finished() { diff --git a/common-algo.c b/common-algo.c index 2a1047e..938695d 100644 --- a/common-algo.c +++ b/common-algo.c @@ -30,6 +30,7 @@ #include "dh_groups.h" #include "ltc_prng.h" #include "ecc.h" +#include "ssh.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*/ @@ -280,6 +281,7 @@ static const struct dropbear_kex kex_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0 static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc }; #endif +/* data == NULL for non-kex algorithm identifiers */ algo_type sshkex[] = { #if DROPBEAR_CURVE25519 {"curve25519-sha256", 0, &kex_curve25519, 1, NULL}, @@ -309,7 +311,11 @@ algo_type sshkex[] = { {"diffie-hellman-group16-sha512", 0, &kex_dh_group16_sha512, 1, NULL}, #endif #if DROPBEAR_KEXGUESS2 - {KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL}, + {KEXGUESS2_ALGO_NAME, 0, NULL, 1, NULL}, +#endif +#if DROPBEAR_CLIENT + /* Set unusable by svr_algos_initialise() */ + {SSH_EXT_INFO_C, 0, NULL, 1, NULL}, #endif {NULL, 0, NULL, 0, NULL} }; @@ -336,15 +342,79 @@ void buf_put_algolist(buffer * buf, const algo_type localalgos[]) { buf_free(algolist); } +/* returns a list of pointers into algolist, of null-terminated names. + ret_list should be passed in with space for *ret_count elements, + on return *ret_count has the number of names filled. + algolist is modified. */ +static void get_algolist(char* algolist, unsigned int algolist_len, + const char* *ret_list, unsigned int *ret_count) { + unsigned int max_count = *ret_count; + unsigned int i; + + if (*ret_count == 0) { + return; + } + if (algolist_len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) { + *ret_count = 0; + } + + /* ret_list will contain a list of the strings parsed out. + We will have at least one string (even if it's just "") */ + ret_list[0] = algolist; + *ret_count = 1; + for (i = 0; i < algolist_len; i++) { + if (algolist[i] == '\0') { + /* someone is trying something strange */ + *ret_count = 0; + return; + } + + if (algolist[i] == ',') { + if (*ret_count >= max_count) { + /* Too many */ + *ret_count = 0; + return; + } + algolist[i] = '\0'; + ret_list[*ret_count] = &algolist[i+1]; + (*ret_count)++; + } + } +} + +/* Return DROPBEAR_SUCCESS if the namelist contains algo, +DROPBEAR_FAILURE otherwise. buf position is not incremented. */ +int buf_has_algo(buffer *buf, const char *algo) { + unsigned char* algolist = NULL; + unsigned int orig_pos = buf->pos; + unsigned int len, remotecount, i; + const char *remotenames[MAX_PROPOSED_ALGO]; + int ret = DROPBEAR_FAILURE; + + algolist = buf_getstring(buf, &len); + remotecount = MAX_PROPOSED_ALGO; + get_algolist(algolist, len, remotenames, &remotecount); + for (i = 0; i < remotecount; i++) + { + if (strcmp(remotenames[i], algo) == 0) { + ret = DROPBEAR_SUCCESS; + break; + } + } + if (algolist) { + m_free(algolist); + } + buf_setpos(buf, orig_pos); + return ret; +} + /* match the first algorithm in the comma-separated list in buf which is * also in localalgos[], or return NULL on failure. * (*goodguess) is set to 1 if the preferred client/server algos match, * 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are * guessed correctly */ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[], - enum kexguess2_used *kexguess2, int *goodguess) -{ - + int kexguess2, int *goodguess) { char * algolist = NULL; const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO]; unsigned int len; @@ -359,40 +429,8 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[], /* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */ algolist = buf_getstring(buf, &len); TRACE(("buf_match_algo: %s", algolist)) - if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) { - goto out; - } - - /* remotenames will contain a list of the strings parsed out */ - /* We will have at least one string (even if it's just "") */ - remotenames[0] = algolist; - remotecount = 1; - for (i = 0; i < len; i++) { - if (algolist[i] == '\0') { - /* someone is trying something strange */ - goto out; - } - if (algolist[i] == ',') { - algolist[i] = '\0'; - remotenames[remotecount] = &algolist[i+1]; - remotecount++; - } - if (remotecount >= MAX_PROPOSED_ALGO) { - break; - } - } - if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) { - for (i = 0; i < remotecount; i++) - { - if (strcmp(remotenames[i], KEXGUESS2_ALGO_NAME) == 0) { - *kexguess2 = KEXGUESS2_YES; - break; - } - } - if (*kexguess2 == KEXGUESS2_LOOK) { - *kexguess2 = KEXGUESS2_NO; - } - } + remotecount = MAX_PROPOSED_ALGO; + get_algolist(algolist, len, remotenames, &remotecount); for (i = 0; localalgos[i].name != NULL; i++) { if (localalgos[i].usable) { @@ -424,12 +462,11 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[], } if (strcmp(servnames[j], clinames[i]) == 0) { /* set if it was a good guess */ - if (goodguess && kexguess2) { - if (*kexguess2 == KEXGUESS2_YES) { + if (goodguess != NULL) { + if (kexguess2) { if (i == 0) { *goodguess = 1; } - } else { if (i == 0 && j == 0) { *goodguess = 1; diff --git a/common-kex.c b/common-kex.c index c1392c1..8172796 100644 --- a/common-kex.c +++ b/common-kex.c @@ -820,21 +820,33 @@ static void read_kex_algos() { int goodguess = 0; int allgood = 1; /* we AND this with each goodguess and see if its still true after */ - -#if DROPBEAR_KEXGUESS2 - enum kexguess2_used kexguess2 = KEXGUESS2_LOOK; -#else - enum kexguess2_used kexguess2 = KEXGUESS2_NO; -#endif + int kexguess2 = 0; buf_incrpos(ses.payload, 16); /* start after the cookie */ memset(ses.newkeys, 0x0, sizeof(*ses.newkeys)); /* kex_algorithms */ - algo = buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess); +#if DROPBEAR_KEXGUESS2 + if (buf_has_algo(ses.payload, KEXGUESS2_ALGO_NAME) == DROPBEAR_SUCCESS) { + kexguess2 = 1; + } +#endif + + /* Determine if SSH_MSG_EXT_INFO messages should be sent. + Should be done for the first key exchange. */ + if (!ses.kexstate.donefirstkex) { + if (IS_DROPBEAR_SERVER) { + if (buf_has_algo(ses.payload, SSH_EXT_INFO_C) == DROPBEAR_SUCCESS) { + ses.allow_ext_info = 1; + } + } + } + + algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess); allgood &= goodguess; - if (algo == NULL || algo->val == KEXGUESS2_ALGO_ID) { + if (algo == NULL || algo->data == NULL) { + /* kexguess2, ext-info-c, ext-info-s should not match negotiation */ erralgo = "kex"; goto error; } @@ -843,7 +855,7 @@ static void read_kex_algos() { ses.newkeys->algo_kex = algo->data; /* server_host_key_algorithms */ - algo = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess); + algo = buf_match_algo(ses.payload, sshhostkey, kexguess2, &goodguess); allgood &= goodguess; if (algo == NULL) { erralgo = "hostkey"; diff --git a/fuzzer-verify.c b/fuzzer-verify.c index cda7723..cdf7804 100644 --- a/fuzzer-verify.c +++ b/fuzzer-verify.c @@ -29,7 +29,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { sign_key *key = new_sign_key(); enum signkey_type keytype = DROPBEAR_SIGNKEY_ANY; if (buf_get_pub_key(fuzz.input, key, &keytype) == DROPBEAR_SUCCESS) { - enum signature_type sigtype = (enum signature_type)keytype; + enum signature_type sigtype; if (keytype == DROPBEAR_SIGNKEY_RSA) { /* Flip a coin to decide rsa signature type */ int flag = buf_getbyte(fuzz_input); @@ -38,6 +38,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { } else { sigtype = DROPBEAR_SIGNATURE_RSA_SHA1; } + } else { + sigtype = signature_type_from_signkey(keytype); } if (buf_verify(fuzz.input, key, sigtype, verifydata) == DROPBEAR_SUCCESS) { /* The fuzzer is capable of generating keys with a signature to match. diff --git a/kex.h b/kex.h index 03dcbb1..3b0ec62 100644 --- a/kex.h +++ b/kex.h @@ -65,6 +65,8 @@ void recv_msg_kexdh_init(void); /* server */ void send_msg_kexdh_init(void); /* client */ void recv_msg_kexdh_reply(void); /* client */ +void recv_msg_ext_info(void); + struct KEXState { unsigned sentkexinit : 1; /*set when we've sent/recv kexinit packet */ diff --git a/session.h b/session.h index cbe9cb5..1059537 100644 --- a/session.h +++ b/session.h @@ -185,6 +185,9 @@ struct sshsession { /* Enables/disables compression */ algo_type *compress_algos; + + /* Other side allows SSH_MSG_EXT_INFO */ + int allow_ext_info; /* a list of queued replies that should be sent after a KEX has concluded (ie, while dataallowed was unset)*/ @@ -313,13 +316,7 @@ struct clientsession { #endif sign_key *lastprivkey; - enum signature_type server_sig_algs[DROPBEAR_SIGNKEY_NUM_NAMED+1]; - int server_sig_algs_count; -#if DROPBEAR_RSA - /* Set to DROPBEAR_SIGNATURE_RSA_SHA256 or DROPBEAR_SIGNATURE_RSA_SHA1 - if depending which the server accepts */ - enum signature_type preferred_rsa_sigtype; -#endif + buffer *server_sig_algs; int retval; /* What the command exit status was - we emulate it */ #if 0 diff --git a/signkey.c b/signkey.c index 47c8c8e..6ed1667 100644 --- a/signkey.c +++ b/signkey.c @@ -114,13 +114,17 @@ enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen) const char* signature_name_from_type(enum signature_type type, unsigned int *namelen) { #if DROPBEAR_RSA_SHA256 if (type == DROPBEAR_SIGNATURE_RSA_SHA256) { - *namelen = strlen(SSH_SIGNATURE_RSA_SHA256); + if (namelen) { + *namelen = strlen(SSH_SIGNATURE_RSA_SHA256); + } return SSH_SIGNATURE_RSA_SHA256; } #endif #if DROPBEAR_RSA_SHA1 if (type == DROPBEAR_SIGNATURE_RSA_SHA1) { - *namelen = strlen(SSH_SIGNKEY_RSA); + if (namelen) { + *namelen = strlen(SSH_SIGNKEY_RSA); + } return SSH_SIGNKEY_RSA; } #endif @@ -144,6 +148,16 @@ enum signature_type signature_type_from_name(const char* name, unsigned int name return (enum signature_type)signkey_type_from_name(name, namelen); } +/* Returns the signature type from a key type. Must not be called + with RSA keytype */ +enum signature_type signature_type_from_signkey(enum signkey_type keytype) { +#if DROPBEAR_RSA + assert(keytype != DROPBEAR_SIGNKEY_RSA); +#endif + assert(keytype < DROPBEAR_SIGNKEY_NUM_NAMED); + return (enum signature_type)keytype; +} + enum signkey_type signkey_type_from_signature(enum signature_type sigtype) { #if DROPBEAR_RSA_SHA256 if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) { @@ -587,8 +601,7 @@ void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype, #if DEBUG_TRACE { - int namelen; - const char* signame = signature_name_from_type(sigtype, &namelen); + const char* signame = signature_name_from_type(sigtype, NULL); TRACE(("buf_put_sign type %d %s", sigtype, signame)); } #endif diff --git a/signkey.h b/signkey.h index 9468509..2640171 100644 --- a/signkey.h +++ b/signkey.h @@ -120,6 +120,8 @@ enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen) const char* signature_name_from_type(enum signature_type type, unsigned int *namelen); enum signature_type signature_type_from_name(const char* name, unsigned int namelen); enum signkey_type signkey_type_from_signature(enum signature_type sigtype); +enum signature_type signature_type_from_signkey(enum signkey_type keytype); + int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type); int buf_get_priv_key(buffer* buf, sign_key *key, enum signkey_type *type); void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type); diff --git a/ssh.h b/ssh.h index 5030fe9..ee4a960 100644 --- a/ssh.h +++ b/ssh.h @@ -32,6 +32,7 @@ #define SSH_MSG_DEBUG 4 #define SSH_MSG_SERVICE_REQUEST 5 #define SSH_MSG_SERVICE_ACCEPT 6 +#define SSH_MSG_EXT_INFO 7 #define SSH_MSG_KEXINIT 20 #define SSH_MSG_NEWKEYS 21 #define SSH_MSG_KEXDH_INIT 30 @@ -94,6 +95,11 @@ #define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 #define SSH_DISCONNECT_ILLEGAL_USER_NAME 15 +/* rfc8308 */ +#define SSH_EXT_INFO_S "ext-info-s" +#define SSH_EXT_INFO_C "ext-info-c" +#define SSH_SERVER_SIG_ALGS "server-sig-algs" + /* service types */ #define SSH_SERVICE_USERAUTH "ssh-userauth" #define SSH_SERVICE_USERAUTH_LEN 12 diff --git a/svr-session.c b/svr-session.c index 0b9eac7..8bc8744 100644 --- a/svr-session.c +++ b/svr-session.c @@ -330,13 +330,16 @@ static void svr_remoteclosed() { } static void svr_algos_initialise(void) { -#if DROPBEAR_DH_GROUP1 && DROPBEAR_DH_GROUP1_CLIENTONLY algo_type *algo; for (algo = sshkex; algo->name; algo++) { +#if DROPBEAR_DH_GROUP1 && DROPBEAR_DH_GROUP1_CLIENTONLY if (strcmp(algo->name, "diffie-hellman-group1-sha1") == 0) { algo->usable = 0; } - } #endif + if (strcmp(algo->name, SSH_EXT_INFO_C) == 0) { + algo->usable = 0; + } + } } -- cgit v1.2.3 From 331d4a714f65772e384e15ff55b850a6e9e6786b Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 21 May 2020 23:00:22 +0800 Subject: Make server send SSH_MSG_EXT_INFO Ensure that only valid hostkey algorithms are sent in the first kex guess --- algo.h | 6 +++++- common-algo.c | 43 +++++++++++++++++++++++++++++++------------ common-kex.c | 27 ++++++++++++++------------- kex.h | 1 + svr-kex.c | 21 +++++++++++++++++++++ svr-runopts.c | 6 +++--- 6 files changed, 75 insertions(+), 29 deletions(-) (limited to 'common-algo.c') diff --git a/algo.h b/algo.h index 1565665..6f6da34 100644 --- a/algo.h +++ b/algo.h @@ -47,7 +47,7 @@ typedef struct Algo_Type algo_type; /* lists mapping ssh types of algorithms to internal values */ extern algo_type sshkex[]; -extern algo_type sshhostkey[]; +extern algo_type sigalgs[]; extern algo_type sshciphers[]; extern algo_type sshhashes[]; extern algo_type ssh_compress[]; @@ -112,11 +112,15 @@ struct dropbear_kex { const struct ltc_hash_descriptor *hash_desc; }; +/* Includes all algorithms is useall is set */ +void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall); +/* Includes "usable" algorithms */ void buf_put_algolist(buffer * buf, const algo_type localalgos[]); #define KEXGUESS2_ALGO_NAME "kexguess2@matt.ucc.asn.au" int buf_has_algo(buffer *buf, const char *algo); +algo_type * first_usable_algo(algo_type algos[]); algo_type * buf_match_algo(buffer* buf, algo_type localalgos[], int kexguess2, int *goodguess); diff --git a/common-algo.c b/common-algo.c index 938695d..54bc559 100644 --- a/common-algo.c +++ b/common-algo.c @@ -222,7 +222,7 @@ algo_type ssh_nocompress[] = { {NULL, 0, NULL, 0, NULL} }; -algo_type sshhostkey[] = { +algo_type sigalgs[] = { #if DROPBEAR_ED25519 {"ssh-ed25519", DROPBEAR_SIGNATURE_ED25519, NULL, 1, NULL}, #endif @@ -321,25 +321,34 @@ algo_type sshkex[] = { }; /* Output a comma separated list of algorithms to a buffer */ -void buf_put_algolist(buffer * buf, const algo_type localalgos[]) { - +void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall) { unsigned int i, len; unsigned int donefirst = 0; - buffer *algolist = NULL; + unsigned int startpos; - algolist = buf_new(300); + startpos = buf->pos; + /* Placeholder for length */ + buf_putint(buf, 0); for (i = 0; localalgos[i].name != NULL; i++) { - if (localalgos[i].usable) { - if (donefirst) - buf_putbyte(algolist, ','); + if (localalgos[i].usable || useall) { + if (donefirst) { + buf_putbyte(buf, ','); + } donefirst = 1; len = strlen(localalgos[i].name); - buf_putbytes(algolist, (const unsigned char *) localalgos[i].name, len); + buf_putbytes(buf, (const unsigned char *) localalgos[i].name, len); } } - buf_putstring(buf, (const char*)algolist->data, algolist->len); - TRACE(("algolist add '%*s'", algolist->len, algolist->data)) - buf_free(algolist); + /* Fill out the length */ + len = buf->pos - startpos - 4; + buf_setpos(buf, startpos); + buf_putint(buf, len); + TRACE(("algolist add %d '%*s'", len, len, buf_getptr(buf, len))) + buf_incrwritepos(buf, len); +} + +void buf_put_algolist(buffer * buf, const algo_type localalgos[]) { + buf_put_algolist_all(buf, localalgos, 0); } /* returns a list of pointers into algolist, of null-terminated names. @@ -408,6 +417,16 @@ int buf_has_algo(buffer *buf, const char *algo) { return ret; } +algo_type * first_usable_algo(algo_type algos[]) { + int i; + for (i = 0; algos[i].name != NULL; i++) { + if (algos[i].usable) { + return &algos[i]; + } + } + return NULL; +} + /* match the first algorithm in the comma-separated list in buf which is * also in localalgos[], or return NULL on failure. * (*goodguess) is set to 1 if the preferred client/server algos match, diff --git a/common-kex.c b/common-kex.c index 8172796..7063c81 100644 --- a/common-kex.c +++ b/common-kex.c @@ -65,7 +65,7 @@ void send_msg_kexinit() { buf_put_algolist(ses.writepayload, sshkex); /* server_host_key_algorithms */ - buf_put_algolist(ses.writepayload, sshhostkey); + buf_put_algolist(ses.writepayload, sigalgs); /* encryption_algorithms_client_to_server */ buf_put_algolist(ses.writepayload, sshciphers); @@ -110,8 +110,8 @@ void send_msg_kexinit() { ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context)); if (ses.send_kex_first_guess) { - ses.newkeys->algo_kex = sshkex[0].data; - ses.newkeys->algo_signature = sshhostkey[0].val; + ses.newkeys->algo_kex = first_usable_algo(sshkex)->data; + ses.newkeys->algo_signature = first_usable_algo(sigalgs)->val; ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature); ses.send_kex_first_guess(); } @@ -834,9 +834,10 @@ static void read_kex_algos() { #endif /* Determine if SSH_MSG_EXT_INFO messages should be sent. - Should be done for the first key exchange. */ - if (!ses.kexstate.donefirstkex) { - if (IS_DROPBEAR_SERVER) { + Should be done for the first key exchange. Only required on server side + for server-sig-algs */ + if (IS_DROPBEAR_SERVER) { + if (!ses.kexstate.donefirstkex) { if (buf_has_algo(ses.payload, SSH_EXT_INFO_C) == DROPBEAR_SUCCESS) { ses.allow_ext_info = 1; } @@ -855,7 +856,7 @@ static void read_kex_algos() { ses.newkeys->algo_kex = algo->data; /* server_host_key_algorithms */ - algo = buf_match_algo(ses.payload, sshhostkey, kexguess2, &goodguess); + algo = buf_match_algo(ses.payload, sigalgs, kexguess2, &goodguess); allgood &= goodguess; if (algo == NULL) { erralgo = "hostkey"; @@ -866,7 +867,7 @@ static void read_kex_algos() { ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature); /* encryption_algorithms_client_to_server */ - c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL); + c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL); if (c2s_cipher_algo == NULL) { erralgo = "enc c->s"; goto error; @@ -874,7 +875,7 @@ static void read_kex_algos() { TRACE(("enc c2s is %s", c2s_cipher_algo->name)) /* encryption_algorithms_server_to_client */ - s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL); + s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL); if (s2c_cipher_algo == NULL) { erralgo = "enc s->c"; goto error; @@ -882,7 +883,7 @@ static void read_kex_algos() { TRACE(("enc s2c is %s", s2c_cipher_algo->name)) /* mac_algorithms_client_to_server */ - c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL); + c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL); if (c2s_hash_algo == NULL) { erralgo = "mac c->s"; goto error; @@ -890,7 +891,7 @@ static void read_kex_algos() { TRACE(("hash c2s is %s", c2s_hash_algo->name)) /* mac_algorithms_server_to_client */ - s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL); + s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL); if (s2c_hash_algo == NULL) { erralgo = "mac s->c"; goto error; @@ -898,7 +899,7 @@ static void read_kex_algos() { TRACE(("hash s2c is %s", s2c_hash_algo->name)) /* compression_algorithms_client_to_server */ - c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL); + c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL); if (c2s_comp_algo == NULL) { erralgo = "comp c->s"; goto error; @@ -906,7 +907,7 @@ static void read_kex_algos() { TRACE(("hash c2s is %s", c2s_comp_algo->name)) /* compression_algorithms_server_to_client */ - s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL); + s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL); if (s2c_comp_algo == NULL) { erralgo = "comp s->c"; goto error; diff --git a/kex.h b/kex.h index 3b0ec62..cdec673 100644 --- a/kex.h +++ b/kex.h @@ -61,6 +61,7 @@ int is_compress_recv(void); #endif void recv_msg_kexdh_init(void); /* server */ +void send_msg_ext_info(void); /* server */ void send_msg_kexdh_init(void); /* client */ void recv_msg_kexdh_reply(void); /* client */ diff --git a/svr-kex.c b/svr-kex.c index e3e63d0..44e10ff 100644 --- a/svr-kex.c +++ b/svr-kex.c @@ -86,6 +86,11 @@ void recv_msg_kexdh_init() { } send_msg_newkeys(); + + if (ses.allow_ext_info) { + send_msg_ext_info(); + } + ses.requirenext = SSH_MSG_NEWKEYS; TRACE(("leave recv_msg_kexdh_init")) } @@ -242,3 +247,19 @@ static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) { TRACE(("leave send_msg_kexdh_reply")) } +/* Only used for server-sig-algs on the server side */ +void send_msg_ext_info(void) { + TRACE(("enter send_msg_ext_info")) + + buf_putbyte(ses.writepayload, SSH_MSG_EXT_INFO); + /* nr-extensions */ + buf_putint(ses.writepayload, 1); + + buf_putstring(ses.writepayload, SSH_SERVER_SIG_ALGS, strlen(SSH_SERVER_SIG_ALGS)); + buf_put_algolist_all(ses.writepayload, sigalgs, 1); + + encrypt_packet(); + + TRACE(("leave send_msg_ext_info")) + +} diff --git a/svr-runopts.c b/svr-runopts.c index d430825..770f70a 100644 --- a/svr-runopts.c +++ b/svr-runopts.c @@ -485,9 +485,9 @@ static void addportandaddress(const char* spec) { static void disablekey(int type) { int i; TRACE(("Disabling key type %d", type)) - for (i = 0; sshhostkey[i].name != NULL; i++) { - if (sshhostkey[i].val == type) { - sshhostkey[i].usable = 0; + for (i = 0; sigalgs[i].name != NULL; i++) { + if (sigalgs[i].val == type) { + sigalgs[i].usable = 0; break; } } -- cgit v1.2.3 From 701d43b8594365b55421e8bc4c53efa920c09ed5 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 24 May 2020 14:16:58 +0800 Subject: send and handle SSH_MSG_EXT_INFO only at the correct point - other fixes for rsa pubkey auth - only include ext-info handling when rsa pubkey auth is compiled --- cli-authpubkey.c | 4 ++-- cli-kex.c | 10 ++++++++++ common-algo.c | 2 ++ common-kex.c | 7 +++++-- dropbearkey.c | 2 +- kex.h | 4 ++-- process-packet.c | 3 +-- session.h | 12 +++++------- signkey.c | 2 +- svr-kex.c | 14 ++++++++++---- svr-runopts.c | 2 +- svr-session.c | 2 ++ sysoptions.h | 4 ++++ 13 files changed, 46 insertions(+), 22 deletions(-) (limited to 'common-algo.c') diff --git a/cli-authpubkey.c b/cli-authpubkey.c index 8426e84..49f79c3 100644 --- a/cli-authpubkey.c +++ b/cli-authpubkey.c @@ -200,7 +200,7 @@ int cli_auth_pubkey() { while (cli_opts.privkeys->first) { sign_key * key = (sign_key*)cli_opts.privkeys->first->item; if (cli_ses.server_sig_algs) { -#ifdef DROPBEAR_RSA +#if DROPBEAR_RSA if (key->type == DROPBEAR_SIGNKEY_RSA) { #if DROPBEAR_RSA_SHA256 if (buf_has_algo(cli_ses.server_sig_algs, SSH_SIGNATURE_RSA_SHA256) @@ -242,7 +242,7 @@ int cli_auth_pubkey() { assume all except rsa-sha256 are OK. */ #if DROPBEAR_RSA if (key->type == DROPBEAR_SIGNKEY_RSA) { -#ifdef DROPBEAR_RSA_SHA1 +#if DROPBEAR_RSA_SHA1 sigtype = DROPBEAR_SIGNATURE_RSA_SHA1; TRACE(("no server-sig-algs, using rsa sha1")) break; diff --git a/cli-kex.c b/cli-kex.c index 99370eb..98b0245 100644 --- a/cli-kex.c +++ b/cli-kex.c @@ -418,6 +418,15 @@ void recv_msg_ext_info(void) { unsigned int num_ext; unsigned int i; + TRACE(("enter recv_msg_ext_info")) + + /* Must be after the first SSH_MSG_NEWKEYS */ + TRACE(("last %d, donefirst %d, donescond %d", ses.lastpacket, ses.kexstate.donefirstkex, ses.kexstate.donesecondkex)) + if (!(ses.lastpacket == SSH_MSG_NEWKEYS && !ses.kexstate.donesecondkex)) { + TRACE(("leave recv_msg_ext_info: ignoring packet received at the wrong time")) + return; + } + num_ext = buf_getint(ses.payload); TRACE(("received SSH_MSG_EXT_INFO with %d items", num_ext)) @@ -435,4 +444,5 @@ void recv_msg_ext_info(void) { } m_free(ext_name); } + TRACE(("leave recv_msg_ext_info")) } diff --git a/common-algo.c b/common-algo.c index 54bc559..8596831 100644 --- a/common-algo.c +++ b/common-algo.c @@ -313,9 +313,11 @@ algo_type sshkex[] = { #if DROPBEAR_KEXGUESS2 {KEXGUESS2_ALGO_NAME, 0, NULL, 1, NULL}, #endif +#if DROPBEAR_EXT_INFO #if DROPBEAR_CLIENT /* Set unusable by svr_algos_initialise() */ {SSH_EXT_INFO_C, 0, NULL, 1, NULL}, +#endif #endif {NULL, 0, NULL, 0, NULL} }; diff --git a/common-kex.c b/common-kex.c index 7063c81..1ef1946 100644 --- a/common-kex.c +++ b/common-kex.c @@ -175,6 +175,9 @@ void send_msg_newkeys() { /* set up our state */ ses.kexstate.sentnewkeys = 1; + if (ses.kexstate.donefirstkex) { + ses.kexstate.donesecondkex = 1; + } ses.kexstate.donefirstkex = 1; ses.dataallowed = 1; /* we can send other packets again now */ gen_new_keys(); @@ -197,8 +200,6 @@ void recv_msg_newkeys() { /* Set up the kex for the first time */ void kexfirstinitialise() { - ses.kexstate.donefirstkex = 0; - #ifdef DISABLE_ZLIB ses.compress_algos = ssh_nocompress; #else @@ -833,6 +834,7 @@ static void read_kex_algos() { } #endif +#if DROPBEAR_EXT_INFO /* Determine if SSH_MSG_EXT_INFO messages should be sent. Should be done for the first key exchange. Only required on server side for server-sig-algs */ @@ -843,6 +845,7 @@ static void read_kex_algos() { } } } +#endif algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess); allgood &= goodguess; diff --git a/dropbearkey.c b/dropbearkey.c index f881855..8d8c7c2 100644 --- a/dropbearkey.c +++ b/dropbearkey.c @@ -133,7 +133,7 @@ static void check_signkey_bits(enum signkey_type type, int bits) } break; #endif -#ifdef DROPEAR_DSS +#if DROPEAR_DSS case DROPBEAR_SIGNKEY_DSS: if (bits != 1024) { dropbear_exit("DSS keys have a fixed size of 1024 bits\n"); diff --git a/kex.h b/kex.h index cdec673..7406f65 100644 --- a/kex.h +++ b/kex.h @@ -61,7 +61,6 @@ int is_compress_recv(void); #endif void recv_msg_kexdh_init(void); /* server */ -void send_msg_ext_info(void); /* server */ void send_msg_kexdh_init(void); /* client */ void recv_msg_kexdh_reply(void); /* client */ @@ -76,8 +75,9 @@ struct KEXState { unsigned sentnewkeys : 1; /* set once we've send MSG_NEWKEYS (will be cleared once we have also received */ unsigned recvnewkeys : 1; /* set once we've received MSG_NEWKEYS (cleared once we have also sent */ - unsigned donefirstkex : 1; /* Set to 1 after the first kex has completed, + unsigned int donefirstkex; /* Set to 1 after the first kex has completed, ie the transport layer has been set up */ + unsigned int donesecondkex; /* Set to 1 after the second kex has completed */ unsigned our_first_follows_matches : 1; diff --git a/process-packet.c b/process-packet.c index 4953cf2..9c58c7c 100644 --- a/process-packet.c +++ b/process-packet.c @@ -51,8 +51,6 @@ void process_packet() { type = buf_getbyte(ses.payload); TRACE(("process_packet: packet type = %d, len %d", type, ses.payload->len)) - ses.lastpacket = type; - now = monotonic_now(); ses.last_packet_time_keepalive_recv = now; @@ -154,6 +152,7 @@ void process_packet() { recv_unimplemented(); out: + ses.lastpacket = type; buf_free(ses.payload); ses.payload = NULL; diff --git a/session.h b/session.h index 1059537..a91401e 100644 --- a/session.h +++ b/session.h @@ -186,7 +186,7 @@ struct sshsession { /* Enables/disables compression */ algo_type *compress_algos; - /* Other side allows SSH_MSG_EXT_INFO */ + /* Other side allows SSH_MSG_EXT_INFO. Currently only set for server */ int allow_ext_info; /* a list of queued replies that should be sent after a KEX has @@ -253,13 +253,12 @@ struct serversession { #endif #if DROPBEAR_PLUGIN - /* The shared library handle */ - void *plugin_handle; + /* The shared library handle */ + void *plugin_handle; - /* The instance created by the plugin_new function */ - struct PluginInstance *plugin_instance; + /* The instance created by the plugin_new function */ + struct PluginInstance *plugin_instance; #endif - }; typedef enum { @@ -288,7 +287,6 @@ struct clientsession { cli_kex_state kex_state; /* Used for progressing KEX */ cli_state state; /* Used to progress auth/channelsession etc */ - unsigned donefirstkex : 1; /* Set when we set sentnewkeys, never reset */ int tty_raw_mode; /* Whether we're in raw mode (and have to clean up) */ struct termios saved_tio; diff --git a/signkey.c b/signkey.c index 6ed1667..49801f3 100644 --- a/signkey.c +++ b/signkey.c @@ -139,7 +139,7 @@ enum signature_type signature_type_from_name(const char* name, unsigned int name return DROPBEAR_SIGNATURE_RSA_SHA256; } #endif -#if DROPBEAR_RSA_SHA256 +#if DROPBEAR_RSA_SHA1 if (namelen == strlen(SSH_SIGNKEY_RSA) && memcmp(name, SSH_SIGNKEY_RSA, namelen) == 0) { return DROPBEAR_SIGNATURE_RSA_SHA1; diff --git a/svr-kex.c b/svr-kex.c index 44e10ff..df1008b 100644 --- a/svr-kex.c +++ b/svr-kex.c @@ -38,13 +38,15 @@ #include "gensignkey.h" static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs); +#if DROPBEAR_EXT_INFO +static void send_msg_ext_info(void); +#endif /* Handle a diffie-hellman key exchange initialisation. This involves * calculating a session key reply value, and corresponding hash. These * are carried out by send_msg_kexdh_reply(). recv_msg_kexdh_init() calls * that function, then brings the new keys into use */ void recv_msg_kexdh_init() { - DEF_MP_INT(dh_e); buffer *ecdh_qs = NULL; @@ -87,9 +89,12 @@ void recv_msg_kexdh_init() { send_msg_newkeys(); - if (ses.allow_ext_info) { +#if DROPBEAR_EXT_INFO + /* Only send it following the first newkeys */ + if (!ses.kexstate.donesecondkex && ses.allow_ext_info) { send_msg_ext_info(); } +#endif ses.requirenext = SSH_MSG_NEWKEYS; TRACE(("leave recv_msg_kexdh_init")) @@ -247,8 +252,9 @@ static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) { TRACE(("leave send_msg_kexdh_reply")) } +#if DROPBEAR_EXT_INFO /* Only used for server-sig-algs on the server side */ -void send_msg_ext_info(void) { +static void send_msg_ext_info(void) { TRACE(("enter send_msg_ext_info")) buf_putbyte(ses.writepayload, SSH_MSG_EXT_INFO); @@ -261,5 +267,5 @@ void send_msg_ext_info(void) { encrypt_packet(); TRACE(("leave send_msg_ext_info")) - } +#endif diff --git a/svr-runopts.c b/svr-runopts.c index 770f70a..2c905dd 100644 --- a/svr-runopts.c +++ b/svr-runopts.c @@ -567,7 +567,7 @@ static void addhostkey(const char *keyfile) { void load_all_hostkeys() { int i; int any_keys = 0; -#ifdef DROPBEAR_ECDSA +#if DROPBEAR_ECDSA int loaded_any_ecdsa = 0; #endif diff --git a/svr-session.c b/svr-session.c index 8bc8744..6c3147f 100644 --- a/svr-session.c +++ b/svr-session.c @@ -337,9 +337,11 @@ static void svr_algos_initialise(void) { algo->usable = 0; } #endif +#if DROPBEAR_EXT_INFO if (strcmp(algo->name, SSH_EXT_INFO_C) == 0) { algo->usable = 0; } +#endif } } diff --git a/sysoptions.h b/sysoptions.h index 0f52431..d5f8da8 100644 --- a/sysoptions.h +++ b/sysoptions.h @@ -161,6 +161,10 @@ If you test it please contact the Dropbear author */ #define DROPBEAR_NORMAL_DH ((DROPBEAR_DH_GROUP1) || (DROPBEAR_DH_GROUP14) || (DROPBEAR_DH_GROUP16)) +/* Dropbear only uses server-sig-algs, only needed if we have rsa-sha256 pubkey auth */ +#define DROPBEAR_EXT_INFO ((DROPBEAR_RSA_SHA256) \ + && ((DROPBEAR_CLI_PUBKEY_AUTH) || (DROPBEAR_SVR_PUBKEY_AUTH))) + /* roughly 2x 521 bits */ #define MAX_ECC_SIZE 140 -- cgit v1.2.3