kex: also compare host keys for 'first_kex_packet_follows'

Also consider the host key type at hand when computing whether a
'first_kex_packet_follows' packet matches the current server settings.
Without this change libssh may incorrectly believe that guessed
settings which match by kex algorithm alone fully match: the host
key types must also match.  Observed when testing with dropbear
clients.

Signed-off-by: Jon Simons <jon@jonsimons.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
Jon Simons
2015-05-04 16:22:35 -07:00
committed by Andreas Schneider
parent f134cb3d57
commit ee460dc04b

View File

@@ -279,43 +279,43 @@ char *ssh_find_matching(const char *available_d, const char *preferred_d){
/** /**
* @internal * @internal
* @brief returns whether the first client key exchange algorithm matches * @brief returns whether the first client key exchange algorithm or
* the first server key exchange algorithm * hostkey type matches its server counterpart
* @returns whether the first client key exchange algorithm matches * @returns whether the first client key exchange algorithm or hostkey type
* the first server key exchange algorithm * matches its server counterpart
*/ */
static int is_first_kex_packet_follows_guess_wrong(const char *client_kex, static int cmp_first_kex_algo(const char *client_str,
const char *server_kex) { const char *server_str) {
int is_wrong = 1; int is_wrong = 1;
char **server_kex_tokens = NULL; char **server_str_tokens = NULL;
char **client_kex_tokens = NULL; char **client_str_tokens = NULL;
if ((client_kex == NULL) || (server_kex == NULL)) { if ((client_str == NULL) || (server_str == NULL)) {
goto out; goto out;
} }
client_kex_tokens = tokenize(client_kex); client_str_tokens = tokenize(client_str);
if (client_kex_tokens == NULL) { if (client_str_tokens == NULL) {
goto out; goto out;
} }
if (client_kex_tokens[0] == NULL) { if (client_str_tokens[0] == NULL) {
goto freeout; goto freeout;
} }
server_kex_tokens = tokenize(server_kex); server_str_tokens = tokenize(server_str);
if (server_kex_tokens == NULL) { if (server_str_tokens == NULL) {
goto freeout; goto freeout;
} }
is_wrong = (strcmp(client_kex_tokens[0], server_kex_tokens[0]) != 0); is_wrong = (strcmp(client_str_tokens[0], server_str_tokens[0]) != 0);
SAFE_FREE(server_kex_tokens[0]); SAFE_FREE(server_str_tokens[0]);
SAFE_FREE(server_kex_tokens); SAFE_FREE(server_str_tokens);
freeout: freeout:
SAFE_FREE(client_kex_tokens[0]); SAFE_FREE(client_str_tokens[0]);
SAFE_FREE(client_kex_tokens); SAFE_FREE(client_str_tokens);
out: out:
return is_wrong; return is_wrong;
} }
@@ -432,8 +432,10 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit){
*/ */
if (first_kex_packet_follows) { if (first_kex_packet_follows) {
session->first_kex_follows_guess_wrong = session->first_kex_follows_guess_wrong =
is_first_kex_packet_follows_guess_wrong(session->next_crypto->client_kex.methods[SSH_KEX], cmp_first_kex_algo(session->next_crypto->client_kex.methods[SSH_KEX],
session->next_crypto->server_kex.methods[SSH_KEX]); session->next_crypto->server_kex.methods[SSH_KEX]) ||
cmp_first_kex_algo(session->next_crypto->client_kex.methods[SSH_HOSTKEYS],
session->next_crypto->server_kex.methods[SSH_HOSTKEYS]);
} }
} }