blob: cacb6eebef119be99f7b227dbfc35806961d5b34 [file] [log] [blame]
markus@openbsd.orgcecee2d2018-07-09 21:03:30 +00001/* $OpenBSD: packet.c,v 1.276 2018/07/09 21:03:30 markus 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) {
625 free(ssh->remote_ipaddr);
626 ssh->remote_ipaddr = NULL;
627 free(ssh->state);
628 ssh->state = NULL;
629 }
630}
631
632void
633ssh_packet_close(struct ssh *ssh)
634{
635 ssh_packet_close_internal(ssh, 1);
636}
637
638void
639ssh_packet_clear_keys(struct ssh *ssh)
640{
641 ssh_packet_close_internal(ssh, 0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000642}
643
644/* Sets remote side protocol flags. */
645
646void
markus@openbsd.org091c3022015-01-19 19:52:16 +0000647ssh_packet_set_protocol_flags(struct ssh *ssh, u_int protocol_flags)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000648{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000649 ssh->state->remote_protocol_flags = protocol_flags;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000650}
651
652/* Returns the remote protocol flags set earlier by the above function. */
653
Ben Lindstrom46c16222000-12-22 01:43:59 +0000654u_int
markus@openbsd.org091c3022015-01-19 19:52:16 +0000655ssh_packet_get_protocol_flags(struct ssh *ssh)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000656{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000657 return ssh->state->remote_protocol_flags;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000658}
659
Damien Miller5428f641999-11-25 11:54:57 +1100660/*
661 * Starts packet compression from the next packet on in both directions.
662 * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
663 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000664
markus@openbsd.org091c3022015-01-19 19:52:16 +0000665static int
666ssh_packet_init_compression(struct ssh *ssh)
Ben Lindstromfb50cdf2001-04-05 23:20:46 +0000667{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000668 if (!ssh->state->compression_buffer &&
669 ((ssh->state->compression_buffer = sshbuf_new()) == NULL))
670 return SSH_ERR_ALLOC_FAIL;
671 return 0;
672}
673
674static int
675start_compression_out(struct ssh *ssh, int level)
676{
677 if (level < 1 || level > 9)
678 return SSH_ERR_INVALID_ARGUMENT;
679 debug("Enabling compression at level %d.", level);
680 if (ssh->state->compression_out_started == 1)
681 deflateEnd(&ssh->state->compression_out_stream);
682 switch (deflateInit(&ssh->state->compression_out_stream, level)) {
683 case Z_OK:
684 ssh->state->compression_out_started = 1;
685 break;
686 case Z_MEM_ERROR:
687 return SSH_ERR_ALLOC_FAIL;
688 default:
689 return SSH_ERR_INTERNAL_ERROR;
690 }
691 return 0;
692}
693
694static int
695start_compression_in(struct ssh *ssh)
696{
697 if (ssh->state->compression_in_started == 1)
698 inflateEnd(&ssh->state->compression_in_stream);
699 switch (inflateInit(&ssh->state->compression_in_stream)) {
700 case Z_OK:
701 ssh->state->compression_in_started = 1;
702 break;
703 case Z_MEM_ERROR:
704 return SSH_ERR_ALLOC_FAIL;
705 default:
706 return SSH_ERR_INTERNAL_ERROR;
707 }
708 return 0;
709}
710
markus@openbsd.org091c3022015-01-19 19:52:16 +0000711/* XXX remove need for separate compression buffer */
712static int
713compress_buffer(struct ssh *ssh, struct sshbuf *in, struct sshbuf *out)
714{
715 u_char buf[4096];
716 int r, status;
717
718 if (ssh->state->compression_out_started != 1)
719 return SSH_ERR_INTERNAL_ERROR;
720
721 /* This case is not handled below. */
722 if (sshbuf_len(in) == 0)
723 return 0;
724
725 /* Input is the contents of the input buffer. */
726 if ((ssh->state->compression_out_stream.next_in =
727 sshbuf_mutable_ptr(in)) == NULL)
728 return SSH_ERR_INTERNAL_ERROR;
729 ssh->state->compression_out_stream.avail_in = sshbuf_len(in);
730
731 /* Loop compressing until deflate() returns with avail_out != 0. */
732 do {
733 /* Set up fixed-size output buffer. */
734 ssh->state->compression_out_stream.next_out = buf;
735 ssh->state->compression_out_stream.avail_out = sizeof(buf);
736
737 /* Compress as much data into the buffer as possible. */
738 status = deflate(&ssh->state->compression_out_stream,
739 Z_PARTIAL_FLUSH);
740 switch (status) {
741 case Z_MEM_ERROR:
742 return SSH_ERR_ALLOC_FAIL;
743 case Z_OK:
744 /* Append compressed data to output_buffer. */
745 if ((r = sshbuf_put(out, buf, sizeof(buf) -
746 ssh->state->compression_out_stream.avail_out)) != 0)
747 return r;
748 break;
749 case Z_STREAM_ERROR:
750 default:
751 ssh->state->compression_out_failures++;
752 return SSH_ERR_INVALID_FORMAT;
753 }
754 } while (ssh->state->compression_out_stream.avail_out == 0);
755 return 0;
756}
757
758static int
759uncompress_buffer(struct ssh *ssh, struct sshbuf *in, struct sshbuf *out)
760{
761 u_char buf[4096];
762 int r, status;
763
764 if (ssh->state->compression_in_started != 1)
765 return SSH_ERR_INTERNAL_ERROR;
766
767 if ((ssh->state->compression_in_stream.next_in =
768 sshbuf_mutable_ptr(in)) == NULL)
769 return SSH_ERR_INTERNAL_ERROR;
770 ssh->state->compression_in_stream.avail_in = sshbuf_len(in);
771
772 for (;;) {
773 /* Set up fixed-size output buffer. */
774 ssh->state->compression_in_stream.next_out = buf;
775 ssh->state->compression_in_stream.avail_out = sizeof(buf);
776
777 status = inflate(&ssh->state->compression_in_stream,
778 Z_PARTIAL_FLUSH);
779 switch (status) {
780 case Z_OK:
781 if ((r = sshbuf_put(out, buf, sizeof(buf) -
782 ssh->state->compression_in_stream.avail_out)) != 0)
783 return r;
784 break;
785 case Z_BUF_ERROR:
786 /*
787 * Comments in zlib.h say that we should keep calling
788 * inflate() until we get an error. This appears to
789 * be the error that we get.
790 */
791 return 0;
792 case Z_DATA_ERROR:
793 return SSH_ERR_INVALID_FORMAT;
794 case Z_MEM_ERROR:
795 return SSH_ERR_ALLOC_FAIL;
796 case Z_STREAM_ERROR:
797 default:
798 ssh->state->compression_in_failures++;
799 return SSH_ERR_INTERNAL_ERROR;
800 }
801 }
802 /* NOTREACHED */
803}
804
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +0000805void
806ssh_clear_newkeys(struct ssh *ssh, int mode)
807{
djm@openbsd.org2d75d742017-06-01 06:16:43 +0000808 if (ssh->kex && ssh->kex->newkeys[mode]) {
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +0000809 kex_free_newkeys(ssh->kex->newkeys[mode]);
810 ssh->kex->newkeys[mode] = NULL;
811 }
812}
813
markus@openbsd.org091c3022015-01-19 19:52:16 +0000814int
815ssh_set_newkeys(struct ssh *ssh, int mode)
Ben Lindstrom2d90e002001-04-04 02:00:54 +0000816{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000817 struct session_state *state = ssh->state;
818 struct sshenc *enc;
819 struct sshmac *mac;
820 struct sshcomp *comp;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +0000821 struct sshcipher_ctx **ccp;
markus@openbsd.org06ce56b2016-09-06 09:22:56 +0000822 struct packet_state *ps;
Damien Millera5539d22003-04-09 20:50:06 +1000823 u_int64_t *max_blocks;
djm@openbsd.org2d75d742017-06-01 06:16:43 +0000824 const char *wmsg;
Damien Miller86687062014-07-02 15:28:02 +1000825 int r, crypt_type;
Ben Lindstrom2d90e002001-04-04 02:00:54 +0000826
Ben Lindstrom064496f2002-12-23 02:04:22 +0000827 debug2("set_newkeys: mode %d", mode);
Ben Lindstrom2d90e002001-04-04 02:00:54 +0000828
Damien Miller963f6b22002-02-19 15:21:23 +1100829 if (mode == MODE_OUT) {
djm@openbsd.org4706c1d2016-08-03 05:41:57 +0000830 ccp = &state->send_context;
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000831 crypt_type = CIPHER_ENCRYPT;
markus@openbsd.org06ce56b2016-09-06 09:22:56 +0000832 ps = &state->p_send;
markus@openbsd.org091c3022015-01-19 19:52:16 +0000833 max_blocks = &state->max_blocks_out;
Damien Miller963f6b22002-02-19 15:21:23 +1100834 } else {
djm@openbsd.org4706c1d2016-08-03 05:41:57 +0000835 ccp = &state->receive_context;
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000836 crypt_type = CIPHER_DECRYPT;
markus@openbsd.org06ce56b2016-09-06 09:22:56 +0000837 ps = &state->p_read;
markus@openbsd.org091c3022015-01-19 19:52:16 +0000838 max_blocks = &state->max_blocks_in;
Damien Miller963f6b22002-02-19 15:21:23 +1100839 }
markus@openbsd.org091c3022015-01-19 19:52:16 +0000840 if (state->newkeys[mode] != NULL) {
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +0000841 debug("set_newkeys: rekeying, input %llu bytes %llu blocks, "
842 "output %llu bytes %llu blocks",
843 (unsigned long long)state->p_read.bytes,
844 (unsigned long long)state->p_read.blocks,
845 (unsigned long long)state->p_send.bytes,
846 (unsigned long long)state->p_send.blocks);
djm@openbsd.org4706c1d2016-08-03 05:41:57 +0000847 cipher_free(*ccp);
848 *ccp = NULL;
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +0000849 kex_free_newkeys(state->newkeys[mode]);
850 state->newkeys[mode] = NULL;
Ben Lindstrom2d90e002001-04-04 02:00:54 +0000851 }
markus@openbsd.org06ce56b2016-09-06 09:22:56 +0000852 /* note that both bytes and the seqnr are not reset */
853 ps->packets = ps->blocks = 0;
markus@openbsd.org091c3022015-01-19 19:52:16 +0000854 /* move newkeys from kex to state */
855 if ((state->newkeys[mode] = ssh->kex->newkeys[mode]) == NULL)
856 return SSH_ERR_INTERNAL_ERROR;
857 ssh->kex->newkeys[mode] = NULL;
858 enc = &state->newkeys[mode]->enc;
859 mac = &state->newkeys[mode]->mac;
860 comp = &state->newkeys[mode]->comp;
861 if (cipher_authlen(enc->cipher) == 0) {
862 if ((r = mac_init(mac)) != 0)
863 return r;
864 }
865 mac->enabled = 1;
Ben Lindstrom2d90e002001-04-04 02:00:54 +0000866 DBG(debug("cipher_init_context: %d", mode));
djm@openbsd.org4706c1d2016-08-03 05:41:57 +0000867 if ((r = cipher_init(ccp, enc->cipher, enc->key, enc->key_len,
Damien Miller86687062014-07-02 15:28:02 +1000868 enc->iv, enc->iv_len, crypt_type)) != 0)
markus@openbsd.org091c3022015-01-19 19:52:16 +0000869 return r;
870 if (!state->cipher_warning_done &&
djm@openbsd.org4706c1d2016-08-03 05:41:57 +0000871 (wmsg = cipher_warning_message(*ccp)) != NULL) {
markus@openbsd.org091c3022015-01-19 19:52:16 +0000872 error("Warning: %s", wmsg);
873 state->cipher_warning_done = 1;
874 }
Ben Lindstromf6027d32002-03-22 01:42:04 +0000875 /* Deleting the keys does not gain extra security */
Damien Millera5103f42014-02-04 11:20:14 +1100876 /* explicit_bzero(enc->iv, enc->block_size);
877 explicit_bzero(enc->key, enc->key_len);
878 explicit_bzero(mac->key, mac->key_len); */
sf@openbsd.org168b46f2018-07-09 13:37:10 +0000879 if ((comp->type == COMP_ZLIB ||
880 (comp->type == COMP_DELAYED &&
881 state->after_authentication)) && comp->enabled == 0) {
markus@openbsd.org091c3022015-01-19 19:52:16 +0000882 if ((r = ssh_packet_init_compression(ssh)) < 0)
883 return r;
884 if (mode == MODE_OUT) {
885 if ((r = start_compression_out(ssh, 6)) != 0)
886 return r;
887 } else {
888 if ((r = start_compression_in(ssh)) != 0)
889 return r;
890 }
Ben Lindstrom2d90e002001-04-04 02:00:54 +0000891 comp->enabled = 1;
Ben Lindstrom2d90e002001-04-04 02:00:54 +0000892 }
Darren Tucker81a0b372003-07-14 17:31:06 +1000893 /*
894 * The 2^(blocksize*2) limit is too expensive for 3DES,
djm@openbsd.orgacaf34f2017-05-07 23:12:57 +0000895 * so enforce a 1GB limit for small blocksizes.
dtucker@openbsd.orgad053162017-06-09 04:40:04 +0000896 * See RFC4344 section 3.2.
Darren Tucker81a0b372003-07-14 17:31:06 +1000897 */
898 if (enc->block_size >= 16)
899 *max_blocks = (u_int64_t)1 << (enc->block_size*2);
900 else
901 *max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
markus@openbsd.org091c3022015-01-19 19:52:16 +0000902 if (state->rekey_limit)
deraadt@openbsd.org9136ec12016-09-12 01:22:38 +0000903 *max_blocks = MINIMUM(*max_blocks,
markus@openbsd.org091c3022015-01-19 19:52:16 +0000904 state->rekey_limit / enc->block_size);
djm@openbsd.org696d1262016-02-04 23:43:48 +0000905 debug("rekey after %llu blocks", (unsigned long long)*max_blocks);
markus@openbsd.org091c3022015-01-19 19:52:16 +0000906 return 0;
Ben Lindstrom2d90e002001-04-04 02:00:54 +0000907}
908
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +0000909#define MAX_PACKETS (1U<<31)
910static int
911ssh_packet_need_rekeying(struct ssh *ssh, u_int outbound_packet_len)
912{
913 struct session_state *state = ssh->state;
914 u_int32_t out_blocks;
915
916 /* XXX client can't cope with rekeying pre-auth */
917 if (!state->after_authentication)
918 return 0;
919
920 /* Haven't keyed yet or KEX in progress. */
921 if (ssh->kex == NULL || ssh_packet_is_rekeying(ssh))
922 return 0;
923
924 /* Peer can't rekey */
925 if (ssh->compat & SSH_BUG_NOREKEY)
926 return 0;
927
928 /*
929 * Permit one packet in or out per rekey - this allows us to
930 * make progress when rekey limits are very small.
931 */
932 if (state->p_send.packets == 0 && state->p_read.packets == 0)
933 return 0;
934
935 /* Time-based rekeying */
936 if (state->rekey_interval != 0 &&
dtucker@openbsd.orgc998bf02017-02-03 02:56:00 +0000937 (int64_t)state->rekey_time + state->rekey_interval <= monotime())
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +0000938 return 1;
939
dtucker@openbsd.orgad053162017-06-09 04:40:04 +0000940 /*
941 * Always rekey when MAX_PACKETS sent in either direction
942 * As per RFC4344 section 3.1 we do this after 2^31 packets.
943 */
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +0000944 if (state->p_send.packets > MAX_PACKETS ||
945 state->p_read.packets > MAX_PACKETS)
946 return 1;
947
Damien Miller10479cc2018-04-10 10:19:02 +1000948 /* Rekey after (cipher-specific) maximum blocks */
deraadt@openbsd.org9136ec12016-09-12 01:22:38 +0000949 out_blocks = ROUNDUP(outbound_packet_len,
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +0000950 state->newkeys[MODE_OUT]->enc.block_size);
951 return (state->max_blocks_out &&
952 (state->p_send.blocks + out_blocks > state->max_blocks_out)) ||
953 (state->max_blocks_in &&
954 (state->p_read.blocks > state->max_blocks_in));
955}
956
Damien Miller5428f641999-11-25 11:54:57 +1100957/*
Damien Miller9786e6e2005-07-26 21:54:56 +1000958 * Delayed compression for SSH2 is enabled after authentication:
Darren Tuckerf676c572006-08-05 18:51:08 +1000959 * This happens on the server side after a SSH2_MSG_USERAUTH_SUCCESS is sent,
Damien Miller9786e6e2005-07-26 21:54:56 +1000960 * and on the client side after a SSH2_MSG_USERAUTH_SUCCESS is received.
961 */
markus@openbsd.org091c3022015-01-19 19:52:16 +0000962static int
963ssh_packet_enable_delayed_compress(struct ssh *ssh)
Damien Miller9786e6e2005-07-26 21:54:56 +1000964{
markus@openbsd.org091c3022015-01-19 19:52:16 +0000965 struct session_state *state = ssh->state;
966 struct sshcomp *comp = NULL;
967 int r, mode;
Damien Miller9786e6e2005-07-26 21:54:56 +1000968
969 /*
970 * Remember that we are past the authentication step, so rekeying
sf@openbsd.org168b46f2018-07-09 13:37:10 +0000971 * with COMP_DELAYED will turn on compression immediately.
Damien Miller9786e6e2005-07-26 21:54:56 +1000972 */
markus@openbsd.org091c3022015-01-19 19:52:16 +0000973 state->after_authentication = 1;
Damien Miller9786e6e2005-07-26 21:54:56 +1000974 for (mode = 0; mode < MODE_MAX; mode++) {
Darren Tucker4aa665b2006-09-21 13:00:25 +1000975 /* protocol error: USERAUTH_SUCCESS received before NEWKEYS */
markus@openbsd.org091c3022015-01-19 19:52:16 +0000976 if (state->newkeys[mode] == NULL)
Darren Tucker4aa665b2006-09-21 13:00:25 +1000977 continue;
markus@openbsd.org091c3022015-01-19 19:52:16 +0000978 comp = &state->newkeys[mode]->comp;
sf@openbsd.org168b46f2018-07-09 13:37:10 +0000979 if (comp && !comp->enabled && comp->type == COMP_DELAYED) {
markus@openbsd.org091c3022015-01-19 19:52:16 +0000980 if ((r = ssh_packet_init_compression(ssh)) != 0)
981 return r;
982 if (mode == MODE_OUT) {
983 if ((r = start_compression_out(ssh, 6)) != 0)
984 return r;
985 } else {
986 if ((r = start_compression_in(ssh)) != 0)
987 return r;
988 }
Damien Miller9786e6e2005-07-26 21:54:56 +1000989 comp->enabled = 1;
990 }
991 }
markus@openbsd.org091c3022015-01-19 19:52:16 +0000992 return 0;
Damien Miller9786e6e2005-07-26 21:54:56 +1000993}
994
djm@openbsd.org28136472016-01-29 05:46:01 +0000995/* Used to mute debug logging for noisy packet types */
markus@openbsd.org8d057842016-09-30 09:19:13 +0000996int
djm@openbsd.org28136472016-01-29 05:46:01 +0000997ssh_packet_log_type(u_char type)
998{
999 switch (type) {
1000 case SSH2_MSG_CHANNEL_DATA:
1001 case SSH2_MSG_CHANNEL_EXTENDED_DATA:
1002 case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
1003 return 0;
1004 default:
1005 return 1;
1006 }
1007}
1008
Damien Miller9786e6e2005-07-26 21:54:56 +10001009/*
Damien Miller33b13562000-04-04 14:38:59 +10001010 * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
1011 */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001012int
1013ssh_packet_send2_wrapped(struct ssh *ssh)
Damien Miller33b13562000-04-04 14:38:59 +10001014{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001015 struct session_state *state = ssh->state;
markus@openbsd.org128343b2015-01-13 19:31:40 +00001016 u_char type, *cp, macbuf[SSH_DIGEST_MAX_LENGTH];
djm@openbsd.orgeb999a42016-07-18 06:08:01 +00001017 u_char tmp, padlen, pad = 0;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001018 u_int authlen = 0, aadlen = 0;
1019 u_int len;
1020 struct sshenc *enc = NULL;
1021 struct sshmac *mac = NULL;
1022 struct sshcomp *comp = NULL;
1023 int r, block_size;
Damien Miller33b13562000-04-04 14:38:59 +10001024
markus@openbsd.org091c3022015-01-19 19:52:16 +00001025 if (state->newkeys[MODE_OUT] != NULL) {
1026 enc = &state->newkeys[MODE_OUT]->enc;
1027 mac = &state->newkeys[MODE_OUT]->mac;
1028 comp = &state->newkeys[MODE_OUT]->comp;
Damien Miller1d75abf2013-01-09 16:12:19 +11001029 /* disable mac for authenticated encryption */
1030 if ((authlen = cipher_authlen(enc->cipher)) != 0)
1031 mac = NULL;
Damien Miller33b13562000-04-04 14:38:59 +10001032 }
Damien Miller963f6b22002-02-19 15:21:23 +11001033 block_size = enc ? enc->block_size : 8;
Damien Miller1d75abf2013-01-09 16:12:19 +11001034 aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0;
Damien Miller33b13562000-04-04 14:38:59 +10001035
markus@openbsd.org091c3022015-01-19 19:52:16 +00001036 type = (sshbuf_ptr(state->outgoing_packet))[5];
djm@openbsd.org28136472016-01-29 05:46:01 +00001037 if (ssh_packet_log_type(type))
1038 debug3("send packet: type %u", type);
Damien Miller33b13562000-04-04 14:38:59 +10001039#ifdef PACKET_DEBUG
1040 fprintf(stderr, "plain: ");
markus@openbsd.org091c3022015-01-19 19:52:16 +00001041 sshbuf_dump(state->outgoing_packet, stderr);
Damien Miller33b13562000-04-04 14:38:59 +10001042#endif
1043
1044 if (comp && comp->enabled) {
markus@openbsd.org091c3022015-01-19 19:52:16 +00001045 len = sshbuf_len(state->outgoing_packet);
Damien Miller33b13562000-04-04 14:38:59 +10001046 /* skip header, compress only payload */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001047 if ((r = sshbuf_consume(state->outgoing_packet, 5)) != 0)
1048 goto out;
1049 sshbuf_reset(state->compression_buffer);
1050 if ((r = compress_buffer(ssh, state->outgoing_packet,
1051 state->compression_buffer)) != 0)
1052 goto out;
1053 sshbuf_reset(state->outgoing_packet);
1054 if ((r = sshbuf_put(state->outgoing_packet,
1055 "\0\0\0\0\0", 5)) != 0 ||
1056 (r = sshbuf_putb(state->outgoing_packet,
1057 state->compression_buffer)) != 0)
1058 goto out;
1059 DBG(debug("compression: raw %d compressed %zd", len,
1060 sshbuf_len(state->outgoing_packet)));
Damien Miller33b13562000-04-04 14:38:59 +10001061 }
1062
1063 /* sizeof (packet_len + pad_len + payload) */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001064 len = sshbuf_len(state->outgoing_packet);
Damien Miller33b13562000-04-04 14:38:59 +10001065
1066 /*
1067 * calc size of padding, alloc space, get random data,
1068 * minimum padding is 4 bytes
1069 */
Damien Milleraf43a7a2012-12-12 10:46:31 +11001070 len -= aadlen; /* packet length is not encrypted for EtM modes */
Damien Miller33b13562000-04-04 14:38:59 +10001071 padlen = block_size - (len % block_size);
1072 if (padlen < 4)
1073 padlen += block_size;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001074 if (state->extra_pad) {
djm@openbsd.orgeb999a42016-07-18 06:08:01 +00001075 tmp = state->extra_pad;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001076 state->extra_pad =
deraadt@openbsd.org9136ec12016-09-12 01:22:38 +00001077 ROUNDUP(state->extra_pad, block_size);
djm@openbsd.orgeb999a42016-07-18 06:08:01 +00001078 /* check if roundup overflowed */
1079 if (state->extra_pad < tmp)
1080 return SSH_ERR_INVALID_ARGUMENT;
1081 tmp = (len + padlen) % state->extra_pad;
1082 /* Check whether pad calculation below will underflow */
1083 if (tmp > state->extra_pad)
1084 return SSH_ERR_INVALID_ARGUMENT;
1085 pad = state->extra_pad - tmp;
Damien Miller2a328432014-04-20 13:24:01 +10001086 DBG(debug3("%s: adding %d (len %d padlen %d extra_pad %d)",
markus@openbsd.org091c3022015-01-19 19:52:16 +00001087 __func__, pad, len, padlen, state->extra_pad));
djm@openbsd.orgeb999a42016-07-18 06:08:01 +00001088 tmp = padlen;
Damien Miller9f643902001-11-12 11:02:52 +11001089 padlen += pad;
djm@openbsd.orgeb999a42016-07-18 06:08:01 +00001090 /* Check whether padlen calculation overflowed */
1091 if (padlen < tmp)
1092 return SSH_ERR_INVALID_ARGUMENT; /* overflow */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001093 state->extra_pad = 0;
Damien Miller9f643902001-11-12 11:02:52 +11001094 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001095 if ((r = sshbuf_reserve(state->outgoing_packet, padlen, &cp)) != 0)
1096 goto out;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00001097 if (enc && !cipher_ctx_is_plaintext(state->send_context)) {
Damien Millere247cc42000-05-07 12:03:14 +10001098 /* random padding */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001099 arc4random_buf(cp, padlen);
Damien Millere247cc42000-05-07 12:03:14 +10001100 } else {
1101 /* clear padding */
Damien Millera5103f42014-02-04 11:20:14 +11001102 explicit_bzero(cp, padlen);
Damien Miller33b13562000-04-04 14:38:59 +10001103 }
Damien Milleraf43a7a2012-12-12 10:46:31 +11001104 /* sizeof (packet_len + pad_len + payload + padding) */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001105 len = sshbuf_len(state->outgoing_packet);
1106 cp = sshbuf_mutable_ptr(state->outgoing_packet);
1107 if (cp == NULL) {
1108 r = SSH_ERR_INTERNAL_ERROR;
1109 goto out;
1110 }
Damien Milleraf43a7a2012-12-12 10:46:31 +11001111 /* packet_length includes payload, padding and padding length field */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001112 POKE_U32(cp, len - 4);
Ben Lindstrom4a7714a2002-02-26 18:04:38 +00001113 cp[4] = padlen;
Damien Milleraf43a7a2012-12-12 10:46:31 +11001114 DBG(debug("send: len %d (includes padlen %d, aadlen %d)",
1115 len, padlen, aadlen));
Damien Miller33b13562000-04-04 14:38:59 +10001116
1117 /* compute MAC over seqnr and packet(length fields, payload, padding) */
Damien Milleraf43a7a2012-12-12 10:46:31 +11001118 if (mac && mac->enabled && !mac->etm) {
markus@openbsd.org091c3022015-01-19 19:52:16 +00001119 if ((r = mac_compute(mac, state->p_send.seqnr,
1120 sshbuf_ptr(state->outgoing_packet), len,
markus@openbsd.org128343b2015-01-13 19:31:40 +00001121 macbuf, sizeof(macbuf))) != 0)
markus@openbsd.org091c3022015-01-19 19:52:16 +00001122 goto out;
1123 DBG(debug("done calc MAC out #%d", state->p_send.seqnr));
Damien Miller33b13562000-04-04 14:38:59 +10001124 }
1125 /* encrypt packet and append to output buffer. */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001126 if ((r = sshbuf_reserve(state->output,
1127 sshbuf_len(state->outgoing_packet) + authlen, &cp)) != 0)
1128 goto out;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00001129 if ((r = cipher_crypt(state->send_context, state->p_send.seqnr, cp,
markus@openbsd.org091c3022015-01-19 19:52:16 +00001130 sshbuf_ptr(state->outgoing_packet),
1131 len - aadlen, aadlen, authlen)) != 0)
1132 goto out;
Damien Miller33b13562000-04-04 14:38:59 +10001133 /* append unencrypted MAC */
Damien Milleraf43a7a2012-12-12 10:46:31 +11001134 if (mac && mac->enabled) {
1135 if (mac->etm) {
1136 /* EtM: compute mac over aadlen + cipher text */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001137 if ((r = mac_compute(mac, state->p_send.seqnr,
1138 cp, len, macbuf, sizeof(macbuf))) != 0)
1139 goto out;
Damien Milleraf43a7a2012-12-12 10:46:31 +11001140 DBG(debug("done calc MAC(EtM) out #%d",
markus@openbsd.org091c3022015-01-19 19:52:16 +00001141 state->p_send.seqnr));
Damien Milleraf43a7a2012-12-12 10:46:31 +11001142 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001143 if ((r = sshbuf_put(state->output, macbuf, mac->mac_len)) != 0)
1144 goto out;
Damien Milleraf43a7a2012-12-12 10:46:31 +11001145 }
Damien Miller33b13562000-04-04 14:38:59 +10001146#ifdef PACKET_DEBUG
1147 fprintf(stderr, "encrypted: ");
markus@openbsd.org091c3022015-01-19 19:52:16 +00001148 sshbuf_dump(state->output, stderr);
Damien Miller33b13562000-04-04 14:38:59 +10001149#endif
Damien Miller4af51302000-04-16 11:18:38 +10001150 /* increment sequence number for outgoing packets */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001151 if (++state->p_send.seqnr == 0)
Damien Miller996acd22003-04-09 20:59:48 +10001152 logit("outgoing seqnr wraps around");
markus@openbsd.org091c3022015-01-19 19:52:16 +00001153 if (++state->p_send.packets == 0)
1154 if (!(ssh->compat & SSH_BUG_NOREKEY))
1155 return SSH_ERR_NEED_REKEY;
1156 state->p_send.blocks += len / block_size;
1157 state->p_send.bytes += len;
1158 sshbuf_reset(state->outgoing_packet);
Damien Miller33b13562000-04-04 14:38:59 +10001159
Ben Lindstrom2d90e002001-04-04 02:00:54 +00001160 if (type == SSH2_MSG_NEWKEYS)
markus@openbsd.org091c3022015-01-19 19:52:16 +00001161 r = ssh_set_newkeys(ssh, MODE_OUT);
1162 else if (type == SSH2_MSG_USERAUTH_SUCCESS && state->server_side)
1163 r = ssh_packet_enable_delayed_compress(ssh);
1164 else
1165 r = 0;
1166 out:
1167 return r;
Damien Miller33b13562000-04-04 14:38:59 +10001168}
1169
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001170/* returns non-zero if the specified packet type is usec by KEX */
1171static int
1172ssh_packet_type_is_kex(u_char type)
1173{
1174 return
1175 type >= SSH2_MSG_TRANSPORT_MIN &&
1176 type <= SSH2_MSG_TRANSPORT_MAX &&
1177 type != SSH2_MSG_SERVICE_REQUEST &&
1178 type != SSH2_MSG_SERVICE_ACCEPT &&
1179 type != SSH2_MSG_EXT_INFO;
1180}
1181
markus@openbsd.org091c3022015-01-19 19:52:16 +00001182int
1183ssh_packet_send2(struct ssh *ssh)
Damien Millera5539d22003-04-09 20:50:06 +10001184{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001185 struct session_state *state = ssh->state;
Damien Millera5539d22003-04-09 20:50:06 +10001186 struct packet *p;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001187 u_char type;
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001188 int r, need_rekey;
Damien Millera5539d22003-04-09 20:50:06 +10001189
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001190 if (sshbuf_len(state->outgoing_packet) < 6)
1191 return SSH_ERR_INTERNAL_ERROR;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001192 type = sshbuf_ptr(state->outgoing_packet)[5];
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001193 need_rekey = !ssh_packet_type_is_kex(type) &&
1194 ssh_packet_need_rekeying(ssh, sshbuf_len(state->outgoing_packet));
Damien Millera5539d22003-04-09 20:50:06 +10001195
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001196 /*
1197 * During rekeying we can only send key exchange messages.
1198 * Queue everything else.
1199 */
1200 if ((need_rekey || state->rekeying) && !ssh_packet_type_is_kex(type)) {
1201 if (need_rekey)
1202 debug3("%s: rekex triggered", __func__);
1203 debug("enqueue packet: %u", type);
1204 p = calloc(1, sizeof(*p));
1205 if (p == NULL)
1206 return SSH_ERR_ALLOC_FAIL;
1207 p->type = type;
1208 p->payload = state->outgoing_packet;
1209 TAILQ_INSERT_TAIL(&state->outgoing, p, next);
1210 state->outgoing_packet = sshbuf_new();
1211 if (state->outgoing_packet == NULL)
1212 return SSH_ERR_ALLOC_FAIL;
1213 if (need_rekey) {
1214 /*
1215 * This packet triggered a rekey, so send the
1216 * KEXINIT now.
1217 * NB. reenters this function via kex_start_rekex().
1218 */
1219 return kex_start_rekex(ssh);
Damien Millera5539d22003-04-09 20:50:06 +10001220 }
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001221 return 0;
Damien Millera5539d22003-04-09 20:50:06 +10001222 }
1223
1224 /* rekeying starts with sending KEXINIT */
1225 if (type == SSH2_MSG_KEXINIT)
markus@openbsd.org091c3022015-01-19 19:52:16 +00001226 state->rekeying = 1;
Damien Millera5539d22003-04-09 20:50:06 +10001227
markus@openbsd.org091c3022015-01-19 19:52:16 +00001228 if ((r = ssh_packet_send2_wrapped(ssh)) != 0)
1229 return r;
Damien Millera5539d22003-04-09 20:50:06 +10001230
1231 /* after a NEWKEYS message we can send the complete queue */
1232 if (type == SSH2_MSG_NEWKEYS) {
markus@openbsd.org091c3022015-01-19 19:52:16 +00001233 state->rekeying = 0;
1234 state->rekey_time = monotime();
1235 while ((p = TAILQ_FIRST(&state->outgoing))) {
Damien Millera5539d22003-04-09 20:50:06 +10001236 type = p->type;
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001237 /*
1238 * If this packet triggers a rekex, then skip the
1239 * remaining packets in the queue for now.
1240 * NB. re-enters this function via kex_start_rekex.
1241 */
1242 if (ssh_packet_need_rekeying(ssh,
1243 sshbuf_len(p->payload))) {
1244 debug3("%s: queued packet triggered rekex",
1245 __func__);
1246 return kex_start_rekex(ssh);
1247 }
Damien Millera5539d22003-04-09 20:50:06 +10001248 debug("dequeue packet: %u", type);
markus@openbsd.org091c3022015-01-19 19:52:16 +00001249 sshbuf_free(state->outgoing_packet);
1250 state->outgoing_packet = p->payload;
1251 TAILQ_REMOVE(&state->outgoing, p, next);
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001252 memset(p, 0, sizeof(*p));
Darren Tuckera627d422013-06-02 07:31:17 +10001253 free(p);
markus@openbsd.org091c3022015-01-19 19:52:16 +00001254 if ((r = ssh_packet_send2_wrapped(ssh)) != 0)
1255 return r;
Damien Millera5539d22003-04-09 20:50:06 +10001256 }
1257 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001258 return 0;
Damien Miller33b13562000-04-04 14:38:59 +10001259}
1260
Damien Miller33b13562000-04-04 14:38:59 +10001261/*
Damien Miller5428f641999-11-25 11:54:57 +11001262 * Waits until a packet has been received, and returns its type. Note that
1263 * no other data is processed until this returns, so this function should not
1264 * be used during the interactive session.
1265 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001266
1267int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001268ssh_packet_read_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001269{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001270 struct session_state *state = ssh->state;
markus@openbsd.orga3068632016-01-14 16:17:39 +00001271 int len, r, ms_remain;
Ben Lindstromcb978aa2001-03-05 07:07:49 +00001272 fd_set *setp;
Damien Miller95def091999-11-25 00:26:21 +11001273 char buf[8192];
Darren Tucker3fc464e2008-06-13 06:42:45 +10001274 struct timeval timeout, start, *timeoutp = NULL;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001275
Darren Tucker99bb7612008-06-13 22:02:50 +10001276 DBG(debug("packet_read()"));
1277
deraadt@openbsd.orgce445b02015-08-20 22:32:42 +00001278 setp = calloc(howmany(state->connection_in + 1,
Darren Tuckerf7288d72009-06-21 18:12:20 +10001279 NFDBITS), sizeof(fd_mask));
markus@openbsd.org091c3022015-01-19 19:52:16 +00001280 if (setp == NULL)
1281 return SSH_ERR_ALLOC_FAIL;
Ben Lindstromcb978aa2001-03-05 07:07:49 +00001282
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001283 /*
1284 * Since we are blocking, ensure that all written packets have
1285 * been sent.
1286 */
markus@openbsd.org4daeb672015-03-24 20:10:08 +00001287 if ((r = ssh_packet_write_wait(ssh)) != 0)
1288 goto out;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001289
Damien Miller95def091999-11-25 00:26:21 +11001290 /* Stay in the loop until we have received a complete packet. */
1291 for (;;) {
1292 /* Try to read a packet from the buffer. */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001293 r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p);
1294 if (r != 0)
1295 break;
Damien Miller95def091999-11-25 00:26:21 +11001296 /* If we got a packet, return it. */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001297 if (*typep != SSH_MSG_NONE)
1298 break;
Damien Miller5428f641999-11-25 11:54:57 +11001299 /*
1300 * Otherwise, wait for some data to arrive, add it to the
1301 * buffer, and try again.
1302 */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001303 memset(setp, 0, howmany(state->connection_in + 1,
Darren Tuckerf7288d72009-06-21 18:12:20 +10001304 NFDBITS) * sizeof(fd_mask));
markus@openbsd.org091c3022015-01-19 19:52:16 +00001305 FD_SET(state->connection_in, setp);
Damien Miller5428f641999-11-25 11:54:57 +11001306
markus@openbsd.org091c3022015-01-19 19:52:16 +00001307 if (state->packet_timeout_ms > 0) {
1308 ms_remain = state->packet_timeout_ms;
Darren Tucker3fc464e2008-06-13 06:42:45 +10001309 timeoutp = &timeout;
1310 }
Damien Miller95def091999-11-25 00:26:21 +11001311 /* Wait for some data to arrive. */
Darren Tucker3fc464e2008-06-13 06:42:45 +10001312 for (;;) {
markus@openbsd.org091c3022015-01-19 19:52:16 +00001313 if (state->packet_timeout_ms != -1) {
Darren Tucker3fc464e2008-06-13 06:42:45 +10001314 ms_to_timeval(&timeout, ms_remain);
dtucker@openbsd.org@openbsd.org5db6fbf2017-11-25 06:46:22 +00001315 monotime_tv(&start);
Darren Tucker3fc464e2008-06-13 06:42:45 +10001316 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001317 if ((r = select(state->connection_in + 1, setp,
Darren Tuckerf7288d72009-06-21 18:12:20 +10001318 NULL, NULL, timeoutp)) >= 0)
Darren Tucker3fc464e2008-06-13 06:42:45 +10001319 break;
Damien Millerea437422009-10-02 11:49:03 +10001320 if (errno != EAGAIN && errno != EINTR &&
dtucker@openbsd.org1da59342018-05-25 03:20:59 +00001321 errno != EWOULDBLOCK) {
1322 r = SSH_ERR_SYSTEM_ERROR;
1323 goto out;
1324 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001325 if (state->packet_timeout_ms == -1)
Darren Tucker3fc464e2008-06-13 06:42:45 +10001326 continue;
1327 ms_subtract_diff(&start, &ms_remain);
1328 if (ms_remain <= 0) {
markus@openbsd.org091c3022015-01-19 19:52:16 +00001329 r = 0;
Darren Tucker3fc464e2008-06-13 06:42:45 +10001330 break;
1331 }
1332 }
djm@openbsd.orgd7abb772017-02-28 06:10:08 +00001333 if (r == 0) {
1334 r = SSH_ERR_CONN_TIMEOUT;
1335 goto out;
1336 }
Damien Miller95def091999-11-25 00:26:21 +11001337 /* Read data from the socket. */
markus@openbsd.orga3068632016-01-14 16:17:39 +00001338 len = read(state->connection_in, buf, sizeof(buf));
markus@openbsd.org4daeb672015-03-24 20:10:08 +00001339 if (len == 0) {
1340 r = SSH_ERR_CONN_CLOSED;
1341 goto out;
1342 }
1343 if (len < 0) {
1344 r = SSH_ERR_SYSTEM_ERROR;
1345 goto out;
1346 }
djm@openbsd.orgfae7bbe2015-01-28 21:15:47 +00001347
Damien Miller95def091999-11-25 00:26:21 +11001348 /* Append it to the buffer. */
djm@openbsd.orgfae7bbe2015-01-28 21:15:47 +00001349 if ((r = ssh_packet_process_incoming(ssh, buf, len)) != 0)
markus@openbsd.org4daeb672015-03-24 20:10:08 +00001350 goto out;
Damien Miller95def091999-11-25 00:26:21 +11001351 }
markus@openbsd.org4daeb672015-03-24 20:10:08 +00001352 out:
markus@openbsd.org091c3022015-01-19 19:52:16 +00001353 free(setp);
1354 return r;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001355}
1356
Damien Miller278f9072001-12-21 15:00:19 +11001357int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001358ssh_packet_read(struct ssh *ssh)
Damien Miller278f9072001-12-21 15:00:19 +11001359{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001360 u_char type;
1361 int r;
1362
1363 if ((r = ssh_packet_read_seqnr(ssh, &type, NULL)) != 0)
1364 fatal("%s: %s", __func__, ssh_err(r));
1365 return type;
Damien Miller278f9072001-12-21 15:00:19 +11001366}
1367
Damien Miller5428f641999-11-25 11:54:57 +11001368/*
1369 * Waits until a packet has been received, verifies that its type matches
1370 * that given, and gives a fatal error and exits if there is a mismatch.
1371 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001372
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001373int
1374ssh_packet_read_expect(struct ssh *ssh, u_int expected_type)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001375{
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001376 int r;
1377 u_char type;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001378
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001379 if ((r = ssh_packet_read_seqnr(ssh, &type, NULL)) != 0)
1380 return r;
1381 if (type != expected_type) {
1382 if ((r = sshpkt_disconnect(ssh,
markus@openbsd.org091c3022015-01-19 19:52:16 +00001383 "Protocol error: expected packet type %d, got %d",
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001384 expected_type, type)) != 0)
1385 return r;
1386 return SSH_ERR_PROTOCOL_ERROR;
1387 }
1388 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001389}
1390
markus@openbsd.org8d057842016-09-30 09:19:13 +00001391static int
1392ssh_packet_read_poll2_mux(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
1393{
1394 struct session_state *state = ssh->state;
1395 const u_char *cp;
1396 size_t need;
1397 int r;
1398
1399 if (ssh->kex)
1400 return SSH_ERR_INTERNAL_ERROR;
1401 *typep = SSH_MSG_NONE;
1402 cp = sshbuf_ptr(state->input);
1403 if (state->packlen == 0) {
1404 if (sshbuf_len(state->input) < 4 + 1)
1405 return 0; /* packet is incomplete */
1406 state->packlen = PEEK_U32(cp);
1407 if (state->packlen < 4 + 1 ||
1408 state->packlen > PACKET_MAX_SIZE)
1409 return SSH_ERR_MESSAGE_INCOMPLETE;
1410 }
1411 need = state->packlen + 4;
1412 if (sshbuf_len(state->input) < need)
1413 return 0; /* packet is incomplete */
1414 sshbuf_reset(state->incoming_packet);
1415 if ((r = sshbuf_put(state->incoming_packet, cp + 4,
1416 state->packlen)) != 0 ||
1417 (r = sshbuf_consume(state->input, need)) != 0 ||
1418 (r = sshbuf_get_u8(state->incoming_packet, NULL)) != 0 ||
1419 (r = sshbuf_get_u8(state->incoming_packet, typep)) != 0)
1420 return r;
1421 if (ssh_packet_log_type(*typep))
1422 debug3("%s: type %u", __func__, *typep);
1423 /* sshbuf_dump(state->incoming_packet, stderr); */
1424 /* reset for next packet */
1425 state->packlen = 0;
1426 return r;
1427}
1428
markus@openbsd.org091c3022015-01-19 19:52:16 +00001429int
1430ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
Damien Miller33b13562000-04-04 14:38:59 +10001431{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001432 struct session_state *state = ssh->state;
Ben Lindstrom46c16222000-12-22 01:43:59 +00001433 u_int padlen, need;
djm@openbsd.org6d311932016-07-08 03:44:42 +00001434 u_char *cp;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001435 u_int maclen, aadlen = 0, authlen = 0, block_size;
1436 struct sshenc *enc = NULL;
1437 struct sshmac *mac = NULL;
1438 struct sshcomp *comp = NULL;
markus@openbsd.org128343b2015-01-13 19:31:40 +00001439 int r;
Damien Miller33b13562000-04-04 14:38:59 +10001440
markus@openbsd.org8d057842016-09-30 09:19:13 +00001441 if (state->mux)
1442 return ssh_packet_read_poll2_mux(ssh, typep, seqnr_p);
1443
markus@openbsd.org091c3022015-01-19 19:52:16 +00001444 *typep = SSH_MSG_NONE;
Damien Miller13ae44c2009-01-28 16:38:41 +11001445
markus@openbsd.org091c3022015-01-19 19:52:16 +00001446 if (state->packet_discard)
1447 return 0;
1448
1449 if (state->newkeys[MODE_IN] != NULL) {
1450 enc = &state->newkeys[MODE_IN]->enc;
1451 mac = &state->newkeys[MODE_IN]->mac;
1452 comp = &state->newkeys[MODE_IN]->comp;
Damien Miller1d75abf2013-01-09 16:12:19 +11001453 /* disable mac for authenticated encryption */
1454 if ((authlen = cipher_authlen(enc->cipher)) != 0)
1455 mac = NULL;
Damien Miller33b13562000-04-04 14:38:59 +10001456 }
1457 maclen = mac && mac->enabled ? mac->mac_len : 0;
Damien Miller963f6b22002-02-19 15:21:23 +11001458 block_size = enc ? enc->block_size : 8;
Damien Miller1d75abf2013-01-09 16:12:19 +11001459 aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0;
Damien Miller33b13562000-04-04 14:38:59 +10001460
markus@openbsd.org091c3022015-01-19 19:52:16 +00001461 if (aadlen && state->packlen == 0) {
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00001462 if (cipher_get_length(state->receive_context,
markus@openbsd.org091c3022015-01-19 19:52:16 +00001463 &state->packlen, state->p_read.seqnr,
1464 sshbuf_ptr(state->input), sshbuf_len(state->input)) != 0)
1465 return 0;
1466 if (state->packlen < 1 + 4 ||
1467 state->packlen > PACKET_MAX_SIZE) {
Damien Milleraf43a7a2012-12-12 10:46:31 +11001468#ifdef PACKET_DEBUG
markus@openbsd.org091c3022015-01-19 19:52:16 +00001469 sshbuf_dump(state->input, stderr);
Damien Milleraf43a7a2012-12-12 10:46:31 +11001470#endif
markus@openbsd.org091c3022015-01-19 19:52:16 +00001471 logit("Bad packet length %u.", state->packlen);
1472 if ((r = sshpkt_disconnect(ssh, "Packet corrupt")) != 0)
1473 return r;
djm@openbsd.org2fecfd42015-11-08 21:59:11 +00001474 return SSH_ERR_CONN_CORRUPT;
Damien Milleraf43a7a2012-12-12 10:46:31 +11001475 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001476 sshbuf_reset(state->incoming_packet);
1477 } else if (state->packlen == 0) {
Damien Miller33b13562000-04-04 14:38:59 +10001478 /*
1479 * check if input size is less than the cipher block size,
1480 * decrypt first block and extract length of incoming packet
1481 */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001482 if (sshbuf_len(state->input) < block_size)
1483 return 0;
1484 sshbuf_reset(state->incoming_packet);
1485 if ((r = sshbuf_reserve(state->incoming_packet, block_size,
1486 &cp)) != 0)
1487 goto out;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00001488 if ((r = cipher_crypt(state->receive_context,
markus@openbsd.org091c3022015-01-19 19:52:16 +00001489 state->p_send.seqnr, cp, sshbuf_ptr(state->input),
1490 block_size, 0, 0)) != 0)
1491 goto out;
1492 state->packlen = PEEK_U32(sshbuf_ptr(state->incoming_packet));
1493 if (state->packlen < 1 + 4 ||
1494 state->packlen > PACKET_MAX_SIZE) {
Darren Tuckera8151da2003-09-22 21:06:46 +10001495#ifdef PACKET_DEBUG
markus@openbsd.org091c3022015-01-19 19:52:16 +00001496 fprintf(stderr, "input: \n");
1497 sshbuf_dump(state->input, stderr);
1498 fprintf(stderr, "incoming_packet: \n");
1499 sshbuf_dump(state->incoming_packet, stderr);
Darren Tuckera8151da2003-09-22 21:06:46 +10001500#endif
markus@openbsd.org091c3022015-01-19 19:52:16 +00001501 logit("Bad packet length %u.", state->packlen);
markus@openbsd.orgb98a2a82016-07-18 11:35:33 +00001502 return ssh_packet_start_discard(ssh, enc, mac, 0,
1503 PACKET_MAX_SIZE);
Damien Miller33b13562000-04-04 14:38:59 +10001504 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001505 if ((r = sshbuf_consume(state->input, block_size)) != 0)
1506 goto out;
Damien Miller33b13562000-04-04 14:38:59 +10001507 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001508 DBG(debug("input: packet len %u", state->packlen+4));
1509
Damien Milleraf43a7a2012-12-12 10:46:31 +11001510 if (aadlen) {
1511 /* only the payload is encrypted */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001512 need = state->packlen;
Damien Milleraf43a7a2012-12-12 10:46:31 +11001513 } else {
1514 /*
1515 * the payload size and the payload are encrypted, but we
1516 * have a partial packet of block_size bytes
1517 */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001518 need = 4 + state->packlen - block_size;
Damien Milleraf43a7a2012-12-12 10:46:31 +11001519 }
Damien Miller1d75abf2013-01-09 16:12:19 +11001520 DBG(debug("partial packet: block %d, need %d, maclen %d, authlen %d,"
1521 " aadlen %d", block_size, need, maclen, authlen, aadlen));
Darren Tucker99d11a32008-12-01 21:40:48 +11001522 if (need % block_size != 0) {
1523 logit("padding error: need %d block %d mod %d",
Damien Miller33b13562000-04-04 14:38:59 +10001524 need, block_size, need % block_size);
markus@openbsd.orgb98a2a82016-07-18 11:35:33 +00001525 return ssh_packet_start_discard(ssh, enc, mac, 0,
1526 PACKET_MAX_SIZE - block_size);
Darren Tucker99d11a32008-12-01 21:40:48 +11001527 }
Damien Miller33b13562000-04-04 14:38:59 +10001528 /*
1529 * check if the entire packet has been received and
Damien Milleraf43a7a2012-12-12 10:46:31 +11001530 * decrypt into incoming_packet:
1531 * 'aadlen' bytes are unencrypted, but authenticated.
Damien Miller1d75abf2013-01-09 16:12:19 +11001532 * 'need' bytes are encrypted, followed by either
1533 * 'authlen' bytes of authentication tag or
Damien Milleraf43a7a2012-12-12 10:46:31 +11001534 * 'maclen' bytes of message authentication code.
Damien Miller33b13562000-04-04 14:38:59 +10001535 */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001536 if (sshbuf_len(state->input) < aadlen + need + authlen + maclen)
djm@openbsd.org6d311932016-07-08 03:44:42 +00001537 return 0; /* packet is incomplete */
Damien Miller33b13562000-04-04 14:38:59 +10001538#ifdef PACKET_DEBUG
1539 fprintf(stderr, "read_poll enc/full: ");
markus@openbsd.org091c3022015-01-19 19:52:16 +00001540 sshbuf_dump(state->input, stderr);
Damien Miller33b13562000-04-04 14:38:59 +10001541#endif
djm@openbsd.org6d311932016-07-08 03:44:42 +00001542 /* EtM: check mac over encrypted input */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001543 if (mac && mac->enabled && mac->etm) {
djm@openbsd.org6d311932016-07-08 03:44:42 +00001544 if ((r = mac_check(mac, state->p_read.seqnr,
markus@openbsd.org091c3022015-01-19 19:52:16 +00001545 sshbuf_ptr(state->input), aadlen + need,
djm@openbsd.org6d311932016-07-08 03:44:42 +00001546 sshbuf_ptr(state->input) + aadlen + need + authlen,
1547 maclen)) != 0) {
1548 if (r == SSH_ERR_MAC_INVALID)
1549 logit("Corrupted MAC on input.");
markus@openbsd.org091c3022015-01-19 19:52:16 +00001550 goto out;
djm@openbsd.org6d311932016-07-08 03:44:42 +00001551 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001552 }
1553 if ((r = sshbuf_reserve(state->incoming_packet, aadlen + need,
1554 &cp)) != 0)
1555 goto out;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00001556 if ((r = cipher_crypt(state->receive_context, state->p_read.seqnr, cp,
markus@openbsd.org091c3022015-01-19 19:52:16 +00001557 sshbuf_ptr(state->input), need, aadlen, authlen)) != 0)
1558 goto out;
1559 if ((r = sshbuf_consume(state->input, aadlen + need + authlen)) != 0)
1560 goto out;
Damien Miller4af51302000-04-16 11:18:38 +10001561 if (mac && mac->enabled) {
djm@openbsd.org6d311932016-07-08 03:44:42 +00001562 /* Not EtM: check MAC over cleartext */
1563 if (!mac->etm && (r = mac_check(mac, state->p_read.seqnr,
1564 sshbuf_ptr(state->incoming_packet),
1565 sshbuf_len(state->incoming_packet),
1566 sshbuf_ptr(state->input), maclen)) != 0) {
1567 if (r != SSH_ERR_MAC_INVALID)
markus@openbsd.org091c3022015-01-19 19:52:16 +00001568 goto out;
Damien Miller13ae44c2009-01-28 16:38:41 +11001569 logit("Corrupted MAC on input.");
markus@openbsd.org0fb1a612017-03-11 13:07:35 +00001570 if (need + block_size > PACKET_MAX_SIZE)
markus@openbsd.org091c3022015-01-19 19:52:16 +00001571 return SSH_ERR_INTERNAL_ERROR;
1572 return ssh_packet_start_discard(ssh, enc, mac,
markus@openbsd.orgb98a2a82016-07-18 11:35:33 +00001573 sshbuf_len(state->incoming_packet),
markus@openbsd.org0fb1a612017-03-11 13:07:35 +00001574 PACKET_MAX_SIZE - need - block_size);
Damien Miller13ae44c2009-01-28 16:38:41 +11001575 }
djm@openbsd.org6d311932016-07-08 03:44:42 +00001576 /* Remove MAC from input buffer */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001577 DBG(debug("MAC #%d ok", state->p_read.seqnr));
1578 if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0)
1579 goto out;
Damien Miller33b13562000-04-04 14:38:59 +10001580 }
Damien Miller278f9072001-12-21 15:00:19 +11001581 if (seqnr_p != NULL)
markus@openbsd.org091c3022015-01-19 19:52:16 +00001582 *seqnr_p = state->p_read.seqnr;
1583 if (++state->p_read.seqnr == 0)
Damien Miller996acd22003-04-09 20:59:48 +10001584 logit("incoming seqnr wraps around");
markus@openbsd.org091c3022015-01-19 19:52:16 +00001585 if (++state->p_read.packets == 0)
1586 if (!(ssh->compat & SSH_BUG_NOREKEY))
1587 return SSH_ERR_NEED_REKEY;
1588 state->p_read.blocks += (state->packlen + 4) / block_size;
1589 state->p_read.bytes += state->packlen + 4;
Damien Miller33b13562000-04-04 14:38:59 +10001590
1591 /* get padlen */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001592 padlen = sshbuf_ptr(state->incoming_packet)[4];
Damien Miller33b13562000-04-04 14:38:59 +10001593 DBG(debug("input: padlen %d", padlen));
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001594 if (padlen < 4) {
1595 if ((r = sshpkt_disconnect(ssh,
1596 "Corrupted padlen %d on input.", padlen)) != 0 ||
1597 (r = ssh_packet_write_wait(ssh)) != 0)
1598 return r;
1599 return SSH_ERR_CONN_CORRUPT;
1600 }
Damien Miller33b13562000-04-04 14:38:59 +10001601
1602 /* skip packet size + padlen, discard padding */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001603 if ((r = sshbuf_consume(state->incoming_packet, 4 + 1)) != 0 ||
1604 ((r = sshbuf_consume_end(state->incoming_packet, padlen)) != 0))
1605 goto out;
Damien Miller33b13562000-04-04 14:38:59 +10001606
markus@openbsd.org091c3022015-01-19 19:52:16 +00001607 DBG(debug("input: len before de-compress %zd",
1608 sshbuf_len(state->incoming_packet)));
Damien Miller33b13562000-04-04 14:38:59 +10001609 if (comp && comp->enabled) {
markus@openbsd.org091c3022015-01-19 19:52:16 +00001610 sshbuf_reset(state->compression_buffer);
1611 if ((r = uncompress_buffer(ssh, state->incoming_packet,
1612 state->compression_buffer)) != 0)
1613 goto out;
1614 sshbuf_reset(state->incoming_packet);
1615 if ((r = sshbuf_putb(state->incoming_packet,
1616 state->compression_buffer)) != 0)
1617 goto out;
1618 DBG(debug("input: len after de-compress %zd",
1619 sshbuf_len(state->incoming_packet)));
Damien Miller33b13562000-04-04 14:38:59 +10001620 }
1621 /*
1622 * get packet type, implies consume.
1623 * return length of payload (without type field)
1624 */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001625 if ((r = sshbuf_get_u8(state->incoming_packet, typep)) != 0)
1626 goto out;
djm@openbsd.org28136472016-01-29 05:46:01 +00001627 if (ssh_packet_log_type(*typep))
1628 debug3("receive packet: type %u", *typep);
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001629 if (*typep < SSH2_MSG_MIN || *typep >= SSH2_MSG_LOCAL_MIN) {
1630 if ((r = sshpkt_disconnect(ssh,
1631 "Invalid ssh2 packet type: %d", *typep)) != 0 ||
1632 (r = ssh_packet_write_wait(ssh)) != 0)
1633 return r;
1634 return SSH_ERR_PROTOCOL_ERROR;
1635 }
djm@openbsd.org39af7b42016-10-11 21:47:45 +00001636 if (state->hook_in != NULL &&
1637 (r = state->hook_in(ssh, state->incoming_packet, typep,
1638 state->hook_in_ctx)) != 0)
1639 return r;
markus@openbsd.org28652bc2016-09-19 19:02:19 +00001640 if (*typep == SSH2_MSG_USERAUTH_SUCCESS && !state->server_side)
markus@openbsd.org091c3022015-01-19 19:52:16 +00001641 r = ssh_packet_enable_delayed_compress(ssh);
1642 else
1643 r = 0;
Damien Miller33b13562000-04-04 14:38:59 +10001644#ifdef PACKET_DEBUG
markus@openbsd.org091c3022015-01-19 19:52:16 +00001645 fprintf(stderr, "read/plain[%d]:\r\n", *typep);
1646 sshbuf_dump(state->incoming_packet, stderr);
Damien Miller33b13562000-04-04 14:38:59 +10001647#endif
Ben Lindstrom80c6d772001-06-05 21:09:18 +00001648 /* reset for next packet */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001649 state->packlen = 0;
djm@openbsd.org19bcf2e2016-02-08 10:57:07 +00001650
1651 /* do we need to rekey? */
1652 if (ssh_packet_need_rekeying(ssh, 0)) {
1653 debug3("%s: rekex triggered", __func__);
1654 if ((r = kex_start_rekex(ssh)) != 0)
1655 return r;
1656 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001657 out:
1658 return r;
Damien Miller33b13562000-04-04 14:38:59 +10001659}
1660
1661int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001662ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
Damien Miller33b13562000-04-04 14:38:59 +10001663{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001664 struct session_state *state = ssh->state;
Ben Lindstrom3f584742002-06-23 21:49:25 +00001665 u_int reason, seqnr;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001666 int r;
1667 u_char *msg;
Damien Miller33b13562000-04-04 14:38:59 +10001668
Ben Lindstrom80c6d772001-06-05 21:09:18 +00001669 for (;;) {
markus@openbsd.org091c3022015-01-19 19:52:16 +00001670 msg = NULL;
djm@openbsd.org97f4d302017-04-30 23:13:25 +00001671 r = ssh_packet_read_poll2(ssh, typep, seqnr_p);
1672 if (r != 0)
1673 return r;
1674 if (*typep) {
1675 state->keep_alive_timeouts = 0;
1676 DBG(debug("received packet type %d", *typep));
1677 }
1678 switch (*typep) {
1679 case SSH2_MSG_IGNORE:
1680 debug3("Received SSH2_MSG_IGNORE");
1681 break;
1682 case SSH2_MSG_DEBUG:
1683 if ((r = sshpkt_get_u8(ssh, NULL)) != 0 ||
1684 (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 ||
1685 (r = sshpkt_get_string(ssh, NULL, NULL)) != 0) {
1686 free(msg);
markus@openbsd.org091c3022015-01-19 19:52:16 +00001687 return r;
Darren Tucker136e56f2008-06-08 12:49:30 +10001688 }
djm@openbsd.org97f4d302017-04-30 23:13:25 +00001689 debug("Remote: %.900s", msg);
1690 free(msg);
1691 break;
1692 case SSH2_MSG_DISCONNECT:
1693 if ((r = sshpkt_get_u32(ssh, &reason)) != 0 ||
1694 (r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
1695 return r;
1696 /* Ignore normal client exit notifications */
1697 do_log2(ssh->state->server_side &&
1698 reason == SSH2_DISCONNECT_BY_APPLICATION ?
1699 SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR,
1700 "Received disconnect from %s port %d:"
1701 "%u: %.400s", ssh_remote_ipaddr(ssh),
1702 ssh_remote_port(ssh), reason, msg);
1703 free(msg);
1704 return SSH_ERR_DISCONNECTED;
1705 case SSH2_MSG_UNIMPLEMENTED:
1706 if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0)
1707 return r;
1708 debug("Received SSH2_MSG_UNIMPLEMENTED for %u",
1709 seqnr);
1710 break;
1711 default:
1712 return 0;
Damien Miller33b13562000-04-04 14:38:59 +10001713 }
1714 }
1715}
1716
Damien Miller5428f641999-11-25 11:54:57 +11001717/*
1718 * Buffers the given amount of input characters. This is intended to be used
1719 * together with packet_read_poll.
1720 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001721
djm@openbsd.orgfae7bbe2015-01-28 21:15:47 +00001722int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001723ssh_packet_process_incoming(struct ssh *ssh, const char *buf, u_int len)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001724{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001725 struct session_state *state = ssh->state;
1726 int r;
1727
1728 if (state->packet_discard) {
1729 state->keep_alive_timeouts = 0; /* ?? */
1730 if (len >= state->packet_discard) {
1731 if ((r = ssh_packet_stop_discard(ssh)) != 0)
djm@openbsd.orgfae7bbe2015-01-28 21:15:47 +00001732 return r;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001733 }
1734 state->packet_discard -= len;
djm@openbsd.orgfae7bbe2015-01-28 21:15:47 +00001735 return 0;
Damien Miller13ae44c2009-01-28 16:38:41 +11001736 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001737 if ((r = sshbuf_put(ssh->state->input, buf, len)) != 0)
djm@openbsd.orgfae7bbe2015-01-28 21:15:47 +00001738 return r;
1739
1740 return 0;
Damien Miller33b13562000-04-04 14:38:59 +10001741}
1742
Damien Miller4af51302000-04-16 11:18:38 +10001743int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001744ssh_packet_remaining(struct ssh *ssh)
Damien Miller4af51302000-04-16 11:18:38 +10001745{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001746 return sshbuf_len(ssh->state->incoming_packet);
Damien Millerda108ec2010-08-31 22:36:39 +10001747}
1748
Damien Miller5428f641999-11-25 11:54:57 +11001749/*
1750 * Sends a diagnostic message from the server to the client. This message
1751 * can be sent at any time (but not while constructing another message). The
1752 * message is printed immediately, but only if the client is being executed
1753 * in verbose mode. These messages are primarily intended to ease debugging
1754 * authentication problems. The length of the formatted message must not
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001755 * exceed 1024 bytes. This will automatically call ssh_packet_write_wait.
Damien Miller5428f641999-11-25 11:54:57 +11001756 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001757void
markus@openbsd.org091c3022015-01-19 19:52:16 +00001758ssh_packet_send_debug(struct ssh *ssh, const char *fmt,...)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001759{
Damien Miller95def091999-11-25 00:26:21 +11001760 char buf[1024];
1761 va_list args;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001762 int r;
Damien Miller95def091999-11-25 00:26:21 +11001763
djm@openbsd.org97f4d302017-04-30 23:13:25 +00001764 if ((ssh->compat & SSH_BUG_DEBUG))
Ben Lindstroma14ee472000-12-07 01:24:58 +00001765 return;
1766
Damien Miller95def091999-11-25 00:26:21 +11001767 va_start(args, fmt);
1768 vsnprintf(buf, sizeof(buf), fmt, args);
1769 va_end(args);
1770
djm@openbsd.orgeb80e262017-10-13 21:13:54 +00001771 debug3("sending debug message: %s", buf);
1772
djm@openbsd.org97f4d302017-04-30 23:13:25 +00001773 if ((r = sshpkt_start(ssh, SSH2_MSG_DEBUG)) != 0 ||
1774 (r = sshpkt_put_u8(ssh, 0)) != 0 || /* always display */
1775 (r = sshpkt_put_cstring(ssh, buf)) != 0 ||
1776 (r = sshpkt_put_cstring(ssh, "")) != 0 ||
1777 (r = sshpkt_send(ssh)) != 0 ||
1778 (r = ssh_packet_write_wait(ssh)) != 0)
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001779 fatal("%s: %s", __func__, ssh_err(r));
1780}
1781
dtucker@openbsd.org48c23a32017-12-10 05:55:29 +00001782void
1783sshpkt_fmt_connection_id(struct ssh *ssh, char *s, size_t l)
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001784{
1785 snprintf(s, l, "%.200s%s%s port %d",
1786 ssh->log_preamble ? ssh->log_preamble : "",
1787 ssh->log_preamble ? " " : "",
1788 ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
1789}
1790
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001791/*
1792 * Pretty-print connection-terminating errors and exit.
1793 */
1794void
1795sshpkt_fatal(struct ssh *ssh, const char *tag, int r)
1796{
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001797 char remote_id[512];
1798
dtucker@openbsd.org48c23a32017-12-10 05:55:29 +00001799 sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001800
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001801 switch (r) {
1802 case SSH_ERR_CONN_CLOSED:
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +00001803 ssh_packet_clear_keys(ssh);
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001804 logdie("Connection closed by %s", remote_id);
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001805 case SSH_ERR_CONN_TIMEOUT:
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +00001806 ssh_packet_clear_keys(ssh);
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001807 logdie("Connection %s %s timed out",
1808 ssh->state->server_side ? "from" : "to", remote_id);
djm@openbsd.org639d6bc2015-05-01 07:10:01 +00001809 case SSH_ERR_DISCONNECTED:
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +00001810 ssh_packet_clear_keys(ssh);
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001811 logdie("Disconnected from %s", remote_id);
djm@openbsd.org639d6bc2015-05-01 07:10:01 +00001812 case SSH_ERR_SYSTEM_ERROR:
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +00001813 if (errno == ECONNRESET) {
1814 ssh_packet_clear_keys(ssh);
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001815 logdie("Connection reset by %s", remote_id);
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +00001816 }
djm@openbsd.org639d6bc2015-05-01 07:10:01 +00001817 /* FALLTHROUGH */
djm@openbsd.orgf3199122015-07-29 04:43:06 +00001818 case SSH_ERR_NO_CIPHER_ALG_MATCH:
1819 case SSH_ERR_NO_MAC_ALG_MATCH:
1820 case SSH_ERR_NO_COMPRESS_ALG_MATCH:
1821 case SSH_ERR_NO_KEX_ALG_MATCH:
1822 case SSH_ERR_NO_HOSTKEY_ALG_MATCH:
1823 if (ssh && ssh->kex && ssh->kex->failed_choice) {
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +00001824 ssh_packet_clear_keys(ssh);
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001825 logdie("Unable to negotiate with %s: %s. "
1826 "Their offer: %s", remote_id, ssh_err(r),
djm@openbsd.orga4b9e0f2015-12-11 03:24:25 +00001827 ssh->kex->failed_choice);
djm@openbsd.orgf3199122015-07-29 04:43:06 +00001828 }
1829 /* FALLTHROUGH */
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001830 default:
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +00001831 ssh_packet_clear_keys(ssh);
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001832 logdie("%s%sConnection %s %s: %s",
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001833 tag != NULL ? tag : "", tag != NULL ? ": " : "",
djm@openbsd.orga4b9e0f2015-12-11 03:24:25 +00001834 ssh->state->server_side ? "from" : "to",
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001835 remote_id, ssh_err(r));
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001836 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001837}
1838
Damien Miller5428f641999-11-25 11:54:57 +11001839/*
1840 * Logs the error plus constructs and sends a disconnect packet, closes the
1841 * connection, and exits. This function never returns. The error message
1842 * should not contain a newline. The length of the formatted message must
1843 * not exceed 1024 bytes.
1844 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001845void
markus@openbsd.org091c3022015-01-19 19:52:16 +00001846ssh_packet_disconnect(struct ssh *ssh, const char *fmt,...)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001847{
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001848 char buf[1024], remote_id[512];
Damien Miller95def091999-11-25 00:26:21 +11001849 va_list args;
1850 static int disconnecting = 0;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001851 int r;
Ben Lindstrom8b2eecd2002-07-07 22:11:51 +00001852
Damien Miller95def091999-11-25 00:26:21 +11001853 if (disconnecting) /* Guard against recursive invocations. */
1854 fatal("packet_disconnect called recursively.");
1855 disconnecting = 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001856
Damien Miller5428f641999-11-25 11:54:57 +11001857 /*
1858 * Format the message. Note that the caller must make sure the
1859 * message is of limited size.
1860 */
dtucker@openbsd.org48c23a32017-12-10 05:55:29 +00001861 sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
Damien Miller95def091999-11-25 00:26:21 +11001862 va_start(args, fmt);
1863 vsnprintf(buf, sizeof(buf), fmt, args);
1864 va_end(args);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001865
Ben Lindstrom9bda7ae2002-11-09 15:46:24 +00001866 /* Display the error locally */
djm@openbsd.org07edd7e2017-02-03 23:03:33 +00001867 logit("Disconnecting %s: %.100s", remote_id, buf);
Ben Lindstrom9bda7ae2002-11-09 15:46:24 +00001868
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001869 /*
1870 * Send the disconnect message to the other side, and wait
1871 * for it to get sent.
1872 */
1873 if ((r = sshpkt_disconnect(ssh, "%s", buf)) != 0)
1874 sshpkt_fatal(ssh, __func__, r);
1875
1876 if ((r = ssh_packet_write_wait(ssh)) != 0)
1877 sshpkt_fatal(ssh, __func__, r);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001878
Damien Miller95def091999-11-25 00:26:21 +11001879 /* Close the connection. */
markus@openbsd.org091c3022015-01-19 19:52:16 +00001880 ssh_packet_close(ssh);
Darren Tucker3e33cec2003-10-02 16:12:36 +10001881 cleanup_exit(255);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001882}
1883
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001884/*
1885 * Checks if there is any buffered output, and tries to write some of
1886 * the output.
1887 */
1888int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001889ssh_packet_write_poll(struct ssh *ssh)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001890{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001891 struct session_state *state = ssh->state;
1892 int len = sshbuf_len(state->output);
markus@openbsd.orga3068632016-01-14 16:17:39 +00001893 int r;
Ben Lindstrom8b2eecd2002-07-07 22:11:51 +00001894
Damien Miller95def091999-11-25 00:26:21 +11001895 if (len > 0) {
markus@openbsd.orga3068632016-01-14 16:17:39 +00001896 len = write(state->connection_out,
1897 sshbuf_ptr(state->output), len);
Damien Millerd874fa52008-07-05 09:40:56 +10001898 if (len == -1) {
Damien Millerea437422009-10-02 11:49:03 +10001899 if (errno == EINTR || errno == EAGAIN ||
1900 errno == EWOULDBLOCK)
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001901 return 0;
1902 return SSH_ERR_SYSTEM_ERROR;
Damien Miller95def091999-11-25 00:26:21 +11001903 }
markus@openbsd.orga3068632016-01-14 16:17:39 +00001904 if (len == 0)
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001905 return SSH_ERR_CONN_CLOSED;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001906 if ((r = sshbuf_consume(state->output, len)) != 0)
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001907 return r;
Damien Miller95def091999-11-25 00:26:21 +11001908 }
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001909 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001910}
1911
Damien Miller5428f641999-11-25 11:54:57 +11001912/*
1913 * Calls packet_write_poll repeatedly until all pending output data has been
1914 * written.
1915 */
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001916int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001917ssh_packet_write_wait(struct ssh *ssh)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001918{
Ben Lindstromcb978aa2001-03-05 07:07:49 +00001919 fd_set *setp;
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001920 int ret, r, ms_remain = 0;
Darren Tucker3fc464e2008-06-13 06:42:45 +10001921 struct timeval start, timeout, *timeoutp = NULL;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001922 struct session_state *state = ssh->state;
Ben Lindstromcb978aa2001-03-05 07:07:49 +00001923
deraadt@openbsd.orgce445b02015-08-20 22:32:42 +00001924 setp = calloc(howmany(state->connection_out + 1,
Darren Tuckerf7288d72009-06-21 18:12:20 +10001925 NFDBITS), sizeof(fd_mask));
markus@openbsd.org091c3022015-01-19 19:52:16 +00001926 if (setp == NULL)
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001927 return SSH_ERR_ALLOC_FAIL;
gsoares@openbsd.org66d2e222015-10-21 11:33:03 +00001928 if ((r = ssh_packet_write_poll(ssh)) != 0) {
1929 free(setp);
djm@openbsd.org84082182015-09-21 04:31:00 +00001930 return r;
gsoares@openbsd.org66d2e222015-10-21 11:33:03 +00001931 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001932 while (ssh_packet_have_data_to_write(ssh)) {
1933 memset(setp, 0, howmany(state->connection_out + 1,
Darren Tuckerf7288d72009-06-21 18:12:20 +10001934 NFDBITS) * sizeof(fd_mask));
markus@openbsd.org091c3022015-01-19 19:52:16 +00001935 FD_SET(state->connection_out, setp);
Darren Tucker3fc464e2008-06-13 06:42:45 +10001936
markus@openbsd.org091c3022015-01-19 19:52:16 +00001937 if (state->packet_timeout_ms > 0) {
1938 ms_remain = state->packet_timeout_ms;
Darren Tucker3fc464e2008-06-13 06:42:45 +10001939 timeoutp = &timeout;
1940 }
1941 for (;;) {
markus@openbsd.org091c3022015-01-19 19:52:16 +00001942 if (state->packet_timeout_ms != -1) {
Darren Tucker3fc464e2008-06-13 06:42:45 +10001943 ms_to_timeval(&timeout, ms_remain);
dtucker@openbsd.org@openbsd.org5db6fbf2017-11-25 06:46:22 +00001944 monotime_tv(&start);
Darren Tucker3fc464e2008-06-13 06:42:45 +10001945 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00001946 if ((ret = select(state->connection_out + 1,
Darren Tuckerf7288d72009-06-21 18:12:20 +10001947 NULL, setp, NULL, timeoutp)) >= 0)
Darren Tucker3fc464e2008-06-13 06:42:45 +10001948 break;
Damien Millerea437422009-10-02 11:49:03 +10001949 if (errno != EAGAIN && errno != EINTR &&
1950 errno != EWOULDBLOCK)
Darren Tucker3fc464e2008-06-13 06:42:45 +10001951 break;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001952 if (state->packet_timeout_ms == -1)
Darren Tucker3fc464e2008-06-13 06:42:45 +10001953 continue;
1954 ms_subtract_diff(&start, &ms_remain);
1955 if (ms_remain <= 0) {
1956 ret = 0;
1957 break;
1958 }
1959 }
1960 if (ret == 0) {
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001961 free(setp);
1962 return SSH_ERR_CONN_TIMEOUT;
Darren Tucker3fc464e2008-06-13 06:42:45 +10001963 }
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001964 if ((r = ssh_packet_write_poll(ssh)) != 0) {
1965 free(setp);
1966 return r;
1967 }
Damien Miller95def091999-11-25 00:26:21 +11001968 }
Darren Tuckera627d422013-06-02 07:31:17 +10001969 free(setp);
djm@openbsd.org4509b5d2015-01-30 01:13:33 +00001970 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001971}
1972
1973/* Returns true if there is buffered data to write to the connection. */
1974
1975int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001976ssh_packet_have_data_to_write(struct ssh *ssh)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001977{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001978 return sshbuf_len(ssh->state->output) != 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001979}
1980
1981/* Returns true if there is not too much data to write to the connection. */
1982
1983int
markus@openbsd.org091c3022015-01-19 19:52:16 +00001984ssh_packet_not_very_much_data_to_write(struct ssh *ssh)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001985{
markus@openbsd.org091c3022015-01-19 19:52:16 +00001986 if (ssh->state->interactive_mode)
1987 return sshbuf_len(ssh->state->output) < 16384;
Damien Miller95def091999-11-25 00:26:21 +11001988 else
markus@openbsd.org091c3022015-01-19 19:52:16 +00001989 return sshbuf_len(ssh->state->output) < 128 * 1024;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001990}
1991
markus@openbsd.org091c3022015-01-19 19:52:16 +00001992void
1993ssh_packet_set_tos(struct ssh *ssh, int tos)
Ben Lindstroma7433982002-12-23 02:41:41 +00001994{
Damien Millerd2ac5d72011-05-15 08:43:13 +10001995#ifndef IP_TOS_IS_BROKEN
djm@openbsd.org51676ec2017-07-23 23:37:02 +00001996 if (!ssh_packet_connection_is_on_socket(ssh) || tos == INT_MAX)
Ben Lindstroma7433982002-12-23 02:41:41 +00001997 return;
markus@openbsd.org091c3022015-01-19 19:52:16 +00001998 switch (ssh_packet_connection_af(ssh)) {
Damien Millerd2ac5d72011-05-15 08:43:13 +10001999# ifdef IP_TOS
2000 case AF_INET:
2001 debug3("%s: set IP_TOS 0x%02x", __func__, tos);
markus@openbsd.org091c3022015-01-19 19:52:16 +00002002 if (setsockopt(ssh->state->connection_in,
Damien Millerd2ac5d72011-05-15 08:43:13 +10002003 IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0)
2004 error("setsockopt IP_TOS %d: %.100s:",
2005 tos, strerror(errno));
2006 break;
2007# endif /* IP_TOS */
2008# ifdef IPV6_TCLASS
2009 case AF_INET6:
2010 debug3("%s: set IPV6_TCLASS 0x%02x", __func__, tos);
markus@openbsd.org091c3022015-01-19 19:52:16 +00002011 if (setsockopt(ssh->state->connection_in,
Damien Millerd2ac5d72011-05-15 08:43:13 +10002012 IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)) < 0)
2013 error("setsockopt IPV6_TCLASS %d: %.100s:",
2014 tos, strerror(errno));
2015 break;
Damien Millerd2ac5d72011-05-15 08:43:13 +10002016# endif /* IPV6_TCLASS */
Damien Miller23f425b2011-05-15 08:58:15 +10002017 }
Damien Millerd2ac5d72011-05-15 08:43:13 +10002018#endif /* IP_TOS_IS_BROKEN */
Damien Miller5924ceb2003-11-22 15:02:42 +11002019}
Ben Lindstroma7433982002-12-23 02:41:41 +00002020
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002021/* Informs that the current session is interactive. Sets IP flags for that. */
2022
2023void
markus@openbsd.org091c3022015-01-19 19:52:16 +00002024ssh_packet_set_interactive(struct ssh *ssh, int interactive, int qos_interactive, int qos_bulk)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002025{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002026 struct session_state *state = ssh->state;
2027
2028 if (state->set_interactive_called)
Ben Lindstrombf555ba2001-01-18 02:04:35 +00002029 return;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002030 state->set_interactive_called = 1;
Ben Lindstrombf555ba2001-01-18 02:04:35 +00002031
Damien Miller95def091999-11-25 00:26:21 +11002032 /* Record that we are in interactive mode. */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002033 state->interactive_mode = interactive;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002034
Damien Miller34132e52000-01-14 15:45:46 +11002035 /* Only set socket options if using a socket. */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002036 if (!ssh_packet_connection_is_on_socket(ssh))
Ben Lindstrom93b6b772003-04-27 17:55:33 +00002037 return;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002038 set_nodelay(state->connection_in);
2039 ssh_packet_set_tos(ssh, interactive ? qos_interactive :
2040 qos_bulk);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002041}
2042
2043/* Returns true if the current connection is interactive. */
2044
2045int
markus@openbsd.org091c3022015-01-19 19:52:16 +00002046ssh_packet_is_interactive(struct ssh *ssh)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002047{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002048 return ssh->state->interactive_mode;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002049}
Damien Miller6162d121999-11-21 13:23:52 +11002050
Darren Tucker1f8311c2004-05-13 16:39:33 +10002051int
markus@openbsd.org091c3022015-01-19 19:52:16 +00002052ssh_packet_set_maxsize(struct ssh *ssh, u_int s)
Damien Miller6162d121999-11-21 13:23:52 +11002053{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002054 struct session_state *state = ssh->state;
2055
2056 if (state->set_maxsize_called) {
Damien Miller996acd22003-04-09 20:59:48 +10002057 logit("packet_set_maxsize: called twice: old %d new %d",
markus@openbsd.org091c3022015-01-19 19:52:16 +00002058 state->max_packet_size, s);
Damien Miller95def091999-11-25 00:26:21 +11002059 return -1;
2060 }
2061 if (s < 4 * 1024 || s > 1024 * 1024) {
Damien Miller996acd22003-04-09 20:59:48 +10002062 logit("packet_set_maxsize: bad size %d", s);
Damien Miller95def091999-11-25 00:26:21 +11002063 return -1;
2064 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00002065 state->set_maxsize_called = 1;
Ben Lindstrom16d45b32001-06-13 04:39:18 +00002066 debug("packet_set_maxsize: setting to %d", s);
markus@openbsd.org091c3022015-01-19 19:52:16 +00002067 state->max_packet_size = s;
Damien Miller95def091999-11-25 00:26:21 +11002068 return s;
Damien Miller6162d121999-11-21 13:23:52 +11002069}
Ben Lindstrom5699c5f2001-03-05 06:17:49 +00002070
Darren Tuckerf7288d72009-06-21 18:12:20 +10002071int
markus@openbsd.org091c3022015-01-19 19:52:16 +00002072ssh_packet_inc_alive_timeouts(struct ssh *ssh)
Darren Tuckerf7288d72009-06-21 18:12:20 +10002073{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002074 return ++ssh->state->keep_alive_timeouts;
Darren Tuckerf7288d72009-06-21 18:12:20 +10002075}
2076
2077void
markus@openbsd.org091c3022015-01-19 19:52:16 +00002078ssh_packet_set_alive_timeouts(struct ssh *ssh, int ka)
Darren Tuckerf7288d72009-06-21 18:12:20 +10002079{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002080 ssh->state->keep_alive_timeouts = ka;
Darren Tuckerf7288d72009-06-21 18:12:20 +10002081}
2082
2083u_int
markus@openbsd.org091c3022015-01-19 19:52:16 +00002084ssh_packet_get_maxsize(struct ssh *ssh)
Darren Tuckerf7288d72009-06-21 18:12:20 +10002085{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002086 return ssh->state->max_packet_size;
Damien Miller9f643902001-11-12 11:02:52 +11002087}
2088
Damien Millera5539d22003-04-09 20:50:06 +10002089void
dtucker@openbsd.orgc998bf02017-02-03 02:56:00 +00002090ssh_packet_set_rekey_limits(struct ssh *ssh, u_int64_t bytes, u_int32_t seconds)
Damien Millera5539d22003-04-09 20:50:06 +10002091{
dtucker@openbsd.orgc998bf02017-02-03 02:56:00 +00002092 debug3("rekey after %llu bytes, %u seconds", (unsigned long long)bytes,
2093 (unsigned int)seconds);
markus@openbsd.org091c3022015-01-19 19:52:16 +00002094 ssh->state->rekey_limit = bytes;
2095 ssh->state->rekey_interval = seconds;
Darren Tuckerc53c2af2013-05-16 20:28:16 +10002096}
2097
2098time_t
markus@openbsd.org091c3022015-01-19 19:52:16 +00002099ssh_packet_get_rekey_timeout(struct ssh *ssh)
Darren Tuckerc53c2af2013-05-16 20:28:16 +10002100{
2101 time_t seconds;
2102
markus@openbsd.org091c3022015-01-19 19:52:16 +00002103 seconds = ssh->state->rekey_time + ssh->state->rekey_interval -
Darren Tuckerb759c9c2013-06-02 07:46:16 +10002104 monotime();
Darren Tucker5f96f3b2013-05-16 20:29:28 +10002105 return (seconds <= 0 ? 1 : seconds);
Damien Millera5539d22003-04-09 20:50:06 +10002106}
Damien Miller9786e6e2005-07-26 21:54:56 +10002107
2108void
markus@openbsd.org091c3022015-01-19 19:52:16 +00002109ssh_packet_set_server(struct ssh *ssh)
Damien Miller9786e6e2005-07-26 21:54:56 +10002110{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002111 ssh->state->server_side = 1;
Damien Miller9786e6e2005-07-26 21:54:56 +10002112}
2113
2114void
markus@openbsd.org091c3022015-01-19 19:52:16 +00002115ssh_packet_set_authenticated(struct ssh *ssh)
Damien Miller9786e6e2005-07-26 21:54:56 +10002116{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002117 ssh->state->after_authentication = 1;
Darren Tuckerf7288d72009-06-21 18:12:20 +10002118}
2119
2120void *
markus@openbsd.org091c3022015-01-19 19:52:16 +00002121ssh_packet_get_input(struct ssh *ssh)
Darren Tuckerf7288d72009-06-21 18:12:20 +10002122{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002123 return (void *)ssh->state->input;
Darren Tuckerf7288d72009-06-21 18:12:20 +10002124}
2125
2126void *
markus@openbsd.org091c3022015-01-19 19:52:16 +00002127ssh_packet_get_output(struct ssh *ssh)
Darren Tuckerf7288d72009-06-21 18:12:20 +10002128{
markus@openbsd.org091c3022015-01-19 19:52:16 +00002129 return (void *)ssh->state->output;
Darren Tuckerf7288d72009-06-21 18:12:20 +10002130}
2131
Damien Millerc31a0cd2014-05-15 14:37:39 +10002132/* Reset after_authentication and reset compression in post-auth privsep */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002133static int
2134ssh_packet_set_postauth(struct ssh *ssh)
Damien Millerc31a0cd2014-05-15 14:37:39 +10002135{
djm@openbsd.org0082fba2016-09-28 16:33:06 +00002136 int r;
Damien Millerc31a0cd2014-05-15 14:37:39 +10002137
2138 debug("%s: called", __func__);
2139 /* This was set in net child, but is not visible in user child */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002140 ssh->state->after_authentication = 1;
2141 ssh->state->rekeying = 0;
djm@openbsd.org0082fba2016-09-28 16:33:06 +00002142 if ((r = ssh_packet_enable_delayed_compress(ssh)) != 0)
2143 return r;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002144 return 0;
2145}
2146
2147/* Packet state (de-)serialization for privsep */
2148
2149/* turn kex into a blob for packet state serialization */
2150static int
2151kex_to_blob(struct sshbuf *m, struct kex *kex)
2152{
2153 int r;
2154
2155 if ((r = sshbuf_put_string(m, kex->session_id,
2156 kex->session_id_len)) != 0 ||
2157 (r = sshbuf_put_u32(m, kex->we_need)) != 0 ||
djm@openbsd.org349ecd42017-12-18 23:13:42 +00002158 (r = sshbuf_put_cstring(m, kex->hostkey_alg)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +00002159 (r = sshbuf_put_u32(m, kex->hostkey_type)) != 0 ||
djm@openbsd.org349ecd42017-12-18 23:13:42 +00002160 (r = sshbuf_put_u32(m, kex->hostkey_nid)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +00002161 (r = sshbuf_put_u32(m, kex->kex_type)) != 0 ||
2162 (r = sshbuf_put_stringb(m, kex->my)) != 0 ||
2163 (r = sshbuf_put_stringb(m, kex->peer)) != 0 ||
2164 (r = sshbuf_put_u32(m, kex->flags)) != 0 ||
2165 (r = sshbuf_put_cstring(m, kex->client_version_string)) != 0 ||
2166 (r = sshbuf_put_cstring(m, kex->server_version_string)) != 0)
2167 return r;
2168 return 0;
2169}
2170
2171/* turn key exchange results into a blob for packet state serialization */
2172static int
2173newkeys_to_blob(struct sshbuf *m, struct ssh *ssh, int mode)
2174{
2175 struct sshbuf *b;
2176 struct sshcipher_ctx *cc;
2177 struct sshcomp *comp;
2178 struct sshenc *enc;
2179 struct sshmac *mac;
2180 struct newkeys *newkey;
2181 int r;
2182
2183 if ((newkey = ssh->state->newkeys[mode]) == NULL)
2184 return SSH_ERR_INTERNAL_ERROR;
2185 enc = &newkey->enc;
2186 mac = &newkey->mac;
2187 comp = &newkey->comp;
djm@openbsd.org4706c1d2016-08-03 05:41:57 +00002188 cc = (mode == MODE_OUT) ? ssh->state->send_context :
2189 ssh->state->receive_context;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002190 if ((r = cipher_get_keyiv(cc, enc->iv, enc->iv_len)) != 0)
2191 return r;
2192 if ((b = sshbuf_new()) == NULL)
2193 return SSH_ERR_ALLOC_FAIL;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002194 if ((r = sshbuf_put_cstring(b, enc->name)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +00002195 (r = sshbuf_put_u32(b, enc->enabled)) != 0 ||
2196 (r = sshbuf_put_u32(b, enc->block_size)) != 0 ||
2197 (r = sshbuf_put_string(b, enc->key, enc->key_len)) != 0 ||
2198 (r = sshbuf_put_string(b, enc->iv, enc->iv_len)) != 0)
2199 goto out;
2200 if (cipher_authlen(enc->cipher) == 0) {
2201 if ((r = sshbuf_put_cstring(b, mac->name)) != 0 ||
2202 (r = sshbuf_put_u32(b, mac->enabled)) != 0 ||
2203 (r = sshbuf_put_string(b, mac->key, mac->key_len)) != 0)
2204 goto out;
2205 }
2206 if ((r = sshbuf_put_u32(b, comp->type)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +00002207 (r = sshbuf_put_cstring(b, comp->name)) != 0)
2208 goto out;
2209 r = sshbuf_put_stringb(m, b);
2210 out:
mmcc@openbsd.org52d70782015-12-11 04:21:11 +00002211 sshbuf_free(b);
markus@openbsd.org091c3022015-01-19 19:52:16 +00002212 return r;
2213}
2214
2215/* serialize packet state into a blob */
2216int
2217ssh_packet_get_state(struct ssh *ssh, struct sshbuf *m)
2218{
2219 struct session_state *state = ssh->state;
djm@openbsd.org97f4d302017-04-30 23:13:25 +00002220 int r;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002221
djm@openbsd.org97f4d302017-04-30 23:13:25 +00002222 if ((r = kex_to_blob(m, ssh->kex)) != 0 ||
2223 (r = newkeys_to_blob(m, ssh, MODE_OUT)) != 0 ||
2224 (r = newkeys_to_blob(m, ssh, MODE_IN)) != 0 ||
2225 (r = sshbuf_put_u64(m, state->rekey_limit)) != 0 ||
2226 (r = sshbuf_put_u32(m, state->rekey_interval)) != 0 ||
2227 (r = sshbuf_put_u32(m, state->p_send.seqnr)) != 0 ||
2228 (r = sshbuf_put_u64(m, state->p_send.blocks)) != 0 ||
2229 (r = sshbuf_put_u32(m, state->p_send.packets)) != 0 ||
2230 (r = sshbuf_put_u64(m, state->p_send.bytes)) != 0 ||
2231 (r = sshbuf_put_u32(m, state->p_read.seqnr)) != 0 ||
2232 (r = sshbuf_put_u64(m, state->p_read.blocks)) != 0 ||
2233 (r = sshbuf_put_u32(m, state->p_read.packets)) != 0 ||
djm@openbsd.org7461a5b2017-05-08 00:21:36 +00002234 (r = sshbuf_put_u64(m, state->p_read.bytes)) != 0 ||
2235 (r = sshbuf_put_stringb(m, state->input)) != 0 ||
2236 (r = sshbuf_put_stringb(m, state->output)) != 0)
djm@openbsd.org2e58a692017-05-08 06:03:39 +00002237 return r;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002238
markus@openbsd.org091c3022015-01-19 19:52:16 +00002239 return 0;
2240}
2241
2242/* restore key exchange results from blob for packet state de-serialization */
2243static int
2244newkeys_from_blob(struct sshbuf *m, struct ssh *ssh, int mode)
2245{
2246 struct sshbuf *b = NULL;
2247 struct sshcomp *comp;
2248 struct sshenc *enc;
2249 struct sshmac *mac;
2250 struct newkeys *newkey = NULL;
2251 size_t keylen, ivlen, maclen;
2252 int r;
2253
2254 if ((newkey = calloc(1, sizeof(*newkey))) == NULL) {
2255 r = SSH_ERR_ALLOC_FAIL;
2256 goto out;
2257 }
2258 if ((r = sshbuf_froms(m, &b)) != 0)
2259 goto out;
2260#ifdef DEBUG_PK
2261 sshbuf_dump(b, stderr);
2262#endif
2263 enc = &newkey->enc;
2264 mac = &newkey->mac;
2265 comp = &newkey->comp;
2266
2267 if ((r = sshbuf_get_cstring(b, &enc->name, NULL)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +00002268 (r = sshbuf_get_u32(b, (u_int *)&enc->enabled)) != 0 ||
2269 (r = sshbuf_get_u32(b, &enc->block_size)) != 0 ||
2270 (r = sshbuf_get_string(b, &enc->key, &keylen)) != 0 ||
2271 (r = sshbuf_get_string(b, &enc->iv, &ivlen)) != 0)
2272 goto out;
djm@openbsd.org33f86262017-06-24 06:38:11 +00002273 if ((enc->cipher = cipher_by_name(enc->name)) == NULL) {
2274 r = SSH_ERR_INVALID_FORMAT;
2275 goto out;
2276 }
markus@openbsd.org091c3022015-01-19 19:52:16 +00002277 if (cipher_authlen(enc->cipher) == 0) {
2278 if ((r = sshbuf_get_cstring(b, &mac->name, NULL)) != 0)
2279 goto out;
2280 if ((r = mac_setup(mac, mac->name)) != 0)
2281 goto out;
2282 if ((r = sshbuf_get_u32(b, (u_int *)&mac->enabled)) != 0 ||
2283 (r = sshbuf_get_string(b, &mac->key, &maclen)) != 0)
2284 goto out;
2285 if (maclen > mac->key_len) {
2286 r = SSH_ERR_INVALID_FORMAT;
2287 goto out;
2288 }
2289 mac->key_len = maclen;
2290 }
2291 if ((r = sshbuf_get_u32(b, &comp->type)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +00002292 (r = sshbuf_get_cstring(b, &comp->name, NULL)) != 0)
2293 goto out;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002294 if (sshbuf_len(b) != 0) {
2295 r = SSH_ERR_INVALID_FORMAT;
2296 goto out;
2297 }
2298 enc->key_len = keylen;
2299 enc->iv_len = ivlen;
2300 ssh->kex->newkeys[mode] = newkey;
2301 newkey = NULL;
2302 r = 0;
2303 out:
mmcc@openbsd.orgd59ce082015-12-10 17:08:40 +00002304 free(newkey);
mmcc@openbsd.org52d70782015-12-11 04:21:11 +00002305 sshbuf_free(b);
markus@openbsd.org091c3022015-01-19 19:52:16 +00002306 return r;
2307}
2308
2309/* restore kex from blob for packet state de-serialization */
2310static int
2311kex_from_blob(struct sshbuf *m, struct kex **kexp)
2312{
2313 struct kex *kex;
2314 int r;
2315
2316 if ((kex = calloc(1, sizeof(struct kex))) == NULL ||
2317 (kex->my = sshbuf_new()) == NULL ||
2318 (kex->peer = sshbuf_new()) == NULL) {
2319 r = SSH_ERR_ALLOC_FAIL;
2320 goto out;
2321 }
2322 if ((r = sshbuf_get_string(m, &kex->session_id, &kex->session_id_len)) != 0 ||
2323 (r = sshbuf_get_u32(m, &kex->we_need)) != 0 ||
djm@openbsd.org349ecd42017-12-18 23:13:42 +00002324 (r = sshbuf_get_cstring(m, &kex->hostkey_alg, NULL)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +00002325 (r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_type)) != 0 ||
djm@openbsd.org349ecd42017-12-18 23:13:42 +00002326 (r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_nid)) != 0 ||
markus@openbsd.org091c3022015-01-19 19:52:16 +00002327 (r = sshbuf_get_u32(m, &kex->kex_type)) != 0 ||
2328 (r = sshbuf_get_stringb(m, kex->my)) != 0 ||
2329 (r = sshbuf_get_stringb(m, kex->peer)) != 0 ||
2330 (r = sshbuf_get_u32(m, &kex->flags)) != 0 ||
2331 (r = sshbuf_get_cstring(m, &kex->client_version_string, NULL)) != 0 ||
2332 (r = sshbuf_get_cstring(m, &kex->server_version_string, NULL)) != 0)
2333 goto out;
2334 kex->server = 1;
2335 kex->done = 1;
2336 r = 0;
2337 out:
2338 if (r != 0 || kexp == NULL) {
2339 if (kex != NULL) {
mmcc@openbsd.org52d70782015-12-11 04:21:11 +00002340 sshbuf_free(kex->my);
2341 sshbuf_free(kex->peer);
markus@openbsd.org091c3022015-01-19 19:52:16 +00002342 free(kex);
2343 }
2344 if (kexp != NULL)
2345 *kexp = NULL;
2346 } else {
2347 *kexp = kex;
2348 }
2349 return r;
2350}
2351
2352/*
2353 * Restore packet state from content of blob 'm' (de-serialization).
2354 * Note that 'm' will be partially consumed on parsing or any other errors.
2355 */
2356int
2357ssh_packet_set_state(struct ssh *ssh, struct sshbuf *m)
2358{
2359 struct session_state *state = ssh->state;
djm@openbsd.orgacaf34f2017-05-07 23:12:57 +00002360 const u_char *input, *output;
2361 size_t ilen, olen;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002362 int r;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002363
djm@openbsd.org97f4d302017-04-30 23:13:25 +00002364 if ((r = kex_from_blob(m, &ssh->kex)) != 0 ||
2365 (r = newkeys_from_blob(m, ssh, MODE_OUT)) != 0 ||
2366 (r = newkeys_from_blob(m, ssh, MODE_IN)) != 0 ||
2367 (r = sshbuf_get_u64(m, &state->rekey_limit)) != 0 ||
2368 (r = sshbuf_get_u32(m, &state->rekey_interval)) != 0 ||
2369 (r = sshbuf_get_u32(m, &state->p_send.seqnr)) != 0 ||
2370 (r = sshbuf_get_u64(m, &state->p_send.blocks)) != 0 ||
2371 (r = sshbuf_get_u32(m, &state->p_send.packets)) != 0 ||
2372 (r = sshbuf_get_u64(m, &state->p_send.bytes)) != 0 ||
2373 (r = sshbuf_get_u32(m, &state->p_read.seqnr)) != 0 ||
2374 (r = sshbuf_get_u64(m, &state->p_read.blocks)) != 0 ||
2375 (r = sshbuf_get_u32(m, &state->p_read.packets)) != 0 ||
2376 (r = sshbuf_get_u64(m, &state->p_read.bytes)) != 0)
2377 return r;
2378 /*
2379 * We set the time here so that in post-auth privsep slave we
2380 * count from the completion of the authentication.
2381 */
2382 state->rekey_time = monotime();
2383 /* XXX ssh_set_newkeys overrides p_read.packets? XXX */
2384 if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0 ||
2385 (r = ssh_set_newkeys(ssh, MODE_OUT)) != 0)
2386 return r;
2387
djm@openbsd.org0082fba2016-09-28 16:33:06 +00002388 if ((r = ssh_packet_set_postauth(ssh)) != 0)
markus@openbsd.org091c3022015-01-19 19:52:16 +00002389 return r;
2390
2391 sshbuf_reset(state->input);
2392 sshbuf_reset(state->output);
2393 if ((r = sshbuf_get_string_direct(m, &input, &ilen)) != 0 ||
2394 (r = sshbuf_get_string_direct(m, &output, &olen)) != 0 ||
2395 (r = sshbuf_put(state->input, input, ilen)) != 0 ||
2396 (r = sshbuf_put(state->output, output, olen)) != 0)
2397 return r;
2398
markus@openbsd.org091c3022015-01-19 19:52:16 +00002399 if (sshbuf_len(m))
2400 return SSH_ERR_INVALID_FORMAT;
2401 debug3("%s: done", __func__);
2402 return 0;
2403}
2404
2405/* NEW API */
2406
2407/* put data to the outgoing packet */
2408
2409int
2410sshpkt_put(struct ssh *ssh, const void *v, size_t len)
2411{
2412 return sshbuf_put(ssh->state->outgoing_packet, v, len);
2413}
2414
2415int
2416sshpkt_putb(struct ssh *ssh, const struct sshbuf *b)
2417{
2418 return sshbuf_putb(ssh->state->outgoing_packet, b);
2419}
2420
2421int
2422sshpkt_put_u8(struct ssh *ssh, u_char val)
2423{
2424 return sshbuf_put_u8(ssh->state->outgoing_packet, val);
2425}
2426
2427int
2428sshpkt_put_u32(struct ssh *ssh, u_int32_t val)
2429{
2430 return sshbuf_put_u32(ssh->state->outgoing_packet, val);
2431}
2432
2433int
2434sshpkt_put_u64(struct ssh *ssh, u_int64_t val)
2435{
2436 return sshbuf_put_u64(ssh->state->outgoing_packet, val);
2437}
2438
2439int
2440sshpkt_put_string(struct ssh *ssh, const void *v, size_t len)
2441{
2442 return sshbuf_put_string(ssh->state->outgoing_packet, v, len);
2443}
2444
2445int
2446sshpkt_put_cstring(struct ssh *ssh, const void *v)
2447{
2448 return sshbuf_put_cstring(ssh->state->outgoing_packet, v);
2449}
2450
2451int
2452sshpkt_put_stringb(struct ssh *ssh, const struct sshbuf *v)
2453{
2454 return sshbuf_put_stringb(ssh->state->outgoing_packet, v);
2455}
2456
djm@openbsd.org734226b2015-04-27 01:52:30 +00002457#ifdef WITH_OPENSSL
2458#ifdef OPENSSL_HAS_ECC
markus@openbsd.org091c3022015-01-19 19:52:16 +00002459int
2460sshpkt_put_ec(struct ssh *ssh, const EC_POINT *v, const EC_GROUP *g)
2461{
2462 return sshbuf_put_ec(ssh->state->outgoing_packet, v, g);
2463}
djm@openbsd.org734226b2015-04-27 01:52:30 +00002464#endif /* OPENSSL_HAS_ECC */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002465
markus@openbsd.org091c3022015-01-19 19:52:16 +00002466
2467int
2468sshpkt_put_bignum2(struct ssh *ssh, const BIGNUM *v)
2469{
2470 return sshbuf_put_bignum2(ssh->state->outgoing_packet, v);
2471}
Damien Miller773dda22015-01-30 23:10:17 +11002472#endif /* WITH_OPENSSL */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002473
2474/* fetch data from the incoming packet */
2475
2476int
2477sshpkt_get(struct ssh *ssh, void *valp, size_t len)
2478{
2479 return sshbuf_get(ssh->state->incoming_packet, valp, len);
2480}
2481
2482int
2483sshpkt_get_u8(struct ssh *ssh, u_char *valp)
2484{
2485 return sshbuf_get_u8(ssh->state->incoming_packet, valp);
2486}
2487
2488int
2489sshpkt_get_u32(struct ssh *ssh, u_int32_t *valp)
2490{
2491 return sshbuf_get_u32(ssh->state->incoming_packet, valp);
2492}
2493
2494int
2495sshpkt_get_u64(struct ssh *ssh, u_int64_t *valp)
2496{
2497 return sshbuf_get_u64(ssh->state->incoming_packet, valp);
2498}
2499
2500int
2501sshpkt_get_string(struct ssh *ssh, u_char **valp, size_t *lenp)
2502{
2503 return sshbuf_get_string(ssh->state->incoming_packet, valp, lenp);
2504}
2505
2506int
2507sshpkt_get_string_direct(struct ssh *ssh, const u_char **valp, size_t *lenp)
2508{
2509 return sshbuf_get_string_direct(ssh->state->incoming_packet, valp, lenp);
2510}
2511
2512int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002513sshpkt_peek_string_direct(struct ssh *ssh, const u_char **valp, size_t *lenp)
2514{
2515 return sshbuf_peek_string_direct(ssh->state->incoming_packet, valp, lenp);
2516}
2517
2518int
markus@openbsd.org091c3022015-01-19 19:52:16 +00002519sshpkt_get_cstring(struct ssh *ssh, char **valp, size_t *lenp)
2520{
2521 return sshbuf_get_cstring(ssh->state->incoming_packet, valp, lenp);
2522}
2523
djm@openbsd.org734226b2015-04-27 01:52:30 +00002524#ifdef WITH_OPENSSL
2525#ifdef OPENSSL_HAS_ECC
markus@openbsd.org091c3022015-01-19 19:52:16 +00002526int
2527sshpkt_get_ec(struct ssh *ssh, EC_POINT *v, const EC_GROUP *g)
2528{
2529 return sshbuf_get_ec(ssh->state->incoming_packet, v, g);
2530}
djm@openbsd.org734226b2015-04-27 01:52:30 +00002531#endif /* OPENSSL_HAS_ECC */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002532
markus@openbsd.org091c3022015-01-19 19:52:16 +00002533
2534int
2535sshpkt_get_bignum2(struct ssh *ssh, BIGNUM *v)
2536{
2537 return sshbuf_get_bignum2(ssh->state->incoming_packet, v);
2538}
Damien Miller773dda22015-01-30 23:10:17 +11002539#endif /* WITH_OPENSSL */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002540
2541int
2542sshpkt_get_end(struct ssh *ssh)
2543{
2544 if (sshbuf_len(ssh->state->incoming_packet) > 0)
2545 return SSH_ERR_UNEXPECTED_TRAILING_DATA;
2546 return 0;
2547}
2548
2549const u_char *
2550sshpkt_ptr(struct ssh *ssh, size_t *lenp)
2551{
2552 if (lenp != NULL)
2553 *lenp = sshbuf_len(ssh->state->incoming_packet);
2554 return sshbuf_ptr(ssh->state->incoming_packet);
2555}
2556
2557/* start a new packet */
2558
2559int
2560sshpkt_start(struct ssh *ssh, u_char type)
2561{
djm@openbsd.org97f4d302017-04-30 23:13:25 +00002562 u_char buf[6]; /* u32 packet length, u8 pad len, u8 type */
markus@openbsd.org091c3022015-01-19 19:52:16 +00002563
2564 DBG(debug("packet_start[%d]", type));
djm@openbsd.org97f4d302017-04-30 23:13:25 +00002565 memset(buf, 0, sizeof(buf));
2566 buf[sizeof(buf) - 1] = type;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002567 sshbuf_reset(ssh->state->outgoing_packet);
djm@openbsd.org97f4d302017-04-30 23:13:25 +00002568 return sshbuf_put(ssh->state->outgoing_packet, buf, sizeof(buf));
markus@openbsd.org091c3022015-01-19 19:52:16 +00002569}
2570
markus@openbsd.org8d057842016-09-30 09:19:13 +00002571static int
2572ssh_packet_send_mux(struct ssh *ssh)
2573{
2574 struct session_state *state = ssh->state;
2575 u_char type, *cp;
2576 size_t len;
2577 int r;
2578
2579 if (ssh->kex)
2580 return SSH_ERR_INTERNAL_ERROR;
2581 len = sshbuf_len(state->outgoing_packet);
2582 if (len < 6)
2583 return SSH_ERR_INTERNAL_ERROR;
2584 cp = sshbuf_mutable_ptr(state->outgoing_packet);
2585 type = cp[5];
2586 if (ssh_packet_log_type(type))
2587 debug3("%s: type %u", __func__, type);
2588 /* drop everything, but the connection protocol */
2589 if (type >= SSH2_MSG_CONNECTION_MIN &&
2590 type <= SSH2_MSG_CONNECTION_MAX) {
2591 POKE_U32(cp, len - 4);
2592 if ((r = sshbuf_putb(state->output,
2593 state->outgoing_packet)) != 0)
2594 return r;
2595 /* sshbuf_dump(state->output, stderr); */
2596 }
2597 sshbuf_reset(state->outgoing_packet);
2598 return 0;
2599}
2600
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002601/*
2602 * 9.2. Ignored Data Message
2603 *
2604 * byte SSH_MSG_IGNORE
2605 * string data
2606 *
2607 * All implementations MUST understand (and ignore) this message at any
2608 * time (after receiving the protocol version). No implementation is
2609 * required to send them. This message can be used as an additional
2610 * protection measure against advanced traffic analysis techniques.
2611 */
2612int
2613sshpkt_msg_ignore(struct ssh *ssh, u_int nbytes)
2614{
2615 u_int32_t rnd = 0;
2616 int r;
2617 u_int i;
2618
2619 if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 ||
2620 (r = sshpkt_put_u32(ssh, nbytes)) != 0)
2621 return r;
2622 for (i = 0; i < nbytes; i++) {
2623 if (i % 4 == 0)
2624 rnd = arc4random();
2625 if ((r = sshpkt_put_u8(ssh, (u_char)rnd & 0xff)) != 0)
2626 return r;
2627 rnd >>= 8;
2628 }
2629 return 0;
2630}
2631
markus@openbsd.org091c3022015-01-19 19:52:16 +00002632/* send it */
2633
2634int
2635sshpkt_send(struct ssh *ssh)
2636{
markus@openbsd.org8d057842016-09-30 09:19:13 +00002637 if (ssh->state && ssh->state->mux)
2638 return ssh_packet_send_mux(ssh);
djm@openbsd.org97f4d302017-04-30 23:13:25 +00002639 return ssh_packet_send2(ssh);
markus@openbsd.org091c3022015-01-19 19:52:16 +00002640}
2641
2642int
2643sshpkt_disconnect(struct ssh *ssh, const char *fmt,...)
2644{
2645 char buf[1024];
2646 va_list args;
2647 int r;
2648
2649 va_start(args, fmt);
2650 vsnprintf(buf, sizeof(buf), fmt, args);
2651 va_end(args);
2652
djm@openbsd.org97f4d302017-04-30 23:13:25 +00002653 if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 ||
2654 (r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 ||
2655 (r = sshpkt_put_cstring(ssh, buf)) != 0 ||
2656 (r = sshpkt_put_cstring(ssh, "")) != 0 ||
2657 (r = sshpkt_send(ssh)) != 0)
2658 return r;
markus@openbsd.org091c3022015-01-19 19:52:16 +00002659 return 0;
2660}
2661
2662/* roundup current message to pad bytes */
2663int
2664sshpkt_add_padding(struct ssh *ssh, u_char pad)
2665{
2666 ssh->state->extra_pad = pad;
2667 return 0;
Damien Millerc31a0cd2014-05-15 14:37:39 +10002668}