summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clientloop.c28
-rw-r--r--kex.c21
-rw-r--r--kex.h3
-rw-r--r--opacket.h2
-rw-r--r--packet.c154
-rw-r--r--packet.h4
-rw-r--r--serverloop.c20
7 files changed, 158 insertions, 74 deletions
diff --git a/clientloop.c b/clientloop.c
index f0a08f234..9820455c4 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: clientloop.c,v 1.283 2016/02/01 21:18:17 millert Exp $ */ 1/* $OpenBSD: clientloop.c,v 1.284 2016/02/08 10:57:07 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1502,7 +1502,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1502{ 1502{
1503 fd_set *readset = NULL, *writeset = NULL; 1503 fd_set *readset = NULL, *writeset = NULL;
1504 double start_time, total_time; 1504 double start_time, total_time;
1505 int r, max_fd = 0, max_fd2 = 0, len, rekeying = 0; 1505 int r, max_fd = 0, max_fd2 = 0, len;
1506 u_int64_t ibytes, obytes; 1506 u_int64_t ibytes, obytes;
1507 u_int nalloc = 0; 1507 u_int nalloc = 0;
1508 char buf[100]; 1508 char buf[100];
@@ -1617,10 +1617,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1617 if (compat20 && session_closed && !channel_still_open()) 1617 if (compat20 && session_closed && !channel_still_open())
1618 break; 1618 break;
1619 1619
1620 rekeying = (active_state->kex != NULL && !active_state->kex->done); 1620 if (ssh_packet_is_rekeying(active_state)) {
1621
1622 if (rekeying) {
1623 debug("rekeying in progress"); 1621 debug("rekeying in progress");
1622 } else if (need_rekeying) {
1623 /* manual rekey request */
1624 debug("need rekeying");
1625 if ((r = kex_start_rekex(active_state)) != 0)
1626 fatal("%s: kex_start_rekex: %s", __func__,
1627 ssh_err(r));
1628 need_rekeying = 0;
1624 } else { 1629 } else {
1625 /* 1630 /*
1626 * Make packets of buffered stdin data, and buffer 1631 * Make packets of buffered stdin data, and buffer
@@ -1651,23 +1656,14 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1651 */ 1656 */
1652 max_fd2 = max_fd; 1657 max_fd2 = max_fd;
1653 client_wait_until_can_do_something(&readset, &writeset, 1658 client_wait_until_can_do_something(&readset, &writeset,
1654 &max_fd2, &nalloc, rekeying); 1659 &max_fd2, &nalloc, ssh_packet_is_rekeying(active_state));
1655 1660
1656 if (quit_pending) 1661 if (quit_pending)
1657 break; 1662 break;
1658 1663
1659 /* Do channel operations unless rekeying in progress. */ 1664 /* Do channel operations unless rekeying in progress. */
1660 if (!rekeying) { 1665 if (!ssh_packet_is_rekeying(active_state))
1661 channel_after_select(readset, writeset); 1666 channel_after_select(readset, writeset);
1662 if (need_rekeying || packet_need_rekeying()) {
1663 debug("need rekeying");
1664 active_state->kex->done = 0;
1665 if ((r = kex_send_kexinit(active_state)) != 0)
1666 fatal("%s: kex_send_kexinit: %s",
1667 __func__, ssh_err(r));
1668 need_rekeying = 0;
1669 }
1670 }
1671 1667
1672 /* Buffer input from the connection. */ 1668 /* Buffer input from the connection. */
1673 client_process_net_input(readset); 1669 client_process_net_input(readset);
diff --git a/kex.c b/kex.c
index 335b789fc..d371f47c4 100644
--- a/kex.c
+++ b/kex.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: kex.c,v 1.116 2016/01/14 16:17:39 markus Exp $ */ 1/* $OpenBSD: kex.c,v 1.117 2016/02/08 10:57:07 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
4 * 4 *
@@ -606,6 +606,25 @@ kex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX])
606 return 0; 606 return 0;
607} 607}
608 608
609/*
610 * Request key re-exchange, returns 0 on success or a ssherr.h error
611 * code otherwise. Must not be called if KEX is incomplete or in-progress.
612 */
613int
614kex_start_rekex(struct ssh *ssh)
615{
616 if (ssh->kex == NULL) {
617 error("%s: no kex", __func__);
618 return SSH_ERR_INTERNAL_ERROR;
619 }
620 if (ssh->kex->done == 0) {
621 error("%s: requested twice", __func__);
622 return SSH_ERR_INTERNAL_ERROR;
623 }
624 ssh->kex->done = 0;
625 return kex_send_kexinit(ssh);
626}
627
609static int 628static int
610choose_enc(struct sshenc *enc, char *client, char *server) 629choose_enc(struct sshenc *enc, char *client, char *server)
611{ 630{
diff --git a/kex.h b/kex.h
index 24d4aa15f..1c5896605 100644
--- a/kex.h
+++ b/kex.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: kex.h,v 1.75 2016/01/14 16:17:39 markus Exp $ */ 1/* $OpenBSD: kex.h,v 1.76 2016/02/08 10:57:07 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -179,6 +179,7 @@ int kex_input_ext_info(int, u_int32_t, void *);
179int kex_derive_keys(struct ssh *, u_char *, u_int, const struct sshbuf *); 179int kex_derive_keys(struct ssh *, u_char *, u_int, const struct sshbuf *);
180int kex_derive_keys_bn(struct ssh *, u_char *, u_int, const BIGNUM *); 180int kex_derive_keys_bn(struct ssh *, u_char *, u_int, const BIGNUM *);
181int kex_send_newkeys(struct ssh *); 181int kex_send_newkeys(struct ssh *);
182int kex_start_rekex(struct ssh *);
182 183
183int kexdh_client(struct ssh *); 184int kexdh_client(struct ssh *);
184int kexdh_server(struct ssh *); 185int kexdh_server(struct ssh *);
diff --git a/opacket.h b/opacket.h
index b14b6769a..c26ade44c 100644
--- a/opacket.h
+++ b/opacket.h
@@ -125,8 +125,6 @@ void packet_disconnect(const char *, ...)
125 sshpkt_add_padding(active_state, (pad)) 125 sshpkt_add_padding(active_state, (pad))
126#define packet_send_ignore(nbytes) \ 126#define packet_send_ignore(nbytes) \
127 ssh_packet_send_ignore(active_state, (nbytes)) 127 ssh_packet_send_ignore(active_state, (nbytes))
128#define packet_need_rekeying() \
129 ssh_packet_need_rekeying(active_state)
130#define packet_set_server() \ 128#define packet_set_server() \
131 ssh_packet_set_server(active_state) 129 ssh_packet_set_server(active_state)
132#define packet_set_authenticated() \ 130#define packet_set_authenticated() \
diff --git a/packet.c b/packet.c
index f7e5bc78f..7ddebeb71 100644
--- a/packet.c
+++ b/packet.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: packet.c,v 1.227 2016/02/04 23:43:48 djm Exp $ */ 1/* $OpenBSD: packet.c,v 1.228 2016/02/08 10:57:07 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -259,6 +259,14 @@ ssh_alloc_session_state(void)
259 return NULL; 259 return NULL;
260} 260}
261 261
262/* Returns nonzero if rekeying is in progress */
263int
264ssh_packet_is_rekeying(struct ssh *ssh)
265{
266 return ssh->state->rekeying ||
267 (ssh->kex != NULL && ssh->kex->done == 0);
268}
269
262/* 270/*
263 * Sets the descriptors used for communication. Disables encryption until 271 * Sets the descriptors used for communication. Disables encryption until
264 * packet_set_encryption_key is called. 272 * packet_set_encryption_key is called.
@@ -1029,6 +1037,51 @@ ssh_set_newkeys(struct ssh *ssh, int mode)
1029 return 0; 1037 return 0;
1030} 1038}
1031 1039
1040#define MAX_PACKETS (1U<<31)
1041static int
1042ssh_packet_need_rekeying(struct ssh *ssh, u_int outbound_packet_len)
1043{
1044 struct session_state *state = ssh->state;
1045 u_int32_t out_blocks;
1046
1047 /* XXX client can't cope with rekeying pre-auth */
1048 if (!state->after_authentication)
1049 return 0;
1050
1051 /* Haven't keyed yet or KEX in progress. */
1052 if (ssh->kex == NULL || ssh_packet_is_rekeying(ssh))
1053 return 0;
1054
1055 /* Peer can't rekey */
1056 if (ssh->compat & SSH_BUG_NOREKEY)
1057 return 0;
1058
1059 /*
1060 * Permit one packet in or out per rekey - this allows us to
1061 * make progress when rekey limits are very small.
1062 */
1063 if (state->p_send.packets == 0 && state->p_read.packets == 0)
1064 return 0;
1065
1066 /* Time-based rekeying */
1067 if (state->rekey_interval != 0 &&
1068 state->rekey_time + state->rekey_interval <= monotime())
1069 return 1;
1070
1071 /* Always rekey when MAX_PACKETS sent in either direction */
1072 if (state->p_send.packets > MAX_PACKETS ||
1073 state->p_read.packets > MAX_PACKETS)
1074 return 1;
1075
1076 /* Rekey after (cipher-specific) maxiumum blocks */
1077 out_blocks = roundup(outbound_packet_len,
1078 state->newkeys[MODE_OUT]->enc.block_size);
1079 return (state->max_blocks_out &&
1080 (state->p_send.blocks + out_blocks > state->max_blocks_out)) ||
1081 (state->max_blocks_in &&
1082 (state->p_read.blocks > state->max_blocks_in));
1083}
1084
1032/* 1085/*
1033 * Delayed compression for SSH2 is enabled after authentication: 1086 * Delayed compression for SSH2 is enabled after authentication:
1034 * This happens on the server side after a SSH2_MSG_USERAUTH_SUCCESS is sent, 1087 * This happens on the server side after a SSH2_MSG_USERAUTH_SUCCESS is sent,
@@ -1232,35 +1285,58 @@ ssh_packet_send2_wrapped(struct ssh *ssh)
1232 return r; 1285 return r;
1233} 1286}
1234 1287
1288/* returns non-zero if the specified packet type is usec by KEX */
1289static int
1290ssh_packet_type_is_kex(u_char type)
1291{
1292 return
1293 type >= SSH2_MSG_TRANSPORT_MIN &&
1294 type <= SSH2_MSG_TRANSPORT_MAX &&
1295 type != SSH2_MSG_SERVICE_REQUEST &&
1296 type != SSH2_MSG_SERVICE_ACCEPT &&
1297 type != SSH2_MSG_EXT_INFO;
1298}
1299
1235int 1300int
1236ssh_packet_send2(struct ssh *ssh) 1301ssh_packet_send2(struct ssh *ssh)
1237{ 1302{
1238 struct session_state *state = ssh->state; 1303 struct session_state *state = ssh->state;
1239 struct packet *p; 1304 struct packet *p;
1240 u_char type; 1305 u_char type;
1241 int r; 1306 int r, need_rekey;
1242 1307
1308 if (sshbuf_len(state->outgoing_packet) < 6)
1309 return SSH_ERR_INTERNAL_ERROR;
1243 type = sshbuf_ptr(state->outgoing_packet)[5]; 1310 type = sshbuf_ptr(state->outgoing_packet)[5];
1311 need_rekey = !ssh_packet_type_is_kex(type) &&
1312 ssh_packet_need_rekeying(ssh, sshbuf_len(state->outgoing_packet));
1244 1313
1245 /* during rekeying we can only send key exchange messages */ 1314 /*
1246 if (state->rekeying) { 1315 * During rekeying we can only send key exchange messages.
1247 if ((type < SSH2_MSG_TRANSPORT_MIN) || 1316 * Queue everything else.
1248 (type > SSH2_MSG_TRANSPORT_MAX) || 1317 */
1249 (type == SSH2_MSG_SERVICE_REQUEST) || 1318 if ((need_rekey || state->rekeying) && !ssh_packet_type_is_kex(type)) {
1250 (type == SSH2_MSG_SERVICE_ACCEPT) || 1319 if (need_rekey)
1251 (type == SSH2_MSG_EXT_INFO)) { 1320 debug3("%s: rekex triggered", __func__);
1252 debug("enqueue packet: %u", type); 1321 debug("enqueue packet: %u", type);
1253 p = calloc(1, sizeof(*p)); 1322 p = calloc(1, sizeof(*p));
1254 if (p == NULL) 1323 if (p == NULL)
1255 return SSH_ERR_ALLOC_FAIL; 1324 return SSH_ERR_ALLOC_FAIL;
1256 p->type = type; 1325 p->type = type;
1257 p->payload = state->outgoing_packet; 1326 p->payload = state->outgoing_packet;
1258 TAILQ_INSERT_TAIL(&state->outgoing, p, next); 1327 TAILQ_INSERT_TAIL(&state->outgoing, p, next);
1259 state->outgoing_packet = sshbuf_new(); 1328 state->outgoing_packet = sshbuf_new();
1260 if (state->outgoing_packet == NULL) 1329 if (state->outgoing_packet == NULL)
1261 return SSH_ERR_ALLOC_FAIL; 1330 return SSH_ERR_ALLOC_FAIL;
1262 return 0; 1331 if (need_rekey) {
1332 /*
1333 * This packet triggered a rekey, so send the
1334 * KEXINIT now.
1335 * NB. reenters this function via kex_start_rekex().
1336 */
1337 return kex_start_rekex(ssh);
1263 } 1338 }
1339 return 0;
1264 } 1340 }
1265 1341
1266 /* rekeying starts with sending KEXINIT */ 1342 /* rekeying starts with sending KEXINIT */
@@ -1276,10 +1352,22 @@ ssh_packet_send2(struct ssh *ssh)
1276 state->rekey_time = monotime(); 1352 state->rekey_time = monotime();
1277 while ((p = TAILQ_FIRST(&state->outgoing))) { 1353 while ((p = TAILQ_FIRST(&state->outgoing))) {
1278 type = p->type; 1354 type = p->type;
1355 /*
1356 * If this packet triggers a rekex, then skip the
1357 * remaining packets in the queue for now.
1358 * NB. re-enters this function via kex_start_rekex.
1359 */
1360 if (ssh_packet_need_rekeying(ssh,
1361 sshbuf_len(p->payload))) {
1362 debug3("%s: queued packet triggered rekex",
1363 __func__);
1364 return kex_start_rekex(ssh);
1365 }
1279 debug("dequeue packet: %u", type); 1366 debug("dequeue packet: %u", type);
1280 sshbuf_free(state->outgoing_packet); 1367 sshbuf_free(state->outgoing_packet);
1281 state->outgoing_packet = p->payload; 1368 state->outgoing_packet = p->payload;
1282 TAILQ_REMOVE(&state->outgoing, p, next); 1369 TAILQ_REMOVE(&state->outgoing, p, next);
1370 memset(p, 0, sizeof(*p));
1283 free(p); 1371 free(p);
1284 if ((r = ssh_packet_send2_wrapped(ssh)) != 0) 1372 if ((r = ssh_packet_send2_wrapped(ssh)) != 0)
1285 return r; 1373 return r;
@@ -1784,6 +1872,13 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
1784#endif 1872#endif
1785 /* reset for next packet */ 1873 /* reset for next packet */
1786 state->packlen = 0; 1874 state->packlen = 0;
1875
1876 /* do we need to rekey? */
1877 if (ssh_packet_need_rekeying(ssh, 0)) {
1878 debug3("%s: rekex triggered", __func__);
1879 if ((r = kex_start_rekex(ssh)) != 0)
1880 return r;
1881 }
1787 out: 1882 out:
1788 return r; 1883 return r;
1789} 1884}
@@ -2268,25 +2363,6 @@ ssh_packet_send_ignore(struct ssh *ssh, int nbytes)
2268 } 2363 }
2269} 2364}
2270 2365
2271#define MAX_PACKETS (1U<<31)
2272int
2273ssh_packet_need_rekeying(struct ssh *ssh)
2274{
2275 struct session_state *state = ssh->state;
2276
2277 if (ssh->compat & SSH_BUG_NOREKEY)
2278 return 0;
2279 return
2280 (state->p_send.packets > MAX_PACKETS) ||
2281 (state->p_read.packets > MAX_PACKETS) ||
2282 (state->max_blocks_out &&
2283 (state->p_send.blocks > state->max_blocks_out)) ||
2284 (state->max_blocks_in &&
2285 (state->p_read.blocks > state->max_blocks_in)) ||
2286 (state->rekey_interval != 0 && state->rekey_time +
2287 state->rekey_interval <= monotime());
2288}
2289
2290void 2366void
2291ssh_packet_set_rekey_limits(struct ssh *ssh, u_int64_t bytes, time_t seconds) 2367ssh_packet_set_rekey_limits(struct ssh *ssh, u_int64_t bytes, time_t seconds)
2292{ 2368{
diff --git a/packet.h b/packet.h
index 62302747d..28516a553 100644
--- a/packet.h
+++ b/packet.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: packet.h,v 1.69 2016/01/29 02:54:45 dtucker Exp $ */ 1/* $OpenBSD: packet.h,v 1.70 2016/02/08 10:57:07 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -86,6 +86,7 @@ int ssh_packet_get_connection_in(struct ssh *);
86int ssh_packet_get_connection_out(struct ssh *); 86int ssh_packet_get_connection_out(struct ssh *);
87void ssh_packet_close(struct ssh *); 87void ssh_packet_close(struct ssh *);
88void ssh_packet_set_encryption_key(struct ssh *, const u_char *, u_int, int); 88void ssh_packet_set_encryption_key(struct ssh *, const u_char *, u_int, int);
89int ssh_packet_is_rekeying(struct ssh *);
89void ssh_packet_set_protocol_flags(struct ssh *, u_int); 90void ssh_packet_set_protocol_flags(struct ssh *, u_int);
90u_int ssh_packet_get_protocol_flags(struct ssh *); 91u_int ssh_packet_get_protocol_flags(struct ssh *);
91int ssh_packet_start_compression(struct ssh *, int); 92int ssh_packet_start_compression(struct ssh *, int);
@@ -145,7 +146,6 @@ int ssh_packet_set_state(struct ssh *, struct sshbuf *);
145const char *ssh_remote_ipaddr(struct ssh *); 146const char *ssh_remote_ipaddr(struct ssh *);
146int ssh_remote_port(struct ssh *); 147int ssh_remote_port(struct ssh *);
147 148
148int ssh_packet_need_rekeying(struct ssh *);
149void ssh_packet_set_rekey_limits(struct ssh *, u_int64_t, time_t); 149void ssh_packet_set_rekey_limits(struct ssh *, u_int64_t, time_t);
150time_t ssh_packet_get_rekey_timeout(struct ssh *); 150time_t ssh_packet_get_rekey_timeout(struct ssh *);
151 151
diff --git a/serverloop.c b/serverloop.c
index 47bc168b2..80d1db549 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: serverloop.c,v 1.181 2016/01/14 16:17:40 markus Exp $ */ 1/* $OpenBSD: serverloop.c,v 1.182 2016/02/08 10:57:07 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -820,7 +820,7 @@ void
820server_loop2(Authctxt *authctxt) 820server_loop2(Authctxt *authctxt)
821{ 821{
822 fd_set *readset = NULL, *writeset = NULL; 822 fd_set *readset = NULL, *writeset = NULL;
823 int rekeying = 0, max_fd; 823 int max_fd;
824 u_int nalloc = 0; 824 u_int nalloc = 0;
825 u_int64_t rekey_timeout_ms = 0; 825 u_int64_t rekey_timeout_ms = 0;
826 826
@@ -847,11 +847,11 @@ server_loop2(Authctxt *authctxt)
847 for (;;) { 847 for (;;) {
848 process_buffered_input_packets(); 848 process_buffered_input_packets();
849 849
850 rekeying = (active_state->kex != NULL && !active_state->kex->done); 850 if (!ssh_packet_is_rekeying(active_state) &&
851 851 packet_not_very_much_data_to_write())
852 if (!rekeying && packet_not_very_much_data_to_write())
853 channel_output_poll(); 852 channel_output_poll();
854 if (options.rekey_interval > 0 && compat20 && !rekeying) 853 if (options.rekey_interval > 0 && compat20 &&
854 !ssh_packet_is_rekeying(active_state))
855 rekey_timeout_ms = packet_get_rekey_timeout() * 1000; 855 rekey_timeout_ms = packet_get_rekey_timeout() * 1000;
856 else 856 else
857 rekey_timeout_ms = 0; 857 rekey_timeout_ms = 0;
@@ -866,14 +866,8 @@ server_loop2(Authctxt *authctxt)
866 } 866 }
867 867
868 collect_children(); 868 collect_children();
869 if (!rekeying) { 869 if (!ssh_packet_is_rekeying(active_state))
870 channel_after_select(readset, writeset); 870 channel_after_select(readset, writeset);
871 if (packet_need_rekeying()) {
872 debug("need rekeying");
873 active_state->kex->done = 0;
874 kex_send_kexinit(active_state);
875 }
876 }
877 process_input(readset); 871 process_input(readset);
878 if (connection_closed) 872 if (connection_closed)
879 break; 873 break;