summaryrefslogtreecommitdiff
path: root/packet.c
diff options
context:
space:
mode:
Diffstat (limited to 'packet.c')
-rw-r--r--packet.c330
1 files changed, 170 insertions, 160 deletions
diff --git a/packet.c b/packet.c
index d6dad2da61417..ad1f6b4971b20 100644
--- a/packet.c
+++ b/packet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.234 2016/07/18 11:35:33 markus Exp $ */
+/* $OpenBSD: packet.c,v 1.243 2016/10/11 21:47:45 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -38,8 +38,7 @@
*/
#include "includes.h"
-
-#include <sys/param.h> /* MIN roundup */
+
#include <sys/types.h>
#include "openbsd-compat/sys-queue.h"
#include <sys/socket.h>
@@ -122,10 +121,10 @@ struct session_state {
u_int remote_protocol_flags;
/* Encryption context for receiving data. Only used for decryption. */
- struct sshcipher_ctx receive_context;
+ struct sshcipher_ctx *receive_context;
/* Encryption context for sending data. Only used for encryption. */
- struct sshcipher_ctx send_context;
+ struct sshcipher_ctx *send_context;
/* Buffer for raw input data from the socket. */
struct sshbuf *input;
@@ -205,6 +204,9 @@ struct session_state {
/* Used in packet_send2 */
int rekeying;
+ /* Used in ssh_packet_send_mux() */
+ int mux;
+
/* Used in packet_set_interactive */
int set_interactive_called;
@@ -217,6 +219,10 @@ struct session_state {
/* SSH1 CRC compensation attack detector */
struct deattack_ctx deattack;
+ /* Hook for fuzzing inbound packets */
+ ssh_packet_hook_fn *hook_in;
+ void *hook_in_ctx;
+
TAILQ_HEAD(, packet) outgoing;
};
@@ -261,6 +267,13 @@ ssh_alloc_session_state(void)
return NULL;
}
+void
+ssh_packet_set_input_hook(struct ssh *ssh, ssh_packet_hook_fn *hook, void *ctx)
+{
+ ssh->state->hook_in = hook;
+ ssh->state->hook_in_ctx = ctx;
+}
+
/* Returns nonzero if rekeying is in progress */
int
ssh_packet_is_rekeying(struct ssh *ssh)
@@ -326,6 +339,19 @@ ssh_packet_set_timeout(struct ssh *ssh, int timeout, int count)
state->packet_timeout_ms = timeout * count * 1000;
}
+void
+ssh_packet_set_mux(struct ssh *ssh)
+{
+ ssh->state->mux = 1;
+ ssh->state->rekeying = 0;
+}
+
+int
+ssh_packet_get_mux(struct ssh *ssh)
+{
+ return ssh->state->mux;
+}
+
int
ssh_packet_stop_discard(struct ssh *ssh)
{
@@ -529,7 +555,6 @@ void
ssh_packet_close(struct ssh *ssh)
{
struct session_state *state = ssh->state;
- int r;
u_int mode;
if (!state->initialized)
@@ -573,10 +598,9 @@ ssh_packet_close(struct ssh *ssh)
inflateEnd(stream);
}
}
- if ((r = cipher_cleanup(&state->send_context)) != 0)
- error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r));
- if ((r = cipher_cleanup(&state->receive_context)) != 0)
- error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r));
+ 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);
@@ -759,86 +783,6 @@ uncompress_buffer(struct ssh *ssh, struct sshbuf *in, struct sshbuf *out)
/* NOTREACHED */
}
-/* Serialise compression state into a blob for privsep */
-static int
-ssh_packet_get_compress_state(struct sshbuf *m, struct ssh *ssh)
-{
- struct session_state *state = ssh->state;
- struct sshbuf *b;
- int r;
-
- if ((b = sshbuf_new()) == NULL)
- return SSH_ERR_ALLOC_FAIL;
- if (state->compression_in_started) {
- if ((r = sshbuf_put_string(b, &state->compression_in_stream,
- sizeof(state->compression_in_stream))) != 0)
- goto out;
- } else if ((r = sshbuf_put_string(b, NULL, 0)) != 0)
- goto out;
- if (state->compression_out_started) {
- if ((r = sshbuf_put_string(b, &state->compression_out_stream,
- sizeof(state->compression_out_stream))) != 0)
- goto out;
- } else if ((r = sshbuf_put_string(b, NULL, 0)) != 0)
- goto out;
- r = sshbuf_put_stringb(m, b);
- out:
- sshbuf_free(b);
- return r;
-}
-
-/* Deserialise compression state from a blob for privsep */
-static int
-ssh_packet_set_compress_state(struct ssh *ssh, struct sshbuf *m)
-{
- struct session_state *state = ssh->state;
- struct sshbuf *b = NULL;
- int r;
- const u_char *inblob, *outblob;
- size_t inl, outl;
-
- if ((r = sshbuf_froms(m, &b)) != 0)
- goto out;
- if ((r = sshbuf_get_string_direct(b, &inblob, &inl)) != 0 ||
- (r = sshbuf_get_string_direct(b, &outblob, &outl)) != 0)
- goto out;
- if (inl == 0)
- state->compression_in_started = 0;
- else if (inl != sizeof(state->compression_in_stream)) {
- r = SSH_ERR_INTERNAL_ERROR;
- goto out;
- } else {
- state->compression_in_started = 1;
- memcpy(&state->compression_in_stream, inblob, inl);
- }
- if (outl == 0)
- state->compression_out_started = 0;
- else if (outl != sizeof(state->compression_out_stream)) {
- r = SSH_ERR_INTERNAL_ERROR;
- goto out;
- } else {
- state->compression_out_started = 1;
- memcpy(&state->compression_out_stream, outblob, outl);
- }
- r = 0;
- out:
- sshbuf_free(b);
- return r;
-}
-
-void
-ssh_packet_set_compress_hooks(struct ssh *ssh, void *ctx,
- void *(*allocfunc)(void *, u_int, u_int),
- void (*freefunc)(void *, void *))
-{
- ssh->state->compression_out_stream.zalloc = (alloc_func)allocfunc;
- ssh->state->compression_out_stream.zfree = (free_func)freefunc;
- ssh->state->compression_out_stream.opaque = ctx;
- ssh->state->compression_in_stream.zalloc = (alloc_func)allocfunc;
- ssh->state->compression_in_stream.zfree = (free_func)freefunc;
- ssh->state->compression_in_stream.opaque = ctx;
-}
-
/*
* 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
@@ -870,8 +814,8 @@ ssh_packet_set_encryption_key(struct ssh *ssh, const u_char *key, u_int 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)) {
+ ((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;
}
@@ -917,7 +861,7 @@ ssh_packet_send1(struct ssh *ssh)
/* Insert padding. Initialized to zero in packet_start1() */
padding = 8 - len % 8;
- if (!state->send_context.plaintext) {
+ if (!cipher_ctx_is_plaintext(state->send_context)) {
cp = sshbuf_mutable_ptr(state->outgoing_packet);
if (cp == NULL) {
r = SSH_ERR_INTERNAL_ERROR;
@@ -947,7 +891,7 @@ ssh_packet_send1(struct ssh *ssh)
if ((r = sshbuf_reserve(state->output,
sshbuf_len(state->outgoing_packet), &cp)) != 0)
goto out;
- if ((r = cipher_crypt(&state->send_context, 0, cp,
+ if ((r = cipher_crypt(state->send_context, 0, cp,
sshbuf_ptr(state->outgoing_packet),
sshbuf_len(state->outgoing_packet), 0, 0)) != 0)
goto out;
@@ -978,33 +922,34 @@ ssh_set_newkeys(struct ssh *ssh, int mode)
struct sshenc *enc;
struct sshmac *mac;
struct sshcomp *comp;
- struct sshcipher_ctx *cc;
+ struct sshcipher_ctx **ccp;
+ struct packet_state *ps;
u_int64_t *max_blocks;
- const char *wmsg;
+ const char *wmsg, *dir;
int r, crypt_type;
debug2("set_newkeys: mode %d", mode);
if (mode == MODE_OUT) {
- cc = &state->send_context;
+ dir = "output";
+ ccp = &state->send_context;
crypt_type = CIPHER_ENCRYPT;
- state->p_send.packets = state->p_send.blocks = 0;
+ ps = &state->p_send;
max_blocks = &state->max_blocks_out;
} else {
- cc = &state->receive_context;
+ dir = "input";
+ ccp = &state->receive_context;
crypt_type = CIPHER_DECRYPT;
- state->p_read.packets = state->p_read.blocks = 0;
+ ps = &state->p_read;
max_blocks = &state->max_blocks_in;
}
if (state->newkeys[mode] != NULL) {
- 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);
- if ((r = cipher_cleanup(cc)) != 0)
- return r;
+ debug("%s: rekeying after %llu %s blocks"
+ " (%llu bytes total)", __func__,
+ (unsigned long long)ps->blocks, dir,
+ (unsigned long long)ps->bytes);
+ cipher_free(*ccp);
+ *ccp = NULL;
enc = &state->newkeys[mode]->enc;
mac = &state->newkeys[mode]->mac;
comp = &state->newkeys[mode]->comp;
@@ -1020,6 +965,8 @@ ssh_set_newkeys(struct ssh *ssh, int mode)
free(comp->name);
free(state->newkeys[mode]);
}
+ /* note that both bytes and the seqnr are not reset */
+ ps->packets = ps->blocks = 0;
/* move newkeys from kex to state */
if ((state->newkeys[mode] = ssh->kex->newkeys[mode]) == NULL)
return SSH_ERR_INTERNAL_ERROR;
@@ -1033,11 +980,11 @@ ssh_set_newkeys(struct ssh *ssh, int mode)
}
mac->enabled = 1;
DBG(debug("cipher_init_context: %d", mode));
- if ((r = cipher_init(cc, enc->cipher, enc->key, enc->key_len,
+ if ((r = cipher_init(ccp, enc->cipher, enc->key, enc->key_len,
enc->iv, enc->iv_len, crypt_type)) != 0)
return r;
if (!state->cipher_warning_done &&
- (wmsg = cipher_warning_message(cc)) != NULL) {
+ (wmsg = cipher_warning_message(*ccp)) != NULL) {
error("Warning: %s", wmsg);
state->cipher_warning_done = 1;
}
@@ -1068,7 +1015,7 @@ ssh_set_newkeys(struct ssh *ssh, int mode)
else
*max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
if (state->rekey_limit)
- *max_blocks = MIN(*max_blocks,
+ *max_blocks = MINIMUM(*max_blocks,
state->rekey_limit / enc->block_size);
debug("rekey after %llu blocks", (unsigned long long)*max_blocks);
return 0;
@@ -1111,7 +1058,7 @@ ssh_packet_need_rekeying(struct ssh *ssh, u_int outbound_packet_len)
return 1;
/* Rekey after (cipher-specific) maxiumum blocks */
- out_blocks = roundup(outbound_packet_len,
+ out_blocks = ROUNDUP(outbound_packet_len,
state->newkeys[MODE_OUT]->enc.block_size);
return (state->max_blocks_out &&
(state->p_send.blocks + out_blocks > state->max_blocks_out)) ||
@@ -1158,7 +1105,7 @@ ssh_packet_enable_delayed_compress(struct ssh *ssh)
}
/* Used to mute debug logging for noisy packet types */
-static int
+int
ssh_packet_log_type(u_char type)
{
switch (type) {
@@ -1239,7 +1186,7 @@ ssh_packet_send2_wrapped(struct ssh *ssh)
if (state->extra_pad) {
tmp = state->extra_pad;
state->extra_pad =
- roundup(state->extra_pad, block_size);
+ ROUNDUP(state->extra_pad, block_size);
/* check if roundup overflowed */
if (state->extra_pad < tmp)
return SSH_ERR_INVALID_ARGUMENT;
@@ -1259,7 +1206,7 @@ ssh_packet_send2_wrapped(struct ssh *ssh)
}
if ((r = sshbuf_reserve(state->outgoing_packet, padlen, &cp)) != 0)
goto out;
- if (enc && !state->send_context.plaintext) {
+ if (enc && !cipher_ctx_is_plaintext(state->send_context)) {
/* random padding */
arc4random_buf(cp, padlen);
} else {
@@ -1291,7 +1238,7 @@ ssh_packet_send2_wrapped(struct ssh *ssh)
if ((r = sshbuf_reserve(state->output,
sshbuf_len(state->outgoing_packet) + authlen, &cp)) != 0)
goto out;
- if ((r = cipher_crypt(&state->send_context, state->p_send.seqnr, cp,
+ if ((r = cipher_crypt(state->send_context, state->p_send.seqnr, cp,
sshbuf_ptr(state->outgoing_packet),
len - aadlen, aadlen, authlen)) != 0)
goto out;
@@ -1606,7 +1553,7 @@ ssh_packet_read_poll1(struct ssh *ssh, u_char *typep)
* (C)1998 CORE-SDI, Buenos Aires Argentina
* Ariel Futoransky(futo@core-sdi.com)
*/
- if (!state->receive_context.plaintext) {
+ if (!cipher_ctx_is_plaintext(state->receive_context)) {
emsg = NULL;
switch (detect_attack(&state->deattack,
sshbuf_ptr(state->input), padded_len)) {
@@ -1635,7 +1582,7 @@ ssh_packet_read_poll1(struct ssh *ssh, u_char *typep)
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,
+ if ((r = cipher_crypt(state->receive_context, 0, p,
sshbuf_ptr(state->input), padded_len, 0, 0)) != 0)
goto out;
@@ -1703,6 +1650,44 @@ ssh_packet_read_poll1(struct ssh *ssh, u_char *typep)
return r;
}
+static int
+ssh_packet_read_poll2_mux(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
+{
+ struct session_state *state = ssh->state;
+ const u_char *cp;
+ size_t need;
+ int r;
+
+ if (ssh->kex)
+ return SSH_ERR_INTERNAL_ERROR;
+ *typep = SSH_MSG_NONE;
+ cp = sshbuf_ptr(state->input);
+ if (state->packlen == 0) {
+ if (sshbuf_len(state->input) < 4 + 1)
+ return 0; /* packet is incomplete */
+ state->packlen = PEEK_U32(cp);
+ if (state->packlen < 4 + 1 ||
+ state->packlen > PACKET_MAX_SIZE)
+ return SSH_ERR_MESSAGE_INCOMPLETE;
+ }
+ need = state->packlen + 4;
+ if (sshbuf_len(state->input) < need)
+ return 0; /* packet is incomplete */
+ sshbuf_reset(state->incoming_packet);
+ if ((r = sshbuf_put(state->incoming_packet, cp + 4,
+ state->packlen)) != 0 ||
+ (r = sshbuf_consume(state->input, need)) != 0 ||
+ (r = sshbuf_get_u8(state->incoming_packet, NULL)) != 0 ||
+ (r = sshbuf_get_u8(state->incoming_packet, typep)) != 0)
+ return r;
+ if (ssh_packet_log_type(*typep))
+ debug3("%s: type %u", __func__, *typep);
+ /* sshbuf_dump(state->incoming_packet, stderr); */
+ /* reset for next packet */
+ state->packlen = 0;
+ return r;
+}
+
int
ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
{
@@ -1715,6 +1700,9 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
struct sshcomp *comp = NULL;
int r;
+ if (state->mux)
+ return ssh_packet_read_poll2_mux(ssh, typep, seqnr_p);
+
*typep = SSH_MSG_NONE;
if (state->packet_discard)
@@ -1733,7 +1721,7 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0;
if (aadlen && state->packlen == 0) {
- if (cipher_get_length(&state->receive_context,
+ if (cipher_get_length(state->receive_context,
&state->packlen, state->p_read.seqnr,
sshbuf_ptr(state->input), sshbuf_len(state->input)) != 0)
return 0;
@@ -1759,7 +1747,7 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
if ((r = sshbuf_reserve(state->incoming_packet, block_size,
&cp)) != 0)
goto out;
- if ((r = cipher_crypt(&state->receive_context,
+ if ((r = cipher_crypt(state->receive_context,
state->p_send.seqnr, cp, sshbuf_ptr(state->input),
block_size, 0, 0)) != 0)
goto out;
@@ -1827,7 +1815,7 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
if ((r = sshbuf_reserve(state->incoming_packet, aadlen + need,
&cp)) != 0)
goto out;
- if ((r = cipher_crypt(&state->receive_context, state->p_read.seqnr, cp,
+ if ((r = cipher_crypt(state->receive_context, state->p_read.seqnr, cp,
sshbuf_ptr(state->input), need, aadlen, authlen)) != 0)
goto out;
if ((r = sshbuf_consume(state->input, aadlen + need + authlen)) != 0)
@@ -1907,9 +1895,11 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
return r;
return SSH_ERR_PROTOCOL_ERROR;
}
- if (*typep == SSH2_MSG_NEWKEYS)
- r = ssh_set_newkeys(ssh, MODE_IN);
- else if (*typep == SSH2_MSG_USERAUTH_SUCCESS && !state->server_side)
+ if (state->hook_in != NULL &&
+ (r = state->hook_in(ssh, state->incoming_packet, typep,
+ state->hook_in_ctx)) != 0)
+ return r;
+ if (*typep == SSH2_MSG_USERAUTH_SUCCESS && !state->server_side)
r = ssh_packet_enable_delayed_compress(ssh);
else
r = 0;
@@ -2452,21 +2442,14 @@ ssh_packet_get_output(struct ssh *ssh)
static int
ssh_packet_set_postauth(struct ssh *ssh)
{
- struct sshcomp *comp;
- int r, mode;
+ int r;
debug("%s: called", __func__);
/* This was set in net child, but is not visible in user child */
ssh->state->after_authentication = 1;
ssh->state->rekeying = 0;
- for (mode = 0; mode < MODE_MAX; mode++) {
- if (ssh->state->newkeys[mode] == NULL)
- continue;
- comp = &ssh->state->newkeys[mode]->comp;
- if (comp && comp->enabled &&
- (r = ssh_packet_init_compression(ssh)) != 0)
- return r;
- }
+ if ((r = ssh_packet_enable_delayed_compress(ssh)) != 0)
+ return r;
return 0;
}
@@ -2509,8 +2492,8 @@ newkeys_to_blob(struct sshbuf *m, struct ssh *ssh, int mode)
enc = &newkey->enc;
mac = &newkey->mac;
comp = &newkey->comp;
- cc = (mode == MODE_OUT) ? &ssh->state->send_context :
- &ssh->state->receive_context;
+ cc = (mode == MODE_OUT) ? ssh->state->send_context :
+ ssh->state->receive_context;
if ((r = cipher_get_keyiv(cc, enc->iv, enc->iv_len)) != 0)
return r;
if ((b = sshbuf_new()) == NULL)
@@ -2530,7 +2513,6 @@ newkeys_to_blob(struct sshbuf *m, struct ssh *ssh, int mode)
goto out;
}
if ((r = sshbuf_put_u32(b, comp->type)) != 0 ||
- (r = sshbuf_put_u32(b, comp->enabled)) != 0 ||
(r = sshbuf_put_cstring(b, comp->name)) != 0)
goto out;
r = sshbuf_put_stringb(m, b);
@@ -2549,18 +2531,18 @@ ssh_packet_get_state(struct ssh *ssh, struct sshbuf *m)
int r, ssh1cipher;
if (!compat20) {
- ssh1cipher = cipher_get_number(state->receive_context.cipher);
- slen = cipher_get_keyiv_len(&state->send_context);
- rlen = cipher_get_keyiv_len(&state->receive_context);
+ 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 = 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)
+ (r = cipher_get_keyiv(state->receive_context, p, rlen)) != 0)
return r;
} else {
if ((r = kex_to_blob(m, ssh->kex)) != 0 ||
@@ -2579,21 +2561,19 @@ ssh_packet_get_state(struct ssh *ssh, struct sshbuf *m)
return r;
}
- slen = cipher_get_keycontext(&state->send_context, NULL);
- rlen = cipher_get_keycontext(&state->receive_context, NULL);
+ 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)
+ 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)
+ if (cipher_get_keycontext(state->receive_context, p) != (int)rlen)
return SSH_ERR_INTERNAL_ERROR;
-
- if ((r = ssh_packet_get_compress_state(m, ssh)) != 0 ||
- (r = sshbuf_put_stringb(m, state->input)) != 0 ||
+ if ((r = sshbuf_put_stringb(m, state->input)) != 0 ||
(r = sshbuf_put_stringb(m, state->output)) != 0)
return r;
@@ -2647,7 +2627,6 @@ newkeys_from_blob(struct sshbuf *m, struct ssh *ssh, int mode)
mac->key_len = maclen;
}
if ((r = sshbuf_get_u32(b, &comp->type)) != 0 ||
- (r = sshbuf_get_u32(b, (u_int *)&comp->enabled)) != 0 ||
(r = sshbuf_get_cstring(b, &comp->name, NULL)) != 0)
goto out;
if (enc->name == NULL ||
@@ -2735,11 +2714,11 @@ ssh_packet_set_state(struct ssh *ssh, struct sshbuf *m)
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)
+ 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)
+ 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 ||
@@ -2769,14 +2748,13 @@ ssh_packet_set_state(struct ssh *ssh, struct sshbuf *m)
if ((r = sshbuf_get_string_direct(m, &keyout, &slen)) != 0 ||
(r = sshbuf_get_string_direct(m, &keyin, &rlen)) != 0)
return r;
- if (cipher_get_keycontext(&state->send_context, NULL) != (int)slen ||
- cipher_get_keycontext(&state->receive_context, NULL) != (int)rlen)
+ 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);
+ cipher_set_keycontext(state->send_context, keyout);
+ cipher_set_keycontext(state->receive_context, keyin);
- if ((r = ssh_packet_set_compress_state(ssh, m)) != 0 ||
- (r = ssh_packet_set_postauth(ssh)) != 0)
+ if ((r = ssh_packet_set_postauth(ssh)) != 0)
return r;
sshbuf_reset(state->input);
@@ -2969,11 +2947,43 @@ sshpkt_start(struct ssh *ssh, u_char type)
return sshbuf_put(ssh->state->outgoing_packet, buf, len);
}
+static int
+ssh_packet_send_mux(struct ssh *ssh)
+{
+ struct session_state *state = ssh->state;
+ u_char type, *cp;
+ size_t len;
+ int r;
+
+ if (ssh->kex)
+ return SSH_ERR_INTERNAL_ERROR;
+ len = sshbuf_len(state->outgoing_packet);
+ if (len < 6)
+ return SSH_ERR_INTERNAL_ERROR;
+ cp = sshbuf_mutable_ptr(state->outgoing_packet);
+ type = cp[5];
+ if (ssh_packet_log_type(type))
+ debug3("%s: type %u", __func__, type);
+ /* drop everything, but the connection protocol */
+ if (type >= SSH2_MSG_CONNECTION_MIN &&
+ type <= SSH2_MSG_CONNECTION_MAX) {
+ POKE_U32(cp, len - 4);
+ if ((r = sshbuf_putb(state->output,
+ state->outgoing_packet)) != 0)
+ return r;
+ /* sshbuf_dump(state->output, stderr); */
+ }
+ sshbuf_reset(state->outgoing_packet);
+ return 0;
+}
+
/* send it */
int
sshpkt_send(struct ssh *ssh)
{
+ if (ssh->state && ssh->state->mux)
+ return ssh_packet_send_mux(ssh);
if (compat20)
return ssh_packet_send2(ssh);
else