Session rekeying support in OpenSSH

Darren Tucker dtucker at zip.com.au
Wed May 15 11:37:50 EST 2013


On Mon, May 13, 2013 at 11:40:43PM +1000, Darren Tucker wrote:
> Looks like it wouldn't be hard to add, but what problem are you trying
> to solve?

As usual it wasn't quite as simple as I initially thought, but this adds
an optional second parameter to RekeyLimit in the client and adds
RekeyLimit to the server.  Basically you should just be able to add
"RekeyLimit 1G 1h" to the config files on both the client and server.

Patch is against -current but should apply to 6.2p1 with some fuzz.

Index: clientloop.c
===================================================================
RCS file: /cvs/openssh/clientloop.c,v
retrieving revision 1.237
diff -u -p -r1.237 clientloop.c
--- clientloop.c	9 Jan 2013 04:55:51 -0000	1.237
+++ clientloop.c	15 May 2013 01:24:13 -0000
@@ -583,7 +583,7 @@ client_wait_until_can_do_something(fd_se
 {
 	struct timeval tv, *tvp;
 	int timeout_secs;
-	time_t minwait_secs = 0;
+	time_t minwait_secs = 0, server_alive_time = 0, now = time(NULL);
 	int ret;
 
 	/* Add any selections by the channel mechanism. */
@@ -632,12 +632,16 @@ client_wait_until_can_do_something(fd_se
 	 */
 
 	timeout_secs = INT_MAX; /* we use INT_MAX to mean no timeout */
-	if (options.server_alive_interval > 0 && compat20)
+	if (options.server_alive_interval > 0 && compat20) {
 		timeout_secs = options.server_alive_interval;
+		server_alive_time = now + options.server_alive_interval;
+	}
+	if (options.rekey_interval > 0 && compat20 && !rekeying)
+		timeout_secs = MIN(timeout_secs, packet_get_rekey_timeout());
 	set_control_persist_exit_time();
 	if (control_persist_exit_time > 0) {
 		timeout_secs = MIN(timeout_secs,
-			control_persist_exit_time - time(NULL));
+			control_persist_exit_time - now);
 		if (timeout_secs < 0)
 			timeout_secs = 0;
 	}
@@ -669,8 +673,15 @@ client_wait_until_can_do_something(fd_se
 		snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno));
 		buffer_append(&stderr_buffer, buf, strlen(buf));
 		quit_pending = 1;
-	} else if (ret == 0)
-		server_alive_check();
+	} else if (ret == 0) {
+		/*
+		 * Timeout.  Could have been either keepalive or rekeying.
+		 * Keepalive we check here, rekeying is checked in clientloop.
+		 */
+		if (server_alive_time != 0 && server_alive_time <= time(NULL))
+			server_alive_check();
+	}
+
 }
 
 static void
Index: monitor.c
===================================================================
RCS file: /cvs/openssh/monitor.c,v
retrieving revision 1.158
diff -u -p -r1.158 monitor.c
--- monitor.c	23 Apr 2013 05:18:10 -0000	1.158
+++ monitor.c	15 May 2013 01:24:13 -0000
@@ -1810,6 +1810,10 @@ monitor_apply_keystate(struct monitor *p
 	if (options.compression)
 		mm_init_compression(pmonitor->m_zlib);
 
+	if (options.rekey_limit || options.rekey_interval)
+		packet_set_rekey_limits((u_int32_t)options.rekey_limit,
+		    (time_t)options.rekey_interval);
+
 	/* Network I/O buffers */
 	/* XXX inefficient for large buffers, need: buffer_init_from_string */
 	buffer_clear(packet_get_input());
Index: packet.c
===================================================================
RCS file: /cvs/openssh/packet.c,v
retrieving revision 1.190
diff -u -p -r1.190 packet.c
--- packet.c	23 Apr 2013 09:24:32 -0000	1.190
+++ packet.c	15 May 2013 01:24:13 -0000
@@ -58,6 +58,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <signal.h>
+#include <time.h>
 
 #include "xmalloc.h"
 #include "buffer.h"
@@ -165,9 +166,14 @@ struct session_state {
 	Newkeys *newkeys[MODE_MAX];
 	struct packet_state p_read, p_send;
 
+	/* Volume-based rekeying */
 	u_int64_t max_blocks_in, max_blocks_out;
 	u_int32_t rekey_limit;
 
+	/* Time-based rekeying */
+	time_t rekey_interval;	/* how often in seconds */
+	time_t rekey_time;	/* time of last rekeying */
+
 	/* Session key for protocol v1 */
 	u_char ssh1_key[SSH_SESSION_KEY_LENGTH];
 	u_int ssh1_keylen;
@@ -1009,6 +1015,7 @@ packet_send2(void)
 	/* after a NEWKEYS message we can send the complete queue */
 	if (type == SSH2_MSG_NEWKEYS) {
 		active_state->rekeying = 0;
+		active_state->rekey_time = time(NULL);
 		while ((p = TAILQ_FIRST(&active_state->outgoing))) {
 			type = p->type;
 			debug("dequeue packet: %u", type);
@@ -1933,13 +1940,29 @@ packet_need_rekeying(void)
 	    (active_state->max_blocks_out &&
 	        (active_state->p_send.blocks > active_state->max_blocks_out)) ||
 	    (active_state->max_blocks_in &&
-	        (active_state->p_read.blocks > active_state->max_blocks_in));
+	        (active_state->p_read.blocks > active_state->max_blocks_in)) ||
+	    (active_state->rekey_interval != 0 && active_state->rekey_time +
+		 active_state->rekey_interval <= time(NULL));
 }
 
 void
-packet_set_rekey_limit(u_int32_t bytes)
+packet_set_rekey_limits(u_int32_t bytes, time_t seconds)
 {
+	debug3("rekey after %lld bytes, %d seconds", (long long)bytes,
+	    (int)seconds);
 	active_state->rekey_limit = bytes;
+	active_state->rekey_interval = seconds;
+	active_state->rekey_time = time(NULL);
+}
+
+time_t
+packet_get_rekey_timeout(void)
+{
+	time_t seconds;
+
+	seconds = active_state->rekey_time + active_state->rekey_interval -
+	    time(NULL);
+	return (seconds < 0 ? 0 : seconds);
 }
 
 void
Index: packet.h
===================================================================
RCS file: /cvs/openssh/packet.h,v
retrieving revision 1.60
diff -u -p -r1.60 packet.h
--- packet.h	10 Feb 2012 21:19:21 -0000	1.60
+++ packet.h	15 May 2013 01:24:13 -0000
@@ -115,7 +115,8 @@ do { \
 } while (0)
 
 int	 packet_need_rekeying(void);
-void	 packet_set_rekey_limit(u_int32_t);
+void	 packet_set_rekey_limits(u_int32_t, time_t);
+time_t	 packet_get_rekey_timeout(void);
 
 void	 packet_backup_state(void);
 void	 packet_restore_state(void);
Index: readconf.c
===================================================================
RCS file: /cvs/openssh/readconf.c,v
retrieving revision 1.177
diff -u -p -r1.177 readconf.c
--- readconf.c	23 Apr 2013 05:17:12 -0000	1.177
+++ readconf.c	15 May 2013 01:24:13 -0000
@@ -562,39 +562,54 @@ parse_yesnoask:
 	case oRekeyLimit:
 		arg = strdelim(&s);
 		if (!arg || *arg == '\0')
-			fatal("%.200s line %d: Missing argument.", filename, linenum);
-		if (arg[0] < '0' || arg[0] > '9')
-			fatal("%.200s line %d: Bad number.", filename, linenum);
-		orig = val64 = strtoll(arg, &endofnumber, 10);
-		if (arg == endofnumber)
-			fatal("%.200s line %d: Bad number.", filename, linenum);
-		switch (toupper(*endofnumber)) {
-		case '\0':
-			scale = 1;
-			break;
-		case 'K':
-			scale = 1<<10;
-			break;
-		case 'M':
-			scale = 1<<20;
-			break;
-		case 'G':
-			scale = 1<<30;
-			break;
-		default:
-			fatal("%.200s line %d: Invalid RekeyLimit suffix",
-			    filename, linenum);
+			fatal("%.200s line %d: Missing argument.", filename,
+			    linenum);
+		if (strcmp(arg, "default") == 0) {
+			val64 = 0;
+		} else {
+			if (arg[0] < '0' || arg[0] > '9')
+				fatal("%.200s line %d: Bad number.", filename,
+				    linenum);
+			orig = val64 = strtoll(arg, &endofnumber, 10);
+			if (arg == endofnumber)
+				fatal("%.200s line %d: Bad number.", filename,
+			 linenum);
+	 		switch (toupper(*endofnumber)) {
+			case '\0':
+				scale = 1;
+				break;
+			case 'K':
+				scale = 1<<10;
+				break;
+			case 'M':
+				scale = 1<<20;
+				break;
+			case 'G':
+				scale = 1<<30;
+				break;
+			default:
+				fatal("%.200s line %d: Invalid RekeyLimit "
+				    "suffix", filename, linenum);
+			}
+			val64 *= scale;
+			/* detect integer wrap and too-large limits */
+			if ((val64 / scale) != orig || val64 > UINT_MAX)
+				fatal("%.200s line %d: RekeyLimit too large",
+				    filename, linenum);
+			if (val64 != 0 && val64 < 16)
+				fatal("%.200s line %d: RekeyLimit too small",
+				    filename, linenum);
 		}
-		val64 *= scale;
-		/* detect integer wrap and too-large limits */
-		if ((val64 / scale) != orig || val64 > UINT_MAX)
-			fatal("%.200s line %d: RekeyLimit too large",
-			    filename, linenum);
-		if (val64 < 16)
-			fatal("%.200s line %d: RekeyLimit too small",
-			    filename, linenum);
 		if (*activep && options->rekey_limit == -1)
 			options->rekey_limit = (u_int32_t)val64;
+		if (s != NULL) { /* optional rekey interval present */
+			if (strcmp(s, "none") == 0) {
+				(void)strdelim(&s);	/* discard */
+				break;
+			}
+			intptr = &options->rekey_interval;
+			goto parse_time;
+		}
 		break;
 
 	case oIdentityFile:
@@ -1202,6 +1217,7 @@ initialize_options(Options * options)
 	options->no_host_authentication_for_localhost = - 1;
 	options->identities_only = - 1;
 	options->rekey_limit = - 1;
+	options->rekey_interval = -1;
 	options->verify_host_key_dns = -1;
 	options->server_alive_interval = -1;
 	options->server_alive_count_max = -1;
@@ -1337,6 +1353,8 @@ fill_default_options(Options * options)
 		options->enable_ssh_keysign = 0;
 	if (options->rekey_limit == -1)
 		options->rekey_limit = 0;
+	if (options->rekey_interval == -1)
+		options->rekey_interval = 0;
 	if (options->verify_host_key_dns == -1)
 		options->verify_host_key_dns = 0;
 	if (options->server_alive_interval == -1)
Index: readconf.h
===================================================================
RCS file: /cvs/openssh/readconf.h,v
retrieving revision 1.85
diff -u -p -r1.85 readconf.h
--- readconf.h	5 Apr 2013 00:18:36 -0000	1.85
+++ readconf.h	15 May 2013 01:24:13 -0000
@@ -110,6 +110,7 @@ typedef struct {
 
 	int	enable_ssh_keysign;
 	int64_t rekey_limit;
+	int	rekey_interval;
 	int	no_host_authentication_for_localhost;
 	int	identities_only;
 	int	server_alive_interval;
Index: servconf.c
===================================================================
RCS file: /cvs/openssh/servconf.c,v
retrieving revision 1.231
diff -u -p -r1.231 servconf.c
--- servconf.c	12 Feb 2013 00:02:08 -0000	1.231
+++ servconf.c	15 May 2013 01:24:13 -0000
@@ -20,6 +20,7 @@
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
 
+#include <ctype.h>
 #include <netdb.h>
 #include <pwd.h>
 #include <stdio.h>
@@ -110,6 +111,8 @@ initialize_server_options(ServerOptions 
 	options->permit_user_env = -1;
 	options->use_login = -1;
 	options->compression = -1;
+	options->rekey_limit = -1;
+	options->rekey_interval = -1;
 	options->allow_tcp_forwarding = -1;
 	options->allow_agent_forwarding = -1;
 	options->num_allow_users = 0;
@@ -249,6 +252,10 @@ fill_default_server_options(ServerOption
 		options->use_login = 0;
 	if (options->compression == -1)
 		options->compression = COMP_DELAYED;
+	if (options->rekey_limit == -1)
+		options->rekey_limit = 0;
+	if (options->rekey_interval == -1)
+		options->rekey_interval = 0;
 	if (options->allow_tcp_forwarding == -1)
 		options->allow_tcp_forwarding = FORWARD_ALLOW;
 	if (options->allow_agent_forwarding == -1)
@@ -320,7 +327,7 @@ typedef enum {
 	sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
 	sStrictModes, sEmptyPasswd, sTCPKeepAlive,
 	sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
-	sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
+	sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
 	sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
 	sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem,
 	sMaxStartups, sMaxAuthTries, sMaxSessions,
@@ -422,6 +429,7 @@ static struct {
 	{ "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
 	{ "uselogin", sUseLogin, SSHCFG_GLOBAL },
 	{ "compression", sCompression, SSHCFG_GLOBAL },
+	{ "rekeylimit", sRekeyLimit, SSHCFG_ALL },
 	{ "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
 	{ "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL },	/* obsolete alias */
 	{ "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
@@ -800,14 +808,15 @@ process_server_config_line(ServerOptions
     const char *filename, int linenum, int *activep,
     struct connection_info *connectinfo)
 {
-	char *cp, **charptr, *arg, *p;
+	char *cp, **charptr, *arg, *p, *endofnumber;
 	int cmdline = 0, *intptr, value, value2, n;
 	SyslogFacility *log_facility_ptr;
 	LogLevel *log_level_ptr;
 	ServerOpCodes opcode;
-	int port;
+	int port, scale;
 	u_int i, flags = 0;
 	size_t len;
+	long long orig, val64;
 	const struct multistate *multistate_ptr;
 
 	cp = line;
@@ -1118,6 +1127,59 @@ process_server_config_line(ServerOptions
 		multistate_ptr = multistate_compression;
 		goto parse_multistate;
 
+	case sRekeyLimit:
+		arg = strdelim(&cp);
+		if (!arg || *arg == '\0')
+			fatal("%.200s line %d: Missing argument.", filename,
+			    linenum);
+		if (strcmp(arg, "default") == 0) {
+			val64 = 0;
+		} else {
+			if (arg[0] < '0' || arg[0] > '9')
+				fatal("%.200s line %d: Bad number.", filename,
+				    linenum);
+			orig = val64 = strtoll(arg, &endofnumber, 10);
+			if (arg == endofnumber)
+				fatal("%.200s line %d: Bad number.", filename,
+			 linenum);
+	 		switch (toupper(*endofnumber)) {
+			case '\0':
+				scale = 1;
+				break;
+			case 'K':
+				scale = 1<<10;
+				break;
+			case 'M':
+				scale = 1<<20;
+				break;
+			case 'G':
+				scale = 1<<30;
+				break;
+			default:
+				fatal("%.200s line %d: Invalid RekeyLimit "
+				    "suffix", filename, linenum);
+			}
+			val64 *= scale;
+			/* detect integer wrap and too-large limits */
+			if ((val64 / scale) != orig || val64 > UINT_MAX)
+				fatal("%.200s line %d: RekeyLimit too large",
+				    filename, linenum);
+			if (val64 != 0 && val64 < 16)
+				fatal("%.200s line %d: RekeyLimit too small",
+				    filename, linenum);
+		}
+		if (*activep && options->rekey_limit == -1)
+			options->rekey_limit = (u_int32_t)val64;
+		if (cp != NULL) { /* optional rekey interval present */
+			if (strcmp(cp, "none") == 0) {
+				(void)strdelim(&cp);	/* discard */
+				break;
+			}
+			intptr = &options->rekey_interval;
+			goto parse_time;
+		}
+		break;
+
 	case sGatewayPorts:
 		intptr = &options->gateway_ports;
 		multistate_ptr = multistate_gatewayports;
@@ -1718,6 +1780,8 @@ copy_set_server_options(ServerOptions *d
 	M_CP_INTOPT(max_authtries);
 	M_CP_INTOPT(ip_qos_interactive);
 	M_CP_INTOPT(ip_qos_bulk);
+	M_CP_INTOPT(rekey_limit);
+	M_CP_INTOPT(rekey_interval);
 
 	/* See comment in servconf.h */
 	COPY_MATCH_STRING_OPTS();
Index: servconf.h
===================================================================
RCS file: /cvs/openssh/servconf.h,v
retrieving revision 1.99
diff -u -p -r1.99 servconf.h
--- servconf.h	9 Jan 2013 04:56:45 -0000	1.99
+++ servconf.h	15 May 2013 01:24:13 -0000
@@ -176,6 +176,9 @@ typedef struct {
 	char   *authorized_keys_command;
 	char   *authorized_keys_command_user;
 
+	int64_t rekey_limit;
+	int	rekey_interval;
+
 	char   *version_addendum;	/* Appended to SSH banner */
 
 	u_int	num_auth_methods;
Index: serverloop.c
===================================================================
RCS file: /cvs/openssh/serverloop.c,v
retrieving revision 1.173
diff -u -p -r1.173 serverloop.c
--- serverloop.c	7 Dec 2012 02:07:47 -0000	1.173
+++ serverloop.c	15 May 2013 01:24:13 -0000
@@ -826,6 +826,7 @@ server_loop2(Authctxt *authctxt)
 {
 	fd_set *readset = NULL, *writeset = NULL;
 	int rekeying = 0, max_fd, nalloc = 0;
+	u_int rekey_timeout_ms = 0;
 
 	debug("Entering interactive session for SSH2.");
 
@@ -854,8 +855,13 @@ server_loop2(Authctxt *authctxt)
 
 		if (!rekeying && packet_not_very_much_data_to_write())
 			channel_output_poll();
+		if (options.rekey_interval > 0 && compat20 && !rekeying)
+			rekey_timeout_ms = packet_get_rekey_timeout() * 1000;
+		else
+			rekey_timeout_ms = 0;
+
 		wait_until_can_do_something(&readset, &writeset, &max_fd,
-		    &nalloc, 0);
+		    &nalloc, rekey_timeout_ms);
 
 		if (received_sigterm) {
 			logit("Exiting on signal %d", (int)received_sigterm);
@@ -870,6 +876,7 @@ server_loop2(Authctxt *authctxt)
 				debug("need rekeying");
 				xxx_kex->done = 0;
 				kex_send_kexinit(xxx_kex);
+				packet_write_wait();
 			}
 		}
 		process_input(readset);
Index: ssh_config
===================================================================
RCS file: /cvs/openssh/ssh_config,v
retrieving revision 1.28
diff -u -p -r1.28 ssh_config
--- ssh_config	12 Jan 2010 08:40:27 -0000	1.28
+++ ssh_config	15 May 2013 01:24:13 -0000
@@ -45,3 +45,4 @@
 #   PermitLocalCommand no
 #   VisualHostKey no
 #   ProxyCommand ssh -q -W %h:%p gateway.example.com
+#   RekeyLimit 1G 1h
Index: ssh_config.5
===================================================================
RCS file: /cvs/openssh/ssh_config.5,v
retrieving revision 1.161
diff -u -p -r1.161 ssh_config.5
--- ssh_config.5	9 Jan 2013 05:12:19 -0000	1.161
+++ ssh_config.5	15 May 2013 01:24:14 -0000
@@ -931,8 +931,9 @@ The default is
 This option applies to protocol version 2 only.
 .It Cm RekeyLimit
 Specifies the maximum amount of data that may be transmitted before the
-session key is renegotiated.
-The argument is the number of bytes, with an optional suffix of
+session key is renegotiated, optionally followed a maximum amount of
+time that may pass before the session key is renegotiated.
+The first argument is specified in bytes and may have a suffix of
 .Sq K ,
 .Sq M ,
 or
@@ -943,6 +944,17 @@ The default is between
 and
 .Sq 4G ,
 depending on the cipher.
+The optional second value is specified in seconds and may use any of the
+units documented in the
+.Sx TIME FORMATS
+section of
+.Xr sshd_config 5 .
+The default value for
+.Cm RekeyLimit
+is
+.Dq default none ,
+which means that rekeying is performed after the cipher's default amount
+of data has been sent or received and no time based rekeying is done.
 This option applies to protocol version 2 only.
 .It Cm RemoteForward
 Specifies that a TCP port on the remote machine be forwarded over
Index: sshconnect2.c
===================================================================
RCS file: /cvs/openssh/sshconnect2.c,v
retrieving revision 1.187
diff -u -p -r1.187 sshconnect2.c
--- sshconnect2.c	23 Apr 2013 05:18:52 -0000	1.187
+++ sshconnect2.c	15 May 2013 01:24:14 -0000
@@ -197,8 +197,9 @@ ssh_kex2(char *host, struct sockaddr *ho
 	if (options.kex_algorithms != NULL)
 		myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
 
-	if (options.rekey_limit)
-		packet_set_rekey_limit((u_int32_t)options.rekey_limit);
+	if (options.rekey_limit || options.rekey_interval)
+		packet_set_rekey_limits((u_int32_t)options.rekey_limit,
+		    (time_t)options.rekey_interval);
 
 	/* start key exchange */
 	kex = kex_setup(myproposal);
Index: sshd.c
===================================================================
RCS file: /cvs/openssh/sshd.c,v
retrieving revision 1.422
diff -u -p -r1.422 sshd.c
--- sshd.c	23 Apr 2013 05:21:07 -0000	1.422
+++ sshd.c	15 May 2013 01:24:14 -0000
@@ -2364,6 +2364,10 @@ do_ssh2_kex(void)
 	if (options.kex_algorithms != NULL)
 		myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
 
+	if (options.rekey_limit || options.rekey_interval)
+		packet_set_rekey_limits((u_int32_t)options.rekey_limit,
+		    (time_t)options.rekey_interval);
+
 	myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
 
 	/* start key exchange */
Index: sshd_config
===================================================================
RCS file: /cvs/openssh/sshd_config,v
retrieving revision 1.91
diff -u -p -r1.91 sshd_config
--- sshd_config	12 Feb 2013 00:02:09 -0000	1.91
+++ sshd_config	15 May 2013 01:24:14 -0000
@@ -29,6 +29,9 @@
 #KeyRegenerationInterval 1h
 #ServerKeyBits 1024
 
+# Ciphers and keying
+#RekeyLimit default none
+
 # Logging
 # obsoletes QuietMode and FascistLogging
 #SyslogFacility AUTH
Index: sshd_config.5
===================================================================
RCS file: /cvs/openssh/sshd_config.5,v
retrieving revision 1.165
diff -u -p -r1.165 sshd_config.5
--- sshd_config.5	23 Apr 2013 05:23:08 -0000	1.165
+++ sshd_config.5	15 May 2013 01:24:14 -0000
@@ -814,6 +814,7 @@ Available keywords are
 .Cm PermitRootLogin ,
 .Cm PermitTunnel ,
 .Cm PubkeyAuthentication ,
+.Cm RekeyLimit ,
 .Cm RhostsRSAAuthentication ,
 .Cm RSAAuthentication ,
 .Cm X11DisplayOffset ,
@@ -1008,6 +1009,33 @@ Specifies whether public key authenticat
 The default is
 .Dq yes .
 Note that this option applies to protocol version 2 only.
+.It Cm RekeyLimit
+Specifies the maximum amount of data that may be transmitted before the
+session key is renegotiated, optionally followed a maximum amount of
+time that may pass before the session key is renegotiated.
+The first argument is specified in bytes and may have a suffix of
+.Sq K ,
+.Sq M ,
+or
+.Sq G
+to indicate Kilobytes, Megabytes, or Gigabytes, respectively.
+The default is between
+.Sq 1G
+and
+.Sq 4G ,
+depending on the cipher.
+The optional second value is specified in seconds and may use any of the
+units documented in the
+.Sx TIME FORMATS
+section of
+.Xr sshd_config 5 .
+The default value for
+.Cm RekeyLimit
+is
+.Dq default none ,
+which means that rekeying is performed after the cipher's default amount
+of data has been sent or received and no time based rekeying is done.
+This option applies to protocol version 2 only.
 .It Cm RevokedKeys
 Specifies revoked public keys.
 Keys listed in this file will be refused for public key authentication.

-- 
Darren Tucker (dtucker at zip.com.au)
GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4  37C9 C982 80C7 8FF4 FA69
    Good judgement comes with experience. Unfortunately, the experience
usually comes from bad judgement.


More information about the openssh-unix-dev mailing list