diff --git a/ChangeLog b/ChangeLog index 7bb8eaa5c..83c02ecf5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,11 @@ - markus@cvs.openbsd.org 2001/04/04 15:50:55 [compat.c] f-secure 1.3.2 does not handle IGNORE; from milliondl@ornl.gov + - markus@cvs.openbsd.org 2001/04/04 20:25:38 + [channels.c channels.h clientloop.c kex.c kex.h serverloop.c + sshconnect2.c sshd.c] + more robust rekeying + don't send channel data after rekeying is started. 20010404 - OpenBSD CVS Sync @@ -4851,4 +4856,4 @@ - Wrote replacements for strlcpy and mkdtemp - Released 1.0pre1 -$Id: ChangeLog,v 1.1057 2001/04/04 23:43:26 mouring Exp $ +$Id: ChangeLog,v 1.1058 2001/04/04 23:46:07 mouring Exp $ diff --git a/channels.c b/channels.c index 941556ace..7790564cc 100644 --- a/channels.c +++ b/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 #include @@ -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/channels.h b/channels.h index 493b04aa2..2cd82148e 100644 --- a/channels.h +++ b/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/clientloop.c b/clientloop.c index 1d09a8dd9..4b87e3b6d 100644 --- a/clientloop.c +++ b/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(); + 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(); - /* - * 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(); + /* + * 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(); - /* - * 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; + /* + * 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/kex.c b/kex.c index ee1e17e02..da9c56eb0 100644 --- a/kex.c +++ b/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 @@ -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/kex.h b/kex.h index 54134221f..8758804c5 100644 --- a/kex.h +++ b/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/serverloop.c b/serverloop.c index 4ae02fd10..ab7472b77 100644 --- a/serverloop.c +++ b/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/sshconnect2.c b/sshconnect2.c index 2f26aa569..918ab38e8 100644 --- a/sshconnect2.c +++ b/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 #include @@ -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/sshd.c b/sshd.c index ea29e75ac..5b5928858 100644 --- a/sshd.c +++ b/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 #include @@ -1437,7 +1437,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;