1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 09:27:59 +00:00

Basic configurability for client-initiated rekeys.

[originally from svn r5027]
This commit is contained in:
Jacob Nevins 2004-12-24 13:39:32 +00:00
parent d0da973746
commit 30896d650e
9 changed files with 116 additions and 23 deletions

View File

@ -1580,11 +1580,23 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
kexlist_handler, P(NULL));
c->listbox.height = 5;
#if 0
s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
"Options controlling key re-exchange");
/* FIXME: at least time and data size */
#endif
/* 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/Auth panel.

View File

@ -2152,22 +2152,56 @@ If the first algorithm PuTTY finds is below the \q{warn below here}
line, you will see a warning box when you make the connection, similar
to that for cipher selection (see \k{config-ssh-encryption}).
\# [Repeat key exchange bumph when config is added:] If the session
key negotiated at connection startup is used too much or for too long,
it may become feasible to mount attacks against the SSH connection.
Therefore, the SSH protocol specifies that a new key exchange should
take place every so often.
\S{config-ssh-kex-rekey} Repeat key exchange
\# While this renegotiation is taking place, no data can pass through
\cfg{winhelp-topic}{ssh.kex.repeat}
If the session key negotiated at connection startup is used too much
or for too long, it may become feasible to mount attacks against the
SSH connection. Therefore, the SSH-2 protocol specifies that a new key
exchange should take place every so often; this can be initiated by
either the client or the server.
While this renegotiation is taking place, no data can pass through
the SSH connection, so it may appear to \q{freeze}. (The occurrence of
repeat key exchange is noted in the Event Log; see
\k{using-eventlog}.) Usually the same algorithm is used as at the
start of the connection, with a similar overhead.
\# [When options are added to frob how often this happens, we should
hardcode the values recommended by the drafts -- 1 hour, 1GB -- in
this documentation, in case PuTTY's defaults are obscured by Default
Settings etc. Assuming we think they're good advice, that is.]
These options control how often PuTTY will initiate a repeat key
exchange (\q{rekey}). You can also force a key exchange at any time
from the Special Commands menu (see \k{using-specials}).
\# FIXME: do we have any additions to the SSH-2 drafts' advice on
these values? Do we want to enforce any limits?
\b \q{Max minutes before rekey} specifies the amount of time that is
allowed to elapse before a rekey is initiated. If this is set to zero,
PuTTY will not rekey due to elapsed time. The SSH-2 protocol
specification recommends a timeout of at most 60 minutes.
\b \q{Max data before rekey} specifies the amount of data (in bytes)
that is permitted to flow in either direction before a rekey is
initiated. If this is set to zero, PuTTY will not rekey due to
transferred data. The SSH-2 protocol specification recommends a limit
of at most 1 gigabyte.
\lcont{
As well as specifying a value in bytes, the following shorthand can be
used:
\b \cq{1k} specifies 1 kilobyte (1024 bytes).
\b \cq{1M} specifies 1 megabyte (1024 kilobytes).
\b \cq{1G} specifies 1 gigabyte (1024 megabytes).
}
PuTTY can be prevented from initiating a rekey entirely by setting
both of these values to zero. (Note, however, that the SSH server may
still initiate rekeys.)
\H{config-ssh-auth} The Auth panel

View File

@ -185,8 +185,8 @@ Should have no effect.
\lcont{
Only available in SSH-2. Forces a repeat key exchange immediately (and
resets associated timers and counters). \#{For more information about
repeat key exchanges, see \k{FIXME}.}
resets associated timers and counters). For more information about
repeat key exchanges, see \k{config-ssh-kex-rekey}.
}
\b \I{Break, SSH special command}Break

33
misc.c
View File

@ -9,6 +9,39 @@
#include <assert.h>
#include "putty.h"
/*
* Parse a string block size specification. This is approximately a
* subset of the block size specs supported by GNU fileutils:
* "nk" = n kilobytes
* "nM" = n megabytes
* "nG" = n gigabytes
* All numbers are decimal, and suffixes refer to powers of two.
* Case-insensitive.
*/
unsigned long parse_blocksize(const char *bs)
{
char *suf;
unsigned long r = strtoul(bs, &suf, 10);
if (*suf != '\0') {
while (isspace(*suf)) suf++;
switch (*suf) {
case 'k': case 'K':
r *= 1024ul;
break;
case 'm': case 'M':
r *= 1024ul * 1024ul;
break;
case 'g': case 'G':
r *= 1024ul * 1024ul * 1024ul;
break;
case '\0':
default:
break;
}
}
return r;
}
/* ----------------------------------------------------------------------
* String handling routines.
*/

2
misc.h
View File

@ -16,6 +16,8 @@
typedef struct Filename Filename;
typedef struct FontSpec FontSpec;
unsigned long parse_blocksize(const char *bs);
char *dupstr(const char *s);
char *dupcat(const char *s1, ...);
char *dupprintf(const char *fmt, ...);

View File

@ -400,6 +400,8 @@ struct config_tag {
int nopty;
int compression;
int ssh_kexlist[KEX_MAX];
int ssh_rekey_time; /* in minutes */
char ssh_rekey_data[16];
int agentfwd;
int change_username; /* allow username switching in SSH2 */
int ssh_cipherlist[CIPHER_MAX];

View File

@ -236,6 +236,8 @@ void save_open_settings(void *sesskey, int do_host, Config *cfg)
wprefs(sesskey, "Cipher", ciphernames, CIPHER_MAX,
cfg->ssh_cipherlist);
wprefs(sesskey, "KEX", kexnames, KEX_MAX, cfg->ssh_kexlist);
write_setting_i(sesskey, "RekeyTime", cfg->ssh_rekey_time);
write_setting_s(sesskey, "RekeyBytes", cfg->ssh_rekey_data);
write_setting_i(sesskey, "AuthTIS", cfg->try_tis_auth);
write_setting_i(sesskey, "AuthKI", cfg->try_ki_auth);
write_setting_i(sesskey, "SshNoShell", cfg->ssh_no_shell);
@ -514,6 +516,9 @@ void load_open_settings(void *sesskey, int do_host, Config *cfg)
gprefs(sesskey, "KEX", default_kexes,
kexnames, KEX_MAX, cfg->ssh_kexlist);
}
gppi(sesskey, "RekeyTime", 60, &cfg->ssh_rekey_time);
gpps(sesskey, "RekeyBytes", "1G", cfg->ssh_rekey_data,
sizeof(cfg->ssh_rekey_data));
gppi(sesskey, "SshProt", 2, &cfg->sshprot);
gppi(sesskey, "SSH2DES", 0, &cfg->ssh2_des_cbc);
gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth);

20
ssh.c
View File

@ -708,13 +708,11 @@ struct ssh_tag {
* size-based rekeys.
*/
unsigned long incoming_data_size, outgoing_data_size, deferred_data_size;
unsigned long max_data_size;
int kex_in_progress;
long next_rekey;
};
#define MAX_DATA_BEFORE_REKEY (0x40000000UL)
#define REKEY_TIMEOUT (3600 * TICKSPERSEC)
#define logevent(s) logevent(ssh->frontend, s)
/* logevent, only printf-formatted. */
@ -1653,7 +1651,8 @@ static void ssh2_pkt_send_noqueue(Ssh ssh, struct Packet *pkt)
ssh->outgoing_data_size += pkt->encrypted_len;
if (!ssh->kex_in_progress &&
ssh->outgoing_data_size > MAX_DATA_BEFORE_REKEY)
ssh->max_data_size != 0 &&
ssh->outgoing_data_size > ssh->max_data_size)
do_ssh2_transport(ssh, "Initiating key re-exchange "
"(too much data sent)", -1, NULL);
@ -1743,7 +1742,8 @@ static void ssh_pkt_defersend(Ssh ssh)
ssh->outgoing_data_size += ssh->deferred_data_size;
if (!ssh->kex_in_progress &&
ssh->outgoing_data_size > MAX_DATA_BEFORE_REKEY)
ssh->max_data_size != 0 &&
ssh->outgoing_data_size > ssh->max_data_size)
do_ssh2_transport(ssh, "Initiating key re-exchange "
"(too much data sent)", -1, NULL);
ssh->deferred_data_size = 0;
@ -4915,8 +4915,10 @@ 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->next_rekey = schedule_timer(REKEY_TIMEOUT, ssh2_timer, ssh);
if (ssh->cfg.ssh_rekey_time != 0)
ssh->next_rekey = schedule_timer(ssh->cfg.ssh_rekey_time*60*TICKSPERSEC,
ssh2_timer, ssh);
/*
* If this is the first key exchange phase, we must pass the
* SSH2_MSG_NEWKEYS packet to the next layer, not because it
@ -7087,7 +7089,8 @@ static void ssh2_protocol(Ssh ssh, unsigned char *in, int inlen,
if (pktin) {
ssh->incoming_data_size += pktin->encrypted_len;
if (!ssh->kex_in_progress &&
ssh->incoming_data_size > MAX_DATA_BEFORE_REKEY)
ssh->max_data_size != 0 &&
ssh->incoming_data_size > ssh->max_data_size)
do_ssh2_transport(ssh, "Initiating key re-exchange "
"(too much data received)", -1, NULL);
}
@ -7209,6 +7212,7 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle,
ssh->incoming_data_size = ssh->outgoing_data_size =
ssh->deferred_data_size = 0L;
ssh->max_data_size = parse_blocksize(ssh->cfg.ssh_rekey_data);
ssh->kex_in_progress = FALSE;
p = connect_to_host(ssh, host, port, realhost, nodelay, keepalive);

View File

@ -87,6 +87,7 @@
#define WINHELP_CTX_ssh_command "ssh.command"
#define WINHELP_CTX_ssh_compress "ssh.compress"
#define WINHELP_CTX_ssh_kexlist "ssh.kex.order"
#define WINHELP_CTX_ssh_kex_repeat "ssh.kex.repeat"
#define WINHELP_CTX_ssh_auth_privkey "ssh.auth.privkey"
#define WINHELP_CTX_ssh_auth_agentfwd "ssh.auth.agentfwd"
#define WINHELP_CTX_ssh_auth_changeuser "ssh.auth.changeuser"