Support reconfiguration of key exchange in mid-session. The fiddly
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Tue, 28 Dec 2004 14:10:32 +0000 (14:10 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Tue, 28 Dec 2004 14:10:32 +0000 (14:10 +0000)
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
ssh.c

index d57a6db..59140db 100644 (file)
--- 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 e619b59..e92eb1d 100644 (file)
--- 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 */
 }