diff options
Diffstat (limited to 'packet.c')
-rw-r--r-- | packet.c | 96 |
1 files changed, 61 insertions, 35 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: packet.c,v 1.256 2017/05/08 06:03:39 djm Exp $ */ | 1 | /* $OpenBSD: packet.c,v 1.257 2017/05/31 08:09:45 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -559,8 +559,8 @@ ssh_local_port(struct ssh *ssh) | |||
559 | 559 | ||
560 | /* Closes the connection and clears and frees internal data structures. */ | 560 | /* Closes the connection and clears and frees internal data structures. */ |
561 | 561 | ||
562 | void | 562 | static void |
563 | ssh_packet_close(struct ssh *ssh) | 563 | ssh_packet_close_internal(struct ssh *ssh, int do_close) |
564 | { | 564 | { |
565 | struct session_state *state = ssh->state; | 565 | struct session_state *state = ssh->state; |
566 | u_int mode; | 566 | u_int mode; |
@@ -568,20 +568,26 @@ ssh_packet_close(struct ssh *ssh) | |||
568 | if (!state->initialized) | 568 | if (!state->initialized) |
569 | return; | 569 | return; |
570 | state->initialized = 0; | 570 | state->initialized = 0; |
571 | if (state->connection_in == state->connection_out) { | 571 | if (do_close) { |
572 | shutdown(state->connection_out, SHUT_RDWR); | 572 | if (state->connection_in == state->connection_out) { |
573 | close(state->connection_out); | 573 | shutdown(state->connection_out, SHUT_RDWR); |
574 | } else { | 574 | close(state->connection_out); |
575 | close(state->connection_in); | 575 | } else { |
576 | close(state->connection_out); | 576 | close(state->connection_in); |
577 | close(state->connection_out); | ||
578 | } | ||
577 | } | 579 | } |
578 | sshbuf_free(state->input); | 580 | sshbuf_free(state->input); |
579 | sshbuf_free(state->output); | 581 | sshbuf_free(state->output); |
580 | sshbuf_free(state->outgoing_packet); | 582 | sshbuf_free(state->outgoing_packet); |
581 | sshbuf_free(state->incoming_packet); | 583 | sshbuf_free(state->incoming_packet); |
582 | for (mode = 0; mode < MODE_MAX; mode++) | 584 | for (mode = 0; mode < MODE_MAX; mode++) { |
583 | kex_free_newkeys(state->newkeys[mode]); | 585 | kex_free_newkeys(state->newkeys[mode]); /* current keys */ |
584 | if (state->compression_buffer) { | 586 | state->newkeys[mode] = NULL; |
587 | ssh_clear_newkeys(ssh, mode); /* next keys */ | ||
588 | } | ||
589 | /* comression state is in shared mem, so we can only release it once */ | ||
590 | if (do_close && state->compression_buffer) { | ||
585 | sshbuf_free(state->compression_buffer); | 591 | sshbuf_free(state->compression_buffer); |
586 | if (state->compression_out_started) { | 592 | if (state->compression_out_started) { |
587 | z_streamp stream = &state->compression_out_stream; | 593 | z_streamp stream = &state->compression_out_stream; |
@@ -609,10 +615,24 @@ ssh_packet_close(struct ssh *ssh) | |||
609 | cipher_free(state->send_context); | 615 | cipher_free(state->send_context); |
610 | cipher_free(state->receive_context); | 616 | cipher_free(state->receive_context); |
611 | state->send_context = state->receive_context = NULL; | 617 | state->send_context = state->receive_context = NULL; |
612 | free(ssh->remote_ipaddr); | 618 | if (do_close) { |
613 | ssh->remote_ipaddr = NULL; | 619 | free(ssh->remote_ipaddr); |
614 | free(ssh->state); | 620 | ssh->remote_ipaddr = NULL; |
615 | ssh->state = NULL; | 621 | free(ssh->state); |
622 | ssh->state = NULL; | ||
623 | } | ||
624 | } | ||
625 | |||
626 | void | ||
627 | ssh_packet_close(struct ssh *ssh) | ||
628 | { | ||
629 | ssh_packet_close_internal(ssh, 1); | ||
630 | } | ||
631 | |||
632 | void | ||
633 | ssh_packet_clear_keys(struct ssh *ssh) | ||
634 | { | ||
635 | ssh_packet_close_internal(ssh, 0); | ||
616 | } | 636 | } |
617 | 637 | ||
618 | /* Sets remote side protocol flags. */ | 638 | /* Sets remote side protocol flags. */ |
@@ -791,6 +811,15 @@ uncompress_buffer(struct ssh *ssh, struct sshbuf *in, struct sshbuf *out) | |||
791 | /* NOTREACHED */ | 811 | /* NOTREACHED */ |
792 | } | 812 | } |
793 | 813 | ||
814 | void | ||
815 | ssh_clear_newkeys(struct ssh *ssh, int mode) | ||
816 | { | ||
817 | if (ssh->kex && ssh->kex->newkeys) { | ||
818 | kex_free_newkeys(ssh->kex->newkeys[mode]); | ||
819 | ssh->kex->newkeys[mode] = NULL; | ||
820 | } | ||
821 | } | ||
822 | |||
794 | int | 823 | int |
795 | ssh_set_newkeys(struct ssh *ssh, int mode) | 824 | ssh_set_newkeys(struct ssh *ssh, int mode) |
796 | { | 825 | { |
@@ -820,26 +849,16 @@ ssh_set_newkeys(struct ssh *ssh, int mode) | |||
820 | max_blocks = &state->max_blocks_in; | 849 | max_blocks = &state->max_blocks_in; |
821 | } | 850 | } |
822 | if (state->newkeys[mode] != NULL) { | 851 | if (state->newkeys[mode] != NULL) { |
823 | debug("%s: rekeying after %llu %s blocks" | 852 | debug("set_newkeys: rekeying, input %llu bytes %llu blocks, " |
824 | " (%llu bytes total)", __func__, | 853 | "output %llu bytes %llu blocks", |
825 | (unsigned long long)ps->blocks, dir, | 854 | (unsigned long long)state->p_read.bytes, |
826 | (unsigned long long)ps->bytes); | 855 | (unsigned long long)state->p_read.blocks, |
856 | (unsigned long long)state->p_send.bytes, | ||
857 | (unsigned long long)state->p_send.blocks); | ||
827 | cipher_free(*ccp); | 858 | cipher_free(*ccp); |
828 | *ccp = NULL; | 859 | *ccp = NULL; |
829 | enc = &state->newkeys[mode]->enc; | 860 | kex_free_newkeys(state->newkeys[mode]); |
830 | mac = &state->newkeys[mode]->mac; | 861 | state->newkeys[mode] = NULL; |
831 | comp = &state->newkeys[mode]->comp; | ||
832 | mac_clear(mac); | ||
833 | explicit_bzero(enc->iv, enc->iv_len); | ||
834 | explicit_bzero(enc->key, enc->key_len); | ||
835 | explicit_bzero(mac->key, mac->key_len); | ||
836 | free(enc->name); | ||
837 | free(enc->iv); | ||
838 | free(enc->key); | ||
839 | free(mac->name); | ||
840 | free(mac->key); | ||
841 | free(comp->name); | ||
842 | free(state->newkeys[mode]); | ||
843 | } | 862 | } |
844 | /* note that both bytes and the seqnr are not reset */ | 863 | /* note that both bytes and the seqnr are not reset */ |
845 | ps->packets = ps->blocks = 0; | 864 | ps->packets = ps->blocks = 0; |
@@ -1784,15 +1803,20 @@ sshpkt_fatal(struct ssh *ssh, const char *tag, int r) | |||
1784 | 1803 | ||
1785 | switch (r) { | 1804 | switch (r) { |
1786 | case SSH_ERR_CONN_CLOSED: | 1805 | case SSH_ERR_CONN_CLOSED: |
1806 | ssh_packet_clear_keys(ssh); | ||
1787 | logdie("Connection closed by %s", remote_id); | 1807 | logdie("Connection closed by %s", remote_id); |
1788 | case SSH_ERR_CONN_TIMEOUT: | 1808 | case SSH_ERR_CONN_TIMEOUT: |
1809 | ssh_packet_clear_keys(ssh); | ||
1789 | logdie("Connection %s %s timed out", | 1810 | logdie("Connection %s %s timed out", |
1790 | ssh->state->server_side ? "from" : "to", remote_id); | 1811 | ssh->state->server_side ? "from" : "to", remote_id); |
1791 | case SSH_ERR_DISCONNECTED: | 1812 | case SSH_ERR_DISCONNECTED: |
1813 | ssh_packet_clear_keys(ssh); | ||
1792 | logdie("Disconnected from %s", remote_id); | 1814 | logdie("Disconnected from %s", remote_id); |
1793 | case SSH_ERR_SYSTEM_ERROR: | 1815 | case SSH_ERR_SYSTEM_ERROR: |
1794 | if (errno == ECONNRESET) | 1816 | if (errno == ECONNRESET) { |
1817 | ssh_packet_clear_keys(ssh); | ||
1795 | logdie("Connection reset by %s", remote_id); | 1818 | logdie("Connection reset by %s", remote_id); |
1819 | } | ||
1796 | /* FALLTHROUGH */ | 1820 | /* FALLTHROUGH */ |
1797 | case SSH_ERR_NO_CIPHER_ALG_MATCH: | 1821 | case SSH_ERR_NO_CIPHER_ALG_MATCH: |
1798 | case SSH_ERR_NO_MAC_ALG_MATCH: | 1822 | case SSH_ERR_NO_MAC_ALG_MATCH: |
@@ -1800,12 +1824,14 @@ sshpkt_fatal(struct ssh *ssh, const char *tag, int r) | |||
1800 | case SSH_ERR_NO_KEX_ALG_MATCH: | 1824 | case SSH_ERR_NO_KEX_ALG_MATCH: |
1801 | case SSH_ERR_NO_HOSTKEY_ALG_MATCH: | 1825 | case SSH_ERR_NO_HOSTKEY_ALG_MATCH: |
1802 | if (ssh && ssh->kex && ssh->kex->failed_choice) { | 1826 | if (ssh && ssh->kex && ssh->kex->failed_choice) { |
1827 | ssh_packet_clear_keys(ssh); | ||
1803 | logdie("Unable to negotiate with %s: %s. " | 1828 | logdie("Unable to negotiate with %s: %s. " |
1804 | "Their offer: %s", remote_id, ssh_err(r), | 1829 | "Their offer: %s", remote_id, ssh_err(r), |
1805 | ssh->kex->failed_choice); | 1830 | ssh->kex->failed_choice); |
1806 | } | 1831 | } |
1807 | /* FALLTHROUGH */ | 1832 | /* FALLTHROUGH */ |
1808 | default: | 1833 | default: |
1834 | ssh_packet_clear_keys(ssh); | ||
1809 | logdie("%s%sConnection %s %s: %s", | 1835 | logdie("%s%sConnection %s %s: %s", |
1810 | tag != NULL ? tag : "", tag != NULL ? ": " : "", | 1836 | tag != NULL ? tag : "", tag != NULL ? ": " : "", |
1811 | ssh->state->server_side ? "from" : "to", | 1837 | ssh->state->server_side ? "from" : "to", |