blob: 0ae65bd3236129ee1c569698187442c7ee969cf4 [file] [log] [blame]
djm@openbsd.orgde2997a2018-07-16 03:09:13 +00001/* $OpenBSD: packet.c,v 1.277 2018/07/16 03:09:13 djm Exp $ */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002/*
Damien Miller95def091999-11-25 00:26:21 +11003 * Author: Tatu Ylonen <ylo@cs.hut.fi>
Damien Miller95def091999-11-25 00:26:21 +11004 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 * All rights reserved
Damien Miller95def091999-11-25 00:26:21 +11006 * This file contains code implementing the packet protocol and communication
7 * with the other side. This same code is used both on client and server side.
Damien Miller33b13562000-04-04 14:38:59 +10008 *
Damien Millere4340be2000-09-16 13:29:08 +11009 * As far as I am concerned, the code I have written for this software
10 * can be used freely for any purpose. Any derived versions of this
11 * software must be clearly marked as such, and if the derived work is
12 * incompatible with the protocol description in the RFC file, it must be
13 * called by a name other than "ssh" or "Secure Shell".
Damien Miller33b13562000-04-04 14:38:59 +100014 *
Damien Millere4340be2000-09-16 13:29:08 +110015 *
16 * SSH2 packet format added by Markus Friedl.
Ben Lindstrom44697232001-07-04 03:32:30 +000017 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
Damien Millere4340be2000-09-16 13:29:08 +110018 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
29 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
30 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
31 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
32 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
33 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
37 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Damien Miller95def091999-11-25 00:26:21 +110038 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100039
40#include "includes.h"
deraadt@openbsd.org9136ec12016-09-12 01:22:38 +000041
Damien Millere3b60b52006-07-10 21:08:03 +100042#include <sys/types.h>
Damien Millera0898b82003-04-09 21:05:52 +100043#include "openbsd-compat/sys-queue.h"
Damien Miller8ec8c3e2006-07-10 20:35:38 +100044#include <sys/socket.h>
Damien Miller9aec9192006-08-05 10:57:45 +100045#ifdef HAVE_SYS_TIME_H
46# include <sys/time.h>
47#endif
Damien Miller8ec8c3e2006-07-10 20:35:38 +100048
Damien Miller8ec8c3e2006-07-10 20:35:38 +100049#include <netinet/in.h>
Damien Miller68f8e992006-03-15 11:24:12 +110050#include <netinet/ip.h>
Darren Tuckerdace2332006-09-22 19:22:17 +100051#include <arpa/inet.h>
Damien Millerd4a8b7e1999-10-27 13:42:43 +100052
Darren Tucker39972492006-07-12 22:22:46 +100053#include <errno.h>
djm@openbsd.org95767262016-03-07 19:02:43 +000054#include <netdb.h>
Darren Tucker5d196262006-07-12 22:15:16 +100055#include <stdarg.h>
Damien Millera7a73ee2006-08-05 11:37:59 +100056#include <stdio.h>
Damien Millere7a1e5c2006-08-05 11:34:19 +100057#include <stdlib.h>
Damien Millere3476ed2006-07-24 14:13:33 +100058#include <string.h>
Damien Millere6b3b612006-07-24 14:01:23 +100059#include <unistd.h>
deraadt@openbsd.org087266e2015-01-20 23:14:00 +000060#include <limits.h>
Damien Millerd7834352006-08-05 12:39:39 +100061#include <signal.h>
Darren Tuckerc53c2af2013-05-16 20:28:16 +100062#include <time.h>
Darren Tucker5d196262006-07-12 22:15:16 +100063
markus@openbsd.org091c3022015-01-19 19:52:16 +000064#include <zlib.h>
65
Damien Millerd4a8b7e1999-10-27 13:42:43 +100066#include "xmalloc.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100067#include "crc32.h"
Damien Miller33b13562000-04-04 14:38:59 +100068#include "compat.h"
69#include "ssh2.h"
Damien Miller874d77b2000-10-14 16:23:11 +110070#include "cipher.h"
markus@openbsd.org091c3022015-01-19 19:52:16 +000071#include "sshkey.h"
Damien Miller33b13562000-04-04 14:38:59 +100072#include "kex.h"
markus@openbsd.org128343b2015-01-13 19:31:40 +000073#include "digest.h"
Ben Lindstrom06b33aa2001-02-15 03:01:59 +000074#include "mac.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000075#include "log.h"
76#include "canohost.h"
Damien Miller4d007762002-02-05 11:52:54 +110077#include "misc.h"
Damien Miller7acefbb2014-07-18 14:11:24 +100078#include "channels.h"
Ben Lindstrom402c6cc2002-06-21 00:43:42 +000079#include "ssh.h"
markus@openbsd.org091c3022015-01-19 19:52:16 +000080#include "packet.h"
markus@openbsd.org091c3022015-01-19 19:52:16 +000081#include "ssherr.h"
82#include "sshbuf.h"
Damien Miller33b13562000-04-04 14:38:59 +100083
84#ifdef PACKET_DEBUG
85#define DBG(x) x
86#else
87#define DBG(x)
88#endif
89
Damien Miller13ae44c2009-01-28 16:38:41 +110090#define PACKET_MAX_SIZE (256 * 1024)
91
Darren Tuckerf7288d72009-06-21 18:12:20 +100092struct packet_state {
Damien Millera5539d22003-04-09 20:50:06 +100093 u_int32_t seqnr;
94 u_int32_t packets;
95 u_int64_t blocks;
Damien Millerb61f3fc2008-07-11 17:36:48 +100096 u_int64_t bytes;
Darren Tuckerf7288d72009-06-21 18:12:20 +100097};
Damien Miller13ae44c2009-01-28 16:38:41 +110098
Damien Millera5539d22003-04-09 20:50:06 +100099struct packet {
100 TAILQ_ENTRY(packet) next;
101 u_char type;
markus@openbsd.org091c3022015-01-19 19:52:16 +0000102 struct sshbuf *payload;
Damien Millera5539d22003-04-09 20:50:06 +1000103};
Darren Tuckerf7288d72009-06-21 18:12:20 +1000104
105struct session_state {
106 /*
107 * This variable contains the file descriptors used for
108 * communicating with the other side. connection_in is used for
109 * reading; connection_out for writing. These can be the same
110 * descriptor, in which case it is assumed to be a socket.
111 */
112 int connection_in;
113 int connection_out;
114
115 /* Protocol flags for the remote side. */
116 u_int remote_protocol_flags;
117
118 /* Encryption context for receiving data. Only used for decryption. */
djm@openbsd.org4706c1d2016-08-03 05:41:57 +0000119 struct sshcipher_ctx *receive_context;
Darren Tuckerf7288d72009-06-21 18:12:20 +1000120
121 /* Encryption context for sending data. Only used for encryption. */
djm@openbsd.org4706c1d2016-08-03 05:41:57 +0000122 struct sshcipher_ctx *send_context;
Darren Tuckerf7288d72009-06-21 18:12:20 +1000123
124 /* Buffer for raw input data from the socket. */
markus@openbsd.org091c3022015-01-19 19:52:16 +0000125 struct sshbuf *input;
Darren Tuckerf7288d72009-06-21 18:12:20 +1000126
127 /* Buffer for raw output data going to the socket. */
markus@openbsd.org091c3022015-01-19 19:52:16 +0000128 struct sshbuf *output;
Darren Tuckerf7288d72009-06-21 18:12:20 +1000129
130 /* Buffer for the partial outgoing packet being constructed. */
markus@openbsd.org091c3022015-01-19 19:52:16 +0000131 struct sshbuf *outgoing_packet;
Darren Tuckerf7288d72009-06-21 18:12:20 +1000132
133 /* Buffer for the incoming packet currently being processed. */
markus@openbsd.org091c3022015-01-19 19:52:16 +0000134 struct sshbuf *incoming_packet;
Darren Tuckerf7288d72009-06-21 18:12:20 +1000135
136 /* Scratch buffer for packet compression/decompression. */
markus@openbsd.org091c3022015-01-19 19:52:16 +0000137 struct sshbuf *compression_buffer;
138
139 /* Incoming/outgoing compression dictionaries */
140 z_stream compression_in_stream;
141 z_stream compression_out_stream;
142 int compression_in_started;
143 int compression_out_started;
144 int compression_in_failures;
145 int compression_out_failures;
Darren Tuckerf7288d72009-06-21 18:12:20 +1000146
Darren Tuckerf7288d72009-06-21 18:12:20 +1000147 /* default maximum packet size */
148 u_int max_packet_size;
149
150 /* Flag indicating whether this module has been initialized. */
151 int initialized;
152
153 /* Set to true if the connection is interactive. */
154 int interactive_mode;
155
156 /* Set to true if we are the server side. */
157 int server_side;
158
159 /* Set to true if we are authenticated. */
160 int after_authentication;
161
162 int keep_alive_timeouts;
163
164 /* The maximum time that we will wait to send or receive a packet */
165 int packet_timeout_ms;
166
167 /* Session key information for Encryption and MAC */
markus@openbsd.org091c3022015-01-19 19:52:16 +0000168 struct newkeys *newkeys[MODE_MAX];
Darren Tuckerf7288d72009-06-21 18:12:20 +1000169 struct packet_state p_read, p_send;
170
Darren Tuckerc53c2af2013-05-16 20:28:16 +1000171 /* Volume-based rekeying */
dtucker@openbsd.org921ff002016-01-29 02:54:45 +0000172 u_int64_t max_blocks_in, max_blocks_out, rekey_limit;
Darren Tuckerf7288d72009-06-21 18:12:20 +1000173
Darren Tuckerc53c2af2013-05-16 20:28:16 +1000174 /* Time-based rekeying */
markus@openbsd.org02db4682015-02-13 18:57:00 +0000175 u_int32_t rekey_interval; /* how often in seconds */
Darren Tuckerc53c2af2013-05-16 20:28:16 +1000176 time_t rekey_time; /* time of last rekeying */
177
Darren Tuckerf7288d72009-06-21 18:12:20 +1000178 /* roundup current message to extra_pad bytes */
179 u_char extra_pad;
180
181 /* XXX discard incoming data after MAC error */
182 u_int packet_discard;
markus@openbsd.orgb98a2a82016-07-18 11:35:33 +0000183 size_t packet_discard_mac_already;
markus@openbsd.org091c3022015-01-19 19:52:16 +0000184 struct sshmac *packet_discard_mac;
Darren Tuckerf7288d72009-06-21 18:12:20 +1000185
186 /* Used in packet_read_poll2() */
187 u_int packlen;
188
Darren Tucker7b935c72009-06-21 18:59:36 +1000189 /* Used in packet_send2 */
190 int rekeying;
191
markus@openbsd.org8d057842016-09-30 09:19:13 +0000192 /* Used in ssh_packet_send_mux() */
193 int mux;
194
Darren Tucker7b935c72009-06-21 18:59:36 +1000195 /* Used in packet_set_interactive */
196 int set_interactive_called;
197
198 /* Used in packet_set_maxsize */
199 int set_maxsize_called;
200
markus@openbsd.org091c3022015-01-19 19:52:16 +0000201 /* One-off warning about weak ciphers */
202 int cipher_warning_done;
203
djm@openbsd.org39af7b42016-10-11 21:47:45 +0000204 /* Hook for fuzzing inbound packets */
205 ssh_packet_hook_fn *hook_in;
206 void *hook_in_ctx;
207
Darren Tuckerf7288d72009-06-21 18:12:20 +1000208 TAILQ_HEAD(, packet) outgoing;
209};
210
markus@openbsd.org091c3022015-01-19 19:52:16 +0000211struct ssh *
212ssh_alloc_session_state(void)
Darren Tuckerf7288d72009-06-21 18:12:20 +1000213{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000214 struct ssh *ssh = NULL;
215 struct session_state *state = NULL;
Darren Tuckerf7288d72009-06-21 18:12:20 +1000216
markus@openbsd.org091c3022015-01-19 19:52:16 +0000217 if ((ssh = calloc(1, sizeof(*ssh))) == NULL ||
218 (state = calloc(1, sizeof(*state))) == NULL ||
219 (state->input = sshbuf_new()) == NULL ||
220 (state->output = sshbuf_new()) == NULL ||
221 (state->outgoing_packet = sshbuf_new()) == NULL ||
222 (state->incoming_packet = sshbuf_new()) == NULL)
223 goto fail;
224 TAILQ_INIT(&state->outgoing);
markus@openbsd.orgf582f0e2015-01-19 20:30:23 +0000225 TAILQ_INIT(&ssh->private_keys);
226 TAILQ_INIT(&ssh->public_keys);
markus@openbsd.org091c3022015-01-19 19:52:16 +0000227 state->connection_in = -1;
228 state->connection_out = -1;
229 state->max_packet_size = 32768;
230 state->packet_timeout_ms = -1;
231 state->p_send.packets = state->p_read.packets = 0;
232 state->initialized = 1;
233 /*
234 * ssh_packet_send2() needs to queue packets until
235 * we've done the initial key exchange.
236 */
237 state->rekeying = 1;
238 ssh->state = state;
239 return ssh;
240 fail:
241 if (state) {
242 sshbuf_free(state->input);
243 sshbuf_free(state->output);
244 sshbuf_free(state->incoming_packet);
245 sshbuf_free(state->outgoing_packet);
246 free(state);
247 }
248 free(ssh);
249 return NULL;
Darren Tuckerf7288d72009-06-21 18:12:20 +1000250}
Damien Millera5539d22003-04-09 20:50:06 +1000251
djm@openbsd.org39af7b42016-10-11 21:47:45 +0000252void
253ssh_packet_set_input_hook(struct ssh *ssh, ssh_packet_hook_fn *hook, void *ctx)
254{
255 ssh->state->hook_in = hook;
256 ssh->state->hook_in_ctx = ctx;
257}
258
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +0000259/* Returns nonzero if rekeying is in progress */
260int
261ssh_packet_is_rekeying(struct ssh *ssh)
262{
djm@openbsd.org97f4d302017-04-30 23:13:25 +0000263 return ssh->state->rekeying ||
264 (ssh->kex != NULL && ssh->kex->done == 0);
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +0000265}
266
Damien Miller5428f641999-11-25 11:54:57 +1100267/*
naddy@openbsd.org768405f2017-05-03 21:08:09 +0000268 * Sets the descriptors used for communication.
Damien Miller5428f641999-11-25 11:54:57 +1100269 */
markus@openbsd.org091c3022015-01-19 19:52:16 +0000270struct ssh *
271ssh_packet_set_connection(struct ssh *ssh, int fd_in, int fd_out)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000272{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000273 struct session_state *state;
274 const struct sshcipher *none = cipher_by_name("none");
Damien Miller86687062014-07-02 15:28:02 +1000275 int r;
Ben Lindstrom8b2eecd2002-07-07 22:11:51 +0000276
djm@openbsd.org4509b5d2015-01-30 01:13:33 +0000277 if (none == NULL) {
278 error("%s: cannot load cipher 'none'", __func__);
279 return NULL;
280 }
markus@openbsd.org091c3022015-01-19 19:52:16 +0000281 if (ssh == NULL)
282 ssh = ssh_alloc_session_state();
djm@openbsd.org4509b5d2015-01-30 01:13:33 +0000283 if (ssh == NULL) {
284 error("%s: cound not allocate state", __func__);
285 return NULL;
286 }
markus@openbsd.org091c3022015-01-19 19:52:16 +0000287 state = ssh->state;
288 state->connection_in = fd_in;
289 state->connection_out = fd_out;
290 if ((r = cipher_init(&state->send_context, none,
Damien Miller86687062014-07-02 15:28:02 +1000291 (const u_char *)"", 0, NULL, 0, CIPHER_ENCRYPT)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +0000292 (r = cipher_init(&state->receive_context, none,
djm@openbsd.org4509b5d2015-01-30 01:13:33 +0000293 (const u_char *)"", 0, NULL, 0, CIPHER_DECRYPT)) != 0) {
294 error("%s: cipher_init failed: %s", __func__, ssh_err(r));
djm@openbsd.org95767262016-03-07 19:02:43 +0000295 free(ssh); /* XXX need ssh_free_session_state? */
djm@openbsd.org4509b5d2015-01-30 01:13:33 +0000296 return NULL;
297 }
markus@openbsd.org091c3022015-01-19 19:52:16 +0000298 state->newkeys[MODE_IN] = state->newkeys[MODE_OUT] = NULL;
djm@openbsd.orgd4c02952015-02-11 01:20:38 +0000299 /*
300 * Cache the IP address of the remote connection for use in error
301 * messages that might be generated after the connection has closed.
302 */
303 (void)ssh_remote_ipaddr(ssh);
markus@openbsd.org091c3022015-01-19 19:52:16 +0000304 return ssh;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000305}
306
Darren Tucker3fc464e2008-06-13 06:42:45 +1000307void
markus@openbsd.org091c3022015-01-19 19:52:16 +0000308ssh_packet_set_timeout(struct ssh *ssh, int timeout, int count)
Darren Tucker3fc464e2008-06-13 06:42:45 +1000309{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000310 struct session_state *state = ssh->state;
311
Damien Miller8ed4de82011-12-19 10:52:50 +1100312 if (timeout <= 0 || count <= 0) {
markus@openbsd.org091c3022015-01-19 19:52:16 +0000313 state->packet_timeout_ms = -1;
Darren Tucker3fc464e2008-06-13 06:42:45 +1000314 return;
315 }
316 if ((INT_MAX / 1000) / count < timeout)
markus@openbsd.org091c3022015-01-19 19:52:16 +0000317 state->packet_timeout_ms = INT_MAX;
Darren Tucker3fc464e2008-06-13 06:42:45 +1000318 else
markus@openbsd.org091c3022015-01-19 19:52:16 +0000319 state->packet_timeout_ms = timeout * count * 1000;
Darren Tucker3fc464e2008-06-13 06:42:45 +1000320}
321
markus@openbsd.org8d057842016-09-30 09:19:13 +0000322void
323ssh_packet_set_mux(struct ssh *ssh)
324{
325 ssh->state->mux = 1;
326 ssh->state->rekeying = 0;
327}
328
329int
330ssh_packet_get_mux(struct ssh *ssh)
331{
332 return ssh->state->mux;
333}
334
markus@openbsd.org091c3022015-01-19 19:52:16 +0000335int
djm@openbsd.org07edd7e2017-02-03 23:03:33 +0000336ssh_packet_set_log_preamble(struct ssh *ssh, const char *fmt, ...)
337{
338 va_list args;
339 int r;
340
341 free(ssh->log_preamble);
342 if (fmt == NULL)
343 ssh->log_preamble = NULL;
344 else {
345 va_start(args, fmt);
346 r = vasprintf(&ssh->log_preamble, fmt, args);
347 va_end(args);
348 if (r < 0 || ssh->log_preamble == NULL)
349 return SSH_ERR_ALLOC_FAIL;
350 }
351 return 0;
352}
353
354int
markus@openbsd.org091c3022015-01-19 19:52:16 +0000355ssh_packet_stop_discard(struct ssh *ssh)
Damien Miller13ae44c2009-01-28 16:38:41 +1100356{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000357 struct session_state *state = ssh->state;
358 int r;
359
360 if (state->packet_discard_mac) {
Damien Miller13ae44c2009-01-28 16:38:41 +1100361 char buf[1024];
markus@openbsd.orgb98a2a82016-07-18 11:35:33 +0000362 size_t dlen = PACKET_MAX_SIZE;
markus@openbsd.org091c3022015-01-19 19:52:16 +0000363
markus@openbsd.orgb98a2a82016-07-18 11:35:33 +0000364 if (dlen > state->packet_discard_mac_already)
365 dlen -= state->packet_discard_mac_already;
Damien Miller13ae44c2009-01-28 16:38:41 +1100366 memset(buf, 'a', sizeof(buf));
markus@openbsd.orgb98a2a82016-07-18 11:35:33 +0000367 while (sshbuf_len(state->incoming_packet) < dlen)
markus@openbsd.org091c3022015-01-19 19:52:16 +0000368 if ((r = sshbuf_put(state->incoming_packet, buf,
369 sizeof(buf))) != 0)
370 return r;
371 (void) mac_compute(state->packet_discard_mac,
372 state->p_read.seqnr,
markus@openbsd.orgb98a2a82016-07-18 11:35:33 +0000373 sshbuf_ptr(state->incoming_packet), dlen,
markus@openbsd.org091c3022015-01-19 19:52:16 +0000374 NULL, 0);
Damien Miller13ae44c2009-01-28 16:38:41 +1100375 }
djm@openbsd.orga4b9e0f2015-12-11 03:24:25 +0000376 logit("Finished discarding for %.200s port %d",
377 ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
markus@openbsd.org091c3022015-01-19 19:52:16 +0000378 return SSH_ERR_MAC_INVALID;
Damien Miller13ae44c2009-01-28 16:38:41 +1100379}
380
markus@openbsd.org091c3022015-01-19 19:52:16 +0000381static int
382ssh_packet_start_discard(struct ssh *ssh, struct sshenc *enc,
markus@openbsd.orgb98a2a82016-07-18 11:35:33 +0000383 struct sshmac *mac, size_t mac_already, u_int discard)
Damien Miller13ae44c2009-01-28 16:38:41 +1100384{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000385 struct session_state *state = ssh->state;
386 int r;
387
388 if (enc == NULL || !cipher_is_cbc(enc->cipher) || (mac && mac->etm)) {
389 if ((r = sshpkt_disconnect(ssh, "Packet corrupt")) != 0)
390 return r;
391 return SSH_ERR_MAC_INVALID;
392 }
markus@openbsd.orgb98a2a82016-07-18 11:35:33 +0000393 /*
394 * Record number of bytes over which the mac has already
395 * been computed in order to minimize timing attacks.
396 */
397 if (mac && mac->enabled) {
markus@openbsd.org091c3022015-01-19 19:52:16 +0000398 state->packet_discard_mac = mac;
markus@openbsd.orgb98a2a82016-07-18 11:35:33 +0000399 state->packet_discard_mac_already = mac_already;
400 }
401 if (sshbuf_len(state->input) >= discard)
402 return ssh_packet_stop_discard(ssh);
markus@openbsd.org091c3022015-01-19 19:52:16 +0000403 state->packet_discard = discard - sshbuf_len(state->input);
404 return 0;
Damien Miller13ae44c2009-01-28 16:38:41 +1100405}
406
Damien Miller34132e52000-01-14 15:45:46 +1100407/* Returns 1 if remote host is connected via socket, 0 if not. */
408
409int
markus@openbsd.org091c3022015-01-19 19:52:16 +0000410ssh_packet_connection_is_on_socket(struct ssh *ssh)
Damien Miller34132e52000-01-14 15:45:46 +1100411{
djm@openbsd.org854ae202018-06-01 04:05:29 +0000412 struct session_state *state;
Damien Miller34132e52000-01-14 15:45:46 +1100413 struct sockaddr_storage from, to;
414 socklen_t fromlen, tolen;
415
djm@openbsd.org854ae202018-06-01 04:05:29 +0000416 if (ssh == NULL || ssh->state == NULL)
djm@openbsd.org95767262016-03-07 19:02:43 +0000417 return 0;
418
djm@openbsd.org854ae202018-06-01 04:05:29 +0000419 state = ssh->state;
420 if (state->connection_in == -1 || state->connection_out == -1)
421 return 0;
Damien Miller34132e52000-01-14 15:45:46 +1100422 /* filedescriptors in and out are the same, so it's a socket */
markus@openbsd.org091c3022015-01-19 19:52:16 +0000423 if (state->connection_in == state->connection_out)
Damien Miller34132e52000-01-14 15:45:46 +1100424 return 1;
425 fromlen = sizeof(from);
426 memset(&from, 0, sizeof(from));
markus@openbsd.org091c3022015-01-19 19:52:16 +0000427 if (getpeername(state->connection_in, (struct sockaddr *)&from,
Darren Tuckerf7288d72009-06-21 18:12:20 +1000428 &fromlen) < 0)
Damien Miller34132e52000-01-14 15:45:46 +1100429 return 0;
430 tolen = sizeof(to);
431 memset(&to, 0, sizeof(to));
markus@openbsd.org091c3022015-01-19 19:52:16 +0000432 if (getpeername(state->connection_out, (struct sockaddr *)&to,
Darren Tuckerf7288d72009-06-21 18:12:20 +1000433 &tolen) < 0)
Damien Miller34132e52000-01-14 15:45:46 +1100434 return 0;
435 if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0)
436 return 0;
437 if (from.ss_family != AF_INET && from.ss_family != AF_INET6)
438 return 0;
439 return 1;
440}
441
Ben Lindstromf6027d32002-03-22 01:42:04 +0000442void
markus@openbsd.org091c3022015-01-19 19:52:16 +0000443ssh_packet_get_bytes(struct ssh *ssh, u_int64_t *ibytes, u_int64_t *obytes)
Ben Lindstromf6027d32002-03-22 01:42:04 +0000444{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000445 if (ibytes)
446 *ibytes = ssh->state->p_read.bytes;
447 if (obytes)
448 *obytes = ssh->state->p_send.bytes;
Ben Lindstromf6027d32002-03-22 01:42:04 +0000449}
450
451int
markus@openbsd.org091c3022015-01-19 19:52:16 +0000452ssh_packet_connection_af(struct ssh *ssh)
Damien Miller34132e52000-01-14 15:45:46 +1100453{
454 struct sockaddr_storage to;
Damien Miller6fe375d2000-01-23 09:38:00 +1100455 socklen_t tolen = sizeof(to);
Damien Miller34132e52000-01-14 15:45:46 +1100456
457 memset(&to, 0, sizeof(to));
markus@openbsd.org091c3022015-01-19 19:52:16 +0000458 if (getsockname(ssh->state->connection_out, (struct sockaddr *)&to,
Darren Tuckerf7288d72009-06-21 18:12:20 +1000459 &tolen) < 0)
Damien Miller34132e52000-01-14 15:45:46 +1100460 return 0;
Damien Milleraa100c52002-04-26 16:54:34 +1000461#ifdef IPV4_IN_IPV6
Damien Millera8e06ce2003-11-21 23:48:55 +1100462 if (to.ss_family == AF_INET6 &&
Damien Milleraa100c52002-04-26 16:54:34 +1000463 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&to)->sin6_addr))
Damien Millerd2ac5d72011-05-15 08:43:13 +1000464 return AF_INET;
Damien Milleraa100c52002-04-26 16:54:34 +1000465#endif
Damien Millerd2ac5d72011-05-15 08:43:13 +1000466 return to.ss_family;
Damien Miller34132e52000-01-14 15:45:46 +1100467}
468
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000469/* Sets the connection into non-blocking mode. */
470
471void
markus@openbsd.org091c3022015-01-19 19:52:16 +0000472ssh_packet_set_nonblocking(struct ssh *ssh)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000473{
Damien Miller95def091999-11-25 00:26:21 +1100474 /* Set the socket into non-blocking mode. */
markus@openbsd.org091c3022015-01-19 19:52:16 +0000475 set_nonblock(ssh->state->connection_in);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000476
markus@openbsd.org091c3022015-01-19 19:52:16 +0000477 if (ssh->state->connection_out != ssh->state->connection_in)
478 set_nonblock(ssh->state->connection_out);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000479}
480
481/* Returns the socket used for reading. */
482
483int
markus@openbsd.org091c3022015-01-19 19:52:16 +0000484ssh_packet_get_connection_in(struct ssh *ssh)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000485{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000486 return ssh->state->connection_in;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000487}
488
489/* Returns the descriptor used for writing. */
490
491int
markus@openbsd.org091c3022015-01-19 19:52:16 +0000492ssh_packet_get_connection_out(struct ssh *ssh)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000493{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000494 return ssh->state->connection_out;
495}
496
497/*
498 * Returns the IP-address of the remote host as a string. The returned
499 * string must not be freed.
500 */
501
502const char *
503ssh_remote_ipaddr(struct ssh *ssh)
504{
djm@openbsd.org854ae202018-06-01 04:05:29 +0000505 int sock;
djm@openbsd.orga4b9e0f2015-12-11 03:24:25 +0000506
markus@openbsd.org091c3022015-01-19 19:52:16 +0000507 /* Check whether we have cached the ipaddr. */
djm@openbsd.orga4b9e0f2015-12-11 03:24:25 +0000508 if (ssh->remote_ipaddr == NULL) {
509 if (ssh_packet_connection_is_on_socket(ssh)) {
djm@openbsd.org854ae202018-06-01 04:05:29 +0000510 sock = ssh->state->connection_in;
djm@openbsd.orga4b9e0f2015-12-11 03:24:25 +0000511 ssh->remote_ipaddr = get_peer_ipaddr(sock);
djm@openbsd.org95767262016-03-07 19:02:43 +0000512 ssh->remote_port = get_peer_port(sock);
513 ssh->local_ipaddr = get_local_ipaddr(sock);
514 ssh->local_port = get_local_port(sock);
djm@openbsd.orga4b9e0f2015-12-11 03:24:25 +0000515 } else {
516 ssh->remote_ipaddr = strdup("UNKNOWN");
djm@openbsd.org95767262016-03-07 19:02:43 +0000517 ssh->remote_port = 65535;
518 ssh->local_ipaddr = strdup("UNKNOWN");
519 ssh->local_port = 65535;
djm@openbsd.orga4b9e0f2015-12-11 03:24:25 +0000520 }
521 }
markus@openbsd.org091c3022015-01-19 19:52:16 +0000522 return ssh->remote_ipaddr;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000523}
524
djm@openbsd.orga4b9e0f2015-12-11 03:24:25 +0000525/* Returns the port number of the remote host. */
526
527int
528ssh_remote_port(struct ssh *ssh)
529{
530 (void)ssh_remote_ipaddr(ssh); /* Will lookup and cache. */
531 return ssh->remote_port;
532}
533
djm@openbsd.org95767262016-03-07 19:02:43 +0000534/*
535 * Returns the IP-address of the local host as a string. The returned
536 * string must not be freed.
537 */
538
539const char *
540ssh_local_ipaddr(struct ssh *ssh)
541{
542 (void)ssh_remote_ipaddr(ssh); /* Will lookup and cache. */
543 return ssh->local_ipaddr;
544}
545
546/* Returns the port number of the local host. */
547
548int
549ssh_local_port(struct ssh *ssh)
550{
551 (void)ssh_remote_ipaddr(ssh); /* Will lookup and cache. */
552 return ssh->local_port;
553}
554
djm@openbsd.org35eb33f2017-10-25 00:17:08 +0000555/* Returns the routing domain of the input socket, or NULL if unavailable */
556const char *
557ssh_packet_rdomain_in(struct ssh *ssh)
558{
559 if (ssh->rdomain_in != NULL)
560 return ssh->rdomain_in;
561 if (!ssh_packet_connection_is_on_socket(ssh))
562 return NULL;
563 ssh->rdomain_in = get_rdomain(ssh->state->connection_in);
564 return ssh->rdomain_in;
565}
566
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000567/* Closes the connection and clears and frees internal data structures. */
568
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +0000569static void
570ssh_packet_close_internal(struct ssh *ssh, int do_close)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000571{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000572 struct session_state *state = ssh->state;
markus@openbsd.org091c3022015-01-19 19:52:16 +0000573 u_int mode;
574
575 if (!state->initialized)
Damien Miller95def091999-11-25 00:26:21 +1100576 return;
markus@openbsd.org091c3022015-01-19 19:52:16 +0000577 state->initialized = 0;
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +0000578 if (do_close) {
579 if (state->connection_in == state->connection_out) {
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +0000580 close(state->connection_out);
581 } else {
582 close(state->connection_in);
583 close(state->connection_out);
584 }
Damien Miller95def091999-11-25 00:26:21 +1100585 }
markus@openbsd.org091c3022015-01-19 19:52:16 +0000586 sshbuf_free(state->input);
587 sshbuf_free(state->output);
588 sshbuf_free(state->outgoing_packet);
589 sshbuf_free(state->incoming_packet);
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +0000590 for (mode = 0; mode < MODE_MAX; mode++) {
591 kex_free_newkeys(state->newkeys[mode]); /* current keys */
592 state->newkeys[mode] = NULL;
593 ssh_clear_newkeys(ssh, mode); /* next keys */
594 }
Damien Miller10479cc2018-04-10 10:19:02 +1000595 /* compression state is in shared mem, so we can only release it once */
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +0000596 if (do_close && state->compression_buffer) {
markus@openbsd.org091c3022015-01-19 19:52:16 +0000597 sshbuf_free(state->compression_buffer);
598 if (state->compression_out_started) {
599 z_streamp stream = &state->compression_out_stream;
600 debug("compress outgoing: "
601 "raw data %llu, compressed %llu, factor %.2f",
602 (unsigned long long)stream->total_in,
603 (unsigned long long)stream->total_out,
604 stream->total_in == 0 ? 0.0 :
605 (double) stream->total_out / stream->total_in);
606 if (state->compression_out_failures == 0)
607 deflateEnd(stream);
608 }
609 if (state->compression_in_started) {
dtucker@openbsd.org550c0532017-06-06 09:12:17 +0000610 z_streamp stream = &state->compression_in_stream;
markus@openbsd.org091c3022015-01-19 19:52:16 +0000611 debug("compress incoming: "
612 "raw data %llu, compressed %llu, factor %.2f",
613 (unsigned long long)stream->total_out,
614 (unsigned long long)stream->total_in,
615 stream->total_out == 0 ? 0.0 :
616 (double) stream->total_in / stream->total_out);
617 if (state->compression_in_failures == 0)
618 inflateEnd(stream);
619 }
Damien Miller95def091999-11-25 00:26:21 +1100620 }
djm@openbsd.org4706c1d2016-08-03 05:41:57 +0000621 cipher_free(state->send_context);
622 cipher_free(state->receive_context);
623 state->send_context = state->receive_context = NULL;
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +0000624 if (do_close) {
djm@openbsd.orgde2997a2018-07-16 03:09:13 +0000625 free(ssh->local_ipaddr);
626 ssh->local_ipaddr = NULL;
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +0000627 free(ssh->remote_ipaddr);
628 ssh->remote_ipaddr = NULL;
629 free(ssh->state);
630 ssh->state = NULL;
631 }
632}
633
634void
635ssh_packet_close(struct ssh *ssh)
636{
637 ssh_packet_close_internal(ssh, 1);
638}
639
640void
641ssh_packet_clear_keys(struct ssh *ssh)
642{
643 ssh_packet_close_internal(ssh, 0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000644}
645
646/* Sets remote side protocol flags. */
647
648void
markus@openbsd.org091c3022015-01-19 19:52:16 +0000649ssh_packet_set_protocol_flags(struct ssh *ssh, u_int protocol_flags)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000650{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000651 ssh->state->remote_protocol_flags = protocol_flags;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000652}
653
654/* Returns the remote protocol flags set earlier by the above function. */
655
Ben Lindstrom46c16222000-12-22 01:43:59 +0000656u_int
markus@openbsd.org091c3022015-01-19 19:52:16 +0000657ssh_packet_get_protocol_flags(struct ssh *ssh)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000658{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000659 return ssh->state->remote_protocol_flags;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000660}
661
Damien Miller5428f641999-11-25 11:54:57 +1100662/*
663 * Starts packet compression from the next packet on in both directions.
664 * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
665 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000666
markus@openbsd.org091c3022015-01-19 19:52:16 +0000667static int
668ssh_packet_init_compression(struct ssh *ssh)
Ben Lindstromfb50cdf2001-04-05 23:20:46 +0000669{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000670 if (!ssh->state->compression_buffer &&
671 ((ssh->state->compression_buffer = sshbuf_new()) == NULL))
672 return SSH_ERR_ALLOC_FAIL;
673 return 0;
674}
675
676static int
677start_compression_out(struct ssh *ssh, int level)
678{
679 if (level < 1 || level > 9)
680 return SSH_ERR_INVALID_ARGUMENT;
681 debug("Enabling compression at level %d.", level);
682 if (ssh->state->compression_out_started == 1)
683 deflateEnd(&ssh->state->compression_out_stream);
684 switch (deflateInit(&ssh->state->compression_out_stream, level)) {
685 case Z_OK:
686 ssh->state->compression_out_started = 1;
687 break;
688 case Z_MEM_ERROR:
689 return SSH_ERR_ALLOC_FAIL;
690 default:
691 return SSH_ERR_INTERNAL_ERROR;
692 }
693 return 0;
694}
695
696static int
697start_compression_in(struct ssh *ssh)
698{
699 if (ssh->state->compression_in_started == 1)
700 inflateEnd(&ssh->state->compression_in_stream);
701 switch (inflateInit(&ssh->state->compression_in_stream)) {
702 case Z_OK:
703 ssh->state->compression_in_started = 1;
704 break;
705 case Z_MEM_ERROR:
706 return SSH_ERR_ALLOC_FAIL;
707 default:
708 return SSH_ERR_INTERNAL_ERROR;
709 }
710 return 0;
711}
712
markus@openbsd.org091c3022015-01-19 19:52:16 +0000713/* XXX remove need for separate compression buffer */
714static int
715compress_buffer(struct ssh *ssh, struct sshbuf *in, struct sshbuf *out)
716{
717 u_char buf[4096];
718 int r, status;
719
720 if (ssh->state->compression_out_started != 1)
721 return SSH_ERR_INTERNAL_ERROR;
722
723 /* This case is not handled below. */
724 if (sshbuf_len(in) == 0)
725 return 0;
726
727 /* Input is the contents of the input buffer. */
728 if ((ssh->state->compression_out_stream.next_in =
729 sshbuf_mutable_ptr(in)) == NULL)
730 return SSH_ERR_INTERNAL_ERROR;
731 ssh->state->compression_out_stream.avail_in = sshbuf_len(in);
732
733 /* Loop compressing until deflate() returns with avail_out != 0. */
734 do {
735 /* Set up fixed-size output buffer. */
736 ssh->state->compression_out_stream.next_out = buf;
737 ssh->state->compression_out_stream.avail_out = sizeof(buf);
738
739 /* Compress as much data into the buffer as possible. */
740 status = deflate(&ssh->state->compression_out_stream,
741 Z_PARTIAL_FLUSH);
742 switch (status) {
743 case Z_MEM_ERROR:
744 return SSH_ERR_ALLOC_FAIL;
745 case Z_OK:
746 /* Append compressed data to output_buffer. */
747 if ((r = sshbuf_put(out, buf, sizeof(buf) -
748 ssh->state->compression_out_stream.avail_out)) != 0)
749 return r;
750 break;
751 case Z_STREAM_ERROR:
752 default:
753 ssh->state->compression_out_failures++;
754 return SSH_ERR_INVALID_FORMAT;
755 }
756 } while (ssh->state->compression_out_stream.avail_out == 0);
757 return 0;
758}
759
760static int
761uncompress_buffer(struct ssh *ssh, struct sshbuf *in, struct sshbuf *out)
762{
763 u_char buf[4096];
764 int r, status;
765
766 if (ssh->state->compression_in_started != 1)
767 return SSH_ERR_INTERNAL_ERROR;
768
769 if ((ssh->state->compression_in_stream.next_in =
770 sshbuf_mutable_ptr(in)) == NULL)
771 return SSH_ERR_INTERNAL_ERROR;
772 ssh->state->compression_in_stream.avail_in = sshbuf_len(in);
773
774 for (;;) {
775 /* Set up fixed-size output buffer. */
776 ssh->state->compression_in_stream.next_out = buf;
777 ssh->state->compression_in_stream.avail_out = sizeof(buf);
778
779 status = inflate(&ssh->state->compression_in_stream,
780 Z_PARTIAL_FLUSH);
781 switch (status) {
782 case Z_OK:
783 if ((r = sshbuf_put(out, buf, sizeof(buf) -
784 ssh->state->compression_in_stream.avail_out)) != 0)
785 return r;
786 break;
787 case Z_BUF_ERROR:
788 /*
789 * Comments in zlib.h say that we should keep calling
790 * inflate() until we get an error. This appears to
791 * be the error that we get.
792 */
793 return 0;
794 case Z_DATA_ERROR:
795 return SSH_ERR_INVALID_FORMAT;
796 case Z_MEM_ERROR:
797 return SSH_ERR_ALLOC_FAIL;
798 case Z_STREAM_ERROR:
799 default:
800 ssh->state->compression_in_failures++;
801 return SSH_ERR_INTERNAL_ERROR;
802 }
803 }
804 /* NOTREACHED */
805}
806
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +0000807void
808ssh_clear_newkeys(struct ssh *ssh, int mode)
809{
djm@openbsd.org2d75d742017-06-01 06:16:43 +0000810 if (ssh->kex && ssh->kex->newkeys[mode]) {
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +0000811 kex_free_newkeys(ssh->kex->newkeys[mode]);
812 ssh->kex->newkeys[mode] = NULL;
813 }
814}
815
markus@openbsd.org091c3022015-01-19 19:52:16 +0000816int
817ssh_set_newkeys(struct ssh *ssh, int mode)
Ben Lindstrom2d90e002001-04-04 02:00:54 +0000818{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000819 struct session_state *state = ssh->state;
820 struct sshenc *enc;
821 struct sshmac *mac;
822 struct sshcomp *comp;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +0000823 struct sshcipher_ctx **ccp;
markus@openbsd.org06ce56b2016-09-06 09:22:56 +0000824 struct packet_state *ps;
Damien Millera5539d22003-04-09 20:50:06 +1000825 u_int64_t *max_blocks;
djm@openbsd.org2d75d742017-06-01 06:16:43 +0000826 const char *wmsg;
Damien Miller86687062014-07-02 15:28:02 +1000827 int r, crypt_type;
Ben Lindstrom2d90e002001-04-04 02:00:54 +0000828
Ben Lindstrom064496f2002-12-23 02:04:22 +0000829 debug2("set_newkeys: mode %d", mode);
Ben Lindstrom2d90e002001-04-04 02:00:54 +0000830
Damien Miller963f6b22002-02-19 15:21:23 +1100831 if (mode == MODE_OUT) {
djm@openbsd.org4706c1d2016-08-03 05:41:57 +0000832 ccp = &state->send_context;
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000833 crypt_type = CIPHER_ENCRYPT;
markus@openbsd.org06ce56b2016-09-06 09:22:56 +0000834 ps = &state->p_send;
markus@openbsd.org091c3022015-01-19 19:52:16 +0000835 max_blocks = &state->max_blocks_out;
Damien Miller963f6b22002-02-19 15:21:23 +1100836 } else {
djm@openbsd.org4706c1d2016-08-03 05:41:57 +0000837 ccp = &state->receive_context;
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000838 crypt_type = CIPHER_DECRYPT;
markus@openbsd.org06ce56b2016-09-06 09:22:56 +0000839 ps = &state->p_read;
markus@openbsd.org091c3022015-01-19 19:52:16 +0000840 max_blocks = &state->max_blocks_in;
Damien Miller963f6b22002-02-19 15:21:23 +1100841 }
markus@openbsd.org091c3022015-01-19 19:52:16 +0000842 if (state->newkeys[mode] != NULL) {
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +0000843 debug("set_newkeys: rekeying, input %llu bytes %llu blocks, "
844 "output %llu bytes %llu blocks",
845 (unsigned long long)state->p_read.bytes,
846 (unsigned long long)state->p_read.blocks,
847 (unsigned long long)state->p_send.bytes,
848 (unsigned long long)state->p_send.blocks);
djm@openbsd.org4706c1d2016-08-03 05:41:57 +0000849 cipher_free(*ccp);
850 *ccp = NULL;
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +0000851 kex_free_newkeys(state->newkeys[mode]);
852 state->newkeys[mode] = NULL;
Ben Lindstrom2d90e002001-04-04 02:00:54 +0000853 }
markus@openbsd.org06ce56b2016-09-06 09:22:56 +0000854 /* note that both bytes and the seqnr are not reset */
855 ps->packets = ps->blocks = 0;
markus@openbsd.org091c3022015-01-19 19:52:16 +0000856 /* move newkeys from kex to state */
857 if ((state->newkeys[mode] = ssh->kex->newkeys[mode]) == NULL)
858 return SSH_ERR_INTERNAL_ERROR;
859 ssh->kex->newkeys[mode] = NULL;
860 enc = &state->newkeys[mode]->enc;
861 mac = &state->newkeys[mode]->mac;
862 comp = &state->newkeys[mode]->comp;
863 if (cipher_authlen(enc->cipher) == 0) {
864 if ((r = mac_init(mac)) != 0)
865 return r;
866 }
867 mac->enabled = 1;
Ben Lindstrom2d90e002001-04-04 02:00:54 +0000868 DBG(debug("cipher_init_context: %d", mode));
djm@openbsd.org4706c1d2016-08-03 05:41:57 +0000869 if ((r = cipher_init(ccp, enc->cipher, enc->key, enc->key_len,
Damien Miller86687062014-07-02 15:28:02 +1000870 enc->iv, enc->iv_len, crypt_type)) != 0)
markus@openbsd.org091c3022015-01-19 19:52:16 +0000871 return r;
872 if (!state->cipher_warning_done &&
djm@openbsd.org4706c1d2016-08-03 05:41:57 +0000873 (wmsg = cipher_warning_message(*ccp)) != NULL) {
markus@openbsd.org091c3022015-01-19 19:52:16 +0000874 error("Warning: %s", wmsg);
875 state->cipher_warning_done = 1;
876 }
Ben Lindstromf6027d32002-03-22 01:42:04 +0000877 /* Deleting the keys does not gain extra security */
Damien Millera5103f42014-02-04 11:20:14 +1100878 /* explicit_bzero(enc->iv, enc->block_size);
879 explicit_bzero(enc->key, enc->key_len);
880 explicit_bzero(mac->key, mac->key_len); */
sf@openbsd.org168b46f2018-07-09 13:37:10 +0000881 if ((comp->type == COMP_ZLIB ||
882 (comp->type == COMP_DELAYED &&
883 state->after_authentication)) && comp->enabled == 0) {
markus@openbsd.org091c3022015-01-19 19:52:16 +0000884 if ((r = ssh_packet_init_compression(ssh)) < 0)
885 return r;
886 if (mode == MODE_OUT) {
887 if ((r = start_compression_out(ssh, 6)) != 0)
888 return r;
889 } else {
890 if ((r = start_compression_in(ssh)) != 0)
891 return r;
892 }
Ben Lindstrom2d90e002001-04-04 02:00:54 +0000893 comp->enabled = 1;
Ben Lindstrom2d90e002001-04-04 02:00:54 +0000894 }
Darren Tucker81a0b372003-07-14 17:31:06 +1000895 /*
896 * The 2^(blocksize*2) limit is too expensive for 3DES,
djm@openbsd.orgacaf34f2017-05-07 23:12:57 +0000897 * so enforce a 1GB limit for small blocksizes.
dtucker@openbsd.orgad053162017-06-09 04:40:04 +0000898 * See RFC4344 section 3.2.
Darren Tucker81a0b372003-07-14 17:31:06 +1000899 */
900 if (enc->block_size >= 16)
901 *max_blocks = (u_int64_t)1 << (enc->block_size*2);
902 else
903 *max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
markus@openbsd.org091c3022015-01-19 19:52:16 +0000904 if (state->rekey_limit)
deraadt@openbsd.org9136ec12016-09-12 01:22:38 +0000905 *max_blocks = MINIMUM(*max_blocks,
markus@openbsd.org091c3022015-01-19 19:52:16 +0000906 state->rekey_limit / enc->block_size);
djm@openbsd.org696d1262016-02-04 23:43:48 +0000907 debug("rekey after %llu blocks", (unsigned long long)*max_blocks);
markus@openbsd.org091c3022015-01-19 19:52:16 +0000908 return 0;
Ben Lindstrom2d90e002001-04-04 02:00:54 +0000909}
910
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +0000911#define MAX_PACKETS (1U<<31)
912static int
913ssh_packet_need_rekeying(struct ssh *ssh, u_int outbound_packet_len)
914{
915 struct session_state *state = ssh->state;
916 u_int32_t out_blocks;
917
918 /* XXX client can't cope with rekeying pre-auth */
919 if (!state->after_authentication)
920 return 0;
921
922 /* Haven't keyed yet or KEX in progress. */
923 if (ssh->kex == NULL || ssh_packet_is_rekeying(ssh))
924 return 0;
925
926 /* Peer can't rekey */
927 if (ssh->compat & SSH_BUG_NOREKEY)
928 return 0;
929
930 /*
931 * Permit one packet in or out per rekey - this allows us to
932 * make progress when rekey limits are very small.
933 */
934 if (state->p_send.packets == 0 && state->p_read.packets == 0)
935 return 0;
936
937 /* Time-based rekeying */
938 if (state->rekey_interval != 0 &&
dtucker@openbsd.orgc998bf02017-02-03 02:56:00 +0000939 (int64_t)state->rekey_time + state->rekey_interval <= monotime())
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +0000940 return 1;
941
dtucker@openbsd.orgad053162017-06-09 04:40:04 +0000942 /*
943 * Always rekey when MAX_PACKETS sent in either direction
944 * As per RFC4344 section 3.1 we do this after 2^31 packets.
945 */
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +0000946 if (state->p_send.packets > MAX_PACKETS ||
947 state->p_read.packets > MAX_PACKETS)
948 return 1;
949
Damien Miller10479cc2018-04-10 10:19:02 +1000950 /* Rekey after (cipher-specific) maximum blocks */
deraadt@openbsd.org9136ec12016-09-12 01:22:38 +0000951 out_blocks = ROUNDUP(outbound_packet_len,
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +0000952 state->newkeys[MODE_OUT]->enc.block_size);
953 return (state->max_blocks_out &&
954 (state->p_send.blocks + out_blocks > state->max_blocks_out)) ||
955 (state->max_blocks_in &&
956 (state->p_read.blocks > state->max_blocks_in));
957}
958
Damien Miller5428f641999-11-25 11:54:57 +1100959/*
Damien Miller9786e6e2005-07-26 21:54:56 +1000960 * Delayed compression for SSH2 is enabled after authentication:
Darren Tuckerf676c572006-08-05 18:51:08 +1000961 * This happens on the server side after a SSH2_MSG_USERAUTH_SUCCESS is sent,
Damien Miller9786e6e2005-07-26 21:54:56 +1000962 * and on the client side after a SSH2_MSG_USERAUTH_SUCCESS is received.
963 */
markus@openbsd.org091c3022015-01-19 19:52:16 +0000964static int
965ssh_packet_enable_delayed_compress(struct ssh *ssh)
Damien Miller9786e6e2005-07-26 21:54:56 +1000966{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000967 struct session_state *state = ssh->state;
968 struct sshcomp *comp = NULL;
969 int r, mode;
Damien Miller9786e6e2005-07-26 21:54:56 +1000970
971 /*
972 * Remember that we are past the authentication step, so rekeying
sf@openbsd.org168b46f2018-07-09 13:37:10 +0000973 * with COMP_DELAYED will turn on compression immediately.
Damien Miller9786e6e2005-07-26 21:54:56 +1000974 */
markus@openbsd.org091c3022015-01-19 19:52:16 +0000975 state->after_authentication = 1;
Damien Miller9786e6e2005-07-26 21:54:56 +1000976 for (mode = 0; mode < MODE_MAX; mode++) {
Darren Tucker4aa665b2006-09-21 13:00:25 +1000977 /* protocol error: USERAUTH_SUCCESS received before NEWKEYS */
markus@openbsd.org091c3022015-01-19 19:52:16 +0000978 if (state->newkeys[mode] == NULL)
Darren Tucker4aa665b2006-09-21 13:00:25 +1000979 continue;
markus@openbsd.org091c3022015-01-19 19:52:16 +0000980 comp = &state->newkeys[mode]->comp;
sf@openbsd.org168b46f2018-07-09 13:37:10 +0000981 if (comp && !comp->enabled && comp->type == COMP_DELAYED) {
markus@openbsd.org091c3022015-01-19 19:52:16 +0000982 if ((r = ssh_packet_init_compression(ssh)) != 0)
983 return r;
984 if (mode == MODE_OUT) {
985 if ((r = start_compression_out(ssh, 6)) != 0)
986 return r;
987 } else {
988 if ((r = start_compression_in(ssh)) != 0)
989 return r;
990 }
Damien Miller9786e6e2005-07-26 21:54:56 +1000991 comp->enabled = 1;
992 }
993 }
markus@openbsd.org091c3022015-01-19 19:52:16 +0000994 return 0;
Damien Miller9786e6e2005-07-26 21:54:56 +1000995}
996
djm@openbsd.org28136472016-01-29 05:46:01 +0000997/* Used to mute debug logging for noisy packet types */
markus@openbsd.org8d057842016-09-30 09:19:13 +0000998int
djm@openbsd.org28136472016-01-29 05:46:01 +0000999ssh_packet_log_type(u_char type)
1000{
1001 switch (type) {
1002 case SSH2_MSG_CHANNEL_DATA:
1003 case SSH2_MSG_CHANNEL_EXTENDED_DATA:
1004 case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
1005 return 0;
1006 default:
1007 return 1;
1008 }
1009}
1010
Damien Miller9786e6e2005-07-26 21:54:56 +10001011/*
Damien Miller33b13562000-04-04 14:38:59 +10001012 * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
1013 */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001014int
1015ssh_packet_send2_wrapped(struct ssh *ssh)
Damien Miller33b13562000-04-04 14:38:59 +10001016{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001017 struct session_state *state = ssh->state;
markus@openbsd.org128343b2015-01-13 19:31:40 +00001018 u_char type, *cp, macbuf[SSH_DIGEST_MAX_LENGTH];
djm@openbsd.orgeb999a42016-07-18 06:08:01 +00001019 u_char tmp, padlen, pad = 0;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001020 u_int authlen = 0, aadlen = 0;
1021 u_int len;
1022 struct sshenc *enc = NULL;
1023 struct sshmac *mac = NULL;
1024 struct sshcomp *comp = NULL;
1025 int r, block_size;
Damien Miller33b13562000-04-04 14:38:59 +10001026
markus@openbsd.org091c3022015-01-19 19:52:16 +00001027 if (state->newkeys[MODE_OUT] != NULL) {
1028 enc = &state->newkeys[MODE_OUT]->enc;
1029 mac = &state->newkeys[MODE_OUT]->mac;
1030 comp = &state->newkeys[MODE_OUT]->comp;
Damien Miller1d75abf2013-01-09 16:12:19 +11001031 /* disable mac for authenticated encryption */
1032 if ((authlen = cipher_authlen(enc->cipher)) != 0)
1033 mac = NULL;
Damien Miller33b13562000-04-04 14:38:59 +10001034 }
Damien Miller963f6b22002-02-19 15:21:23 +11001035 block_size = enc ? enc->block_size : 8;
Damien Miller1d75abf2013-01-09 16:12:19 +11001036 aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0;
Damien Miller33b13562000-04-04 14:38:59 +10001037
markus@openbsd.org091c3022015-01-19 19:52:16 +00001038 type = (sshbuf_ptr(state->outgoing_packet))[5];
djm@openbsd.org28136472016-01-29 05:46:01 +00001039 if (ssh_packet_log_type(type))
1040 debug3("send packet: type %u", type);
Damien Miller33b13562000-04-04 14:38:59 +10001041#ifdef PACKET_DEBUG
1042 fprintf(stderr, "plain: ");
markus@openbsd.org091c3022015-01-19 19:52:16 +00001043 sshbuf_dump(state->outgoing_packet, stderr);
Damien Miller33b13562000-04-04 14:38:59 +10001044#endif
1045
1046 if (comp && comp->enabled) {
markus@openbsd.org091c3022015-01-19 19:52:16 +00001047 len = sshbuf_len(state->outgoing_packet);
Damien Miller33b13562000-04-04 14:38:59 +10001048 /* skip header, compress only payload */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001049 if ((r = sshbuf_consume(state->outgoing_packet, 5)) != 0)
1050 goto out;
1051 sshbuf_reset(state->compression_buffer);
1052 if ((r = compress_buffer(ssh, state->outgoing_packet,
1053 state->compression_buffer)) != 0)
1054 goto out;
1055 sshbuf_reset(state->outgoing_packet);
1056 if ((r = sshbuf_put(state->outgoing_packet,
1057 "\0\0\0\0\0", 5)) != 0 ||
1058 (r = sshbuf_putb(state->outgoing_packet,
1059 state->compression_buffer)) != 0)
1060 goto out;
1061 DBG(debug("compression: raw %d compressed %zd", len,
1062 sshbuf_len(state->outgoing_packet)));
Damien Miller33b13562000-04-04 14:38:59 +10001063 }
1064
1065 /* sizeof (packet_len + pad_len + payload) */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001066 len = sshbuf_len(state->outgoing_packet);
Damien Miller33b13562000-04-04 14:38:59 +10001067
1068 /*
1069 * calc size of padding, alloc space, get random data,
1070 * minimum padding is 4 bytes
1071 */
Damien Milleraf43a7a2012-12-12 10:46:31 +11001072 len -= aadlen; /* packet length is not encrypted for EtM modes */
Damien Miller33b13562000-04-04 14:38:59 +10001073 padlen = block_size - (len % block_size);
1074 if (padlen < 4)
1075 padlen += block_size;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001076 if (state->extra_pad) {
djm@openbsd.orgeb999a42016-07-18 06:08:01 +00001077 tmp = state->extra_pad;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001078 state->extra_pad =
deraadt@openbsd.org9136ec12016-09-12 01:22:38 +00001079 ROUNDUP(state->extra_pad, block_size);
djm@openbsd.orgeb999a42016-07-18 06:08:01 +00001080 /* check if roundup overflowed */
1081 if (state->extra_pad < tmp)
1082 return SSH_ERR_INVALID_ARGUMENT;
1083 tmp = (len + padlen) % state->extra_pad;
1084 /* Check whether pad calculation below will underflow */
1085 if (tmp > state->extra_pad)
1086 return SSH_ERR_INVALID_ARGUMENT;
1087 pad = state->extra_pad - tmp;
Damien Miller2a328432014-04-20 13:24:01 +10001088 DBG(debug3("%s: adding %d (len %d padlen %d extra_pad %d)",
markus@openbsd.org091c3022015-01-19 19:52:16 +00001089 __func__, pad, len, padlen, state->extra_pad));
djm@openbsd.orgeb999a42016-07-18 06:08:01 +00001090 tmp = padlen;
Damien Miller9f643902001-11-12 11:02:52 +11001091 padlen += pad;
djm@openbsd.orgeb999a42016-07-18 06:08:01 +00001092 /* Check whether padlen calculation overflowed */
1093 if (padlen < tmp)
1094 return SSH_ERR_INVALID_ARGUMENT; /* overflow */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001095 state->extra_pad = 0;
Damien Miller9f643902001-11-12 11:02:52 +11001096 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001097 if ((r = sshbuf_reserve(state->outgoing_packet, padlen, &cp)) != 0)
1098 goto out;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00001099 if (enc && !cipher_ctx_is_plaintext(state->send_context)) {
Damien Millere247cc42000-05-07 12:03:14 +10001100 /* random padding */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001101 arc4random_buf(cp, padlen);
Damien Millere247cc42000-05-07 12:03:14 +10001102 } else {
1103 /* clear padding */
Damien Millera5103f42014-02-04 11:20:14 +11001104 explicit_bzero(cp, padlen);
Damien Miller33b13562000-04-04 14:38:59 +10001105 }
Damien Milleraf43a7a2012-12-12 10:46:31 +11001106 /* sizeof (packet_len + pad_len + payload + padding) */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001107 len = sshbuf_len(state->outgoing_packet);
1108 cp = sshbuf_mutable_ptr(state->outgoing_packet);
1109 if (cp == NULL) {
1110 r = SSH_ERR_INTERNAL_ERROR;
1111 goto out;
1112 }
Damien Milleraf43a7a2012-12-12 10:46:31 +11001113 /* packet_length includes payload, padding and padding length field */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001114 POKE_U32(cp, len - 4);
Ben Lindstrom4a7714a2002-02-26 18:04:38 +00001115 cp[4] = padlen;
Damien Milleraf43a7a2012-12-12 10:46:31 +11001116 DBG(debug("send: len %d (includes padlen %d, aadlen %d)",
1117 len, padlen, aadlen));
Damien Miller33b13562000-04-04 14:38:59 +10001118
1119 /* compute MAC over seqnr and packet(length fields, payload, padding) */
Damien Milleraf43a7a2012-12-12 10:46:31 +11001120 if (mac && mac->enabled && !mac->etm) {
markus@openbsd.org091c3022015-01-19 19:52:16 +00001121 if ((r = mac_compute(mac, state->p_send.seqnr,
1122 sshbuf_ptr(state->outgoing_packet), len,
markus@openbsd.org128343b2015-01-13 19:31:40 +00001123 macbuf, sizeof(macbuf))) != 0)
markus@openbsd.org091c3022015-01-19 19:52:16 +00001124 goto out;
1125 DBG(debug("done calc MAC out #%d", state->p_send.seqnr));
Damien Miller33b13562000-04-04 14:38:59 +10001126 }
1127 /* encrypt packet and append to output buffer. */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001128 if ((r = sshbuf_reserve(state->output,
1129 sshbuf_len(state->outgoing_packet) + authlen, &cp)) != 0)
1130 goto out;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00001131 if ((r = cipher_crypt(state->send_context, state->p_send.seqnr, cp,
markus@openbsd.org091c3022015-01-19 19:52:16 +00001132 sshbuf_ptr(state->outgoing_packet),
1133 len - aadlen, aadlen, authlen)) != 0)
1134 goto out;
Damien Miller33b13562000-04-04 14:38:59 +10001135 /* append unencrypted MAC */
Damien Milleraf43a7a2012-12-12 10:46:31 +11001136 if (mac && mac->enabled) {
1137 if (mac->etm) {
1138 /* EtM: compute mac over aadlen + cipher text */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001139 if ((r = mac_compute(mac, state->p_send.seqnr,
1140 cp, len, macbuf, sizeof(macbuf))) != 0)
1141 goto out;
Damien Milleraf43a7a2012-12-12 10:46:31 +11001142 DBG(debug("done calc MAC(EtM) out #%d",
markus@openbsd.org091c3022015-01-19 19:52:16 +00001143 state->p_send.seqnr));
Damien Milleraf43a7a2012-12-12 10:46:31 +11001144 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001145 if ((r = sshbuf_put(state->output, macbuf, mac->mac_len)) != 0)
1146 goto out;
Damien Milleraf43a7a2012-12-12 10:46:31 +11001147 }
Damien Miller33b13562000-04-04 14:38:59 +10001148#ifdef PACKET_DEBUG
1149 fprintf(stderr, "encrypted: ");
markus@openbsd.org091c3022015-01-19 19:52:16 +00001150 sshbuf_dump(state->output, stderr);
Damien Miller33b13562000-04-04 14:38:59 +10001151#endif
Damien Miller4af51302000-04-16 11:18:38 +10001152 /* increment sequence number for outgoing packets */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001153 if (++state->p_send.seqnr == 0)
Damien Miller996acd22003-04-09 20:59:48 +10001154 logit("outgoing seqnr wraps around");
markus@openbsd.org091c3022015-01-19 19:52:16 +00001155 if (++state->p_send.packets == 0)
1156 if (!(ssh->compat & SSH_BUG_NOREKEY))
1157 return SSH_ERR_NEED_REKEY;
1158 state->p_send.blocks += len / block_size;
1159 state->p_send.bytes += len;
1160 sshbuf_reset(state->outgoing_packet);
Damien Miller33b13562000-04-04 14:38:59 +10001161
Ben Lindstrom2d90e002001-04-04 02:00:54 +00001162 if (type == SSH2_MSG_NEWKEYS)
markus@openbsd.org091c3022015-01-19 19:52:16 +00001163 r = ssh_set_newkeys(ssh, MODE_OUT);
1164 else if (type == SSH2_MSG_USERAUTH_SUCCESS && state->server_side)
1165 r = ssh_packet_enable_delayed_compress(ssh);
1166 else
1167 r = 0;
1168 out:
1169 return r;
Damien Miller33b13562000-04-04 14:38:59 +10001170}
1171
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001172/* returns non-zero if the specified packet type is usec by KEX */
1173static int
1174ssh_packet_type_is_kex(u_char type)
1175{
1176 return
1177 type >= SSH2_MSG_TRANSPORT_MIN &&
1178 type <= SSH2_MSG_TRANSPORT_MAX &&
1179 type != SSH2_MSG_SERVICE_REQUEST &&
1180 type != SSH2_MSG_SERVICE_ACCEPT &&
1181 type != SSH2_MSG_EXT_INFO;
1182}
1183
markus@openbsd.org091c3022015-01-19 19:52:16 +00001184int
1185ssh_packet_send2(struct ssh *ssh)
Damien Millera5539d22003-04-09 20:50:06 +10001186{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001187 struct session_state *state = ssh->state;
Damien Millera5539d22003-04-09 20:50:06 +10001188 struct packet *p;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001189 u_char type;
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001190 int r, need_rekey;
Damien Millera5539d22003-04-09 20:50:06 +10001191
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001192 if (sshbuf_len(state->outgoing_packet) < 6)
1193 return SSH_ERR_INTERNAL_ERROR;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001194 type = sshbuf_ptr(state->outgoing_packet)[5];
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001195 need_rekey = !ssh_packet_type_is_kex(type) &&
1196 ssh_packet_need_rekeying(ssh, sshbuf_len(state->outgoing_packet));
Damien Millera5539d22003-04-09 20:50:06 +10001197
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001198 /*
1199 * During rekeying we can only send key exchange messages.
1200 * Queue everything else.
1201 */
1202 if ((need_rekey || state->rekeying) && !ssh_packet_type_is_kex(type)) {
1203 if (need_rekey)
1204 debug3("%s: rekex triggered", __func__);
1205 debug("enqueue packet: %u", type);
1206 p = calloc(1, sizeof(*p));
1207 if (p == NULL)
1208 return SSH_ERR_ALLOC_FAIL;
1209 p->type = type;
1210 p->payload = state->outgoing_packet;
1211 TAILQ_INSERT_TAIL(&state->outgoing, p, next);
1212 state->outgoing_packet = sshbuf_new();
1213 if (state->outgoing_packet == NULL)
1214 return SSH_ERR_ALLOC_FAIL;
1215 if (need_rekey) {
1216 /*
1217 * This packet triggered a rekey, so send the
1218 * KEXINIT now.
1219 * NB. reenters this function via kex_start_rekex().
1220 */
1221 return kex_start_rekex(ssh);
Damien Millera5539d22003-04-09 20:50:06 +10001222 }
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001223 return 0;
Damien Millera5539d22003-04-09 20:50:06 +10001224 }
1225
1226 /* rekeying starts with sending KEXINIT */
1227 if (type == SSH2_MSG_KEXINIT)
markus@openbsd.org091c3022015-01-19 19:52:16 +00001228 state->rekeying = 1;
Damien Millera5539d22003-04-09 20:50:06 +10001229
markus@openbsd.org091c3022015-01-19 19:52:16 +00001230 if ((r = ssh_packet_send2_wrapped(ssh)) != 0)
1231 return r;
Damien Millera5539d22003-04-09 20:50:06 +10001232
1233 /* after a NEWKEYS message we can send the complete queue */
1234 if (type == SSH2_MSG_NEWKEYS) {
markus@openbsd.org091c3022015-01-19 19:52:16 +00001235 state->rekeying = 0;
1236 state->rekey_time = monotime();
1237 while ((p = TAILQ_FIRST(&state->outgoing))) {
Damien Millera5539d22003-04-09 20:50:06 +10001238 type = p->type;
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001239 /*
1240 * If this packet triggers a rekex, then skip the
1241 * remaining packets in the queue for now.
1242 * NB. re-enters this function via kex_start_rekex.
1243 */
1244 if (ssh_packet_need_rekeying(ssh,
1245 sshbuf_len(p->payload))) {
1246 debug3("%s: queued packet triggered rekex",
1247 __func__);
1248 return kex_start_rekex(ssh);
1249 }
Damien Millera5539d22003-04-09 20:50:06 +10001250 debug("dequeue packet: %u", type);
markus@openbsd.org091c3022015-01-19 19:52:16 +00001251 sshbuf_free(state->outgoing_packet);
1252 state->outgoing_packet = p->payload;
1253 TAILQ_REMOVE(&state->outgoing, p, next);
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001254 memset(p, 0, sizeof(*p));
Darren Tuckera627d422013-06-02 07:31:17 +10001255 free(p);
markus@openbsd.org091c3022015-01-19 19:52:16 +00001256 if ((r = ssh_packet_send2_wrapped(ssh)) != 0)
1257 return r;
Damien Millera5539d22003-04-09 20:50:06 +10001258 }
1259 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001260 return 0;
Damien Miller33b13562000-04-04 14:38:59 +10001261}
1262
Damien Miller33b13562000-04-04 14:38:59 +10001263/*
Damien Miller5428f641999-11-25 11:54:57 +11001264 * Waits until a packet has been received, and returns its type. Note that
1265 * no other data is processed until this returns, so this function should not
1266 * be used during the interactive session.
1267 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001268
1269int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001270ssh_packet_read_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001271{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001272 struct session_state *state = ssh->state;
markus@openbsd.orga3068632016-01-14 16:17:39 +00001273 int len, r, ms_remain;
Ben Lindstromcb978aa2001-03-05 07:07:49 +00001274 fd_set *setp;
Damien Miller95def091999-11-25 00:26:21 +11001275 char buf[8192];
Darren Tucker3fc464e2008-06-13 06:42:45 +10001276 struct timeval timeout, start, *timeoutp = NULL;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001277
Darren Tucker99bb7612008-06-13 22:02:50 +10001278 DBG(debug("packet_read()"));
1279
deraadt@openbsd.orgce445b02015-08-20 22:32:42 +00001280 setp = calloc(howmany(state->connection_in + 1,
Darren Tuckerf7288d72009-06-21 18:12:20 +10001281 NFDBITS), sizeof(fd_mask));
markus@openbsd.org091c3022015-01-19 19:52:16 +00001282 if (setp == NULL)
1283 return SSH_ERR_ALLOC_FAIL;
Ben Lindstromcb978aa2001-03-05 07:07:49 +00001284
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001285 /*
1286 * Since we are blocking, ensure that all written packets have
1287 * been sent.
1288 */
markus@openbsd.org4daeb672015-03-24 20:10:08 +00001289 if ((r = ssh_packet_write_wait(ssh)) != 0)
1290 goto out;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001291
Damien Miller95def091999-11-25 00:26:21 +11001292 /* Stay in the loop until we have received a complete packet. */
1293 for (;;) {
1294 /* Try to read a packet from the buffer. */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001295 r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p);
1296 if (r != 0)
1297 break;
Damien Miller95def091999-11-25 00:26:21 +11001298 /* If we got a packet, return it. */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001299 if (*typep != SSH_MSG_NONE)
1300 break;
Damien Miller5428f641999-11-25 11:54:57 +11001301 /*
1302 * Otherwise, wait for some data to arrive, add it to the
1303 * buffer, and try again.
1304 */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001305 memset(setp, 0, howmany(state->connection_in + 1,
Darren Tuckerf7288d72009-06-21 18:12:20 +10001306 NFDBITS) * sizeof(fd_mask));
markus@openbsd.org091c3022015-01-19 19:52:16 +00001307 FD_SET(state->connection_in, setp);
Damien Miller5428f641999-11-25 11:54:57 +11001308
markus@openbsd.org091c3022015-01-19 19:52:16 +00001309 if (state->packet_timeout_ms > 0) {
1310 ms_remain = state->packet_timeout_ms;
Darren Tucker3fc464e2008-06-13 06:42:45 +10001311 timeoutp = &timeout;
1312 }
Damien Miller95def091999-11-25 00:26:21 +11001313 /* Wait for some data to arrive. */
Darren Tucker3fc464e2008-06-13 06:42:45 +10001314 for (;;) {
markus@openbsd.org091c3022015-01-19 19:52:16 +00001315 if (state->packet_timeout_ms != -1) {
Darren Tucker3fc464e2008-06-13 06:42:45 +10001316 ms_to_timeval(&timeout, ms_remain);
dtucker@openbsd.org@openbsd.org5db6fbf2017-11-25 06:46:22 +00001317 monotime_tv(&start);
Darren Tucker3fc464e2008-06-13 06:42:45 +10001318 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001319 if ((r = select(state->connection_in + 1, setp,
Darren Tuckerf7288d72009-06-21 18:12:20 +10001320 NULL, NULL, timeoutp)) >= 0)
Darren Tucker3fc464e2008-06-13 06:42:45 +10001321 break;
Damien Millerea437422009-10-02 11:49:03 +10001322 if (errno != EAGAIN && errno != EINTR &&
dtucker@openbsd.org1da59342018-05-25 03:20:59 +00001323 errno != EWOULDBLOCK) {
1324 r = SSH_ERR_SYSTEM_ERROR;
1325 goto out;
1326 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001327 if (state->packet_timeout_ms == -1)
Darren Tucker3fc464e2008-06-13 06:42:45 +10001328 continue;
1329 ms_subtract_diff(&start, &ms_remain);
1330 if (ms_remain <= 0) {
markus@openbsd.org091c3022015-01-19 19:52:16 +00001331 r = 0;
Darren Tucker3fc464e2008-06-13 06:42:45 +10001332 break;
1333 }
1334 }
djm@openbsd.orgd7abb772017-02-28 06:10:08 +00001335 if (r == 0) {
1336 r = SSH_ERR_CONN_TIMEOUT;
1337 goto out;
1338 }
Damien Miller95def091999-11-25 00:26:21 +11001339 /* Read data from the socket. */
markus@openbsd.orga3068632016-01-14 16:17:39 +00001340 len = read(state->connection_in, buf, sizeof(buf));
markus@openbsd.org4daeb672015-03-24 20:10:08 +00001341 if (len == 0) {
1342 r = SSH_ERR_CONN_CLOSED;
1343 goto out;
1344 }
1345 if (len < 0) {
1346 r = SSH_ERR_SYSTEM_ERROR;
1347 goto out;
1348 }
djm@openbsd.orgfae7bbe2015-01-28 21:15:47 +00001349
Damien Miller95def091999-11-25 00:26:21 +11001350 /* Append it to the buffer. */
djm@openbsd.orgfae7bbe2015-01-28 21:15:47 +00001351 if ((r = ssh_packet_process_incoming(ssh, buf, len)) != 0)
markus@openbsd.org4daeb672015-03-24 20:10:08 +00001352 goto out;
Damien Miller95def091999-11-25 00:26:21 +11001353 }
markus@openbsd.org4daeb672015-03-24 20:10:08 +00001354 out:
markus@openbsd.org091c3022015-01-19 19:52:16 +00001355 free(setp);
1356 return r;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001357}
1358
Damien Miller278f9072001-12-21 15:00:19 +11001359int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001360ssh_packet_read(struct ssh *ssh)
Damien Miller278f9072001-12-21 15:00:19 +11001361{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001362 u_char type;
1363 int r;
1364
1365 if ((r = ssh_packet_read_seqnr(ssh, &type, NULL)) != 0)
1366 fatal("%s: %s", __func__, ssh_err(r));
1367 return type;
Damien Miller278f9072001-12-21 15:00:19 +11001368}
1369
Damien Miller5428f641999-11-25 11:54:57 +11001370/*
1371 * Waits until a packet has been received, verifies that its type matches
1372 * that given, and gives a fatal error and exits if there is a mismatch.
1373 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001374
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001375int
1376ssh_packet_read_expect(struct ssh *ssh, u_int expected_type)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001377{
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001378 int r;
1379 u_char type;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001380
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001381 if ((r = ssh_packet_read_seqnr(ssh, &type, NULL)) != 0)
1382 return r;
1383 if (type != expected_type) {
1384 if ((r = sshpkt_disconnect(ssh,
markus@openbsd.org091c3022015-01-19 19:52:16 +00001385 "Protocol error: expected packet type %d, got %d",
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001386 expected_type, type)) != 0)
1387 return r;
1388 return SSH_ERR_PROTOCOL_ERROR;
1389 }
1390 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001391}
1392
markus@openbsd.org8d057842016-09-30 09:19:13 +00001393static int
1394ssh_packet_read_poll2_mux(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
1395{
1396 struct session_state *state = ssh->state;
1397 const u_char *cp;
1398 size_t need;
1399 int r;
1400
1401 if (ssh->kex)
1402 return SSH_ERR_INTERNAL_ERROR;
1403 *typep = SSH_MSG_NONE;
1404 cp = sshbuf_ptr(state->input);
1405 if (state->packlen == 0) {
1406 if (sshbuf_len(state->input) < 4 + 1)
1407 return 0; /* packet is incomplete */
1408 state->packlen = PEEK_U32(cp);
1409 if (state->packlen < 4 + 1 ||
1410 state->packlen > PACKET_MAX_SIZE)
1411 return SSH_ERR_MESSAGE_INCOMPLETE;
1412 }
1413 need = state->packlen + 4;
1414 if (sshbuf_len(state->input) < need)
1415 return 0; /* packet is incomplete */
1416 sshbuf_reset(state->incoming_packet);
1417 if ((r = sshbuf_put(state->incoming_packet, cp + 4,
1418 state->packlen)) != 0 ||
1419 (r = sshbuf_consume(state->input, need)) != 0 ||
1420 (r = sshbuf_get_u8(state->incoming_packet, NULL)) != 0 ||
1421 (r = sshbuf_get_u8(state->incoming_packet, typep)) != 0)
1422 return r;
1423 if (ssh_packet_log_type(*typep))
1424 debug3("%s: type %u", __func__, *typep);
1425 /* sshbuf_dump(state->incoming_packet, stderr); */
1426 /* reset for next packet */
1427 state->packlen = 0;
1428 return r;
1429}
1430
markus@openbsd.org091c3022015-01-19 19:52:16 +00001431int
1432ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
Damien Miller33b13562000-04-04 14:38:59 +10001433{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001434 struct session_state *state = ssh->state;
Ben Lindstrom46c16222000-12-22 01:43:59 +00001435 u_int padlen, need;
djm@openbsd.org6d311932016-07-08 03:44:42 +00001436 u_char *cp;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001437 u_int maclen, aadlen = 0, authlen = 0, block_size;
1438 struct sshenc *enc = NULL;
1439 struct sshmac *mac = NULL;
1440 struct sshcomp *comp = NULL;
markus@openbsd.org128343b2015-01-13 19:31:40 +00001441 int r;
Damien Miller33b13562000-04-04 14:38:59 +10001442
markus@openbsd.org8d057842016-09-30 09:19:13 +00001443 if (state->mux)
1444 return ssh_packet_read_poll2_mux(ssh, typep, seqnr_p);
1445
markus@openbsd.org091c3022015-01-19 19:52:16 +00001446 *typep = SSH_MSG_NONE;
Damien Miller13ae44c2009-01-28 16:38:41 +11001447
markus@openbsd.org091c3022015-01-19 19:52:16 +00001448 if (state->packet_discard)
1449 return 0;
1450
1451 if (state->newkeys[MODE_IN] != NULL) {
1452 enc = &state->newkeys[MODE_IN]->enc;
1453 mac = &state->newkeys[MODE_IN]->mac;
1454 comp = &state->newkeys[MODE_IN]->comp;
Damien Miller1d75abf2013-01-09 16:12:19 +11001455 /* disable mac for authenticated encryption */
1456 if ((authlen = cipher_authlen(enc->cipher)) != 0)
1457 mac = NULL;
Damien Miller33b13562000-04-04 14:38:59 +10001458 }
1459 maclen = mac && mac->enabled ? mac->mac_len : 0;
Damien Miller963f6b22002-02-19 15:21:23 +11001460 block_size = enc ? enc->block_size : 8;
Damien Miller1d75abf2013-01-09 16:12:19 +11001461 aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0;
Damien Miller33b13562000-04-04 14:38:59 +10001462
markus@openbsd.org091c3022015-01-19 19:52:16 +00001463 if (aadlen && state->packlen == 0) {
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00001464 if (cipher_get_length(state->receive_context,
markus@openbsd.org091c3022015-01-19 19:52:16 +00001465 &state->packlen, state->p_read.seqnr,
1466 sshbuf_ptr(state->input), sshbuf_len(state->input)) != 0)
1467 return 0;
1468 if (state->packlen < 1 + 4 ||
1469 state->packlen > PACKET_MAX_SIZE) {
Damien Milleraf43a7a2012-12-12 10:46:31 +11001470#ifdef PACKET_DEBUG
markus@openbsd.org091c3022015-01-19 19:52:16 +00001471 sshbuf_dump(state->input, stderr);
Damien Milleraf43a7a2012-12-12 10:46:31 +11001472#endif
markus@openbsd.org091c3022015-01-19 19:52:16 +00001473 logit("Bad packet length %u.", state->packlen);
1474 if ((r = sshpkt_disconnect(ssh, "Packet corrupt")) != 0)
1475 return r;
djm@openbsd.org2fecfd42015-11-08 21:59:11 +00001476 return SSH_ERR_CONN_CORRUPT;
Damien Milleraf43a7a2012-12-12 10:46:31 +11001477 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001478 sshbuf_reset(state->incoming_packet);
1479 } else if (state->packlen == 0) {
Damien Miller33b13562000-04-04 14:38:59 +10001480 /*
1481 * check if input size is less than the cipher block size,
1482 * decrypt first block and extract length of incoming packet
1483 */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001484 if (sshbuf_len(state->input) < block_size)
1485 return 0;
1486 sshbuf_reset(state->incoming_packet);
1487 if ((r = sshbuf_reserve(state->incoming_packet, block_size,
1488 &cp)) != 0)
1489 goto out;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00001490 if ((r = cipher_crypt(state->receive_context,
markus@openbsd.org091c3022015-01-19 19:52:16 +00001491 state->p_send.seqnr, cp, sshbuf_ptr(state->input),
1492 block_size, 0, 0)) != 0)
1493 goto out;
1494 state->packlen = PEEK_U32(sshbuf_ptr(state->incoming_packet));
1495 if (state->packlen < 1 + 4 ||
1496 state->packlen > PACKET_MAX_SIZE) {
Darren Tuckera8151da2003-09-22 21:06:46 +10001497#ifdef PACKET_DEBUG
markus@openbsd.org091c3022015-01-19 19:52:16 +00001498 fprintf(stderr, "input: \n");
1499 sshbuf_dump(state->input, stderr);
1500 fprintf(stderr, "incoming_packet: \n");
1501 sshbuf_dump(state->incoming_packet, stderr);
Darren Tuckera8151da2003-09-22 21:06:46 +10001502#endif
markus@openbsd.org091c3022015-01-19 19:52:16 +00001503 logit("Bad packet length %u.", state->packlen);
markus@openbsd.orgb98a2a82016-07-18 11:35:33 +00001504 return ssh_packet_start_discard(ssh, enc, mac, 0,
1505 PACKET_MAX_SIZE);
Damien Miller33b13562000-04-04 14:38:59 +10001506 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001507 if ((r = sshbuf_consume(state->input, block_size)) != 0)
1508 goto out;
Damien Miller33b13562000-04-04 14:38:59 +10001509 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001510 DBG(debug("input: packet len %u", state->packlen+4));
1511
Damien Milleraf43a7a2012-12-12 10:46:31 +11001512 if (aadlen) {
1513 /* only the payload is encrypted */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001514 need = state->packlen;
Damien Milleraf43a7a2012-12-12 10:46:31 +11001515 } else {
1516 /*
1517 * the payload size and the payload are encrypted, but we
1518 * have a partial packet of block_size bytes
1519 */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001520 need = 4 + state->packlen - block_size;
Damien Milleraf43a7a2012-12-12 10:46:31 +11001521 }
Damien Miller1d75abf2013-01-09 16:12:19 +11001522 DBG(debug("partial packet: block %d, need %d, maclen %d, authlen %d,"
1523 " aadlen %d", block_size, need, maclen, authlen, aadlen));
Darren Tucker99d11a32008-12-01 21:40:48 +11001524 if (need % block_size != 0) {
1525 logit("padding error: need %d block %d mod %d",
Damien Miller33b13562000-04-04 14:38:59 +10001526 need, block_size, need % block_size);
markus@openbsd.orgb98a2a82016-07-18 11:35:33 +00001527 return ssh_packet_start_discard(ssh, enc, mac, 0,
1528 PACKET_MAX_SIZE - block_size);
Darren Tucker99d11a32008-12-01 21:40:48 +11001529 }
Damien Miller33b13562000-04-04 14:38:59 +10001530 /*
1531 * check if the entire packet has been received and
Damien Milleraf43a7a2012-12-12 10:46:31 +11001532 * decrypt into incoming_packet:
1533 * 'aadlen' bytes are unencrypted, but authenticated.
Damien Miller1d75abf2013-01-09 16:12:19 +11001534 * 'need' bytes are encrypted, followed by either
1535 * 'authlen' bytes of authentication tag or
Damien Milleraf43a7a2012-12-12 10:46:31 +11001536 * 'maclen' bytes of message authentication code.
Damien Miller33b13562000-04-04 14:38:59 +10001537 */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001538 if (sshbuf_len(state->input) < aadlen + need + authlen + maclen)
djm@openbsd.org6d311932016-07-08 03:44:42 +00001539 return 0; /* packet is incomplete */
Damien Miller33b13562000-04-04 14:38:59 +10001540#ifdef PACKET_DEBUG
1541 fprintf(stderr, "read_poll enc/full: ");
markus@openbsd.org091c3022015-01-19 19:52:16 +00001542 sshbuf_dump(state->input, stderr);
Damien Miller33b13562000-04-04 14:38:59 +10001543#endif
djm@openbsd.org6d311932016-07-08 03:44:42 +00001544 /* EtM: check mac over encrypted input */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001545 if (mac && mac->enabled && mac->etm) {
djm@openbsd.org6d311932016-07-08 03:44:42 +00001546 if ((r = mac_check(mac, state->p_read.seqnr,
markus@openbsd.org091c3022015-01-19 19:52:16 +00001547 sshbuf_ptr(state->input), aadlen + need,
djm@openbsd.org6d311932016-07-08 03:44:42 +00001548 sshbuf_ptr(state->input) + aadlen + need + authlen,
1549 maclen)) != 0) {
1550 if (r == SSH_ERR_MAC_INVALID)
1551 logit("Corrupted MAC on input.");
markus@openbsd.org091c3022015-01-19 19:52:16 +00001552 goto out;
djm@openbsd.org6d311932016-07-08 03:44:42 +00001553 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001554 }
1555 if ((r = sshbuf_reserve(state->incoming_packet, aadlen + need,
1556 &cp)) != 0)
1557 goto out;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00001558 if ((r = cipher_crypt(state->receive_context, state->p_read.seqnr, cp,
markus@openbsd.org091c3022015-01-19 19:52:16 +00001559 sshbuf_ptr(state->input), need, aadlen, authlen)) != 0)
1560 goto out;
1561 if ((r = sshbuf_consume(state->input, aadlen + need + authlen)) != 0)
1562 goto out;
Damien Miller4af51302000-04-16 11:18:38 +10001563 if (mac && mac->enabled) {
djm@openbsd.org6d311932016-07-08 03:44:42 +00001564 /* Not EtM: check MAC over cleartext */
1565 if (!mac->etm && (r = mac_check(mac, state->p_read.seqnr,
1566 sshbuf_ptr(state->incoming_packet),
1567 sshbuf_len(state->incoming_packet),
1568 sshbuf_ptr(state->input), maclen)) != 0) {
1569 if (r != SSH_ERR_MAC_INVALID)
markus@openbsd.org091c3022015-01-19 19:52:16 +00001570 goto out;
Damien Miller13ae44c2009-01-28 16:38:41 +11001571 logit("Corrupted MAC on input.");
markus@openbsd.org0fb1a612017-03-11 13:07:35 +00001572 if (need + block_size > PACKET_MAX_SIZE)
markus@openbsd.org091c3022015-01-19 19:52:16 +00001573 return SSH_ERR_INTERNAL_ERROR;
1574 return ssh_packet_start_discard(ssh, enc, mac,
markus@openbsd.orgb98a2a82016-07-18 11:35:33 +00001575 sshbuf_len(state->incoming_packet),
markus@openbsd.org0fb1a612017-03-11 13:07:35 +00001576 PACKET_MAX_SIZE - need - block_size);
Damien Miller13ae44c2009-01-28 16:38:41 +11001577 }
djm@openbsd.org6d311932016-07-08 03:44:42 +00001578 /* Remove MAC from input buffer */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001579 DBG(debug("MAC #%d ok", state->p_read.seqnr));
1580 if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0)
1581 goto out;
Damien Miller33b13562000-04-04 14:38:59 +10001582 }
Damien Miller278f9072001-12-21 15:00:19 +11001583 if (seqnr_p != NULL)
markus@openbsd.org091c3022015-01-19 19:52:16 +00001584 *seqnr_p = state->p_read.seqnr;
1585 if (++state->p_read.seqnr == 0)
Damien Miller996acd22003-04-09 20:59:48 +10001586 logit("incoming seqnr wraps around");
markus@openbsd.org091c3022015-01-19 19:52:16 +00001587 if (++state->p_read.packets == 0)
1588 if (!(ssh->compat & SSH_BUG_NOREKEY))
1589 return SSH_ERR_NEED_REKEY;
1590 state->p_read.blocks += (state->packlen + 4) / block_size;
1591 state->p_read.bytes += state->packlen + 4;
Damien Miller33b13562000-04-04 14:38:59 +10001592
1593 /* get padlen */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001594 padlen = sshbuf_ptr(state->incoming_packet)[4];
Damien Miller33b13562000-04-04 14:38:59 +10001595 DBG(debug("input: padlen %d", padlen));
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001596 if (padlen < 4) {
1597 if ((r = sshpkt_disconnect(ssh,
1598 "Corrupted padlen %d on input.", padlen)) != 0 ||
1599 (r = ssh_packet_write_wait(ssh)) != 0)
1600 return r;
1601 return SSH_ERR_CONN_CORRUPT;
1602 }
Damien Miller33b13562000-04-04 14:38:59 +10001603
1604 /* skip packet size + padlen, discard padding */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001605 if ((r = sshbuf_consume(state->incoming_packet, 4 + 1)) != 0 ||
1606 ((r = sshbuf_consume_end(state->incoming_packet, padlen)) != 0))
1607 goto out;
Damien Miller33b13562000-04-04 14:38:59 +10001608
markus@openbsd.org091c3022015-01-19 19:52:16 +00001609 DBG(debug("input: len before de-compress %zd",
1610 sshbuf_len(state->incoming_packet)));
Damien Miller33b13562000-04-04 14:38:59 +10001611 if (comp && comp->enabled) {
markus@openbsd.org091c3022015-01-19 19:52:16 +00001612 sshbuf_reset(state->compression_buffer);
1613 if ((r = uncompress_buffer(ssh, state->incoming_packet,
1614 state->compression_buffer)) != 0)
1615 goto out;
1616 sshbuf_reset(state->incoming_packet);
1617 if ((r = sshbuf_putb(state->incoming_packet,
1618 state->compression_buffer)) != 0)
1619 goto out;
1620 DBG(debug("input: len after de-compress %zd",
1621 sshbuf_len(state->incoming_packet)));
Damien Miller33b13562000-04-04 14:38:59 +10001622 }
1623 /*
1624 * get packet type, implies consume.
1625 * return length of payload (without type field)
1626 */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001627 if ((r = sshbuf_get_u8(state->incoming_packet, typep)) != 0)
1628 goto out;
djm@openbsd.org28136472016-01-29 05:46:01 +00001629 if (ssh_packet_log_type(*typep))
1630 debug3("receive packet: type %u", *typep);
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001631 if (*typep < SSH2_MSG_MIN || *typep >= SSH2_MSG_LOCAL_MIN) {
1632 if ((r = sshpkt_disconnect(ssh,
1633 "Invalid ssh2 packet type: %d", *typep)) != 0 ||
1634 (r = ssh_packet_write_wait(ssh)) != 0)
1635 return r;
1636 return SSH_ERR_PROTOCOL_ERROR;
1637 }
djm@openbsd.org39af7b42016-10-11 21:47:45 +00001638 if (state->hook_in != NULL &&
1639 (r = state->hook_in(ssh, state->incoming_packet, typep,
1640 state->hook_in_ctx)) != 0)
1641 return r;
markus@openbsd.org28652bc2016-09-19 19:02:19 +00001642 if (*typep == SSH2_MSG_USERAUTH_SUCCESS && !state->server_side)
markus@openbsd.org091c3022015-01-19 19:52:16 +00001643 r = ssh_packet_enable_delayed_compress(ssh);
1644 else
1645 r = 0;
Damien Miller33b13562000-04-04 14:38:59 +10001646#ifdef PACKET_DEBUG
markus@openbsd.org091c3022015-01-19 19:52:16 +00001647 fprintf(stderr, "read/plain[%d]:\r\n", *typep);
1648 sshbuf_dump(state->incoming_packet, stderr);
Damien Miller33b13562000-04-04 14:38:59 +10001649#endif
Ben Lindstrom80c6d772001-06-05 21:09:18 +00001650 /* reset for next packet */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001651 state->packlen = 0;
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001652
1653 /* do we need to rekey? */
1654 if (ssh_packet_need_rekeying(ssh, 0)) {
1655 debug3("%s: rekex triggered", __func__);
1656 if ((r = kex_start_rekex(ssh)) != 0)
1657 return r;
1658 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001659 out:
1660 return r;
Damien Miller33b13562000-04-04 14:38:59 +10001661}
1662
1663int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001664ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
Damien Miller33b13562000-04-04 14:38:59 +10001665{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001666 struct session_state *state = ssh->state;
Ben Lindstrom3f584742002-06-23 21:49:25 +00001667 u_int reason, seqnr;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001668 int r;
1669 u_char *msg;
Damien Miller33b13562000-04-04 14:38:59 +10001670
Ben Lindstrom80c6d772001-06-05 21:09:18 +00001671 for (;;) {
markus@openbsd.org091c3022015-01-19 19:52:16 +00001672 msg = NULL;
djm@openbsd.org97f4d302017-04-30 23:13:25 +00001673 r = ssh_packet_read_poll2(ssh, typep, seqnr_p);
1674 if (r != 0)
1675 return r;
1676 if (*typep) {
1677 state->keep_alive_timeouts = 0;
1678 DBG(debug("received packet type %d", *typep));
1679 }
1680 switch (*typep) {
1681 case SSH2_MSG_IGNORE:
1682 debug3("Received SSH2_MSG_IGNORE");
1683 break;
1684 case SSH2_MSG_DEBUG:
1685 if ((r = sshpkt_get_u8(ssh, NULL)) != 0 ||
1686 (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 ||
1687 (r = sshpkt_get_string(ssh, NULL, NULL)) != 0) {
1688 free(msg);
markus@openbsd.org091c3022015-01-19 19:52:16 +00001689 return r;
Darren Tucker136e56f2008-06-08 12:49:30 +10001690 }
djm@openbsd.org97f4d302017-04-30 23:13:25 +00001691 debug("Remote: %.900s", msg);
1692 free(msg);
1693 break;
1694 case SSH2_MSG_DISCONNECT:
1695 if ((r = sshpkt_get_u32(ssh, &reason)) != 0 ||
1696 (r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
1697 return r;
1698 /* Ignore normal client exit notifications */
1699 do_log2(ssh->state->server_side &&
1700 reason == SSH2_DISCONNECT_BY_APPLICATION ?
1701 SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR,
1702 "Received disconnect from %s port %d:"
1703 "%u: %.400s", ssh_remote_ipaddr(ssh),
1704 ssh_remote_port(ssh), reason, msg);
1705 free(msg);
1706 return SSH_ERR_DISCONNECTED;
1707 case SSH2_MSG_UNIMPLEMENTED:
1708 if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0)
1709 return r;
1710 debug("Received SSH2_MSG_UNIMPLEMENTED for %u",
1711 seqnr);
1712 break;
1713 default:
1714 return 0;
Damien Miller33b13562000-04-04 14:38:59 +10001715 }
1716 }
1717}
1718
Damien Miller5428f641999-11-25 11:54:57 +11001719/*
1720 * Buffers the given amount of input characters. This is intended to be used
1721 * together with packet_read_poll.
1722 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001723
djm@openbsd.orgfae7bbe2015-01-28 21:15:47 +00001724int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001725ssh_packet_process_incoming(struct ssh *ssh, const char *buf, u_int len)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001726{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001727 struct session_state *state = ssh->state;
1728 int r;
1729
1730 if (state->packet_discard) {
1731 state->keep_alive_timeouts = 0; /* ?? */
1732 if (len >= state->packet_discard) {
1733 if ((r = ssh_packet_stop_discard(ssh)) != 0)
djm@openbsd.orgfae7bbe2015-01-28 21:15:47 +00001734 return r;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001735 }
1736 state->packet_discard -= len;
djm@openbsd.orgfae7bbe2015-01-28 21:15:47 +00001737 return 0;
Damien Miller13ae44c2009-01-28 16:38:41 +11001738 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001739 if ((r = sshbuf_put(ssh->state->input, buf, len)) != 0)
djm@openbsd.orgfae7bbe2015-01-28 21:15:47 +00001740 return r;
1741
1742 return 0;
Damien Miller33b13562000-04-04 14:38:59 +10001743}
1744
Damien Miller4af51302000-04-16 11:18:38 +10001745int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001746ssh_packet_remaining(struct ssh *ssh)
Damien Miller4af51302000-04-16 11:18:38 +10001747{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001748 return sshbuf_len(ssh->state->incoming_packet);
Damien Millerda108ec2010-08-31 22:36:39 +10001749}
1750
Damien Miller5428f641999-11-25 11:54:57 +11001751/*
1752 * Sends a diagnostic message from the server to the client. This message
1753 * can be sent at any time (but not while constructing another message). The
1754 * message is printed immediately, but only if the client is being executed
1755 * in verbose mode. These messages are primarily intended to ease debugging
1756 * authentication problems. The length of the formatted message must not
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001757 * exceed 1024 bytes. This will automatically call ssh_packet_write_wait.
Damien Miller5428f641999-11-25 11:54:57 +11001758 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001759void
markus@openbsd.org091c3022015-01-19 19:52:16 +00001760ssh_packet_send_debug(struct ssh *ssh, const char *fmt,...)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001761{
Damien Miller95def091999-11-25 00:26:21 +11001762 char buf[1024];
1763 va_list args;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001764 int r;
Damien Miller95def091999-11-25 00:26:21 +11001765
djm@openbsd.org97f4d302017-04-30 23:13:25 +00001766 if ((ssh->compat & SSH_BUG_DEBUG))
Ben Lindstroma14ee472000-12-07 01:24:58 +00001767 return;
1768
Damien Miller95def091999-11-25 00:26:21 +11001769 va_start(args, fmt);
1770 vsnprintf(buf, sizeof(buf), fmt, args);
1771 va_end(args);
1772
djm@openbsd.orgeb80e262017-10-13 21:13:54 +00001773 debug3("sending debug message: %s", buf);
1774
djm@openbsd.org97f4d302017-04-30 23:13:25 +00001775 if ((r = sshpkt_start(ssh, SSH2_MSG_DEBUG)) != 0 ||
1776 (r = sshpkt_put_u8(ssh, 0)) != 0 || /* always display */
1777 (r = sshpkt_put_cstring(ssh, buf)) != 0 ||
1778 (r = sshpkt_put_cstring(ssh, "")) != 0 ||
1779 (r = sshpkt_send(ssh)) != 0 ||
1780 (r = ssh_packet_write_wait(ssh)) != 0)
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001781 fatal("%s: %s", __func__, ssh_err(r));
1782}
1783
dtucker@openbsd.org48c23a32017-12-10 05:55:29 +00001784void
1785sshpkt_fmt_connection_id(struct ssh *ssh, char *s, size_t l)
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001786{
1787 snprintf(s, l, "%.200s%s%s port %d",
1788 ssh->log_preamble ? ssh->log_preamble : "",
1789 ssh->log_preamble ? " " : "",
1790 ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
1791}
1792
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001793/*
1794 * Pretty-print connection-terminating errors and exit.
1795 */
1796void
1797sshpkt_fatal(struct ssh *ssh, const char *tag, int r)
1798{
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001799 char remote_id[512];
1800
dtucker@openbsd.org48c23a32017-12-10 05:55:29 +00001801 sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001802
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001803 switch (r) {
1804 case SSH_ERR_CONN_CLOSED:
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +00001805 ssh_packet_clear_keys(ssh);
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001806 logdie("Connection closed by %s", remote_id);
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001807 case SSH_ERR_CONN_TIMEOUT:
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +00001808 ssh_packet_clear_keys(ssh);
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001809 logdie("Connection %s %s timed out",
1810 ssh->state->server_side ? "from" : "to", remote_id);
djm@openbsd.org639d6bc2015-05-01 07:10:01 +00001811 case SSH_ERR_DISCONNECTED:
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +00001812 ssh_packet_clear_keys(ssh);
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001813 logdie("Disconnected from %s", remote_id);
djm@openbsd.org639d6bc2015-05-01 07:10:01 +00001814 case SSH_ERR_SYSTEM_ERROR:
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +00001815 if (errno == ECONNRESET) {
1816 ssh_packet_clear_keys(ssh);
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001817 logdie("Connection reset by %s", remote_id);
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +00001818 }
djm@openbsd.org639d6bc2015-05-01 07:10:01 +00001819 /* FALLTHROUGH */
djm@openbsd.orgf3199122015-07-29 04:43:06 +00001820 case SSH_ERR_NO_CIPHER_ALG_MATCH:
1821 case SSH_ERR_NO_MAC_ALG_MATCH:
1822 case SSH_ERR_NO_COMPRESS_ALG_MATCH:
1823 case SSH_ERR_NO_KEX_ALG_MATCH:
1824 case SSH_ERR_NO_HOSTKEY_ALG_MATCH:
1825 if (ssh && ssh->kex && ssh->kex->failed_choice) {
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +00001826 ssh_packet_clear_keys(ssh);
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001827 logdie("Unable to negotiate with %s: %s. "
1828 "Their offer: %s", remote_id, ssh_err(r),
djm@openbsd.orga4b9e0f2015-12-11 03:24:25 +00001829 ssh->kex->failed_choice);
djm@openbsd.orgf3199122015-07-29 04:43:06 +00001830 }
1831 /* FALLTHROUGH */
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001832 default:
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +00001833 ssh_packet_clear_keys(ssh);
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001834 logdie("%s%sConnection %s %s: %s",
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001835 tag != NULL ? tag : "", tag != NULL ? ": " : "",
djm@openbsd.orga4b9e0f2015-12-11 03:24:25 +00001836 ssh->state->server_side ? "from" : "to",
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001837 remote_id, ssh_err(r));
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001838 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001839}
1840
Damien Miller5428f641999-11-25 11:54:57 +11001841/*
1842 * Logs the error plus constructs and sends a disconnect packet, closes the
1843 * connection, and exits. This function never returns. The error message
1844 * should not contain a newline. The length of the formatted message must
1845 * not exceed 1024 bytes.
1846 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001847void
markus@openbsd.org091c3022015-01-19 19:52:16 +00001848ssh_packet_disconnect(struct ssh *ssh, const char *fmt,...)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001849{
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001850 char buf[1024], remote_id[512];
Damien Miller95def091999-11-25 00:26:21 +11001851 va_list args;
1852 static int disconnecting = 0;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001853 int r;
Ben Lindstrom8b2eecd2002-07-07 22:11:51 +00001854
Damien Miller95def091999-11-25 00:26:21 +11001855 if (disconnecting) /* Guard against recursive invocations. */
1856 fatal("packet_disconnect called recursively.");
1857 disconnecting = 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001858
Damien Miller5428f641999-11-25 11:54:57 +11001859 /*
1860 * Format the message. Note that the caller must make sure the
1861 * message is of limited size.
1862 */
dtucker@openbsd.org48c23a32017-12-10 05:55:29 +00001863 sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
Damien Miller95def091999-11-25 00:26:21 +11001864 va_start(args, fmt);
1865 vsnprintf(buf, sizeof(buf), fmt, args);
1866 va_end(args);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001867
Ben Lindstrom9bda7ae2002-11-09 15:46:24 +00001868 /* Display the error locally */
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001869 logit("Disconnecting %s: %.100s", remote_id, buf);
Ben Lindstrom9bda7ae2002-11-09 15:46:24 +00001870
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001871 /*
1872 * Send the disconnect message to the other side, and wait
1873 * for it to get sent.
1874 */
1875 if ((r = sshpkt_disconnect(ssh, "%s", buf)) != 0)
1876 sshpkt_fatal(ssh, __func__, r);
1877
1878 if ((r = ssh_packet_write_wait(ssh)) != 0)
1879 sshpkt_fatal(ssh, __func__, r);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001880
Damien Miller95def091999-11-25 00:26:21 +11001881 /* Close the connection. */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001882 ssh_packet_close(ssh);
Darren Tucker3e33cec2003-10-02 16:12:36 +10001883 cleanup_exit(255);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001884}
1885
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001886/*
1887 * Checks if there is any buffered output, and tries to write some of
1888 * the output.
1889 */
1890int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001891ssh_packet_write_poll(struct ssh *ssh)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001892{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001893 struct session_state *state = ssh->state;
1894 int len = sshbuf_len(state->output);
markus@openbsd.orga3068632016-01-14 16:17:39 +00001895 int r;
Ben Lindstrom8b2eecd2002-07-07 22:11:51 +00001896
Damien Miller95def091999-11-25 00:26:21 +11001897 if (len > 0) {
markus@openbsd.orga3068632016-01-14 16:17:39 +00001898 len = write(state->connection_out,
1899 sshbuf_ptr(state->output), len);
Damien Millerd874fa52008-07-05 09:40:56 +10001900 if (len == -1) {
Damien Millerea437422009-10-02 11:49:03 +10001901 if (errno == EINTR || errno == EAGAIN ||
1902 errno == EWOULDBLOCK)
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001903 return 0;
1904 return SSH_ERR_SYSTEM_ERROR;
Damien Miller95def091999-11-25 00:26:21 +11001905 }
markus@openbsd.orga3068632016-01-14 16:17:39 +00001906 if (len == 0)
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001907 return SSH_ERR_CONN_CLOSED;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001908 if ((r = sshbuf_consume(state->output, len)) != 0)
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001909 return r;
Damien Miller95def091999-11-25 00:26:21 +11001910 }
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001911 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001912}
1913
Damien Miller5428f641999-11-25 11:54:57 +11001914/*
1915 * Calls packet_write_poll repeatedly until all pending output data has been
1916 * written.
1917 */
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001918int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001919ssh_packet_write_wait(struct ssh *ssh)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001920{
Ben Lindstromcb978aa2001-03-05 07:07:49 +00001921 fd_set *setp;
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001922 int ret, r, ms_remain = 0;
Darren Tucker3fc464e2008-06-13 06:42:45 +10001923 struct timeval start, timeout, *timeoutp = NULL;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001924 struct session_state *state = ssh->state;
Ben Lindstromcb978aa2001-03-05 07:07:49 +00001925
deraadt@openbsd.orgce445b02015-08-20 22:32:42 +00001926 setp = calloc(howmany(state->connection_out + 1,
Darren Tuckerf7288d72009-06-21 18:12:20 +10001927 NFDBITS), sizeof(fd_mask));
markus@openbsd.org091c3022015-01-19 19:52:16 +00001928 if (setp == NULL)
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001929 return SSH_ERR_ALLOC_FAIL;
gsoares@openbsd.org66d2e222015-10-21 11:33:03 +00001930 if ((r = ssh_packet_write_poll(ssh)) != 0) {
1931 free(setp);
djm@openbsd.org84082182015-09-21 04:31:00 +00001932 return r;
gsoares@openbsd.org66d2e222015-10-21 11:33:03 +00001933 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001934 while (ssh_packet_have_data_to_write(ssh)) {
1935 memset(setp, 0, howmany(state->connection_out + 1,
Darren Tuckerf7288d72009-06-21 18:12:20 +10001936 NFDBITS) * sizeof(fd_mask));
markus@openbsd.org091c3022015-01-19 19:52:16 +00001937 FD_SET(state->connection_out, setp);
Darren Tucker3fc464e2008-06-13 06:42:45 +10001938
markus@openbsd.org091c3022015-01-19 19:52:16 +00001939 if (state->packet_timeout_ms > 0) {
1940 ms_remain = state->packet_timeout_ms;
Darren Tucker3fc464e2008-06-13 06:42:45 +10001941 timeoutp = &timeout;
1942 }
1943 for (;;) {
markus@openbsd.org091c3022015-01-19 19:52:16 +00001944 if (state->packet_timeout_ms != -1) {
Darren Tucker3fc464e2008-06-13 06:42:45 +10001945 ms_to_timeval(&timeout, ms_remain);
dtucker@openbsd.org@openbsd.org5db6fbf2017-11-25 06:46:22 +00001946 monotime_tv(&start);
Darren Tucker3fc464e2008-06-13 06:42:45 +10001947 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001948 if ((ret = select(state->connection_out + 1,
Darren Tuckerf7288d72009-06-21 18:12:20 +10001949 NULL, setp, NULL, timeoutp)) >= 0)
Darren Tucker3fc464e2008-06-13 06:42:45 +10001950 break;
Damien Millerea437422009-10-02 11:49:03 +10001951 if (errno != EAGAIN && errno != EINTR &&
1952 errno != EWOULDBLOCK)
Darren Tucker3fc464e2008-06-13 06:42:45 +10001953 break;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001954 if (state->packet_timeout_ms == -1)
Darren Tucker3fc464e2008-06-13 06:42:45 +10001955 continue;
1956 ms_subtract_diff(&start, &ms_remain);
1957 if (ms_remain <= 0) {
1958 ret = 0;
1959 break;
1960 }
1961 }
1962 if (ret == 0) {
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001963 free(setp);
1964 return SSH_ERR_CONN_TIMEOUT;
Darren Tucker3fc464e2008-06-13 06:42:45 +10001965 }
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001966 if ((r = ssh_packet_write_poll(ssh)) != 0) {
1967 free(setp);
1968 return r;
1969 }
Damien Miller95def091999-11-25 00:26:21 +11001970 }
Darren Tuckera627d422013-06-02 07:31:17 +10001971 free(setp);
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001972 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001973}
1974
1975/* Returns true if there is buffered data to write to the connection. */
1976
1977int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001978ssh_packet_have_data_to_write(struct ssh *ssh)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001979{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001980 return sshbuf_len(ssh->state->output) != 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001981}
1982
1983/* Returns true if there is not too much data to write to the connection. */
1984
1985int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001986ssh_packet_not_very_much_data_to_write(struct ssh *ssh)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001987{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001988 if (ssh->state->interactive_mode)
1989 return sshbuf_len(ssh->state->output) < 16384;
Damien Miller95def091999-11-25 00:26:21 +11001990 else
markus@openbsd.org091c3022015-01-19 19:52:16 +00001991 return sshbuf_len(ssh->state->output) < 128 * 1024;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001992}
1993
markus@openbsd.org091c3022015-01-19 19:52:16 +00001994void
1995ssh_packet_set_tos(struct ssh *ssh, int tos)
Ben Lindstroma7433982002-12-23 02:41:41 +00001996{
Damien Millerd2ac5d72011-05-15 08:43:13 +10001997#ifndef IP_TOS_IS_BROKEN
djm@openbsd.org51676ec2017-07-23 23:37:02 +00001998 if (!ssh_packet_connection_is_on_socket(ssh) || tos == INT_MAX)
Ben Lindstroma7433982002-12-23 02:41:41 +00001999 return;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002000 switch (ssh_packet_connection_af(ssh)) {
Damien Millerd2ac5d72011-05-15 08:43:13 +10002001# ifdef IP_TOS
2002 case AF_INET:
2003 debug3("%s: set IP_TOS 0x%02x", __func__, tos);
markus@openbsd.org091c3022015-01-19 19:52:16 +00002004 if (setsockopt(ssh->state->connection_in,
Damien Millerd2ac5d72011-05-15 08:43:13 +10002005 IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0)
2006 error("setsockopt IP_TOS %d: %.100s:",
2007 tos, strerror(errno));
2008 break;
2009# endif /* IP_TOS */
2010# ifdef IPV6_TCLASS
2011 case AF_INET6:
2012 debug3("%s: set IPV6_TCLASS 0x%02x", __func__, tos);
markus@openbsd.org091c3022015-01-19 19:52:16 +00002013 if (setsockopt(ssh->state->connection_in,
Damien Millerd2ac5d72011-05-15 08:43:13 +10002014 IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)) < 0)
2015 error("setsockopt IPV6_TCLASS %d: %.100s:",
2016 tos, strerror(errno));
2017 break;
Damien Millerd2ac5d72011-05-15 08:43:13 +10002018# endif /* IPV6_TCLASS */
Damien Miller23f425b2011-05-15 08:58:15 +10002019 }
Damien Millerd2ac5d72011-05-15 08:43:13 +10002020#endif /* IP_TOS_IS_BROKEN */
Damien Miller5924ceb2003-11-22 15:02:42 +11002021}
Ben Lindstroma7433982002-12-23 02:41:41 +00002022
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002023/* Informs that the current session is interactive. Sets IP flags for that. */
2024
2025void
markus@openbsd.org091c3022015-01-19 19:52:16 +00002026ssh_packet_set_interactive(struct ssh *ssh, int interactive, int qos_interactive, int qos_bulk)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002027{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002028 struct session_state *state = ssh->state;
2029
2030 if (state->set_interactive_called)
Ben Lindstrombf555ba2001-01-18 02:04:35 +00002031 return;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002032 state->set_interactive_called = 1;
Ben Lindstrombf555ba2001-01-18 02:04:35 +00002033
Damien Miller95def091999-11-25 00:26:21 +11002034 /* Record that we are in interactive mode. */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002035 state->interactive_mode = interactive;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002036
Damien Miller34132e52000-01-14 15:45:46 +11002037 /* Only set socket options if using a socket. */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002038 if (!ssh_packet_connection_is_on_socket(ssh))
Ben Lindstrom93b6b772003-04-27 17:55:33 +00002039 return;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002040 set_nodelay(state->connection_in);
2041 ssh_packet_set_tos(ssh, interactive ? qos_interactive :
2042 qos_bulk);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002043}
2044
2045/* Returns true if the current connection is interactive. */
2046
2047int
markus@openbsd.org091c3022015-01-19 19:52:16 +00002048ssh_packet_is_interactive(struct ssh *ssh)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002049{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002050 return ssh->state->interactive_mode;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002051}
Damien Miller6162d121999-11-21 13:23:52 +11002052
Darren Tucker1f8311c2004-05-13 16:39:33 +10002053int
markus@openbsd.org091c3022015-01-19 19:52:16 +00002054ssh_packet_set_maxsize(struct ssh *ssh, u_int s)
Damien Miller6162d121999-11-21 13:23:52 +11002055{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002056 struct session_state *state = ssh->state;
2057
2058 if (state->set_maxsize_called) {
Damien Miller996acd22003-04-09 20:59:48 +10002059 logit("packet_set_maxsize: called twice: old %d new %d",
markus@openbsd.org091c3022015-01-19 19:52:16 +00002060 state->max_packet_size, s);
Damien Miller95def091999-11-25 00:26:21 +11002061 return -1;
2062 }
2063 if (s < 4 * 1024 || s > 1024 * 1024) {
Damien Miller996acd22003-04-09 20:59:48 +10002064 logit("packet_set_maxsize: bad size %d", s);
Damien Miller95def091999-11-25 00:26:21 +11002065 return -1;
2066 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00002067 state->set_maxsize_called = 1;
Ben Lindstrom16d45b32001-06-13 04:39:18 +00002068 debug("packet_set_maxsize: setting to %d", s);
markus@openbsd.org091c3022015-01-19 19:52:16 +00002069 state->max_packet_size = s;
Damien Miller95def091999-11-25 00:26:21 +11002070 return s;
Damien Miller6162d121999-11-21 13:23:52 +11002071}
Ben Lindstrom5699c5f2001-03-05 06:17:49 +00002072
Darren Tuckerf7288d72009-06-21 18:12:20 +10002073int
markus@openbsd.org091c3022015-01-19 19:52:16 +00002074ssh_packet_inc_alive_timeouts(struct ssh *ssh)
Darren Tuckerf7288d72009-06-21 18:12:20 +10002075{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002076 return ++ssh->state->keep_alive_timeouts;
Darren Tuckerf7288d72009-06-21 18:12:20 +10002077}
2078
2079void
markus@openbsd.org091c3022015-01-19 19:52:16 +00002080ssh_packet_set_alive_timeouts(struct ssh *ssh, int ka)
Darren Tuckerf7288d72009-06-21 18:12:20 +10002081{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002082 ssh->state->keep_alive_timeouts = ka;
Darren Tuckerf7288d72009-06-21 18:12:20 +10002083}
2084
2085u_int
markus@openbsd.org091c3022015-01-19 19:52:16 +00002086ssh_packet_get_maxsize(struct ssh *ssh)
Darren Tuckerf7288d72009-06-21 18:12:20 +10002087{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002088 return ssh->state->max_packet_size;
Damien Miller9f643902001-11-12 11:02:52 +11002089}
2090
Damien Millera5539d22003-04-09 20:50:06 +10002091void
dtucker@openbsd.orgc998bf02017-02-03 02:56:00 +00002092ssh_packet_set_rekey_limits(struct ssh *ssh, u_int64_t bytes, u_int32_t seconds)
Damien Millera5539d22003-04-09 20:50:06 +10002093{
dtucker@openbsd.orgc998bf02017-02-03 02:56:00 +00002094 debug3("rekey after %llu bytes, %u seconds", (unsigned long long)bytes,
2095 (unsigned int)seconds);
markus@openbsd.org091c3022015-01-19 19:52:16 +00002096 ssh->state->rekey_limit = bytes;
2097 ssh->state->rekey_interval = seconds;
Darren Tuckerc53c2af2013-05-16 20:28:16 +10002098}
2099
2100time_t
markus@openbsd.org091c3022015-01-19 19:52:16 +00002101ssh_packet_get_rekey_timeout(struct ssh *ssh)
Darren Tuckerc53c2af2013-05-16 20:28:16 +10002102{
2103 time_t seconds;
2104
markus@openbsd.org091c3022015-01-19 19:52:16 +00002105 seconds = ssh->state->rekey_time + ssh->state->rekey_interval -
Darren Tuckerb759c9c2013-06-02 07:46:16 +10002106 monotime();
Darren Tucker5f96f3b2013-05-16 20:29:28 +10002107 return (seconds <= 0 ? 1 : seconds);
Damien Millera5539d22003-04-09 20:50:06 +10002108}
Damien Miller9786e6e2005-07-26 21:54:56 +10002109
2110void
markus@openbsd.org091c3022015-01-19 19:52:16 +00002111ssh_packet_set_server(struct ssh *ssh)
Damien Miller9786e6e2005-07-26 21:54:56 +10002112{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002113 ssh->state->server_side = 1;
Damien Miller9786e6e2005-07-26 21:54:56 +10002114}
2115
2116void
markus@openbsd.org091c3022015-01-19 19:52:16 +00002117ssh_packet_set_authenticated(struct ssh *ssh)
Damien Miller9786e6e2005-07-26 21:54:56 +10002118{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002119 ssh->state->after_authentication = 1;
Darren Tuckerf7288d72009-06-21 18:12:20 +10002120}
2121
2122void *
markus@openbsd.org091c3022015-01-19 19:52:16 +00002123ssh_packet_get_input(struct ssh *ssh)
Darren Tuckerf7288d72009-06-21 18:12:20 +10002124{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002125 return (void *)ssh->state->input;
Darren Tuckerf7288d72009-06-21 18:12:20 +10002126}
2127
2128void *
markus@openbsd.org091c3022015-01-19 19:52:16 +00002129ssh_packet_get_output(struct ssh *ssh)
Darren Tuckerf7288d72009-06-21 18:12:20 +10002130{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002131 return (void *)ssh->state->output;
Darren Tuckerf7288d72009-06-21 18:12:20 +10002132}
2133
Damien Millerc31a0cd2014-05-15 14:37:39 +10002134/* Reset after_authentication and reset compression in post-auth privsep */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002135static int
2136ssh_packet_set_postauth(struct ssh *ssh)
Damien Millerc31a0cd2014-05-15 14:37:39 +10002137{
djm@openbsd.org0082fba2016-09-28 16:33:06 +00002138 int r;
Damien Millerc31a0cd2014-05-15 14:37:39 +10002139
2140 debug("%s: called", __func__);
2141 /* This was set in net child, but is not visible in user child */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002142 ssh->state->after_authentication = 1;
2143 ssh->state->rekeying = 0;
djm@openbsd.org0082fba2016-09-28 16:33:06 +00002144 if ((r = ssh_packet_enable_delayed_compress(ssh)) != 0)
2145 return r;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002146 return 0;
2147}
2148
2149/* Packet state (de-)serialization for privsep */
2150
2151/* turn kex into a blob for packet state serialization */
2152static int
2153kex_to_blob(struct sshbuf *m, struct kex *kex)
2154{
2155 int r;
2156
2157 if ((r = sshbuf_put_string(m, kex->session_id,
2158 kex->session_id_len)) != 0 ||
2159 (r = sshbuf_put_u32(m, kex->we_need)) != 0 ||
djm@openbsd.org349ecd42017-12-18 23:13:42 +00002160 (r = sshbuf_put_cstring(m, kex->hostkey_alg)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +00002161 (r = sshbuf_put_u32(m, kex->hostkey_type)) != 0 ||
djm@openbsd.org349ecd42017-12-18 23:13:42 +00002162 (r = sshbuf_put_u32(m, kex->hostkey_nid)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +00002163 (r = sshbuf_put_u32(m, kex->kex_type)) != 0 ||
2164 (r = sshbuf_put_stringb(m, kex->my)) != 0 ||
2165 (r = sshbuf_put_stringb(m, kex->peer)) != 0 ||
2166 (r = sshbuf_put_u32(m, kex->flags)) != 0 ||
2167 (r = sshbuf_put_cstring(m, kex->client_version_string)) != 0 ||
2168 (r = sshbuf_put_cstring(m, kex->server_version_string)) != 0)
2169 return r;
2170 return 0;
2171}
2172
2173/* turn key exchange results into a blob for packet state serialization */
2174static int
2175newkeys_to_blob(struct sshbuf *m, struct ssh *ssh, int mode)
2176{
2177 struct sshbuf *b;
2178 struct sshcipher_ctx *cc;
2179 struct sshcomp *comp;
2180 struct sshenc *enc;
2181 struct sshmac *mac;
2182 struct newkeys *newkey;
2183 int r;
2184
2185 if ((newkey = ssh->state->newkeys[mode]) == NULL)
2186 return SSH_ERR_INTERNAL_ERROR;
2187 enc = &newkey->enc;
2188 mac = &newkey->mac;
2189 comp = &newkey->comp;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00002190 cc = (mode == MODE_OUT) ? ssh->state->send_context :
2191 ssh->state->receive_context;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002192 if ((r = cipher_get_keyiv(cc, enc->iv, enc->iv_len)) != 0)
2193 return r;
2194 if ((b = sshbuf_new()) == NULL)
2195 return SSH_ERR_ALLOC_FAIL;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002196 if ((r = sshbuf_put_cstring(b, enc->name)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +00002197 (r = sshbuf_put_u32(b, enc->enabled)) != 0 ||
2198 (r = sshbuf_put_u32(b, enc->block_size)) != 0 ||
2199 (r = sshbuf_put_string(b, enc->key, enc->key_len)) != 0 ||
2200 (r = sshbuf_put_string(b, enc->iv, enc->iv_len)) != 0)
2201 goto out;
2202 if (cipher_authlen(enc->cipher) == 0) {
2203 if ((r = sshbuf_put_cstring(b, mac->name)) != 0 ||
2204 (r = sshbuf_put_u32(b, mac->enabled)) != 0 ||
2205 (r = sshbuf_put_string(b, mac->key, mac->key_len)) != 0)
2206 goto out;
2207 }
2208 if ((r = sshbuf_put_u32(b, comp->type)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +00002209 (r = sshbuf_put_cstring(b, comp->name)) != 0)
2210 goto out;
2211 r = sshbuf_put_stringb(m, b);
2212 out:
mmcc@openbsd.org52d70782015-12-11 04:21:11 +00002213 sshbuf_free(b);
markus@openbsd.org091c3022015-01-19 19:52:16 +00002214 return r;
2215}
2216
2217/* serialize packet state into a blob */
2218int
2219ssh_packet_get_state(struct ssh *ssh, struct sshbuf *m)
2220{
2221 struct session_state *state = ssh->state;
djm@openbsd.org97f4d302017-04-30 23:13:25 +00002222 int r;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002223
djm@openbsd.org97f4d302017-04-30 23:13:25 +00002224 if ((r = kex_to_blob(m, ssh->kex)) != 0 ||
2225 (r = newkeys_to_blob(m, ssh, MODE_OUT)) != 0 ||
2226 (r = newkeys_to_blob(m, ssh, MODE_IN)) != 0 ||
2227 (r = sshbuf_put_u64(m, state->rekey_limit)) != 0 ||
2228 (r = sshbuf_put_u32(m, state->rekey_interval)) != 0 ||
2229 (r = sshbuf_put_u32(m, state->p_send.seqnr)) != 0 ||
2230 (r = sshbuf_put_u64(m, state->p_send.blocks)) != 0 ||
2231 (r = sshbuf_put_u32(m, state->p_send.packets)) != 0 ||
2232 (r = sshbuf_put_u64(m, state->p_send.bytes)) != 0 ||
2233 (r = sshbuf_put_u32(m, state->p_read.seqnr)) != 0 ||
2234 (r = sshbuf_put_u64(m, state->p_read.blocks)) != 0 ||
2235 (r = sshbuf_put_u32(m, state->p_read.packets)) != 0 ||
djm@openbsd.org7461a5b2017-05-08 00:21:36 +00002236 (r = sshbuf_put_u64(m, state->p_read.bytes)) != 0 ||
2237 (r = sshbuf_put_stringb(m, state->input)) != 0 ||
2238 (r = sshbuf_put_stringb(m, state->output)) != 0)
djm@openbsd.org2e58a692017-05-08 06:03:39 +00002239 return r;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002240
markus@openbsd.org091c3022015-01-19 19:52:16 +00002241 return 0;
2242}
2243
2244/* restore key exchange results from blob for packet state de-serialization */
2245static int
2246newkeys_from_blob(struct sshbuf *m, struct ssh *ssh, int mode)
2247{
2248 struct sshbuf *b = NULL;
2249 struct sshcomp *comp;
2250 struct sshenc *enc;
2251 struct sshmac *mac;
2252 struct newkeys *newkey = NULL;
2253 size_t keylen, ivlen, maclen;
2254 int r;
2255
2256 if ((newkey = calloc(1, sizeof(*newkey))) == NULL) {
2257 r = SSH_ERR_ALLOC_FAIL;
2258 goto out;
2259 }
2260 if ((r = sshbuf_froms(m, &b)) != 0)
2261 goto out;
2262#ifdef DEBUG_PK
2263 sshbuf_dump(b, stderr);
2264#endif
2265 enc = &newkey->enc;
2266 mac = &newkey->mac;
2267 comp = &newkey->comp;
2268
2269 if ((r = sshbuf_get_cstring(b, &enc->name, NULL)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +00002270 (r = sshbuf_get_u32(b, (u_int *)&enc->enabled)) != 0 ||
2271 (r = sshbuf_get_u32(b, &enc->block_size)) != 0 ||
2272 (r = sshbuf_get_string(b, &enc->key, &keylen)) != 0 ||
2273 (r = sshbuf_get_string(b, &enc->iv, &ivlen)) != 0)
2274 goto out;
djm@openbsd.org33f86262017-06-24 06:38:11 +00002275 if ((enc->cipher = cipher_by_name(enc->name)) == NULL) {
2276 r = SSH_ERR_INVALID_FORMAT;
2277 goto out;
2278 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00002279 if (cipher_authlen(enc->cipher) == 0) {
2280 if ((r = sshbuf_get_cstring(b, &mac->name, NULL)) != 0)
2281 goto out;
2282 if ((r = mac_setup(mac, mac->name)) != 0)
2283 goto out;
2284 if ((r = sshbuf_get_u32(b, (u_int *)&mac->enabled)) != 0 ||
2285 (r = sshbuf_get_string(b, &mac->key, &maclen)) != 0)
2286 goto out;
2287 if (maclen > mac->key_len) {
2288 r = SSH_ERR_INVALID_FORMAT;
2289 goto out;
2290 }
2291 mac->key_len = maclen;
2292 }
2293 if ((r = sshbuf_get_u32(b, &comp->type)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +00002294 (r = sshbuf_get_cstring(b, &comp->name, NULL)) != 0)
2295 goto out;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002296 if (sshbuf_len(b) != 0) {
2297 r = SSH_ERR_INVALID_FORMAT;
2298 goto out;
2299 }
2300 enc->key_len = keylen;
2301 enc->iv_len = ivlen;
2302 ssh->kex->newkeys[mode] = newkey;
2303 newkey = NULL;
2304 r = 0;
2305 out:
mmcc@openbsd.orgd59ce082015-12-10 17:08:40 +00002306 free(newkey);
mmcc@openbsd.org52d70782015-12-11 04:21:11 +00002307 sshbuf_free(b);
markus@openbsd.org091c3022015-01-19 19:52:16 +00002308 return r;
2309}
2310
2311/* restore kex from blob for packet state de-serialization */
2312static int
2313kex_from_blob(struct sshbuf *m, struct kex **kexp)
2314{
2315 struct kex *kex;
2316 int r;
2317
2318 if ((kex = calloc(1, sizeof(struct kex))) == NULL ||
2319 (kex->my = sshbuf_new()) == NULL ||
2320 (kex->peer = sshbuf_new()) == NULL) {
2321 r = SSH_ERR_ALLOC_FAIL;
2322 goto out;
2323 }
2324 if ((r = sshbuf_get_string(m, &kex->session_id, &kex->session_id_len)) != 0 ||
2325 (r = sshbuf_get_u32(m, &kex->we_need)) != 0 ||
djm@openbsd.org349ecd42017-12-18 23:13:42 +00002326 (r = sshbuf_get_cstring(m, &kex->hostkey_alg, NULL)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +00002327 (r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_type)) != 0 ||
djm@openbsd.org349ecd42017-12-18 23:13:42 +00002328 (r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_nid)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +00002329 (r = sshbuf_get_u32(m, &kex->kex_type)) != 0 ||
2330 (r = sshbuf_get_stringb(m, kex->my)) != 0 ||
2331 (r = sshbuf_get_stringb(m, kex->peer)) != 0 ||
2332 (r = sshbuf_get_u32(m, &kex->flags)) != 0 ||
2333 (r = sshbuf_get_cstring(m, &kex->client_version_string, NULL)) != 0 ||
2334 (r = sshbuf_get_cstring(m, &kex->server_version_string, NULL)) != 0)
2335 goto out;
2336 kex->server = 1;
2337 kex->done = 1;
2338 r = 0;
2339 out:
2340 if (r != 0 || kexp == NULL) {
2341 if (kex != NULL) {
mmcc@openbsd.org52d70782015-12-11 04:21:11 +00002342 sshbuf_free(kex->my);
2343 sshbuf_free(kex->peer);
markus@openbsd.org091c3022015-01-19 19:52:16 +00002344 free(kex);
2345 }
2346 if (kexp != NULL)
2347 *kexp = NULL;
2348 } else {
2349 *kexp = kex;
2350 }
2351 return r;
2352}
2353
2354/*
2355 * Restore packet state from content of blob 'm' (de-serialization).
2356 * Note that 'm' will be partially consumed on parsing or any other errors.
2357 */
2358int
2359ssh_packet_set_state(struct ssh *ssh, struct sshbuf *m)
2360{
2361 struct session_state *state = ssh->state;
djm@openbsd.orgacaf34f2017-05-07 23:12:57 +00002362 const u_char *input, *output;
2363 size_t ilen, olen;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002364 int r;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002365
djm@openbsd.org97f4d302017-04-30 23:13:25 +00002366 if ((r = kex_from_blob(m, &ssh->kex)) != 0 ||
2367 (r = newkeys_from_blob(m, ssh, MODE_OUT)) != 0 ||
2368 (r = newkeys_from_blob(m, ssh, MODE_IN)) != 0 ||
2369 (r = sshbuf_get_u64(m, &state->rekey_limit)) != 0 ||
2370 (r = sshbuf_get_u32(m, &state->rekey_interval)) != 0 ||
2371 (r = sshbuf_get_u32(m, &state->p_send.seqnr)) != 0 ||
2372 (r = sshbuf_get_u64(m, &state->p_send.blocks)) != 0 ||
2373 (r = sshbuf_get_u32(m, &state->p_send.packets)) != 0 ||
2374 (r = sshbuf_get_u64(m, &state->p_send.bytes)) != 0 ||
2375 (r = sshbuf_get_u32(m, &state->p_read.seqnr)) != 0 ||
2376 (r = sshbuf_get_u64(m, &state->p_read.blocks)) != 0 ||
2377 (r = sshbuf_get_u32(m, &state->p_read.packets)) != 0 ||
2378 (r = sshbuf_get_u64(m, &state->p_read.bytes)) != 0)
2379 return r;
2380 /*
2381 * We set the time here so that in post-auth privsep slave we
2382 * count from the completion of the authentication.
2383 */
2384 state->rekey_time = monotime();
2385 /* XXX ssh_set_newkeys overrides p_read.packets? XXX */
2386 if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0 ||
2387 (r = ssh_set_newkeys(ssh, MODE_OUT)) != 0)
2388 return r;
2389
djm@openbsd.org0082fba2016-09-28 16:33:06 +00002390 if ((r = ssh_packet_set_postauth(ssh)) != 0)
markus@openbsd.org091c3022015-01-19 19:52:16 +00002391 return r;
2392
2393 sshbuf_reset(state->input);
2394 sshbuf_reset(state->output);
2395 if ((r = sshbuf_get_string_direct(m, &input, &ilen)) != 0 ||
2396 (r = sshbuf_get_string_direct(m, &output, &olen)) != 0 ||
2397 (r = sshbuf_put(state->input, input, ilen)) != 0 ||
2398 (r = sshbuf_put(state->output, output, olen)) != 0)
2399 return r;
2400
markus@openbsd.org091c3022015-01-19 19:52:16 +00002401 if (sshbuf_len(m))
2402 return SSH_ERR_INVALID_FORMAT;
2403 debug3("%s: done", __func__);
2404 return 0;
2405}
2406
2407/* NEW API */
2408
2409/* put data to the outgoing packet */
2410
2411int
2412sshpkt_put(struct ssh *ssh, const void *v, size_t len)
2413{
2414 return sshbuf_put(ssh->state->outgoing_packet, v, len);
2415}
2416
2417int
2418sshpkt_putb(struct ssh *ssh, const struct sshbuf *b)
2419{
2420 return sshbuf_putb(ssh->state->outgoing_packet, b);
2421}
2422
2423int
2424sshpkt_put_u8(struct ssh *ssh, u_char val)
2425{
2426 return sshbuf_put_u8(ssh->state->outgoing_packet, val);
2427}
2428
2429int
2430sshpkt_put_u32(struct ssh *ssh, u_int32_t val)
2431{
2432 return sshbuf_put_u32(ssh->state->outgoing_packet, val);
2433}
2434
2435int
2436sshpkt_put_u64(struct ssh *ssh, u_int64_t val)
2437{
2438 return sshbuf_put_u64(ssh->state->outgoing_packet, val);
2439}
2440
2441int
2442sshpkt_put_string(struct ssh *ssh, const void *v, size_t len)
2443{
2444 return sshbuf_put_string(ssh->state->outgoing_packet, v, len);
2445}
2446
2447int
2448sshpkt_put_cstring(struct ssh *ssh, const void *v)
2449{
2450 return sshbuf_put_cstring(ssh->state->outgoing_packet, v);
2451}
2452
2453int
2454sshpkt_put_stringb(struct ssh *ssh, const struct sshbuf *v)
2455{
2456 return sshbuf_put_stringb(ssh->state->outgoing_packet, v);
2457}
2458
djm@openbsd.org734226b2015-04-27 01:52:30 +00002459#ifdef WITH_OPENSSL
2460#ifdef OPENSSL_HAS_ECC
markus@openbsd.org091c3022015-01-19 19:52:16 +00002461int
2462sshpkt_put_ec(struct ssh *ssh, const EC_POINT *v, const EC_GROUP *g)
2463{
2464 return sshbuf_put_ec(ssh->state->outgoing_packet, v, g);
2465}
djm@openbsd.org734226b2015-04-27 01:52:30 +00002466#endif /* OPENSSL_HAS_ECC */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002467
markus@openbsd.org091c3022015-01-19 19:52:16 +00002468
2469int
2470sshpkt_put_bignum2(struct ssh *ssh, const BIGNUM *v)
2471{
2472 return sshbuf_put_bignum2(ssh->state->outgoing_packet, v);
2473}
Damien Miller773dda22015-01-30 23:10:17 +11002474#endif /* WITH_OPENSSL */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002475
2476/* fetch data from the incoming packet */
2477
2478int
2479sshpkt_get(struct ssh *ssh, void *valp, size_t len)
2480{
2481 return sshbuf_get(ssh->state->incoming_packet, valp, len);
2482}
2483
2484int
2485sshpkt_get_u8(struct ssh *ssh, u_char *valp)
2486{
2487 return sshbuf_get_u8(ssh->state->incoming_packet, valp);
2488}
2489
2490int
2491sshpkt_get_u32(struct ssh *ssh, u_int32_t *valp)
2492{
2493 return sshbuf_get_u32(ssh->state->incoming_packet, valp);
2494}
2495
2496int
2497sshpkt_get_u64(struct ssh *ssh, u_int64_t *valp)
2498{
2499 return sshbuf_get_u64(ssh->state->incoming_packet, valp);
2500}
2501
2502int
2503sshpkt_get_string(struct ssh *ssh, u_char **valp, size_t *lenp)
2504{
2505 return sshbuf_get_string(ssh->state->incoming_packet, valp, lenp);
2506}
2507
2508int
2509sshpkt_get_string_direct(struct ssh *ssh, const u_char **valp, size_t *lenp)
2510{
2511 return sshbuf_get_string_direct(ssh->state->incoming_packet, valp, lenp);
2512}
2513
2514int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002515sshpkt_peek_string_direct(struct ssh *ssh, const u_char **valp, size_t *lenp)
2516{
2517 return sshbuf_peek_string_direct(ssh->state->incoming_packet, valp, lenp);
2518}
2519
2520int
markus@openbsd.org091c3022015-01-19 19:52:16 +00002521sshpkt_get_cstring(struct ssh *ssh, char **valp, size_t *lenp)
2522{
2523 return sshbuf_get_cstring(ssh->state->incoming_packet, valp, lenp);
2524}
2525
djm@openbsd.org734226b2015-04-27 01:52:30 +00002526#ifdef WITH_OPENSSL
2527#ifdef OPENSSL_HAS_ECC
markus@openbsd.org091c3022015-01-19 19:52:16 +00002528int
2529sshpkt_get_ec(struct ssh *ssh, EC_POINT *v, const EC_GROUP *g)
2530{
2531 return sshbuf_get_ec(ssh->state->incoming_packet, v, g);
2532}
djm@openbsd.org734226b2015-04-27 01:52:30 +00002533#endif /* OPENSSL_HAS_ECC */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002534
markus@openbsd.org091c3022015-01-19 19:52:16 +00002535
2536int
2537sshpkt_get_bignum2(struct ssh *ssh, BIGNUM *v)
2538{
2539 return sshbuf_get_bignum2(ssh->state->incoming_packet, v);
2540}
Damien Miller773dda22015-01-30 23:10:17 +11002541#endif /* WITH_OPENSSL */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002542
2543int
2544sshpkt_get_end(struct ssh *ssh)
2545{
2546 if (sshbuf_len(ssh->state->incoming_packet) > 0)
2547 return SSH_ERR_UNEXPECTED_TRAILING_DATA;
2548 return 0;
2549}
2550
2551const u_char *
2552sshpkt_ptr(struct ssh *ssh, size_t *lenp)
2553{
2554 if (lenp != NULL)
2555 *lenp = sshbuf_len(ssh->state->incoming_packet);
2556 return sshbuf_ptr(ssh->state->incoming_packet);
2557}
2558
2559/* start a new packet */
2560
2561int
2562sshpkt_start(struct ssh *ssh, u_char type)
2563{
djm@openbsd.org97f4d302017-04-30 23:13:25 +00002564 u_char buf[6]; /* u32 packet length, u8 pad len, u8 type */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002565
2566 DBG(debug("packet_start[%d]", type));
djm@openbsd.org97f4d302017-04-30 23:13:25 +00002567 memset(buf, 0, sizeof(buf));
2568 buf[sizeof(buf) - 1] = type;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002569 sshbuf_reset(ssh->state->outgoing_packet);
djm@openbsd.org97f4d302017-04-30 23:13:25 +00002570 return sshbuf_put(ssh->state->outgoing_packet, buf, sizeof(buf));
markus@openbsd.org091c3022015-01-19 19:52:16 +00002571}
2572
markus@openbsd.org8d057842016-09-30 09:19:13 +00002573static int
2574ssh_packet_send_mux(struct ssh *ssh)
2575{
2576 struct session_state *state = ssh->state;
2577 u_char type, *cp;
2578 size_t len;
2579 int r;
2580
2581 if (ssh->kex)
2582 return SSH_ERR_INTERNAL_ERROR;
2583 len = sshbuf_len(state->outgoing_packet);
2584 if (len < 6)
2585 return SSH_ERR_INTERNAL_ERROR;
2586 cp = sshbuf_mutable_ptr(state->outgoing_packet);
2587 type = cp[5];
2588 if (ssh_packet_log_type(type))
2589 debug3("%s: type %u", __func__, type);
2590 /* drop everything, but the connection protocol */
2591 if (type >= SSH2_MSG_CONNECTION_MIN &&
2592 type <= SSH2_MSG_CONNECTION_MAX) {
2593 POKE_U32(cp, len - 4);
2594 if ((r = sshbuf_putb(state->output,
2595 state->outgoing_packet)) != 0)
2596 return r;
2597 /* sshbuf_dump(state->output, stderr); */
2598 }
2599 sshbuf_reset(state->outgoing_packet);
2600 return 0;
2601}
2602
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002603/*
2604 * 9.2. Ignored Data Message
2605 *
2606 * byte SSH_MSG_IGNORE
2607 * string data
2608 *
2609 * All implementations MUST understand (and ignore) this message at any
2610 * time (after receiving the protocol version). No implementation is
2611 * required to send them. This message can be used as an additional
2612 * protection measure against advanced traffic analysis techniques.
2613 */
2614int
2615sshpkt_msg_ignore(struct ssh *ssh, u_int nbytes)
2616{
2617 u_int32_t rnd = 0;
2618 int r;
2619 u_int i;
2620
2621 if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 ||
2622 (r = sshpkt_put_u32(ssh, nbytes)) != 0)
2623 return r;
2624 for (i = 0; i < nbytes; i++) {
2625 if (i % 4 == 0)
2626 rnd = arc4random();
2627 if ((r = sshpkt_put_u8(ssh, (u_char)rnd & 0xff)) != 0)
2628 return r;
2629 rnd >>= 8;
2630 }
2631 return 0;
2632}
2633
markus@openbsd.org091c3022015-01-19 19:52:16 +00002634/* send it */
2635
2636int
2637sshpkt_send(struct ssh *ssh)
2638{
markus@openbsd.org8d057842016-09-30 09:19:13 +00002639 if (ssh->state && ssh->state->mux)
2640 return ssh_packet_send_mux(ssh);
djm@openbsd.org97f4d302017-04-30 23:13:25 +00002641 return ssh_packet_send2(ssh);
markus@openbsd.org091c3022015-01-19 19:52:16 +00002642}
2643
2644int
2645sshpkt_disconnect(struct ssh *ssh, const char *fmt,...)
2646{
2647 char buf[1024];
2648 va_list args;
2649 int r;
2650
2651 va_start(args, fmt);
2652 vsnprintf(buf, sizeof(buf), fmt, args);
2653 va_end(args);
2654
djm@openbsd.org97f4d302017-04-30 23:13:25 +00002655 if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 ||
2656 (r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 ||
2657 (r = sshpkt_put_cstring(ssh, buf)) != 0 ||
2658 (r = sshpkt_put_cstring(ssh, "")) != 0 ||
2659 (r = sshpkt_send(ssh)) != 0)
2660 return r;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002661 return 0;
2662}
2663
2664/* roundup current message to pad bytes */
2665int
2666sshpkt_add_padding(struct ssh *ssh, u_char pad)
2667{
2668 ssh->state->extra_pad = pad;
2669 return 0;
Damien Millerc31a0cd2014-05-15 14:37:39 +10002670}