Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/crypto/external/bsd/openssh/dist/packet.c,v rcsdiff: /ftp/cvs/cvsroot/src/crypto/external/bsd/openssh/dist/packet.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.27 retrieving revision 1.28 diff -u -p -r1.27 -r1.28 --- src/crypto/external/bsd/openssh/dist/packet.c 2017/04/18 18:41:46 1.27 +++ src/crypto/external/bsd/openssh/dist/packet.c 2017/10/07 19:39:19 1.28 @@ -1,5 +1,5 @@ -/* $NetBSD: packet.c,v 1.27 2017/04/18 18:41:46 christos Exp $ */ -/* $OpenBSD: packet.c,v 1.247 2017/03/11 13:07:35 markus Exp $ */ +/* $NetBSD: packet.c,v 1.28 2017/10/07 19:39:19 christos Exp $ */ +/* $OpenBSD: packet.c,v 1.264 2017/09/12 06:32:07 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -39,7 +39,7 @@ */ #include "includes.h" -__RCSID("$NetBSD: packet.c,v 1.27 2017/04/18 18:41:46 christos Exp $"); +__RCSID("$NetBSD: packet.c,v 1.28 2017/10/07 19:39:19 christos Exp $"); #include /* MIN roundup */ #include @@ -67,9 +67,7 @@ __RCSID("$NetBSD: packet.c,v 1.27 2017/0 #include "xmalloc.h" #include "crc32.h" -#include "deattack.h" #include "compat.h" -#include "ssh1.h" #include "ssh2.h" #include "cipher.h" #include "sshkey.h" @@ -185,10 +183,6 @@ struct session_state { u_int32_t rekey_interval; /* how often in seconds */ time_t rekey_time; /* time of last rekeying */ - /* Session key for protocol v1 */ - u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; - u_int ssh1_keylen; - /* roundup current message to extra_pad bytes */ u_char extra_pad; @@ -215,9 +209,6 @@ struct session_state { /* One-off warning about weak ciphers */ int cipher_warning_done; - /* SSH1 CRC compensation attack detector */ - struct deattack_ctx deattack; - /* Hook for fuzzing inbound packets */ ssh_packet_hook_fn *hook_in; void *hook_in_ctx; @@ -277,13 +268,12 @@ ssh_packet_set_input_hook(struct ssh *ss int ssh_packet_is_rekeying(struct ssh *ssh) { - return compat20 && - (ssh->state->rekeying || (ssh->kex != NULL && ssh->kex->done == 0)); + return ssh->state->rekeying || + (ssh->kex != NULL && ssh->kex->done == 0); } /* - * Sets the descriptors used for communication. Disables encryption until - * packet_set_encryption_key is called. + * Sets the descriptors used for communication. */ struct ssh * ssh_packet_set_connection(struct ssh *ssh, int fd_in, int fd_out) @@ -314,7 +304,6 @@ ssh_packet_set_connection(struct ssh *ss return NULL; } state->newkeys[MODE_IN] = state->newkeys[MODE_OUT] = NULL; - deattack_init(&state->deattack); /* * Cache the IP address of the remote connection for use in error * messages that might be generated after the connection has closed. @@ -564,8 +553,8 @@ ssh_local_port(struct ssh *ssh) /* Closes the connection and clears and frees internal data structures. */ -void -ssh_packet_close(struct ssh *ssh) +static void +ssh_packet_close_internal(struct ssh *ssh, int do_close) { struct session_state *state = ssh->state; u_int mode; @@ -573,20 +562,25 @@ ssh_packet_close(struct ssh *ssh) if (!state->initialized) return; state->initialized = 0; - if (state->connection_in == state->connection_out) { - shutdown(state->connection_out, SHUT_RDWR); - close(state->connection_out); - } else { - close(state->connection_in); - close(state->connection_out); + if (do_close) { + if (state->connection_in == state->connection_out) { + close(state->connection_out); + } else { + close(state->connection_in); + close(state->connection_out); + } } sshbuf_free(state->input); 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) { + for (mode = 0; mode < MODE_MAX; mode++) { + kex_free_newkeys(state->newkeys[mode]); /* current keys */ + state->newkeys[mode] = NULL; + ssh_clear_newkeys(ssh, mode); /* next keys */ + } + /* comression state is in shared mem, so we can only release it once */ + if (do_close && state->compression_buffer) { sshbuf_free(state->compression_buffer); if (state->compression_out_started) { z_streamp stream = &state->compression_out_stream; @@ -600,7 +594,7 @@ ssh_packet_close(struct ssh *ssh) deflateEnd(stream); } if (state->compression_in_started) { - z_streamp stream = &state->compression_out_stream; + z_streamp stream = &state->compression_in_stream; debug("compress incoming: " "raw data %llu, compressed %llu, factor %.2f", (unsigned long long)stream->total_out, @@ -614,10 +608,24 @@ ssh_packet_close(struct ssh *ssh) cipher_free(state->send_context); cipher_free(state->receive_context); state->send_context = state->receive_context = NULL; - free(ssh->remote_ipaddr); - ssh->remote_ipaddr = NULL; - free(ssh->state); - ssh->state = NULL; + if (do_close) { + free(ssh->remote_ipaddr); + ssh->remote_ipaddr = NULL; + free(ssh->state); + ssh->state = NULL; + } +} + +void +ssh_packet_close(struct ssh *ssh) +{ + ssh_packet_close_internal(ssh, 1); +} + +void +ssh_packet_clear_keys(struct ssh *ssh) +{ + ssh_packet_close_internal(ssh, 0); } /* Sets remote side protocol flags. */ @@ -692,7 +700,7 @@ ssh_packet_start_compression(struct ssh { int r; - if (ssh->state->packet_compression && !compat20) + if (ssh->state->packet_compression) return SSH_ERR_INTERNAL_ERROR; ssh->state->packet_compression = 1; if ((r = ssh_packet_init_compression(ssh)) != 0 || @@ -796,136 +804,13 @@ uncompress_buffer(struct ssh *ssh, struc /* NOTREACHED */ } -/* - * Causes any further packets to be encrypted using the given key. The same - * key is used for both sending and reception. However, both directions are - * encrypted independently of each other. - */ - void -ssh_packet_set_encryption_key(struct ssh *ssh, const u_char *key, u_int keylen, int number) +ssh_clear_newkeys(struct ssh *ssh, int mode) { -#ifndef WITH_SSH1 - fatal("no SSH protocol 1 support"); -#else /* WITH_SSH1 */ - struct session_state *state = ssh->state; - const struct sshcipher *cipher = cipher_by_number(number); - int r; - const char *wmsg; - - if (cipher == NULL) - fatal("%s: unknown cipher number %d", __func__, number); - if (keylen < 20) - fatal("%s: keylen too small: %d", __func__, keylen); - if (keylen > SSH_SESSION_KEY_LENGTH) - fatal("%s: keylen too big: %d", __func__, keylen); - memcpy(state->ssh1_key, key, keylen); - state->ssh1_keylen = keylen; - if ((r = cipher_init(&state->send_context, cipher, key, keylen, - NULL, 0, CIPHER_ENCRYPT)) != 0 || - (r = cipher_init(&state->receive_context, cipher, key, keylen, - NULL, 0, CIPHER_DECRYPT) != 0)) - fatal("%s: cipher_init failed: %s", __func__, ssh_err(r)); - if (!state->cipher_warning_done && - ((wmsg = cipher_warning_message(state->send_context)) != NULL || - (wmsg = cipher_warning_message(state->send_context)) != NULL)) { - error("Warning: %s", wmsg); - state->cipher_warning_done = 1; + if (ssh->kex && ssh->kex->newkeys[mode]) { + kex_free_newkeys(ssh->kex->newkeys[mode]); + ssh->kex->newkeys[mode] = NULL; } -#endif /* WITH_SSH1 */ -} - -/* - * Finalizes and sends the packet. If the encryption key has been set, - * encrypts the packet before sending. - */ - -int -ssh_packet_send1(struct ssh *ssh) -{ - struct session_state *state = ssh->state; - u_char buf[8], *cp; - int r, padding, len; - u_int checksum; - - /* - * If using packet compression, compress the payload of the outgoing - * packet. - */ - if (state->packet_compression) { - sshbuf_reset(state->compression_buffer); - /* Skip padding. */ - if ((r = sshbuf_consume(state->outgoing_packet, 8)) != 0) - goto out; - /* padding */ - if ((r = sshbuf_put(state->compression_buffer, - "\0\0\0\0\0\0\0\0", 8)) != 0) - goto out; - if ((r = compress_buffer(ssh, state->outgoing_packet, - state->compression_buffer)) != 0) - goto out; - sshbuf_reset(state->outgoing_packet); - if ((r = sshbuf_putb(state->outgoing_packet, - state->compression_buffer)) != 0) - goto out; - } - /* Compute packet length without padding (add checksum, remove padding). */ - len = sshbuf_len(state->outgoing_packet) + 4 - 8; - - /* Insert padding. Initialized to zero in packet_start1() */ - padding = 8 - len % 8; - if (!cipher_ctx_is_plaintext(state->send_context)) { - cp = sshbuf_mutable_ptr(state->outgoing_packet); - if (cp == NULL) { - r = SSH_ERR_INTERNAL_ERROR; - goto out; - } - arc4random_buf(cp + 8 - padding, padding); - } - if ((r = sshbuf_consume(state->outgoing_packet, 8 - padding)) != 0) - goto out; - - /* Add check bytes. */ - checksum = ssh_crc32(sshbuf_ptr(state->outgoing_packet), - sshbuf_len(state->outgoing_packet)); - POKE_U32(buf, checksum); - if ((r = sshbuf_put(state->outgoing_packet, buf, 4)) != 0) - goto out; - -#ifdef PACKET_DEBUG - fprintf(stderr, "packet_send plain: "); - sshbuf_dump(state->outgoing_packet, stderr); -#endif - - /* Append to output. */ - POKE_U32(buf, len); - if ((r = sshbuf_put(state->output, buf, 4)) != 0) - goto out; - if ((r = sshbuf_reserve(state->output, - sshbuf_len(state->outgoing_packet), &cp)) != 0) - goto out; - if ((r = cipher_crypt(state->send_context, 0, cp, - sshbuf_ptr(state->outgoing_packet), - sshbuf_len(state->outgoing_packet), 0, 0)) != 0) - goto out; - -#ifdef PACKET_DEBUG - fprintf(stderr, "encrypted: "); - sshbuf_dump(state->output, stderr); -#endif - state->p_send.packets++; - state->p_send.bytes += len + - sshbuf_len(state->outgoing_packet); - sshbuf_reset(state->outgoing_packet); - - /* - * Note that the packet is now only buffered in output. It won't be - * actually sent until ssh_packet_write_wait or ssh_packet_write_poll - * is called. - */ - r = 0; - out: - return r; } int @@ -938,45 +823,33 @@ ssh_set_newkeys(struct ssh *ssh, int mod struct sshcipher_ctx **ccp; struct packet_state *ps; u_int64_t *max_blocks; - const char *wmsg, *dir; + const char *wmsg; int r, crypt_type; debug2("set_newkeys: mode %d", mode); if (mode == MODE_OUT) { - dir = "output"; ccp = &state->send_context; crypt_type = CIPHER_ENCRYPT; ps = &state->p_send; max_blocks = &state->max_blocks_out; } else { - dir = "input"; ccp = &state->receive_context; crypt_type = CIPHER_DECRYPT; ps = &state->p_read; max_blocks = &state->max_blocks_in; } if (state->newkeys[mode] != NULL) { - debug("%s: rekeying after %llu %s blocks" - " (%llu bytes total)", __func__, - (unsigned long long)ps->blocks, dir, - (unsigned long long)ps->bytes); + debug("set_newkeys: rekeying, input %llu bytes %llu blocks, " + "output %llu bytes %llu blocks", + (unsigned long long)state->p_read.bytes, + (unsigned long long)state->p_read.blocks, + (unsigned long long)state->p_send.bytes, + (unsigned long long)state->p_send.blocks); cipher_free(*ccp); *ccp = NULL; - enc = &state->newkeys[mode]->enc; - mac = &state->newkeys[mode]->mac; - comp = &state->newkeys[mode]->comp; - mac_clear(mac); - explicit_bzero(enc->iv, enc->iv_len); - explicit_bzero(enc->key, enc->key_len); - explicit_bzero(mac->key, mac->key_len); - free(enc->name); - free(enc->iv); - free(enc->key); - free(mac->name); - free(mac->key); - free(comp->name); - free(state->newkeys[mode]); + kex_free_newkeys(state->newkeys[mode]); + state->newkeys[mode] = NULL; } /* note that both bytes and the seqnr are not reset */ ps->packets = ps->blocks = 0; @@ -1021,7 +894,8 @@ ssh_set_newkeys(struct ssh *ssh, int mod } /* * The 2^(blocksize*2) limit is too expensive for 3DES, - * blowfish, etc, so enforce a 1GB limit for small blocksizes. + * so enforce a 1GB limit for small blocksizes. + * See RFC4344 section 3.2. */ if (enc->block_size >= 16) *max_blocks = (u_int64_t)1 << (enc->block_size*2); @@ -1065,7 +939,10 @@ ssh_packet_need_rekeying(struct ssh *ssh (int64_t)state->rekey_time + state->rekey_interval <= monotime()) return 1; - /* Always rekey when MAX_PACKETS sent in either direction */ + /* + * Always rekey when MAX_PACKETS sent in either direction + * As per RFC4344 section 3.1 we do this after 2^31 packets. + */ if (state->p_send.packets > MAX_PACKETS || state->p_read.packets > MAX_PACKETS) return 1; @@ -1426,13 +1303,6 @@ ssh_packet_read_seqnr(struct ssh *ssh, u r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p); if (r != 0) break; - if (!compat20 && ( - *typep == SSH_SMSG_SUCCESS - || *typep == SSH_SMSG_FAILURE - || *typep == SSH_CMSG_EOF - || *typep == SSH_CMSG_EXIT_CONFIRMATION)) - if ((r = sshpkt_get_end(ssh)) != 0) - break; /* If we got a packet, return it. */ if (*typep != SSH_MSG_NONE) break; @@ -1525,153 +1395,6 @@ ssh_packet_read_expect(struct ssh *ssh, return 0; } -/* Checks if a full packet is available in the data received so far via - * packet_process_incoming. If so, reads the packet; otherwise returns - * SSH_MSG_NONE. This does not wait for data from the connection. - * - * SSH_MSG_DISCONNECT is handled specially here. Also, - * SSH_MSG_IGNORE messages are skipped by this function and are never returned - * to higher levels. - */ - -int -ssh_packet_read_poll1(struct ssh *ssh, u_char *typep) -{ - struct session_state *state = ssh->state; - u_int len, padded_len; - const char *emsg; - const u_char *cp; - u_char *p; - u_int checksum, stored_checksum; - int r; - - *typep = SSH_MSG_NONE; - - /* Check if input size is less than minimum packet size. */ - if (sshbuf_len(state->input) < 4 + 8) - return 0; - /* Get length of incoming packet. */ - len = PEEK_U32(sshbuf_ptr(state->input)); - if (len < 1 + 2 + 2 || len > 256 * 1024) { - if ((r = sshpkt_disconnect(ssh, "Bad packet length %u", - len)) != 0) - return r; - return SSH_ERR_CONN_CORRUPT; - } - padded_len = (len + 8) & ~7; - - /* Check if the packet has been entirely received. */ - if (sshbuf_len(state->input) < 4 + padded_len) - return 0; - - /* The entire packet is in buffer. */ - - /* Consume packet length. */ - if ((r = sshbuf_consume(state->input, 4)) != 0) - goto out; - - /* - * Cryptographic attack detector for ssh - * (C)1998 CORE-SDI, Buenos Aires Argentina - * Ariel Futoransky(futo@core-sdi.com) - */ - if (!cipher_ctx_is_plaintext(state->receive_context)) { - emsg = NULL; - switch (detect_attack(&state->deattack, - sshbuf_ptr(state->input), padded_len)) { - case DEATTACK_OK: - break; - case DEATTACK_DETECTED: - emsg = "crc32 compensation attack detected"; - break; - case DEATTACK_DOS_DETECTED: - emsg = "deattack denial of service detected"; - break; - default: - emsg = "deattack error"; - break; - } - if (emsg != NULL) { - error("%s", emsg); - if ((r = sshpkt_disconnect(ssh, "%s", emsg)) != 0 || - (r = ssh_packet_write_wait(ssh)) < 0) - return r; - return SSH_ERR_CONN_CORRUPT; - } - } - - /* Decrypt data to incoming_packet. */ - sshbuf_reset(state->incoming_packet); - if ((r = sshbuf_reserve(state->incoming_packet, padded_len, &p)) != 0) - goto out; - if ((r = cipher_crypt(state->receive_context, 0, p, - sshbuf_ptr(state->input), padded_len, 0, 0)) != 0) - goto out; - - if ((r = sshbuf_consume(state->input, padded_len)) != 0) - goto out; - -#ifdef PACKET_DEBUG - fprintf(stderr, "read_poll plain: "); - sshbuf_dump(state->incoming_packet, stderr); -#endif - - /* Compute packet checksum. */ - checksum = ssh_crc32(sshbuf_ptr(state->incoming_packet), - sshbuf_len(state->incoming_packet) - 4); - - /* Skip padding. */ - if ((r = sshbuf_consume(state->incoming_packet, 8 - len % 8)) != 0) - goto out; - - /* Test check bytes. */ - if (len != sshbuf_len(state->incoming_packet)) { - error("%s: len %d != sshbuf_len %zd", __func__, - len, sshbuf_len(state->incoming_packet)); - if ((r = sshpkt_disconnect(ssh, "invalid packet length")) != 0 || - (r = ssh_packet_write_wait(ssh)) < 0) - return r; - return SSH_ERR_CONN_CORRUPT; - } - - cp = sshbuf_ptr(state->incoming_packet) + len - 4; - stored_checksum = PEEK_U32(cp); - if (checksum != stored_checksum) { - error("Corrupted check bytes on input"); - if ((r = sshpkt_disconnect(ssh, "connection corrupted")) != 0 || - (r = ssh_packet_write_wait(ssh)) < 0) - return r; - return SSH_ERR_CONN_CORRUPT; - } - if ((r = sshbuf_consume_end(state->incoming_packet, 4)) < 0) - goto out; - - if (state->packet_compression) { - sshbuf_reset(state->compression_buffer); - if ((r = uncompress_buffer(ssh, state->incoming_packet, - state->compression_buffer)) != 0) - goto out; - sshbuf_reset(state->incoming_packet); - if ((r = sshbuf_putb(state->incoming_packet, - state->compression_buffer)) != 0) - goto out; - } - state->p_read.packets++; - state->p_read.bytes += padded_len + 4; - if ((r = sshbuf_get_u8(state->incoming_packet, typep)) != 0) - goto out; - if (*typep < SSH_MSG_MIN || *typep > SSH_MSG_MAX) { - error("Invalid ssh1 packet type: %d", *typep); - if ((r = sshpkt_disconnect(ssh, "invalid packet type")) != 0 || - (r = ssh_packet_write_wait(ssh)) < 0) - return r; - return SSH_ERR_PROTOCOL_ERROR; - } - r = 0; - out: - return r; -} - static int ssh_packet_read_poll2_mux(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) { @@ -1952,75 +1675,48 @@ ssh_packet_read_poll_seqnr(struct ssh *s for (;;) { msg = NULL; - if (compat20) { - r = ssh_packet_read_poll2(ssh, typep, seqnr_p); - if (r != 0) - return r; - if (*typep) { - state->keep_alive_timeouts = 0; - DBG(debug("received packet type %d", *typep)); - } - switch (*typep) { - case SSH2_MSG_IGNORE: - debug3("Received SSH2_MSG_IGNORE"); - break; - case SSH2_MSG_DEBUG: - if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || - (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 || - (r = sshpkt_get_string(ssh, NULL, NULL)) != 0) { - free(msg); - return r; - } - debug("Remote: %.900s", msg); - free(msg); - break; - case SSH2_MSG_DISCONNECT: - if ((r = sshpkt_get_u32(ssh, &reason)) != 0 || - (r = sshpkt_get_string(ssh, &msg, NULL)) != 0) - return r; - /* Ignore normal client exit notifications */ - do_log2(ssh->state->server_side && - reason == SSH2_DISCONNECT_BY_APPLICATION ? - SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR, - "Received disconnect from %s port %d:" - "%u: %.400s", ssh_remote_ipaddr(ssh), - ssh_remote_port(ssh), reason, msg); - free(msg); - return SSH_ERR_DISCONNECTED; - case SSH2_MSG_UNIMPLEMENTED: - if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0) - return r; - debug("Received SSH2_MSG_UNIMPLEMENTED for %u", - seqnr); - break; - default: - return 0; - } - } else { - r = ssh_packet_read_poll1(ssh, typep); - switch (*typep) { - case SSH_MSG_NONE: - return SSH_MSG_NONE; - case SSH_MSG_IGNORE: - break; - case SSH_MSG_DEBUG: - if ((r = sshpkt_get_string(ssh, &msg, NULL)) != 0) - return r; - debug("Remote: %.900s", msg); - free(msg); - break; - case SSH_MSG_DISCONNECT: - if ((r = sshpkt_get_string(ssh, &msg, NULL)) != 0) - return r; - error("Received disconnect from %s port %d: " - "%.400s", ssh_remote_ipaddr(ssh), - ssh_remote_port(ssh), msg); + r = ssh_packet_read_poll2(ssh, typep, seqnr_p); + if (r != 0) + return r; + if (*typep) { + state->keep_alive_timeouts = 0; + DBG(debug("received packet type %d", *typep)); + } + switch (*typep) { + case SSH2_MSG_IGNORE: + debug3("Received SSH2_MSG_IGNORE"); + break; + case SSH2_MSG_DEBUG: + if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || + (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 || + (r = sshpkt_get_string(ssh, NULL, NULL)) != 0) { free(msg); - return SSH_ERR_DISCONNECTED; - default: - DBG(debug("received packet type %d", *typep)); - return 0; + return r; } + debug("Remote: %.900s", msg); + free(msg); + break; + case SSH2_MSG_DISCONNECT: + if ((r = sshpkt_get_u32(ssh, &reason)) != 0 || + (r = sshpkt_get_string(ssh, &msg, NULL)) != 0) + return r; + /* Ignore normal client exit notifications */ + do_log2(ssh->state->server_side && + reason == SSH2_DISCONNECT_BY_APPLICATION ? + SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR, + "Received disconnect from %s port %d:" + "%u: %.400s", ssh_remote_ipaddr(ssh), + ssh_remote_port(ssh), reason, msg); + free(msg); + return SSH_ERR_DISCONNECTED; + case SSH2_MSG_UNIMPLEMENTED: + if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0) + return r; + debug("Received SSH2_MSG_UNIMPLEMENTED for %u", + seqnr); + break; + default: + return 0; } } } @@ -2072,27 +1768,19 @@ ssh_packet_send_debug(struct ssh *ssh, c va_list args; int r; - if (compat20 && (ssh->compat & SSH_BUG_DEBUG)) + if ((ssh->compat & SSH_BUG_DEBUG)) return; va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); - if (compat20) { - if ((r = sshpkt_start(ssh, SSH2_MSG_DEBUG)) != 0 || - (r = sshpkt_put_u8(ssh, 0)) != 0 || /* always display */ - (r = sshpkt_put_cstring(ssh, buf)) != 0 || - (r = sshpkt_put_cstring(ssh, "")) != 0 || - (r = sshpkt_send(ssh)) != 0) - fatal("%s: %s", __func__, ssh_err(r)); - } else { - if ((r = sshpkt_start(ssh, SSH_MSG_DEBUG)) != 0 || - (r = sshpkt_put_cstring(ssh, buf)) != 0 || - (r = sshpkt_send(ssh)) != 0) - fatal("%s: %s", __func__, ssh_err(r)); - } - if ((r = ssh_packet_write_wait(ssh)) < 0) + if ((r = sshpkt_start(ssh, SSH2_MSG_DEBUG)) != 0 || + (r = sshpkt_put_u8(ssh, 0)) != 0 || /* always display */ + (r = sshpkt_put_cstring(ssh, buf)) != 0 || + (r = sshpkt_put_cstring(ssh, "")) != 0 || + (r = sshpkt_send(ssh)) != 0 || + (r = ssh_packet_write_wait(ssh)) != 0) fatal("%s: %s", __func__, ssh_err(r)); } @@ -2117,15 +1805,20 @@ sshpkt_fatal(struct ssh *ssh, const char switch (r) { case SSH_ERR_CONN_CLOSED: + ssh_packet_clear_keys(ssh); logdie("Connection closed by %s", remote_id); case SSH_ERR_CONN_TIMEOUT: + ssh_packet_clear_keys(ssh); logdie("Connection %s %s timed out", ssh->state->server_side ? "from" : "to", remote_id); case SSH_ERR_DISCONNECTED: + ssh_packet_clear_keys(ssh); logdie("Disconnected from %s", remote_id); case SSH_ERR_SYSTEM_ERROR: - if (errno == ECONNRESET) + if (errno == ECONNRESET) { + ssh_packet_clear_keys(ssh); logdie("Connection reset by %s", remote_id); + } /* FALLTHROUGH */ case SSH_ERR_NO_CIPHER_ALG_MATCH: case SSH_ERR_NO_MAC_ALG_MATCH: @@ -2133,12 +1826,14 @@ sshpkt_fatal(struct ssh *ssh, const char case SSH_ERR_NO_KEX_ALG_MATCH: case SSH_ERR_NO_HOSTKEY_ALG_MATCH: if (ssh && ssh->kex && ssh->kex->failed_choice) { + ssh_packet_clear_keys(ssh); logdie("Unable to negotiate with %s: %s. " "Their offer: %s", remote_id, ssh_err(r), ssh->kex->failed_choice); } /* FALLTHROUGH */ default: + ssh_packet_clear_keys(ssh); logdie("%s%sConnection %s %s: %s", tag != NULL ? tag : "", tag != NULL ? ": " : "", ssh->state->server_side ? "from" : "to", @@ -2305,7 +2000,7 @@ ssh_packet_not_very_much_data_to_write(s void ssh_packet_set_tos(struct ssh *ssh, int tos) { - if (!ssh_packet_connection_is_on_socket(ssh)) + if (!ssh_packet_connection_is_on_socket(ssh) || tos == INT_MAX) return; switch (ssh_packet_connection_af(ssh)) { case AF_INET: @@ -2393,36 +2088,6 @@ ssh_packet_get_maxsize(struct ssh *ssh) return ssh->state->max_packet_size; } -/* - * 9.2. Ignored Data Message - * - * byte SSH_MSG_IGNORE - * string data - * - * All implementations MUST understand (and ignore) this message at any - * time (after receiving the protocol version). No implementation is - * required to send them. This message can be used as an additional - * protection measure against advanced traffic analysis techniques. - */ -void -ssh_packet_send_ignore(struct ssh *ssh, int nbytes) -{ - u_int32_t rnd = 0; - int r, i; - - if ((r = sshpkt_start(ssh, compat20 ? - SSH2_MSG_IGNORE : SSH_MSG_IGNORE)) != 0 || - (r = sshpkt_put_u32(ssh, nbytes)) != 0) - fatal("%s: %s", __func__, ssh_err(r)); - for (i = 0; i < nbytes; i++) { - if (i % 4 == 0) - rnd = arc4random(); - if ((r = sshpkt_put_u8(ssh, (u_char)rnd & 0xff)) != 0) - fatal("%s: %s", __func__, ssh_err(r)); - rnd >>= 8; - } -} - void ssh_packet_set_rekey_limits(struct ssh *ssh, u_int64_t bytes, u_int32_t seconds) { @@ -2526,9 +2191,7 @@ newkeys_to_blob(struct sshbuf *m, struct return r; if ((b = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; - /* The cipher struct is constant and shared, you export pointer */ if ((r = sshbuf_put_cstring(b, enc->name)) != 0 || - (r = sshbuf_put(b, &enc->cipher, sizeof(enc->cipher))) != 0 || (r = sshbuf_put_u32(b, enc->enabled)) != 0 || (r = sshbuf_put_u32(b, enc->block_size)) != 0 || (r = sshbuf_put_string(b, enc->key, enc->key_len)) != 0 || @@ -2554,54 +2217,22 @@ int ssh_packet_get_state(struct ssh *ssh, struct sshbuf *m) { struct session_state *state = ssh->state; - u_char *p; - size_t slen, rlen; - int r, ssh1cipher; - - if (!compat20) { - ssh1cipher = cipher_ctx_get_number(state->receive_context); - slen = cipher_get_keyiv_len(state->send_context); - rlen = cipher_get_keyiv_len(state->receive_context); - if ((r = sshbuf_put_u32(m, state->remote_protocol_flags)) != 0 || - (r = sshbuf_put_u32(m, ssh1cipher)) != 0 || - (r = sshbuf_put_string(m, state->ssh1_key, state->ssh1_keylen)) != 0 || - (r = sshbuf_put_u32(m, slen)) != 0 || - (r = sshbuf_reserve(m, slen, &p)) != 0 || - (r = cipher_get_keyiv(state->send_context, p, slen)) != 0 || - (r = sshbuf_put_u32(m, rlen)) != 0 || - (r = sshbuf_reserve(m, rlen, &p)) != 0 || - (r = cipher_get_keyiv(state->receive_context, p, rlen)) != 0) - return r; - } else { - if ((r = kex_to_blob(m, ssh->kex)) != 0 || - (r = newkeys_to_blob(m, ssh, MODE_OUT)) != 0 || - (r = newkeys_to_blob(m, ssh, MODE_IN)) != 0 || - (r = sshbuf_put_u64(m, state->rekey_limit)) != 0 || - (r = sshbuf_put_u32(m, state->rekey_interval)) != 0 || - (r = sshbuf_put_u32(m, state->p_send.seqnr)) != 0 || - (r = sshbuf_put_u64(m, state->p_send.blocks)) != 0 || - (r = sshbuf_put_u32(m, state->p_send.packets)) != 0 || - (r = sshbuf_put_u64(m, state->p_send.bytes)) != 0 || - (r = sshbuf_put_u32(m, state->p_read.seqnr)) != 0 || - (r = sshbuf_put_u64(m, state->p_read.blocks)) != 0 || - (r = sshbuf_put_u32(m, state->p_read.packets)) != 0 || - (r = sshbuf_put_u64(m, state->p_read.bytes)) != 0) - return r; - } + int r; - slen = cipher_get_keycontext(state->send_context, NULL); - rlen = cipher_get_keycontext(state->receive_context, NULL); - if ((r = sshbuf_put_u32(m, slen)) != 0 || - (r = sshbuf_reserve(m, slen, &p)) != 0) - return r; - if (cipher_get_keycontext(state->send_context, p) != (int)slen) - return SSH_ERR_INTERNAL_ERROR; - if ((r = sshbuf_put_u32(m, rlen)) != 0 || - (r = sshbuf_reserve(m, rlen, &p)) != 0) - return r; - if (cipher_get_keycontext(state->receive_context, p) != (int)rlen) - return SSH_ERR_INTERNAL_ERROR; - if ((r = sshbuf_put_stringb(m, state->input)) != 0 || + if ((r = kex_to_blob(m, ssh->kex)) != 0 || + (r = newkeys_to_blob(m, ssh, MODE_OUT)) != 0 || + (r = newkeys_to_blob(m, ssh, MODE_IN)) != 0 || + (r = sshbuf_put_u64(m, state->rekey_limit)) != 0 || + (r = sshbuf_put_u32(m, state->rekey_interval)) != 0 || + (r = sshbuf_put_u32(m, state->p_send.seqnr)) != 0 || + (r = sshbuf_put_u64(m, state->p_send.blocks)) != 0 || + (r = sshbuf_put_u32(m, state->p_send.packets)) != 0 || + (r = sshbuf_put_u64(m, state->p_send.bytes)) != 0 || + (r = sshbuf_put_u32(m, state->p_read.seqnr)) != 0 || + (r = sshbuf_put_u64(m, state->p_read.blocks)) != 0 || + (r = sshbuf_put_u32(m, state->p_read.packets)) != 0 || + (r = sshbuf_put_u64(m, state->p_read.bytes)) != 0 || + (r = sshbuf_put_stringb(m, state->input)) != 0 || (r = sshbuf_put_stringb(m, state->output)) != 0) return r; @@ -2634,12 +2265,15 @@ newkeys_from_blob(struct sshbuf *m, stru comp = &newkey->comp; if ((r = sshbuf_get_cstring(b, &enc->name, NULL)) != 0 || - (r = sshbuf_get(b, &enc->cipher, sizeof(enc->cipher))) != 0 || (r = sshbuf_get_u32(b, (u_int *)&enc->enabled)) != 0 || (r = sshbuf_get_u32(b, &enc->block_size)) != 0 || (r = sshbuf_get_string(b, &enc->key, &keylen)) != 0 || (r = sshbuf_get_string(b, &enc->iv, &ivlen)) != 0) goto out; + if ((enc->cipher = cipher_by_name(enc->name)) == NULL) { + r = SSH_ERR_INVALID_FORMAT; + goto out; + } if (cipher_authlen(enc->cipher) == 0) { if ((r = sshbuf_get_cstring(b, &mac->name, NULL)) != 0) goto out; @@ -2657,11 +2291,6 @@ newkeys_from_blob(struct sshbuf *m, stru if ((r = sshbuf_get_u32(b, &comp->type)) != 0 || (r = sshbuf_get_cstring(b, &comp->name, NULL)) != 0) goto out; - if (enc->name == NULL || - cipher_by_name(enc->name) != enc->cipher) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } if (sshbuf_len(b) != 0) { r = SSH_ERR_INVALID_FORMAT; goto out; @@ -2726,61 +2355,33 @@ int ssh_packet_set_state(struct ssh *ssh, struct sshbuf *m) { struct session_state *state = ssh->state; - const u_char *ssh1key, *ivin, *ivout, *keyin, *keyout, *input, *output; - size_t ssh1keylen, rlen, slen, ilen, olen; + const u_char *input, *output; + size_t ilen, olen; int r; - u_int ssh1cipher = 0; - if (!compat20) { - if ((r = sshbuf_get_u32(m, &state->remote_protocol_flags)) != 0 || - (r = sshbuf_get_u32(m, &ssh1cipher)) != 0 || - (r = sshbuf_get_string_direct(m, &ssh1key, &ssh1keylen)) != 0 || - (r = sshbuf_get_string_direct(m, &ivout, &slen)) != 0 || - (r = sshbuf_get_string_direct(m, &ivin, &rlen)) != 0) - return r; - if (ssh1cipher > INT_MAX) - return SSH_ERR_KEY_UNKNOWN_CIPHER; - ssh_packet_set_encryption_key(ssh, ssh1key, ssh1keylen, - (int)ssh1cipher); - if (cipher_get_keyiv_len(state->send_context) != (int)slen || - cipher_get_keyiv_len(state->receive_context) != (int)rlen) - return SSH_ERR_INVALID_FORMAT; - if ((r = cipher_set_keyiv(state->send_context, ivout)) != 0 || - (r = cipher_set_keyiv(state->receive_context, ivin)) != 0) - return r; - } else { - if ((r = kex_from_blob(m, &ssh->kex)) != 0 || - (r = newkeys_from_blob(m, ssh, MODE_OUT)) != 0 || - (r = newkeys_from_blob(m, ssh, MODE_IN)) != 0 || - (r = sshbuf_get_u64(m, &state->rekey_limit)) != 0 || - (r = sshbuf_get_u32(m, &state->rekey_interval)) != 0 || - (r = sshbuf_get_u32(m, &state->p_send.seqnr)) != 0 || - (r = sshbuf_get_u64(m, &state->p_send.blocks)) != 0 || - (r = sshbuf_get_u32(m, &state->p_send.packets)) != 0 || - (r = sshbuf_get_u64(m, &state->p_send.bytes)) != 0 || - (r = sshbuf_get_u32(m, &state->p_read.seqnr)) != 0 || - (r = sshbuf_get_u64(m, &state->p_read.blocks)) != 0 || - (r = sshbuf_get_u32(m, &state->p_read.packets)) != 0 || - (r = sshbuf_get_u64(m, &state->p_read.bytes)) != 0) - return r; - /* - * We set the time here so that in post-auth privsep slave we - * count from the completion of the authentication. - */ - state->rekey_time = monotime(); - /* XXX ssh_set_newkeys overrides p_read.packets? XXX */ - if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0 || - (r = ssh_set_newkeys(ssh, MODE_OUT)) != 0) - return r; - } - if ((r = sshbuf_get_string_direct(m, &keyout, &slen)) != 0 || - (r = sshbuf_get_string_direct(m, &keyin, &rlen)) != 0) + if ((r = kex_from_blob(m, &ssh->kex)) != 0 || + (r = newkeys_from_blob(m, ssh, MODE_OUT)) != 0 || + (r = newkeys_from_blob(m, ssh, MODE_IN)) != 0 || + (r = sshbuf_get_u64(m, &state->rekey_limit)) != 0 || + (r = sshbuf_get_u32(m, &state->rekey_interval)) != 0 || + (r = sshbuf_get_u32(m, &state->p_send.seqnr)) != 0 || + (r = sshbuf_get_u64(m, &state->p_send.blocks)) != 0 || + (r = sshbuf_get_u32(m, &state->p_send.packets)) != 0 || + (r = sshbuf_get_u64(m, &state->p_send.bytes)) != 0 || + (r = sshbuf_get_u32(m, &state->p_read.seqnr)) != 0 || + (r = sshbuf_get_u64(m, &state->p_read.blocks)) != 0 || + (r = sshbuf_get_u32(m, &state->p_read.packets)) != 0 || + (r = sshbuf_get_u64(m, &state->p_read.bytes)) != 0) + return r; + /* + * We set the time here so that in post-auth privsep slave we + * count from the completion of the authentication. + */ + state->rekey_time = monotime(); + /* XXX ssh_set_newkeys overrides p_read.packets? XXX */ + if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0 || + (r = ssh_set_newkeys(ssh, MODE_OUT)) != 0) return r; - if (cipher_get_keycontext(state->send_context, NULL) != (int)slen || - cipher_get_keycontext(state->receive_context, NULL) != (int)rlen) - return SSH_ERR_INVALID_FORMAT; - cipher_set_keycontext(state->send_context, keyout); - cipher_set_keycontext(state->receive_context, keyin); if ((r = ssh_packet_set_postauth(ssh)) != 0) return r; @@ -2858,13 +2459,6 @@ sshpkt_put_ec(struct ssh *ssh, const EC_ return sshbuf_put_ec(ssh->state->outgoing_packet, v, g); } -#ifdef WITH_SSH1 -int -sshpkt_put_bignum1(struct ssh *ssh, const BIGNUM *v) -{ - return sshbuf_put_bignum1(ssh->state->outgoing_packet, v); -} -#endif /* WITH_SSH1 */ int sshpkt_put_bignum2(struct ssh *ssh, const BIGNUM *v) @@ -2912,6 +2506,12 @@ sshpkt_get_string_direct(struct ssh *ssh } int +sshpkt_peek_string_direct(struct ssh *ssh, const u_char **valp, size_t *lenp) +{ + return sshbuf_peek_string_direct(ssh->state->incoming_packet, valp, lenp); +} + +int sshpkt_get_cstring(struct ssh *ssh, char **valp, size_t *lenp) { return sshbuf_get_cstring(ssh->state->incoming_packet, valp, lenp); @@ -2924,13 +2524,6 @@ sshpkt_get_ec(struct ssh *ssh, EC_POINT return sshbuf_get_ec(ssh->state->incoming_packet, v, g); } -#ifdef WITH_SSH1 -int -sshpkt_get_bignum1(struct ssh *ssh, BIGNUM *v) -{ - return sshbuf_get_bignum1(ssh->state->incoming_packet, v); -} -#endif /* WITH_SSH1 */ int sshpkt_get_bignum2(struct ssh *ssh, BIGNUM *v) @@ -2960,15 +2553,13 @@ sshpkt_ptr(struct ssh *ssh, size_t *lenp int sshpkt_start(struct ssh *ssh, u_char type) { - u_char buf[9]; - int len; + u_char buf[6]; /* u32 packet length, u8 pad len, u8 type */ DBG(debug("packet_start[%d]", type)); - len = compat20 ? 6 : 9; - memset(buf, 0, len - 1); - buf[len - 1] = type; + memset(buf, 0, sizeof(buf)); + buf[sizeof(buf) - 1] = type; sshbuf_reset(ssh->state->outgoing_packet); - return sshbuf_put(ssh->state->outgoing_packet, buf, len); + return sshbuf_put(ssh->state->outgoing_packet, buf, sizeof(buf)); } static int @@ -3001,6 +2592,37 @@ ssh_packet_send_mux(struct ssh *ssh) return 0; } +/* + * 9.2. Ignored Data Message + * + * byte SSH_MSG_IGNORE + * string data + * + * All implementations MUST understand (and ignore) this message at any + * time (after receiving the protocol version). No implementation is + * required to send them. This message can be used as an additional + * protection measure against advanced traffic analysis techniques. + */ +int +sshpkt_msg_ignore(struct ssh *ssh, u_int nbytes) +{ + u_int32_t rnd = 0; + int r; + u_int i; + + if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 || + (r = sshpkt_put_u32(ssh, nbytes)) != 0) + return r; + for (i = 0; i < nbytes; i++) { + if (i % 4 == 0) + rnd = arc4random(); + if ((r = sshpkt_put_u8(ssh, (u_char)rnd & 0xff)) != 0) + return r; + rnd >>= 8; + } + return 0; +} + /* send it */ int @@ -3008,10 +2630,7 @@ sshpkt_sendx(struct ssh *ssh) { if (ssh->state && ssh->state->mux) return ssh_packet_send_mux(ssh); - if (compat20) - return ssh_packet_send2(ssh); - else - return ssh_packet_send1(ssh); + return ssh_packet_send2(ssh); } int @@ -3032,19 +2651,12 @@ sshpkt_disconnect(struct ssh *ssh, const vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); - if (compat20) { - if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 || - (r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 || - (r = sshpkt_put_cstring(ssh, buf)) != 0 || - (r = sshpkt_put_cstring(ssh, "")) != 0 || - (r = sshpkt_send(ssh)) != 0) - return r; - } else { - if ((r = sshpkt_start(ssh, SSH_MSG_DISCONNECT)) != 0 || - (r = sshpkt_put_cstring(ssh, buf)) != 0 || - (r = sshpkt_send(ssh)) != 0) - return r; - } + if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 || + (r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 || + (r = sshpkt_put_cstring(ssh, buf)) != 0 || + (r = sshpkt_put_cstring(ssh, "")) != 0 || + (r = sshpkt_send(ssh)) != 0) + return r; return 0; }