From e6c1536e0910c5ffce7720d67c474f668b8f6039 Mon Sep 17 00:00:00 2001 From: simon Date: Tue, 28 Dec 2004 14:10:32 +0000 Subject: [PATCH] Support reconfiguration of key exchange in mid-session. The fiddly bit is working out when to reschedule the next rekey for when the timeout or data limit changes; sometimes it will be _right now_ because we're already over the new limit. Still to do: the Kex panel should not appear in mid-session if we are using SSHv1. git-svn-id: svn://svn.tartarus.org/sgt/putty@5031 cda61777-01e9-0310-a592-d414129be87e --- config.c | 62 ++++++++++++++++++++++++++++++++------------------------------ ssh.c | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 32 deletions(-) diff --git a/config.c b/config.c index d57a6db1..59140dbe 100644 --- a/config.c +++ b/config.c @@ -1576,37 +1576,39 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist, HELPCTX(ssh_ciphers), dlg_stdcheckbox_handler, I(offsetof(Config,ssh2_des_cbc))); + } - /* - * The Connection/SSH/Kex panel. - */ - ctrl_settitle(b, "Connection/SSH/Kex", - "Options controlling SSH key exchange"); - - s = ctrl_getset(b, "Connection/SSH/Kex", "main", - "Key exchange algorithm options"); - c = ctrl_draglist(s, "Algorithm selection policy", 's', - HELPCTX(ssh_kexlist), - kexlist_handler, P(NULL)); - c->listbox.height = 5; - - s = ctrl_getset(b, "Connection/SSH/Kex", "repeat", - "Options controlling key re-exchange"); - - /* FIXME: these could usefully be configured mid-session in SSH-2. - * (So could cipher/compression/kex, now we have rekey.) */ - ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20, - HELPCTX(ssh_kex_repeat), - dlg_stdeditbox_handler, - I(offsetof(Config,ssh_rekey_time)), - I(-1)); - ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'd', 20, - HELPCTX(ssh_kex_repeat), - dlg_stdeditbox_handler, - I(offsetof(Config,ssh_rekey_data)), - I(16)); - ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)", - HELPCTX(ssh_kex_repeat)); + /* + * The Connection/SSH/Kex panel. (Owing to repeat key + * exchange, this is all meaningful in mid-session.) + */ + ctrl_settitle(b, "Connection/SSH/Kex", + "Options controlling SSH key exchange"); + + s = ctrl_getset(b, "Connection/SSH/Kex", "main", + "Key exchange algorithm options"); + c = ctrl_draglist(s, "Algorithm selection policy", 's', + HELPCTX(ssh_kexlist), + kexlist_handler, P(NULL)); + c->listbox.height = 5; + + s = ctrl_getset(b, "Connection/SSH/Kex", "repeat", + "Options controlling key re-exchange"); + + ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20, + HELPCTX(ssh_kex_repeat), + dlg_stdeditbox_handler, + I(offsetof(Config,ssh_rekey_time)), + I(-1)); + ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'd', 20, + HELPCTX(ssh_kex_repeat), + dlg_stdeditbox_handler, + I(offsetof(Config,ssh_rekey_data)), + I(16)); + ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)", + HELPCTX(ssh_kex_repeat)); + + if (!midsession) { /* * The Connection/SSH/Auth panel. diff --git a/ssh.c b/ssh.c index e619b599..e92eb1d7 100644 --- a/ssh.c +++ b/ssh.c @@ -746,7 +746,7 @@ struct ssh_tag { unsigned long incoming_data_size, outgoing_data_size, deferred_data_size; unsigned long max_data_size; int kex_in_progress; - long next_rekey; + long next_rekey, last_rekey; }; #define logevent(s) logevent(ssh->frontend, s) @@ -5211,6 +5211,7 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, * Key exchange is over. Schedule a timer for our next rekey. */ ssh->kex_in_progress = FALSE; + ssh->last_rekey = GETTICKCOUNT(); if (ssh->cfg.ssh_rekey_time != 0) ssh->next_rekey = schedule_timer(ssh->cfg.ssh_rekey_time*60*TICKSPERSEC, ssh2_timer, ssh); @@ -7213,7 +7214,7 @@ static void ssh2_timer(void *ctx, long now) { Ssh ssh = (Ssh)ctx; - if (!ssh->kex_in_progress && + if (!ssh->kex_in_progress && ssh->cfg.ssh_rekey_time != 0 && now - ssh->next_rekey >= 0) { do_ssh2_transport(ssh, "Initiating key re-exchange (timeout)", -1, NULL); @@ -7459,8 +7460,37 @@ static void ssh_free(void *handle) static void ssh_reconfig(void *handle, Config *cfg) { Ssh ssh = (Ssh) handle; + char *rekeying = NULL; + unsigned long old_max_data_size; + pinger_reconfig(ssh->pinger, &ssh->cfg, cfg); ssh_setup_portfwd(ssh, cfg); + + if (ssh->cfg.ssh_rekey_time != cfg->ssh_rekey_time && + cfg->ssh_rekey_time != 0) { + long new_next = ssh->last_rekey + cfg->ssh_rekey_time*60*TICKSPERSEC; + long now = GETTICKCOUNT(); + + if (new_next - now < 0) { + rekeying = "Initiating key re-exchange (timeout shortened)"; + } else { + ssh->next_rekey = schedule_timer(new_next - now, ssh2_timer, ssh); + } + } + + old_max_data_size = ssh->max_data_size; + ssh->max_data_size = parse_blocksize(cfg->ssh_rekey_data); + if (old_max_data_size != ssh->max_data_size && + ssh->max_data_size != 0) { + if (ssh->outgoing_data_size > ssh->max_data_size || + ssh->incoming_data_size > ssh->max_data_size) + rekeying = "Initiating key re-exchange (data limit lowered)"; + } + + if (rekeying && !ssh->kex_in_progress) { + do_ssh2_transport(ssh, rekeying, -1, NULL); + } + ssh->cfg = *cfg; /* STRUCTURE COPY */ } -- 2.11.0