summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2001-04-04 20:25:39 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2001-04-04 20:25:39 +0000
commit4f83dbd35d9809179c73680ee7670a6d96845477 (patch)
treef76851900dbfa1d119d94a8aaa27ccb1749f7e12
parent7c7a85a9b3c7bc0ff2c463a08388ccb42f256746 (diff)
more robust rekeying
don't send channel data after rekeying is started.
-rw-r--r--usr.bin/ssh/channels.c8
-rw-r--r--usr.bin/ssh/channels.h5
-rw-r--r--usr.bin/ssh/clientloop.c75
-rw-r--r--usr.bin/ssh/kex.c46
-rw-r--r--usr.bin/ssh/kex.h6
-rw-r--r--usr.bin/ssh/serverloop.c4
-rw-r--r--usr.bin/ssh/sshconnect2.c4
-rw-r--r--usr.bin/ssh/sshd.c4
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;