diff --git a/ssh/kex.c b/ssh/kex.c index fda2988..2fd621b 100644 --- a/ssh/kex.c +++ b/ssh/kex.c @@ -310,9 +310,42 @@ kex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], Kex **kexp) return r; } +void +kex_free_newkeys(Newkeys *newkeys) +{ + if (newkeys == NULL) + return; + if (newkeys->enc.key) { + bzero(newkeys->enc.key, newkeys->enc.key_len); + free(newkeys->enc.key); + newkeys->enc.key = NULL; + } + if (newkeys->enc.iv) { + bzero(newkeys->enc.iv, newkeys->enc.block_size); + free(newkeys->enc.iv); + newkeys->enc.iv = NULL; + } + free(newkeys->enc.name); + bzero(&newkeys->enc, sizeof(newkeys->enc)); + free(newkeys->comp.name); + bzero(&newkeys->comp, sizeof(newkeys->comp)); + mac_clear(&newkeys->mac); + if (newkeys->mac.key) { + bzero(newkeys->mac.key, newkeys->mac.key_len); + free(newkeys->mac.key); + newkeys->mac.key = NULL; + } + free(newkeys->mac.name); + bzero(&newkeys->mac, sizeof(newkeys->mac)); + bzero(newkeys, sizeof(*newkeys)); + free(newkeys); +} + void kex_free(Kex *kex) { + u_int mode; + if (kex->peer != NULL) sshbuf_free(kex->peer); if (kex->my != NULL) @@ -321,6 +354,10 @@ kex_free(Kex *kex) DH_free(kex->dh); if (kex->ec_client_key) EC_KEY_free(kex->ec_client_key); + for (mode = 0; mode < MODE_MAX; mode++) { + kex_free_newkeys(kex->newkeys[mode]); + kex->newkeys[mode] = NULL; + } free(kex); } @@ -610,7 +647,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, r = 0; out: if (digest) - free (digest); + free(digest); if (b) sshbuf_free(b); return r; @@ -635,6 +672,7 @@ kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen, } } for (mode = 0; mode < MODE_MAX; mode++) { + kex_free_newkeys(ssh->current_keys[mode]); ssh->current_keys[mode] = kex->newkeys[mode]; kex->newkeys[mode] = NULL; ctos = (!kex->server && mode == MODE_OUT) || diff --git a/ssh/kex.h b/ssh/kex.h index 9359219..bb45561 100644 --- a/ssh/kex.h +++ b/ssh/kex.h @@ -137,6 +137,7 @@ int kex_names_valid(const char *); int kex_new(struct ssh *, char *[PROPOSAL_MAX], Kex **); int kex_setup(struct ssh *, char *[PROPOSAL_MAX]); +void kex_free_newkeys(Newkeys *); void kex_free(Kex *); int kex_buf2prop(struct sshbuf *, int *, char ***); diff --git a/ssh/packet.c b/ssh/packet.c index 7d6f750..dad87df 100644 --- a/ssh/packet.c +++ b/ssh/packet.c @@ -530,6 +530,7 @@ ssh_packet_close(struct ssh *ssh) { struct session_state *state = ssh->state; int r; + u_int mode; if (!state->initialized) return; @@ -545,6 +546,8 @@ ssh_packet_close(struct ssh *ssh) sshbuf_free(state->output); sshbuf_free(state->outgoing_packet); sshbuf_free(state->incoming_packet); + for (mode = 0; mode < MODE_MAX; mode++) + kex_free_newkeys(state->newkeys[mode]); if (state->compression_buffer) { sshbuf_free(state->compression_buffer); if (ssh->state->compression_out_started) { diff --git a/ssh/ssh_api.c b/ssh/ssh_api.c index cd2f825..d9b0787 100644 --- a/ssh/ssh_api.c +++ b/ssh/ssh_api.c @@ -96,9 +96,15 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) void ssh_free(struct ssh *ssh) { + u_int mode; + ssh_packet_close(ssh); - if (ssh->kex); + if (ssh->kex) kex_free(ssh->kex); + for (mode = 0; mode < MODE_MAX; mode++) { + kex_free_newkeys(ssh->current_keys[mode]); + ssh->current_keys[mode] = NULL; + } free(ssh); } diff --git a/unittests/kex/test_kex.c b/unittests/kex/test_kex.c index 11e5b72..8821f3d 100644 --- a/unittests/kex/test_kex.c +++ b/unittests/kex/test_kex.c @@ -101,7 +101,7 @@ do_kex_with_key(char *kex, int key_type, int bits) ASSERT_INT_EQ(ssh_add_hostkey(client, public), 0); TEST_DONE(); - TEST_START(kex); + TEST_START("kex"); run_kex(client, server); TEST_DONE(); @@ -148,6 +148,12 @@ do_kex_with_key(char *kex, int key_type, int bits) ASSERT_INT_EQ(kex_send_kexinit(client), 0); run_kex(client, server2); TEST_DONE(); + + TEST_START("cleanup"); + ssh_free(client); + ssh_free(server); + ssh_free(server2); + TEST_DONE(); } static void