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
This commit is contained in:
Matt Johnston 2020-05-24 14:16:58 +08:00
parent 79bedc90a1
commit 701d43b859
13 changed files with 46 additions and 22 deletions

View File

@ -200,7 +200,7 @@ int cli_auth_pubkey() {
while (cli_opts.privkeys->first) { while (cli_opts.privkeys->first) {
sign_key * key = (sign_key*)cli_opts.privkeys->first->item; sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
if (cli_ses.server_sig_algs) { if (cli_ses.server_sig_algs) {
#ifdef DROPBEAR_RSA #if DROPBEAR_RSA
if (key->type == DROPBEAR_SIGNKEY_RSA) { if (key->type == DROPBEAR_SIGNKEY_RSA) {
#if DROPBEAR_RSA_SHA256 #if DROPBEAR_RSA_SHA256
if (buf_has_algo(cli_ses.server_sig_algs, SSH_SIGNATURE_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. */ assume all except rsa-sha256 are OK. */
#if DROPBEAR_RSA #if DROPBEAR_RSA
if (key->type == DROPBEAR_SIGNKEY_RSA) { if (key->type == DROPBEAR_SIGNKEY_RSA) {
#ifdef DROPBEAR_RSA_SHA1 #if DROPBEAR_RSA_SHA1
sigtype = DROPBEAR_SIGNATURE_RSA_SHA1; sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
TRACE(("no server-sig-algs, using rsa sha1")) TRACE(("no server-sig-algs, using rsa sha1"))
break; break;

View File

@ -418,6 +418,15 @@ void recv_msg_ext_info(void) {
unsigned int num_ext; unsigned int num_ext;
unsigned int i; 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); num_ext = buf_getint(ses.payload);
TRACE(("received SSH_MSG_EXT_INFO with %d items", num_ext)) 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); m_free(ext_name);
} }
TRACE(("leave recv_msg_ext_info"))
} }

View File

@ -313,9 +313,11 @@ algo_type sshkex[] = {
#if DROPBEAR_KEXGUESS2 #if DROPBEAR_KEXGUESS2
{KEXGUESS2_ALGO_NAME, 0, NULL, 1, NULL}, {KEXGUESS2_ALGO_NAME, 0, NULL, 1, NULL},
#endif #endif
#if DROPBEAR_EXT_INFO
#if DROPBEAR_CLIENT #if DROPBEAR_CLIENT
/* Set unusable by svr_algos_initialise() */ /* Set unusable by svr_algos_initialise() */
{SSH_EXT_INFO_C, 0, NULL, 1, NULL}, {SSH_EXT_INFO_C, 0, NULL, 1, NULL},
#endif
#endif #endif
{NULL, 0, NULL, 0, NULL} {NULL, 0, NULL, 0, NULL}
}; };

View File

@ -175,6 +175,9 @@ void send_msg_newkeys() {
/* set up our state */ /* set up our state */
ses.kexstate.sentnewkeys = 1; ses.kexstate.sentnewkeys = 1;
if (ses.kexstate.donefirstkex) {
ses.kexstate.donesecondkex = 1;
}
ses.kexstate.donefirstkex = 1; ses.kexstate.donefirstkex = 1;
ses.dataallowed = 1; /* we can send other packets again now */ ses.dataallowed = 1; /* we can send other packets again now */
gen_new_keys(); gen_new_keys();
@ -197,8 +200,6 @@ void recv_msg_newkeys() {
/* Set up the kex for the first time */ /* Set up the kex for the first time */
void kexfirstinitialise() { void kexfirstinitialise() {
ses.kexstate.donefirstkex = 0;
#ifdef DISABLE_ZLIB #ifdef DISABLE_ZLIB
ses.compress_algos = ssh_nocompress; ses.compress_algos = ssh_nocompress;
#else #else
@ -833,6 +834,7 @@ static void read_kex_algos() {
} }
#endif #endif
#if DROPBEAR_EXT_INFO
/* Determine if SSH_MSG_EXT_INFO messages should be sent. /* Determine if SSH_MSG_EXT_INFO messages should be sent.
Should be done for the first key exchange. Only required on server side Should be done for the first key exchange. Only required on server side
for server-sig-algs */ for server-sig-algs */
@ -843,6 +845,7 @@ static void read_kex_algos() {
} }
} }
} }
#endif
algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess); algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess);
allgood &= goodguess; allgood &= goodguess;

View File

@ -133,7 +133,7 @@ static void check_signkey_bits(enum signkey_type type, int bits)
} }
break; break;
#endif #endif
#ifdef DROPEAR_DSS #if DROPEAR_DSS
case DROPBEAR_SIGNKEY_DSS: case DROPBEAR_SIGNKEY_DSS:
if (bits != 1024) { if (bits != 1024) {
dropbear_exit("DSS keys have a fixed size of 1024 bits\n"); dropbear_exit("DSS keys have a fixed size of 1024 bits\n");

4
kex.h
View File

@ -61,7 +61,6 @@ int is_compress_recv(void);
#endif #endif
void recv_msg_kexdh_init(void); /* server */ void recv_msg_kexdh_init(void); /* server */
void send_msg_ext_info(void); /* server */
void send_msg_kexdh_init(void); /* client */ void send_msg_kexdh_init(void); /* client */
void recv_msg_kexdh_reply(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 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 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 */ 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; unsigned our_first_follows_matches : 1;

View File

@ -51,8 +51,6 @@ void process_packet() {
type = buf_getbyte(ses.payload); type = buf_getbyte(ses.payload);
TRACE(("process_packet: packet type = %d, len %d", type, ses.payload->len)) TRACE(("process_packet: packet type = %d, len %d", type, ses.payload->len))
ses.lastpacket = type;
now = monotonic_now(); now = monotonic_now();
ses.last_packet_time_keepalive_recv = now; ses.last_packet_time_keepalive_recv = now;
@ -154,6 +152,7 @@ void process_packet() {
recv_unimplemented(); recv_unimplemented();
out: out:
ses.lastpacket = type;
buf_free(ses.payload); buf_free(ses.payload);
ses.payload = NULL; ses.payload = NULL;

View File

@ -186,7 +186,7 @@ struct sshsession {
/* Enables/disables compression */ /* Enables/disables compression */
algo_type *compress_algos; 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; int allow_ext_info;
/* a list of queued replies that should be sent after a KEX has /* a list of queued replies that should be sent after a KEX has
@ -259,7 +259,6 @@ struct serversession {
/* The instance created by the plugin_new function */ /* The instance created by the plugin_new function */
struct PluginInstance *plugin_instance; struct PluginInstance *plugin_instance;
#endif #endif
}; };
typedef enum { typedef enum {
@ -288,7 +287,6 @@ struct clientsession {
cli_kex_state kex_state; /* Used for progressing KEX */ cli_kex_state kex_state; /* Used for progressing KEX */
cli_state state; /* Used to progress auth/channelsession etc */ 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) */ int tty_raw_mode; /* Whether we're in raw mode (and have to clean up) */
struct termios saved_tio; struct termios saved_tio;

View File

@ -139,7 +139,7 @@ enum signature_type signature_type_from_name(const char* name, unsigned int name
return DROPBEAR_SIGNATURE_RSA_SHA256; return DROPBEAR_SIGNATURE_RSA_SHA256;
} }
#endif #endif
#if DROPBEAR_RSA_SHA256 #if DROPBEAR_RSA_SHA1
if (namelen == strlen(SSH_SIGNKEY_RSA) if (namelen == strlen(SSH_SIGNKEY_RSA)
&& memcmp(name, SSH_SIGNKEY_RSA, namelen) == 0) { && memcmp(name, SSH_SIGNKEY_RSA, namelen) == 0) {
return DROPBEAR_SIGNATURE_RSA_SHA1; return DROPBEAR_SIGNATURE_RSA_SHA1;

View File

@ -38,13 +38,15 @@
#include "gensignkey.h" #include "gensignkey.h"
static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs); 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 /* Handle a diffie-hellman key exchange initialisation. This involves
* calculating a session key reply value, and corresponding hash. These * calculating a session key reply value, and corresponding hash. These
* are carried out by send_msg_kexdh_reply(). recv_msg_kexdh_init() calls * are carried out by send_msg_kexdh_reply(). recv_msg_kexdh_init() calls
* that function, then brings the new keys into use */ * that function, then brings the new keys into use */
void recv_msg_kexdh_init() { void recv_msg_kexdh_init() {
DEF_MP_INT(dh_e); DEF_MP_INT(dh_e);
buffer *ecdh_qs = NULL; buffer *ecdh_qs = NULL;
@ -87,9 +89,12 @@ void recv_msg_kexdh_init() {
send_msg_newkeys(); 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(); send_msg_ext_info();
} }
#endif
ses.requirenext = SSH_MSG_NEWKEYS; ses.requirenext = SSH_MSG_NEWKEYS;
TRACE(("leave recv_msg_kexdh_init")) 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")) TRACE(("leave send_msg_kexdh_reply"))
} }
#if DROPBEAR_EXT_INFO
/* Only used for server-sig-algs on the server side */ /* 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")) TRACE(("enter send_msg_ext_info"))
buf_putbyte(ses.writepayload, SSH_MSG_EXT_INFO); buf_putbyte(ses.writepayload, SSH_MSG_EXT_INFO);
@ -261,5 +267,5 @@ void send_msg_ext_info(void) {
encrypt_packet(); encrypt_packet();
TRACE(("leave send_msg_ext_info")) TRACE(("leave send_msg_ext_info"))
} }
#endif

View File

@ -567,7 +567,7 @@ static void addhostkey(const char *keyfile) {
void load_all_hostkeys() { void load_all_hostkeys() {
int i; int i;
int any_keys = 0; int any_keys = 0;
#ifdef DROPBEAR_ECDSA #if DROPBEAR_ECDSA
int loaded_any_ecdsa = 0; int loaded_any_ecdsa = 0;
#endif #endif

View File

@ -337,9 +337,11 @@ static void svr_algos_initialise(void) {
algo->usable = 0; algo->usable = 0;
} }
#endif #endif
#if DROPBEAR_EXT_INFO
if (strcmp(algo->name, SSH_EXT_INFO_C) == 0) { if (strcmp(algo->name, SSH_EXT_INFO_C) == 0) {
algo->usable = 0; algo->usable = 0;
} }
#endif
} }
} }

View File

@ -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)) #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 */ /* roughly 2x 521 bits */
#define MAX_ECC_SIZE 140 #define MAX_ECC_SIZE 140