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:
parent
d0da973746
commit
30896d650e
18
config.c
18
config.c
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
33
misc.c
@ -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
2
misc.h
@ -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, ...);
|
||||
|
2
putty.h
2
putty.h
@ -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];
|
||||
|
@ -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
20
ssh.c
@ -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);
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user