mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +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));
|
kexlist_handler, P(NULL));
|
||||||
c->listbox.height = 5;
|
c->listbox.height = 5;
|
||||||
|
|
||||||
#if 0
|
|
||||||
s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
|
s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
|
||||||
"Options controlling key re-exchange");
|
"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.
|
* 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
|
line, you will see a warning box when you make the connection, similar
|
||||||
to that for cipher selection (see \k{config-ssh-encryption}).
|
to that for cipher selection (see \k{config-ssh-encryption}).
|
||||||
|
|
||||||
\# [Repeat key exchange bumph when config is added:] If the session
|
\S{config-ssh-kex-rekey} Repeat key exchange
|
||||||
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.
|
|
||||||
|
|
||||||
\# 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
|
the SSH connection, so it may appear to \q{freeze}. (The occurrence of
|
||||||
repeat key exchange is noted in the Event Log; see
|
repeat key exchange is noted in the Event Log; see
|
||||||
\k{using-eventlog}.) Usually the same algorithm is used as at the
|
\k{using-eventlog}.) Usually the same algorithm is used as at the
|
||||||
start of the connection, with a similar overhead.
|
start of the connection, with a similar overhead.
|
||||||
|
|
||||||
\# [When options are added to frob how often this happens, we should
|
These options control how often PuTTY will initiate a repeat key
|
||||||
hardcode the values recommended by the drafts -- 1 hour, 1GB -- in
|
exchange (\q{rekey}). You can also force a key exchange at any time
|
||||||
this documentation, in case PuTTY's defaults are obscured by Default
|
from the Special Commands menu (see \k{using-specials}).
|
||||||
Settings etc. Assuming we think they're good advice, that is.]
|
|
||||||
|
\# 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
|
\H{config-ssh-auth} The Auth panel
|
||||||
|
|
||||||
|
@ -185,8 +185,8 @@ Should have no effect.
|
|||||||
|
|
||||||
\lcont{
|
\lcont{
|
||||||
Only available in SSH-2. Forces a repeat key exchange immediately (and
|
Only available in SSH-2. Forces a repeat key exchange immediately (and
|
||||||
resets associated timers and counters). \#{For more information about
|
resets associated timers and counters). For more information about
|
||||||
repeat key exchanges, see \k{FIXME}.}
|
repeat key exchanges, see \k{config-ssh-kex-rekey}.
|
||||||
}
|
}
|
||||||
|
|
||||||
\b \I{Break, SSH special command}Break
|
\b \I{Break, SSH special command}Break
|
||||||
|
33
misc.c
33
misc.c
@ -9,6 +9,39 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "putty.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.
|
* String handling routines.
|
||||||
*/
|
*/
|
||||||
|
2
misc.h
2
misc.h
@ -16,6 +16,8 @@
|
|||||||
typedef struct Filename Filename;
|
typedef struct Filename Filename;
|
||||||
typedef struct FontSpec FontSpec;
|
typedef struct FontSpec FontSpec;
|
||||||
|
|
||||||
|
unsigned long parse_blocksize(const char *bs);
|
||||||
|
|
||||||
char *dupstr(const char *s);
|
char *dupstr(const char *s);
|
||||||
char *dupcat(const char *s1, ...);
|
char *dupcat(const char *s1, ...);
|
||||||
char *dupprintf(const char *fmt, ...);
|
char *dupprintf(const char *fmt, ...);
|
||||||
|
2
putty.h
2
putty.h
@ -400,6 +400,8 @@ struct config_tag {
|
|||||||
int nopty;
|
int nopty;
|
||||||
int compression;
|
int compression;
|
||||||
int ssh_kexlist[KEX_MAX];
|
int ssh_kexlist[KEX_MAX];
|
||||||
|
int ssh_rekey_time; /* in minutes */
|
||||||
|
char ssh_rekey_data[16];
|
||||||
int agentfwd;
|
int agentfwd;
|
||||||
int change_username; /* allow username switching in SSH2 */
|
int change_username; /* allow username switching in SSH2 */
|
||||||
int ssh_cipherlist[CIPHER_MAX];
|
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,
|
wprefs(sesskey, "Cipher", ciphernames, CIPHER_MAX,
|
||||||
cfg->ssh_cipherlist);
|
cfg->ssh_cipherlist);
|
||||||
wprefs(sesskey, "KEX", kexnames, KEX_MAX, cfg->ssh_kexlist);
|
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, "AuthTIS", cfg->try_tis_auth);
|
||||||
write_setting_i(sesskey, "AuthKI", cfg->try_ki_auth);
|
write_setting_i(sesskey, "AuthKI", cfg->try_ki_auth);
|
||||||
write_setting_i(sesskey, "SshNoShell", cfg->ssh_no_shell);
|
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,
|
gprefs(sesskey, "KEX", default_kexes,
|
||||||
kexnames, KEX_MAX, cfg->ssh_kexlist);
|
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, "SshProt", 2, &cfg->sshprot);
|
||||||
gppi(sesskey, "SSH2DES", 0, &cfg->ssh2_des_cbc);
|
gppi(sesskey, "SSH2DES", 0, &cfg->ssh2_des_cbc);
|
||||||
gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth);
|
gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth);
|
||||||
|
20
ssh.c
20
ssh.c
@ -708,13 +708,11 @@ struct ssh_tag {
|
|||||||
* size-based rekeys.
|
* size-based rekeys.
|
||||||
*/
|
*/
|
||||||
unsigned long incoming_data_size, outgoing_data_size, deferred_data_size;
|
unsigned long incoming_data_size, outgoing_data_size, deferred_data_size;
|
||||||
|
unsigned long max_data_size;
|
||||||
int kex_in_progress;
|
int kex_in_progress;
|
||||||
long next_rekey;
|
long next_rekey;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_DATA_BEFORE_REKEY (0x40000000UL)
|
|
||||||
#define REKEY_TIMEOUT (3600 * TICKSPERSEC)
|
|
||||||
|
|
||||||
#define logevent(s) logevent(ssh->frontend, s)
|
#define logevent(s) logevent(ssh->frontend, s)
|
||||||
|
|
||||||
/* logevent, only printf-formatted. */
|
/* 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;
|
ssh->outgoing_data_size += pkt->encrypted_len;
|
||||||
if (!ssh->kex_in_progress &&
|
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 "
|
do_ssh2_transport(ssh, "Initiating key re-exchange "
|
||||||
"(too much data sent)", -1, NULL);
|
"(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;
|
ssh->outgoing_data_size += ssh->deferred_data_size;
|
||||||
if (!ssh->kex_in_progress &&
|
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 "
|
do_ssh2_transport(ssh, "Initiating key re-exchange "
|
||||||
"(too much data sent)", -1, NULL);
|
"(too much data sent)", -1, NULL);
|
||||||
ssh->deferred_data_size = 0;
|
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.
|
* Key exchange is over. Schedule a timer for our next rekey.
|
||||||
*/
|
*/
|
||||||
ssh->kex_in_progress = FALSE;
|
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
|
* If this is the first key exchange phase, we must pass the
|
||||||
* SSH2_MSG_NEWKEYS packet to the next layer, not because it
|
* 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) {
|
if (pktin) {
|
||||||
ssh->incoming_data_size += pktin->encrypted_len;
|
ssh->incoming_data_size += pktin->encrypted_len;
|
||||||
if (!ssh->kex_in_progress &&
|
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 "
|
do_ssh2_transport(ssh, "Initiating key re-exchange "
|
||||||
"(too much data received)", -1, NULL);
|
"(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->incoming_data_size = ssh->outgoing_data_size =
|
||||||
ssh->deferred_data_size = 0L;
|
ssh->deferred_data_size = 0L;
|
||||||
|
ssh->max_data_size = parse_blocksize(ssh->cfg.ssh_rekey_data);
|
||||||
ssh->kex_in_progress = FALSE;
|
ssh->kex_in_progress = FALSE;
|
||||||
|
|
||||||
p = connect_to_host(ssh, host, port, realhost, nodelay, keepalive);
|
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_command "ssh.command"
|
||||||
#define WINHELP_CTX_ssh_compress "ssh.compress"
|
#define WINHELP_CTX_ssh_compress "ssh.compress"
|
||||||
#define WINHELP_CTX_ssh_kexlist "ssh.kex.order"
|
#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_privkey "ssh.auth.privkey"
|
||||||
#define WINHELP_CTX_ssh_auth_agentfwd "ssh.auth.agentfwd"
|
#define WINHELP_CTX_ssh_auth_agentfwd "ssh.auth.agentfwd"
|
||||||
#define WINHELP_CTX_ssh_auth_changeuser "ssh.auth.changeuser"
|
#define WINHELP_CTX_ssh_auth_changeuser "ssh.auth.changeuser"
|
||||||
|
Loading…
Reference in New Issue
Block a user