diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2001-04-04 20:25:39 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2001-04-04 20:25:39 +0000 |
commit | 4f83dbd35d9809179c73680ee7670a6d96845477 (patch) | |
tree | f76851900dbfa1d119d94a8aaa27ccb1749f7e12 | |
parent | 7c7a85a9b3c7bc0ff2c463a08388ccb42f256746 (diff) |
more robust rekeying
don't send channel data after rekeying is started.
-rw-r--r-- | usr.bin/ssh/channels.c | 8 | ||||
-rw-r--r-- | usr.bin/ssh/channels.h | 5 | ||||
-rw-r--r-- | usr.bin/ssh/clientloop.c | 75 | ||||
-rw-r--r-- | usr.bin/ssh/kex.c | 46 | ||||
-rw-r--r-- | usr.bin/ssh/kex.h | 6 | ||||
-rw-r--r-- | usr.bin/ssh/serverloop.c | 4 | ||||
-rw-r--r-- | usr.bin/ssh/sshconnect2.c | 4 | ||||
-rw-r--r-- | usr.bin/ssh/sshd.c | 4 |
8 files changed, 90 insertions, 62 deletions
diff --git a/usr.bin/ssh/channels.c b/usr.bin/ssh/channels.c index 097a1d4a9f2..da426a38c9b 100644 --- a/usr.bin/ssh/channels.c +++ b/usr.bin/ssh/channels.c @@ -40,7 +40,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: channels.c,v 1.99 2001/03/16 19:06:29 markus Exp $"); +RCSID("$OpenBSD: channels.c,v 1.100 2001/04/04 20:25:35 markus Exp $"); #include <openssl/rsa.h> #include <openssl/dsa.h> @@ -1005,7 +1005,8 @@ channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) } void -channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp) +channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, + int rekeying) { int n; u_int sz; @@ -1025,7 +1026,8 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp) memset(*readsetp, 0, sz); memset(*writesetp, 0, sz); - channel_handler(channel_pre, *readsetp, *writesetp); + if (!rekeying) + channel_handler(channel_pre, *readsetp, *writesetp); } void diff --git a/usr.bin/ssh/channels.h b/usr.bin/ssh/channels.h index 493b04aa290..2cd82148e55 100644 --- a/usr.bin/ssh/channels.h +++ b/usr.bin/ssh/channels.h @@ -32,7 +32,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* RCSID("$OpenBSD: channels.h,v 1.28 2001/03/16 19:06:29 markus Exp $"); */ +/* RCSID("$OpenBSD: channels.h,v 1.29 2001/04/04 20:25:36 markus Exp $"); */ #ifndef CHANNELS_H #define CHANNELS_H @@ -171,7 +171,8 @@ void channel_free(int channel); * select bitmasks. */ void -channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp); +channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, + int rekeying); /* * After select, perform any appropriate operations for channels which have diff --git a/usr.bin/ssh/clientloop.c b/usr.bin/ssh/clientloop.c index 1d09a8dd9fe..4b87e3b6d76 100644 --- a/usr.bin/ssh/clientloop.c +++ b/usr.bin/ssh/clientloop.c @@ -59,7 +59,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: clientloop.c,v 1.55 2001/04/04 14:34:58 markus Exp $"); +RCSID("$OpenBSD: clientloop.c,v 1.56 2001/04/04 20:25:37 markus Exp $"); #include "ssh.h" #include "ssh1.h" @@ -127,6 +127,7 @@ static u_long stdin_bytes, stdout_bytes, stderr_bytes; static u_int buffer_high;/* Soft max buffer size. */ static int connection_in; /* Connection to server (input). */ static int connection_out; /* Connection to server (output). */ +static int need_rekeying; /* Set to non-zero if rekeying is requested. */ void client_init_dispatch(void); int session_ident = -1; @@ -367,10 +368,10 @@ client_check_window_change(void) void client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, - int *maxfdp) + int *maxfdp, int rekeying) { /* Add any selections by the channel mechanism. */ - channel_prepare_select(readsetp, writesetp, maxfdp); + channel_prepare_select(readsetp, writesetp, maxfdp, rekeying); if (!compat20) { /* Read from the connection, unless our buffers are full. */ @@ -553,8 +554,8 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) continue; case 'R': - debug("Rekeying"); - kex_send_kexinit(xxx_kex); + if (compat20) + need_rekeying = 1; continue; case '&': @@ -794,9 +795,8 @@ int client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) { fd_set *readset = NULL, *writeset = NULL; - int max_fd = 0; double start_time, total_time; - int len; + int max_fd = 0, len, rekeying = 0; char buf[100]; debug("Entering interactive session."); @@ -858,45 +858,60 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) /* Process buffered packets sent by the server. */ client_process_buffered_input_packets(); + rekeying = (xxx_kex != NULL && !xxx_kex->done); + if (compat20 && !channel_still_open()) { debug2("!channel_still_open."); break; } - /* - * Make packets of buffered stdin data, and buffer them for - * sending to the server. - */ - if (!compat20) - client_make_packets_from_stdin_data(); - - /* - * Make packets from buffered channel data, and enqueue them - * for sending to the server. - */ - if (packet_not_very_much_data_to_write()) - channel_output_poll(); + if (rekeying) { + debug("rekeying in progress"); + } else { + /* + * Make packets of buffered stdin data, and buffer + * them for sending to the server. + */ + if (!compat20) + client_make_packets_from_stdin_data(); - /* - * Check if the window size has changed, and buffer a message - * about it to the server if so. - */ - client_check_window_change(); + /* + * Make packets from buffered channel data, and + * enqueue them for sending to the server. + */ + if (packet_not_very_much_data_to_write()) + channel_output_poll(); - if (quit_pending) - break; + /* + * Check if the window size has changed, and buffer a + * message about it to the server if so. + */ + client_check_window_change(); + if (quit_pending) + break; + } /* * Wait until we have something to do (something becomes * available on one of the descriptors). */ - client_wait_until_can_do_something(&readset, &writeset, &max_fd); + client_wait_until_can_do_something(&readset, &writeset, + &max_fd, rekeying); if (quit_pending) break; - /* Do channel operations. */ - channel_after_select(readset, writeset); + /* Do channel operations unless rekeying in progress. */ + if (!rekeying) { + channel_after_select(readset, writeset); + + if (need_rekeying) { + debug("user requests rekeying"); + xxx_kex->done = 0; + kex_send_kexinit(xxx_kex); + need_rekeying = 0; + } + } /* Buffer input from the connection. */ client_process_net_input(readset); diff --git a/usr.bin/ssh/kex.c b/usr.bin/ssh/kex.c index ee1e17e02a6..da9c56eb0ab 100644 --- a/usr.bin/ssh/kex.c +++ b/usr.bin/ssh/kex.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: kex.c,v 1.29 2001/04/04 14:34:58 markus Exp $"); +RCSID("$OpenBSD: kex.c,v 1.30 2001/04/04 20:25:37 markus Exp $"); #include <openssl/crypto.h> @@ -136,7 +136,7 @@ kex_finish(Kex *kex) debug("waiting for SSH2_MSG_NEWKEYS"); packet_read_expect(&plen, SSH2_MSG_NEWKEYS); debug("SSH2_MSG_NEWKEYS received"); - kex->newkeys = 1; + kex->done = 1; buffer_clear(&kex->peer); /* buffer_clear(&kex->my); */ kex->flags &= ~KEX_INIT_SENT; @@ -153,6 +153,7 @@ kex_send_kexinit(Kex *kex) debug("KEX_INIT_SENT"); return; } + kex->done = 0; packet_start(SSH2_MSG_KEXINIT); packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); packet_send(); @@ -187,7 +188,7 @@ kex_setup(char *proposal[PROPOSAL_MAX]) buffer_init(&kex->peer); buffer_init(&kex->my); kex_prop2buf(&kex->my, proposal); - kex->newkeys = 0; + kex->done = 0; kex_send_kexinit(kex); /* we start */ kex_clear_dispatch(); @@ -307,10 +308,11 @@ kex_choose_conf(Kex *kex) sprop=peer; } + /* Algorithm Negotiation */ for (mode = 0; mode < MODE_MAX; mode++) { newkeys = xmalloc(sizeof(*newkeys)); memset(newkeys, 0, sizeof(*newkeys)); - kex->keys[mode] = newkeys; + kex->newkeys[mode] = newkeys; ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; @@ -329,7 +331,7 @@ kex_choose_conf(Kex *kex) sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); need = 0; for (mode = 0; mode < MODE_MAX; mode++) { - newkeys = kex->keys[mode]; + newkeys = kex->newkeys[mode]; if (need < newkeys->enc.cipher->key_len) need = newkeys->enc.cipher->key_len; if (need < newkeys->enc.cipher->block_size) @@ -353,19 +355,24 @@ derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret) char c = id; int have; int mdsz = evp_md->md_size; - u_char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz); + u_char *digest = xmalloc(roundup(need, mdsz)); buffer_init(&b); buffer_put_bignum2(&b, shared_secret); + /* K1 = HASH(K || H || "A" || session_id) */ EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */ - EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */ - EVP_DigestUpdate(&md, &c, 1); /* key id */ + EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestUpdate(&md, hash, mdsz); + EVP_DigestUpdate(&md, &c, 1); EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); EVP_DigestFinal(&md, digest, NULL); - /* expand */ + /* + * expand key: + * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) + * Key = K1 || K2 || ... || Kn + */ for (have = mdsz; need > have; have += mdsz) { EVP_DigestInit(&md, evp_md); EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); @@ -381,13 +388,12 @@ derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret) return digest; } -Newkeys *x_newkeys[MODE_MAX]; +Newkeys *current_keys[MODE_MAX]; #define NKEYS 6 void kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret) { - Newkeys *newkeys; u_char *keys[NKEYS]; int i, mode, ctos; @@ -396,19 +402,23 @@ kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret) debug("kex_derive_keys"); for (mode = 0; mode < MODE_MAX; mode++) { - newkeys = kex->keys[mode]; + current_keys[mode] = kex->newkeys[mode]; + kex->newkeys[mode] = NULL; ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); - newkeys->enc.iv = keys[ctos ? 0 : 1]; - newkeys->enc.key = keys[ctos ? 2 : 3]; - newkeys->mac.key = keys[ctos ? 4 : 5]; - x_newkeys[mode] = newkeys; + current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; + current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; + current_keys[mode]->mac.key = keys[ctos ? 4 : 5]; } } Newkeys * kex_get_newkeys(int mode) { - return x_newkeys[mode]; + Newkeys *ret; + + ret = current_keys[mode]; + current_keys[mode] = NULL; + return ret; } #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) diff --git a/usr.bin/ssh/kex.h b/usr.bin/ssh/kex.h index 54134221ff0..8758804c554 100644 --- a/usr.bin/ssh/kex.h +++ b/usr.bin/ssh/kex.h @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.h,v 1.21 2001/04/04 14:34:58 markus Exp $ */ +/* $OpenBSD: kex.h,v 1.22 2001/04/04 20:25:37 markus Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -95,7 +95,7 @@ struct Newkeys { struct Kex { u_char *session_id; int session_id_len; - Newkeys *keys[MODE_MAX]; + Newkeys *newkeys[MODE_MAX]; int we_need; int server; char *name; @@ -103,7 +103,7 @@ struct Kex { int kex_type; Buffer my; Buffer peer; - int newkeys; + int done; int flags; char *client_version_string; char *server_version_string; diff --git a/usr.bin/ssh/serverloop.c b/usr.bin/ssh/serverloop.c index b1948611299..95592be7da6 100644 --- a/usr.bin/ssh/serverloop.c +++ b/usr.bin/ssh/serverloop.c @@ -35,7 +35,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: serverloop.c,v 1.56 2001/04/04 14:34:58 markus Exp $"); +RCSID("$OpenBSD: serverloop.c,v 1.57 2001/04/04 20:25:37 markus Exp $"); #include "xmalloc.h" #include "packet.h" @@ -194,7 +194,7 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, retry_select: /* Allocate and update select() masks for channel descriptors. */ - channel_prepare_select(readsetp, writesetp, maxfdp); + channel_prepare_select(readsetp, writesetp, maxfdp, 0); if (compat20) { /* wrong: bad condition XXX */ diff --git a/usr.bin/ssh/sshconnect2.c b/usr.bin/ssh/sshconnect2.c index 2f26aa56997..918ab38e82b 100644 --- a/usr.bin/ssh/sshconnect2.c +++ b/usr.bin/ssh/sshconnect2.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect2.c,v 1.65 2001/04/04 14:34:58 markus Exp $"); +RCSID("$OpenBSD: sshconnect2.c,v 1.66 2001/04/04 20:25:38 markus Exp $"); #include <openssl/bn.h> #include <openssl/md5.h> @@ -119,7 +119,7 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) xxx_kex = kex; - dispatch_run(DISPATCH_BLOCK, &kex->newkeys, kex); + dispatch_run(DISPATCH_BLOCK, &kex->done, kex); session_id2 = kex->session_id; session_id2_len = kex->session_id_len; diff --git a/usr.bin/ssh/sshd.c b/usr.bin/ssh/sshd.c index af7f9bbe78d..29cd7748315 100644 --- a/usr.bin/ssh/sshd.c +++ b/usr.bin/ssh/sshd.c @@ -40,7 +40,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.189 2001/04/04 14:34:58 markus Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.190 2001/04/04 20:25:38 markus Exp $"); #include <openssl/dh.h> #include <openssl/bn.h> @@ -1411,7 +1411,7 @@ do_ssh2_kex(void) xxx_kex = kex; - dispatch_run(DISPATCH_BLOCK, &kex->newkeys, kex); + dispatch_run(DISPATCH_BLOCK, &kex->done, kex); session_id2 = kex->session_id; session_id2_len = kex->session_id_len; |