diff options
Diffstat (limited to 'libs/libssh2/src/kex.c')
-rw-r--r-- | libs/libssh2/src/kex.c | 456 |
1 files changed, 321 insertions, 135 deletions
diff --git a/libs/libssh2/src/kex.c b/libs/libssh2/src/kex.c index 8c65a0fee6..4ca9c34c74 100644 --- a/libs/libssh2/src/kex.c +++ b/libs/libssh2/src/kex.c @@ -228,6 +228,60 @@ static void _libssh2_sha_algo_value_hash(int sha_algo, } +static void +diffie_hellman_state_cleanup(LIBSSH2_SESSION * session, + kmdhgGPshakex_state_t *exchange_state) +{ + libssh2_dh_dtor(&exchange_state->x); + _libssh2_bn_free(exchange_state->e); + exchange_state->e = NULL; + _libssh2_bn_free(exchange_state->f); + exchange_state->f = NULL; + _libssh2_bn_free(exchange_state->k); + exchange_state->k = NULL; + _libssh2_bn_ctx_free(exchange_state->ctx); + exchange_state->ctx = NULL; + + if(exchange_state->e_packet) { + LIBSSH2_FREE(session, exchange_state->e_packet); + exchange_state->e_packet = NULL; + } + + if(exchange_state->s_packet) { + LIBSSH2_FREE(session, exchange_state->s_packet); + exchange_state->s_packet = NULL; + } + + if(exchange_state->k_value) { + LIBSSH2_FREE(session, exchange_state->k_value); + exchange_state->k_value = NULL; + } + + exchange_state->state = libssh2_NB_state_idle; +} + +static void +kex_diffie_hellman_cleanup(LIBSSH2_SESSION * session, + key_exchange_state_low_t * key_state) { + if(key_state->state != libssh2_NB_state_idle) { + _libssh2_bn_free(key_state->p); + key_state->p = NULL; + _libssh2_bn_free(key_state->g); + key_state->g = NULL; + + if(key_state->data) { + LIBSSH2_FREE(session, key_state->data); + key_state->data = NULL; + } + key_state->state = libssh2_NB_state_idle; + } + + if(key_state->exchange_state.state != libssh2_NB_state_idle) { + diffie_hellman_state_cleanup(session, &key_state->exchange_state); + } +} + + /*! * @function diffie_hellman_sha_algo * @abstract Diffie Hellman Key Exchange, Group Agnostic, @@ -316,13 +370,21 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, _libssh2_htonu32(exchange_state->e_packet + 1, (uint32_t)(exchange_state->e_packet_len - 5)); if(_libssh2_bn_bits(exchange_state->e) % 8) { - _libssh2_bn_to_bin(exchange_state->e, - exchange_state->e_packet + 5); + if(_libssh2_bn_to_bin(exchange_state->e, + exchange_state->e_packet + 5)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Can't write exchange_state->e"); + goto clean_exit; + } } else { exchange_state->e_packet[5] = 0; - _libssh2_bn_to_bin(exchange_state->e, - exchange_state->e_packet + 6); + if(_libssh2_bn_to_bin(exchange_state->e, + exchange_state->e_packet + 6)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Can't write exchange_state->e"); + goto clean_exit; + } } _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Sending KEX packet %u", @@ -407,8 +469,11 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, buf.dataptr = buf.data; buf.dataptr++; /* advance past type */ - if(session->server_hostkey) + if(session->server_hostkey) { LIBSSH2_FREE(session, session->server_hostkey); + session->server_hostkey = NULL; + session->server_hostkey_len = 0; + } if(_libssh2_copy_string(session, &buf, &(session->server_hostkey), &host_key_len)) { @@ -522,8 +587,13 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, goto clean_exit; } - _libssh2_bn_from_bin(exchange_state->f, exchange_state->f_value_len, - exchange_state->f_value); + if(_libssh2_bn_from_bin(exchange_state->f, + exchange_state->f_value_len, + exchange_state->f_value)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, + "Invalid DH-SHA f value"); + goto clean_exit; + } if(_libssh2_get_string(&buf, &(exchange_state->h_sig), &(exchange_state->h_sig_len))) { @@ -550,11 +620,21 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, _libssh2_htonu32(exchange_state->k_value, (uint32_t)(exchange_state->k_value_len - 4)); if(_libssh2_bn_bits(exchange_state->k) % 8) { - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4); + if(_libssh2_bn_to_bin(exchange_state->k, + exchange_state->k_value + 4)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Can't write exchange_state->k"); + goto clean_exit; + } } else { exchange_state->k_value[4] = 0; - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5); + if(_libssh2_bn_to_bin(exchange_state->k, + exchange_state->k_value + 5)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Can't write exchange_state->k"); + goto clean_exit; + } } exchange_state->exchange_hash = (void *)&exchange_hash_ctx; @@ -933,32 +1013,7 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, } clean_exit: - libssh2_dh_dtor(&exchange_state->x); - _libssh2_bn_free(exchange_state->e); - exchange_state->e = NULL; - _libssh2_bn_free(exchange_state->f); - exchange_state->f = NULL; - _libssh2_bn_free(exchange_state->k); - exchange_state->k = NULL; - _libssh2_bn_ctx_free(exchange_state->ctx); - exchange_state->ctx = NULL; - - if(exchange_state->e_packet) { - LIBSSH2_FREE(session, exchange_state->e_packet); - exchange_state->e_packet = NULL; - } - - if(exchange_state->s_packet) { - LIBSSH2_FREE(session, exchange_state->s_packet); - exchange_state->s_packet = NULL; - } - - if(exchange_state->k_value) { - LIBSSH2_FREE(session, exchange_state->k_value); - exchange_state->k_value = NULL; - } - - exchange_state->state = libssh2_NB_state_idle; + diffie_hellman_state_cleanup(session, exchange_state); return ret; } @@ -1002,8 +1057,16 @@ kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *session, key_state->g = _libssh2_bn_init(); /* SSH2 defined value (2) */ /* Initialize P and G */ - _libssh2_bn_set_word(key_state->g, 2); - _libssh2_bn_from_bin(key_state->p, 128, p_value); + if(!key_state->g || _libssh2_bn_set_word(key_state->g, 2)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to allocate key state g."); + goto clean_exit; + } + if(!key_state->p || _libssh2_bn_from_bin(key_state->p, 128, p_value)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to allocate key state p."); + goto clean_exit; + } _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Initiating Diffie-Hellman Group1 Key Exchange")); @@ -1019,11 +1082,8 @@ kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *session, return ret; } - _libssh2_bn_free(key_state->p); - key_state->p = NULL; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; - key_state->state = libssh2_NB_state_idle; +clean_exit: + kex_diffie_hellman_cleanup(session, key_state); return ret; } @@ -1095,8 +1155,17 @@ kex_method_diffie_hellman_group14_key_exchange(LIBSSH2_SESSION *session, /* g == 2 */ /* Initialize P and G */ - _libssh2_bn_set_word(key_state->g, 2); - _libssh2_bn_from_bin(key_state->p, 256, p_value); + if(!key_state->g || _libssh2_bn_set_word(key_state->g, 2)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to allocate key state g."); + goto clean_exit; + } + else if(!key_state->p || + _libssh2_bn_from_bin(key_state->p, 256, p_value)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to allocate key state p."); + goto clean_exit; + } _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Initiating Diffie-Hellman Group14 Key Exchange")); @@ -1110,11 +1179,8 @@ kex_method_diffie_hellman_group14_key_exchange(LIBSSH2_SESSION *session, return ret; } - key_state->state = libssh2_NB_state_idle; - _libssh2_bn_free(key_state->p); - key_state->p = NULL; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; +clean_exit: + kex_diffie_hellman_cleanup(session, key_state); return ret; } @@ -1216,8 +1282,16 @@ kex_method_diffie_hellman_group16_sha512_key_exchange(LIBSSH2_SESSION *session, /* g == 2 */ /* Initialize P and G */ - _libssh2_bn_set_word(key_state->g, 2); - _libssh2_bn_from_bin(key_state->p, 512, p_value); + if(!key_state->g || _libssh2_bn_set_word(key_state->g, 2)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to allocate key state g."); + goto clean_exit; + } + if(!key_state->p || _libssh2_bn_from_bin(key_state->p, 512, p_value)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to allocate key state p."); + goto clean_exit; + } _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Initiating Diffie-Hellman Group16 Key Exchange")); @@ -1233,11 +1307,8 @@ kex_method_diffie_hellman_group16_sha512_key_exchange(LIBSSH2_SESSION *session, return ret; } - key_state->state = libssh2_NB_state_idle; - _libssh2_bn_free(key_state->p); - key_state->p = NULL; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; +clean_exit: + kex_diffie_hellman_cleanup(session, key_state); return ret; } @@ -1348,8 +1419,17 @@ kex_method_diffie_hellman_group18_sha512_key_exchange(LIBSSH2_SESSION *session, /* g == 2 */ /* Initialize P and G */ - _libssh2_bn_set_word(key_state->g, 2); - _libssh2_bn_from_bin(key_state->p, 1024, p_value); + if(!key_state->g || _libssh2_bn_set_word(key_state->g, 2)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to allocate key state g."); + goto clean_exit; + } + else if(!key_state->p || + _libssh2_bn_from_bin(key_state->p, 1024, p_value)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to allocate key state p."); + goto clean_exit; + } _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Initiating Diffie-Hellman Group18 Key Exchange")); @@ -1365,11 +1445,8 @@ kex_method_diffie_hellman_group18_sha512_key_exchange(LIBSSH2_SESSION *session, return ret; } - key_state->state = libssh2_NB_state_idle; - _libssh2_bn_free(key_state->p); - key_state->p = NULL; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; +clean_exit: + kex_diffie_hellman_cleanup(session, key_state); return ret; } @@ -1462,8 +1539,17 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange( goto dh_gex_clean_exit; } - _libssh2_bn_from_bin(key_state->p, p_len, p); - _libssh2_bn_from_bin(key_state->g, g_len, g); + if(_libssh2_bn_from_bin(key_state->p, p_len, p)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Invalid DH-SHA1 p"); + goto dh_gex_clean_exit; + } + + if(_libssh2_bn_from_bin(key_state->g, g_len, g)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Invalid DH-SHA1 g"); + goto dh_gex_clean_exit; + } ret = diffie_hellman_sha_algo(session, key_state->g, key_state->p, (int)p_len, 1, @@ -1476,16 +1562,10 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange( if(ret == LIBSSH2_ERROR_EAGAIN) { return ret; } - - LIBSSH2_FREE(session, key_state->data); } dh_gex_clean_exit: - key_state->state = libssh2_NB_state_idle; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; - _libssh2_bn_free(key_state->p); - key_state->p = NULL; + kex_diffie_hellman_cleanup(session, key_state); return ret; } @@ -1581,8 +1661,17 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange( goto dh_gex_clean_exit; } - _libssh2_bn_from_bin(key_state->p, p_len, p); - _libssh2_bn_from_bin(key_state->g, g_len, g); + if(_libssh2_bn_from_bin(key_state->p, p_len, p)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Invalid DH-SHA256 p"); + goto dh_gex_clean_exit; + } + + if(_libssh2_bn_from_bin(key_state->g, g_len, g)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Invalid DH-SHA256 g"); + goto dh_gex_clean_exit; + } ret = diffie_hellman_sha_algo(session, key_state->g, key_state->p, (int)p_len, 256, @@ -1595,16 +1684,10 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange( if(ret == LIBSSH2_ERROR_EAGAIN) { return ret; } - - LIBSSH2_FREE(session, key_state->data); } dh_gex_clean_exit: - key_state->state = libssh2_NB_state_idle; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; - _libssh2_bn_free(key_state->p); - key_state->p = NULL; + kex_diffie_hellman_cleanup(session, key_state); return ret; } @@ -1755,6 +1838,49 @@ kex_session_ecdh_curve_type(const char *name, libssh2_curve_type *out_type) } +static void +ecdh_exchange_state_cleanup(LIBSSH2_SESSION * session, + kmdhgGPshakex_state_t *exchange_state) +{ + _libssh2_bn_free(exchange_state->k); + exchange_state->k = NULL; + + if(exchange_state->k_value) { + LIBSSH2_FREE(session, exchange_state->k_value); + exchange_state->k_value = NULL; + } + + exchange_state->state = libssh2_NB_state_idle; +} + + +static void +kex_method_ecdh_cleanup +(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) +{ + if(key_state->public_key_oct) { + LIBSSH2_FREE(session, key_state->public_key_oct); + key_state->public_key_oct = NULL; + } + + if(key_state->private_key) { + _libssh2_ecdsa_free(key_state->private_key); + key_state->private_key = NULL; + } + + if(key_state->data) { + LIBSSH2_FREE(session, key_state->data); + key_state->data = NULL; + } + + key_state->state = libssh2_NB_state_idle; + + if(key_state->exchange_state.state != libssh2_NB_state_idle) { + ecdh_exchange_state_cleanup(session, &key_state->exchange_state); + } +} + + /* ecdh_sha2_nistp * Elliptic Curve Diffie Hellman Key Exchange */ @@ -1941,11 +2067,21 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, _libssh2_htonu32(exchange_state->k_value, (uint32_t)(exchange_state->k_value_len - 4)); if(_libssh2_bn_bits(exchange_state->k) % 8) { - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4); + if(_libssh2_bn_to_bin(exchange_state->k, + exchange_state->k_value + 4)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Can't write exchange_state->k"); + goto clean_exit; + } } else { exchange_state->k_value[4] = 0; - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5); + if(_libssh2_bn_to_bin(exchange_state->k, + exchange_state->k_value + 5)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Can't write exchange_state->e"); + goto clean_exit; + } } /* verify hash */ @@ -2231,15 +2367,7 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, } clean_exit: - _libssh2_bn_free(exchange_state->k); - exchange_state->k = NULL; - - if(exchange_state->k_value) { - LIBSSH2_FREE(session, exchange_state->k_value); - exchange_state->k_value = NULL; - } - - exchange_state->state = libssh2_NB_state_idle; + ecdh_exchange_state_cleanup(session, exchange_state); return ret; } @@ -2347,23 +2475,11 @@ kex_method_ecdh_key_exchange if(ret == LIBSSH2_ERROR_EAGAIN) { return ret; } - - LIBSSH2_FREE(session, key_state->data); } ecdh_clean_exit: - if(key_state->public_key_oct) { - LIBSSH2_FREE(session, key_state->public_key_oct); - key_state->public_key_oct = NULL; - } - - if(key_state->private_key) { - _libssh2_ecdsa_free(key_state->private_key); - key_state->private_key = NULL; - } - - key_state->state = libssh2_NB_state_idle; + kex_method_ecdh_cleanup(session, key_state); return ret; } @@ -2373,6 +2489,51 @@ ecdh_clean_exit: #if LIBSSH2_ED25519 +static void +curve25519_exchange_state_cleanup(LIBSSH2_SESSION * session, + kmdhgGPshakex_state_t *exchange_state) +{ + _libssh2_bn_free(exchange_state->k); + exchange_state->k = NULL; + + if(exchange_state->k_value) { + LIBSSH2_FREE(session, exchange_state->k_value); + exchange_state->k_value = NULL; + } + + exchange_state->state = libssh2_NB_state_idle; +} + +static void +kex_method_curve25519_cleanup +(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) +{ + if(key_state->curve25519_public_key) { + _libssh2_explicit_zero(key_state->curve25519_public_key, + LIBSSH2_ED25519_KEY_LEN); + LIBSSH2_FREE(session, key_state->curve25519_public_key); + key_state->curve25519_public_key = NULL; + } + + if(key_state->curve25519_private_key) { + _libssh2_explicit_zero(key_state->curve25519_private_key, + LIBSSH2_ED25519_KEY_LEN); + LIBSSH2_FREE(session, key_state->curve25519_private_key); + key_state->curve25519_private_key = NULL; + } + + if(key_state->data) { + LIBSSH2_FREE(session, key_state->data); + key_state->data = NULL; + } + + key_state->state = libssh2_NB_state_idle; + + if(key_state->exchange_state.state != libssh2_NB_state_idle) { + curve25519_exchange_state_cleanup(session, &key_state->exchange_state); + } +} + /* curve25519_sha256 * Elliptic Curve Key Exchange */ @@ -2579,11 +2740,21 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, _libssh2_htonu32(exchange_state->k_value, (uint32_t)(exchange_state->k_value_len - 4)); if(_libssh2_bn_bits(exchange_state->k) % 8) { - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4); + if(_libssh2_bn_to_bin(exchange_state->k, + exchange_state->k_value + 4)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Can't write exchange_state->e"); + goto clean_exit; + } } else { exchange_state->k_value[4] = 0; - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5); + if(_libssh2_bn_to_bin(exchange_state->k, + exchange_state->k_value + 5)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Can't write exchange_state->e"); + goto clean_exit; + } } /*/ verify hash */ @@ -2845,15 +3016,7 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, } clean_exit: - _libssh2_bn_free(exchange_state->k); - exchange_state->k = NULL; - - if(exchange_state->k_value) { - LIBSSH2_FREE(session, exchange_state->k_value); - exchange_state->k_value = NULL; - } - - exchange_state->state = libssh2_NB_state_idle; + curve25519_exchange_state_cleanup(session, exchange_state); return ret; } @@ -2952,27 +3115,11 @@ kex_method_curve25519_key_exchange if(ret == LIBSSH2_ERROR_EAGAIN) { return ret; } - - LIBSSH2_FREE(session, key_state->data); } clean_exit: - if(key_state->curve25519_public_key) { - _libssh2_explicit_zero(key_state->curve25519_public_key, - LIBSSH2_ED25519_KEY_LEN); - LIBSSH2_FREE(session, key_state->curve25519_public_key); - key_state->curve25519_public_key = NULL; - } - - if(key_state->curve25519_private_key) { - _libssh2_explicit_zero(key_state->curve25519_private_key, - LIBSSH2_ED25519_KEY_LEN); - LIBSSH2_FREE(session, key_state->curve25519_private_key); - key_state->curve25519_private_key = NULL; - } - - key_state->state = libssh2_NB_state_idle; + kex_method_curve25519_cleanup(session, key_state); return ret; } @@ -2987,30 +3134,35 @@ clean_exit: static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group1_sha1 = { "diffie-hellman-group1-sha1", kex_method_diffie_hellman_group1_sha1_key_exchange, + kex_diffie_hellman_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group14_sha1 = { "diffie-hellman-group14-sha1", kex_method_diffie_hellman_group14_sha1_key_exchange, + kex_diffie_hellman_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group14_sha256 = { "diffie-hellman-group14-sha256", kex_method_diffie_hellman_group14_sha256_key_exchange, + kex_diffie_hellman_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group16_sha512 = { "diffie-hellman-group16-sha512", kex_method_diffie_hellman_group16_sha512_key_exchange, + kex_diffie_hellman_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group18_sha512 = { "diffie-hellman-group18-sha512", kex_method_diffie_hellman_group18_sha512_key_exchange, + kex_diffie_hellman_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; @@ -3018,6 +3170,7 @@ static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group_exchange_sha1 = { "diffie-hellman-group-exchange-sha1", kex_method_diffie_hellman_group_exchange_sha1_key_exchange, + kex_diffie_hellman_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; @@ -3025,6 +3178,7 @@ static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group_exchange_sha256 = { "diffie-hellman-group-exchange-sha256", kex_method_diffie_hellman_group_exchange_sha256_key_exchange, + kex_diffie_hellman_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; @@ -3033,6 +3187,7 @@ static const LIBSSH2_KEX_METHOD kex_method_ecdh_sha2_nistp256 = { "ecdh-sha2-nistp256", kex_method_ecdh_key_exchange, + kex_method_ecdh_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; @@ -3040,6 +3195,7 @@ static const LIBSSH2_KEX_METHOD kex_method_ecdh_sha2_nistp384 = { "ecdh-sha2-nistp384", kex_method_ecdh_key_exchange, + kex_method_ecdh_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; @@ -3047,6 +3203,7 @@ static const LIBSSH2_KEX_METHOD kex_method_ecdh_sha2_nistp521 = { "ecdh-sha2-nistp521", kex_method_ecdh_key_exchange, + kex_method_ecdh_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; #endif @@ -3056,12 +3213,14 @@ static const LIBSSH2_KEX_METHOD kex_method_ssh_curve25519_sha256_libssh = { "curve25519-sha256@libssh.org", kex_method_curve25519_key_exchange, + kex_method_curve25519_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; static const LIBSSH2_KEX_METHOD kex_method_ssh_curve25519_sha256 = { "curve25519-sha256", kex_method_curve25519_key_exchange, + kex_method_curve25519_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; #endif @@ -3074,6 +3233,7 @@ static const LIBSSH2_KEX_METHOD kex_method_extension_negotiation = { "ext-info-c", NULL, + NULL, 0, }; @@ -3081,6 +3241,7 @@ static const LIBSSH2_KEX_METHOD kex_method_strict_client_extension = { "kex-strict-c-v00@openssh.com", NULL, + NULL, 0, }; @@ -3900,6 +4061,10 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, session->state |= LIBSSH2_STATE_EXCHANGING_KEYS; if(reexchange) { + if(session->kex && session->kex->cleanup) { + session->kex->cleanup(session, &key_state->key_state_low); + } + session->kex = NULL; if(session->hostkey && session->hostkey->dtor) { @@ -3970,9 +4135,10 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, } session->remote.kexinit = key_state->data; session->remote.kexinit_len = key_state->data_len; + key_state->data = NULL; - if(kex_agree_methods(session, key_state->data, - key_state->data_len)) + if(kex_agree_methods(session, session->remote.kexinit, + session->remote.kexinit_len)) rc = LIBSSH2_ERROR_KEX_FAILURE; key_state->state = libssh2_NB_state_sent2; @@ -4027,13 +4193,26 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, const char *prefs) { char **prefvar, *s, *newprefs; + char *tmpprefs = NULL; size_t prefs_len = strlen(prefs); const LIBSSH2_COMMON_METHOD **mlist; + const char *kex_extensions = "ext-info-c,kex-strict-c-v00@openssh.com,"; + size_t kex_extensions_len = strlen(kex_extensions); switch(method_type) { case LIBSSH2_METHOD_KEX: prefvar = &session->kex_prefs; mlist = (const LIBSSH2_COMMON_METHOD **)libssh2_kex_methods; + tmpprefs = LIBSSH2_ALLOC(session, kex_extensions_len + prefs_len + 1); + if(!tmpprefs) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Error allocated space for kex method" + " preferences"); + } + memcpy(tmpprefs, kex_extensions, kex_extensions_len); + memcpy(tmpprefs + kex_extensions_len, prefs, prefs_len + 1); + prefs = tmpprefs; + prefs_len = strlen(prefs); break; case LIBSSH2_METHOD_HOSTKEY: @@ -4093,6 +4272,9 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, s = newprefs = LIBSSH2_ALLOC(session, prefs_len + 1); if(!newprefs) { + if(tmpprefs) { + LIBSSH2_FREE(session, tmpprefs); + } return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Error allocated space for method preferences"); } @@ -4121,6 +4303,10 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, } } + if(tmpprefs) { + LIBSSH2_FREE(session, tmpprefs); + } + if(!*newprefs) { LIBSSH2_FREE(session, newprefs); return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, |