| Message ID | 20171111134758.7373-1-steffan@karger.me |
|---|---|
| State | Superseded |
| Headers | show |
| Series | [Openvpn-devel,v3] Add per session pseudo-random jitter to --reneg-sec intervals | expand |
On Sat, Nov 11, 2017 at 02:47:58PM +0100, Steffan Karger wrote: > --- a/src/openvpn/init.c > +++ b/src/openvpn/init.c > @@ -2693,7 +2693,20 @@ do_init_crypto_tls(struct context *c, const unsigned int flags) > to.packet_timeout = options->tls_timeout; > to.renegotiate_bytes = options->renegotiate_bytes; > to.renegotiate_packets = options->renegotiate_packets; > - to.renegotiate_seconds = options->renegotiate_seconds; > + if (options->renegotiate_seconds_min < 0) > + { > + /* Add 10% jitter to the reneg-sec of each connection by default */ Maybe change that to "of each server connection". > + int auto_jitter = options->mode != MODE_SERVER ? 0 : > + get_random() % max_int(options->renegotiate_seconds / 10, 1); > + to.renegotiate_seconds = options->renegotiate_seconds - auto_jitter; > + } > + else > + { > + /* Add user-specific jitter to the renge-sec of each connection */ s/renge/reneg/ > + to.renegotiate_seconds = options->renegotiate_seconds - > + (get_random() % max_int(options->renegotiate_seconds > + - options->renegotiate_seconds_min, 1)); > + } > to.single_session = options->single_session; > to.mode = options->mode; > to.pull = options->pull; Regards Simon
Hi Steffan, Thanks for taking the time to improve this! Regards, Simon > From: Simon Matter <simon.matter@invoca.ch> > > While we were suffering from the "TLS Renegotiation Slowdown" bug here > https://community.openvpn.net/openvpn/ticket/854 we realized that there is > still room for improvement in our use case. > > It appears that TLS renegotiation is getting more and more expensive in > terms of CPU cycles with recent changes for more security. To make things > worse, we realized that most renegotiation procedures took place at almost > the same time and increased the CPU load too much during these periods. > That's especially true on large, multi-instance openvpn setups. > > I've created attached patch to add a per session pseudo-random component > to > the --reneg-sec intervals so that renegotiation is evenly spread over > time. > It is configured by simply adding a second value to --reneg-sec as > described in the --help text: > > --reneg-sec max [min] : Renegotiate data chan. key after at most max > (default=3600) and at least min (default 90% of max on > servers and equal to max on clients). > > The jitter is only enabled by default on servers, because the actual reneg > time is min(reneg_server, reneg_client). Introducing jitter at both ends > would bias the actual reneg time to the min value. > > Note that the patch also slightly changes the log output to show the sec > value in the same way as the bytes/pkts values: > > TLS: soft reset sec=3084/3084 bytes=279897/-1 pkts=1370/0 > > The idea and first versions of this patch are from Simon Matter. Steffan > Karger later incorporated the mailing list comments into this patch. So > credits go to Simon, and all bugs are Steffan's fault ;-) > > Signed-off-by: Simon Matter <simon.matter@invoca.ch> > Signed-off-by: Steffan Karger <steffan@karger.me> > --- > v3: incorporate comments from openvpn-devel@, don't add jitter by > default on the client side. > > doc/openvpn.8 | 26 +++++++++++++++++++++----- > src/openvpn/init.c | 15 ++++++++++++++- > src/openvpn/options.c | 11 +++++++++-- > src/openvpn/options.h | 1 + > src/openvpn/ssl.c | 6 +++--- > 5 files changed, 48 insertions(+), 11 deletions(-) > > diff --git a/doc/openvpn.8 b/doc/openvpn.8 > index a4189ac2..eb5258f9 100644 > --- a/doc/openvpn.8 > +++ b/doc/openvpn.8 > @@ -33,7 +33,7 @@ > .\" .ft -- normal face > .\" .in +|-{n} -- indent > .\" > -.TH openvpn 8 "25 August 2016" > +.TH openvpn 8 "04 April 2017" > .\"********************************************************* > .SH NAME > openvpn \- secure IP tunnel daemon. > @@ -4957,10 +4957,26 @@ Renegotiate data channel key after > packets sent and received (disabled by default). > .\"********************************************************* > .TP > -.B \-\-reneg\-sec n > -Renegotiate data channel key after > -.B n > -seconds (default=3600). > +.B \-\-reneg\-sec max [min] > +Renegotiate data channel key after at most > +.B max > +seconds (default=3600) and at least > +.B min > +seconds (default is 90% of > +.B max > +for servers, and equal to > +.B max > +for clients). > + > +The effective > +.B reneg\-sec > +value used is per session pseudo-uniform-randomized between > +.B min > +and > +.B max\fR. > + > +With the default value of 3600 this results in an effective per session > value > +in the range of 3240..3600 seconds for servers, or just 3600 for clients. > > When using dual\-factor authentication, note that this default value may > cause the end user to be challenged to reauthorize once per hour. > diff --git a/src/openvpn/init.c b/src/openvpn/init.c > index 1ed2c55e..0b64930e 100644 > --- a/src/openvpn/init.c > +++ b/src/openvpn/init.c > @@ -2693,7 +2693,20 @@ do_init_crypto_tls(struct context *c, const > unsigned int flags) > to.packet_timeout = options->tls_timeout; > to.renegotiate_bytes = options->renegotiate_bytes; > to.renegotiate_packets = options->renegotiate_packets; > - to.renegotiate_seconds = options->renegotiate_seconds; > + if (options->renegotiate_seconds_min < 0) > + { > + /* Add 10% jitter to the reneg-sec of each connection by default > */ > + int auto_jitter = options->mode != MODE_SERVER ? 0 : > + get_random() % max_int(options->renegotiate_seconds / 10, > 1); > + to.renegotiate_seconds = options->renegotiate_seconds - > auto_jitter; > + } > + else > + { > + /* Add user-specific jitter to the renge-sec of each connection > */ > + to.renegotiate_seconds = options->renegotiate_seconds - > + (get_random() % max_int(options->renegotiate_seconds > + - > options->renegotiate_seconds_min, 1)); > + } > to.single_session = options->single_session; > to.mode = options->mode; > to.pull = options->pull; > diff --git a/src/openvpn/options.c b/src/openvpn/options.c > index 641a26e2..7fe22064 100644 > --- a/src/openvpn/options.c > +++ b/src/openvpn/options.c > @@ -603,7 +603,9 @@ static const char usage_message[] = > " if no ACK from remote within n seconds > (default=%d).\n" > "--reneg-bytes n : Renegotiate data chan. key after n bytes sent and > recvd.\n" > "--reneg-pkts n : Renegotiate data chan. key after n packets sent > and recvd.\n" > - "--reneg-sec n : Renegotiate data chan. key after n seconds > (default=%d).\n" > + "--reneg-sec max [min] : Renegotiate data chan. key after at most max > (default=%d)\n" > + " and at least min (defaults to 90%% of max on > servers and equal\n" > + " to max on clients).\n" > "--hand-window n : Data channel key exchange must finalize within n > seconds\n" > " of handshake initiation by any peer > (default=%d).\n" > "--tran-window n : Transition window -- old key can live this many > seconds\n" > @@ -870,6 +872,7 @@ init_options(struct options *o, const bool init_gc) > o->tls_timeout = 2; > o->renegotiate_bytes = -1; > o->renegotiate_seconds = 3600; > + o->renegotiate_seconds_min = -1; > o->handshake_window = 60; > o->transition_window = 3600; > o->ecdh_curve = NULL; > @@ -7999,10 +8002,14 @@ add_option(struct options *options, > VERIFY_PERMISSION(OPT_P_TLS_PARMS); > options->renegotiate_packets = positive_atoi(p[1]); > } > - else if (streq(p[0], "reneg-sec") && p[1] && !p[2]) > + else if (streq(p[0], "reneg-sec") && p[1] && !p[3]) > { > VERIFY_PERMISSION(OPT_P_TLS_PARMS); > options->renegotiate_seconds = positive_atoi(p[1]); > + if (p[2]) > + { > + options->renegotiate_seconds_min = positive_atoi(p[2]); > + } > } > else if (streq(p[0], "hand-window") && p[1] && !p[2]) > { > diff --git a/src/openvpn/options.h b/src/openvpn/options.h > index 496c1143..a74dc94d 100644 > --- a/src/openvpn/options.h > +++ b/src/openvpn/options.h > @@ -548,6 +548,7 @@ struct options > int renegotiate_bytes; > int renegotiate_packets; > int renegotiate_seconds; > + int renegotiate_seconds_min; > > /* Data channel key handshake must finalize > * within n seconds of handshake initiation. */ > diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c > index cb94229a..174f13cb 100644 > --- a/src/openvpn/ssl.c > +++ b/src/openvpn/ssl.c > @@ -2732,9 +2732,9 @@ tls_process(struct tls_multi *multi, > && ks->n_packets >= session->opt->renegotiate_packets) > || > (packet_id_close_to_wrapping(&ks->crypto_options.packet_id.send)))) > { > - msg(D_TLS_DEBUG_LOW, > - "TLS: soft reset sec=%d bytes=" counter_format "/%d pkts=" > counter_format "/%d", > - (int)(ks->established + session->opt->renegotiate_seconds - > now), > + msg(D_TLS_DEBUG_LOW, "TLS: soft reset sec=%lld/%d bytes=" > counter_format > + "/%d pkts=" counter_format "/%d", > + (now - ks->established), session->opt->renegotiate_seconds, > ks->n_bytes, session->opt->renegotiate_bytes, > ks->n_packets, session->opt->renegotiate_packets); > key_state_soft_reset(session); > -- > 2.14.1 > ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot
Hi Steffan,
While running your v3 version of the patch I found an issue with the
modified logging. It gives the following error while building
gcc -DHAVE_CONFIG_H -I. -I../.. -I../../include -I../../include
-I../../src/compat -DPLUGIN_LIBDIR=\"/usr/lib64/openvpn/plugins\"
-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions
-fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches
-m64 -mtune=generic -std=c99 -c -o ssl.o ssl.c
ssl.c: In function 'tls_process':
ssl.c:2735:9: warning: format '%lld' expects argument of type 'long long
int', but argument 3 has type 'time_t' [-Wformat=]
msg(D_TLS_DEBUG_LOW, "TLS: soft reset sec=%lld/%d bytes="
counter_format
^
and the log output is also corrupted
TLS: soft reset sec=14774687501680/336605974
bytes=18446744069414584320/581335 pkts=0/0
TLS: soft reset sec=14787572403571/77375 bytes=18446744069414584320/885
pkts=0/-1080308296
TLS: soft reset sec=14164802145506/6746662
bytes=18446744069414584320/86778 pkts=0/0
TLS: soft reset sec=15264313773538/186529 bytes=18446744069414584320/1108
pkts=0/13935244
Please have a look at the attached v4 patch which fixes it for me. The
output is now
TLS: soft reset sec=3474/3474 bytes=8470454/-1 pkts=108673/0
TLS: soft reset sec=3489/3489 bytes=429623769/-1 pkts=656033/0
TLS: soft reset sec=3517/3517 bytes=89365/-1 pkts=877/0
TLS: soft reset sec=3537/3537 bytes=206142/-1 pkts=1123/0
which seems reasonable to me.
In the patch I've modified the lines below:
msg(D_TLS_DEBUG_LOW,
- "TLS: soft reset sec=%d bytes=" counter_format "/%d pkts="
counter_format "/%d",
- (int)(ks->established + session->opt->renegotiate_seconds -
now),
+ "TLS: soft reset sec=%d/%d bytes=" counter_format "/%d pkts="
counter_format "/%d",
+ (int)(now - ks->established), session->opt->renegotiate_seconds,
ks->n_bytes, session->opt->renegotiate_bytes,
I'm not a developer and not a git user, so please accept my hand crafted
patch work :-)
Thanks and regards,
Simon
> From: Simon Matter <simon.matter@invoca.ch>
>
> While we were suffering from the "TLS Renegotiation Slowdown" bug here
> https://community.openvpn.net/openvpn/ticket/854 we realized that there is
> still room for improvement in our use case.
>
> It appears that TLS renegotiation is getting more and more expensive in
> terms of CPU cycles with recent changes for more security. To make things
> worse, we realized that most renegotiation procedures took place at almost
> the same time and increased the CPU load too much during these periods.
> That's especially true on large, multi-instance openvpn setups.
>
> I've created attached patch to add a per session pseudo-random component
> to
> the --reneg-sec intervals so that renegotiation is evenly spread over
> time.
> It is configured by simply adding a second value to --reneg-sec as
> described in the --help text:
>
> --reneg-sec max [min] : Renegotiate data chan. key after at most max
> (default=3600) and at least min (default 90% of max on
> servers and equal to max on clients).
>
> The jitter is only enabled by default on servers, because the actual reneg
> time is min(reneg_server, reneg_client). Introducing jitter at both ends
> would bias the actual reneg time to the min value.
>
> Note that the patch also slightly changes the log output to show the sec
> value in the same way as the bytes/pkts values:
>
> TLS: soft reset sec=3084/3084 bytes=279897/-1 pkts=1370/0
>
> The idea and first versions of this patch are from Simon Matter. Steffan
> Karger later incorporated the mailing list comments into this patch. So
> credits go to Simon, and all bugs are Steffan's fault ;-)
>
> Signed-off-by: Simon Matter <simon.matter@invoca.ch>
> Signed-off-by: Steffan Karger <steffan@karger.me>
> ---
> v3: incorporate comments from openvpn-devel@, don't add jitter by
> default on the client side.
>
> doc/openvpn.8 | 26 +++++++++++++++++++++-----
> src/openvpn/init.c | 15 ++++++++++++++-
> src/openvpn/options.c | 11 +++++++++--
> src/openvpn/options.h | 1 +
> src/openvpn/ssl.c | 6 +++---
> 5 files changed, 48 insertions(+), 11 deletions(-)
>
> diff --git a/doc/openvpn.8 b/doc/openvpn.8
> index a4189ac2..eb5258f9 100644
> --- a/doc/openvpn.8
> +++ b/doc/openvpn.8
> @@ -33,7 +33,7 @@
> .\" .ft -- normal face
> .\" .in +|-{n} -- indent
> .\"
> -.TH openvpn 8 "25 August 2016"
> +.TH openvpn 8 "04 April 2017"
> .\"*********************************************************
> .SH NAME
> openvpn \- secure IP tunnel daemon.
> @@ -4957,10 +4957,26 @@ Renegotiate data channel key after
> packets sent and received (disabled by default).
> .\"*********************************************************
> .TP
> -.B \-\-reneg\-sec n
> -Renegotiate data channel key after
> -.B n
> -seconds (default=3600).
> +.B \-\-reneg\-sec max [min]
> +Renegotiate data channel key after at most
> +.B max
> +seconds (default=3600) and at least
> +.B min
> +seconds (default is 90% of
> +.B max
> +for servers, and equal to
> +.B max
> +for clients).
> +
> +The effective
> +.B reneg\-sec
> +value used is per session pseudo-uniform-randomized between
> +.B min
> +and
> +.B max\fR.
> +
> +With the default value of 3600 this results in an effective per session
> value
> +in the range of 3240..3600 seconds for servers, or just 3600 for clients.
>
> When using dual\-factor authentication, note that this default value may
> cause the end user to be challenged to reauthorize once per hour.
> diff --git a/src/openvpn/init.c b/src/openvpn/init.c
> index 1ed2c55e..0b64930e 100644
> --- a/src/openvpn/init.c
> +++ b/src/openvpn/init.c
> @@ -2693,7 +2693,20 @@ do_init_crypto_tls(struct context *c, const
> unsigned int flags)
> to.packet_timeout = options->tls_timeout;
> to.renegotiate_bytes = options->renegotiate_bytes;
> to.renegotiate_packets = options->renegotiate_packets;
> - to.renegotiate_seconds = options->renegotiate_seconds;
> + if (options->renegotiate_seconds_min < 0)
> + {
> + /* Add 10% jitter to the reneg-sec of each connection by default
> */
> + int auto_jitter = options->mode != MODE_SERVER ? 0 :
> + get_random() % max_int(options->renegotiate_seconds / 10,
> 1);
> + to.renegotiate_seconds = options->renegotiate_seconds -
> auto_jitter;
> + }
> + else
> + {
> + /* Add user-specific jitter to the renge-sec of each connection
> */
> + to.renegotiate_seconds = options->renegotiate_seconds -
> + (get_random() % max_int(options->renegotiate_seconds
> + -
> options->renegotiate_seconds_min, 1));
> + }
> to.single_session = options->single_session;
> to.mode = options->mode;
> to.pull = options->pull;
> diff --git a/src/openvpn/options.c b/src/openvpn/options.c
> index 641a26e2..7fe22064 100644
> --- a/src/openvpn/options.c
> +++ b/src/openvpn/options.c
> @@ -603,7 +603,9 @@ static const char usage_message[] =
> " if no ACK from remote within n seconds
> (default=%d).\n"
> "--reneg-bytes n : Renegotiate data chan. key after n bytes sent and
> recvd.\n"
> "--reneg-pkts n : Renegotiate data chan. key after n packets sent
> and recvd.\n"
> - "--reneg-sec n : Renegotiate data chan. key after n seconds
> (default=%d).\n"
> + "--reneg-sec max [min] : Renegotiate data chan. key after at most max
> (default=%d)\n"
> + " and at least min (defaults to 90%% of max on
> servers and equal\n"
> + " to max on clients).\n"
> "--hand-window n : Data channel key exchange must finalize within n
> seconds\n"
> " of handshake initiation by any peer
> (default=%d).\n"
> "--tran-window n : Transition window -- old key can live this many
> seconds\n"
> @@ -870,6 +872,7 @@ init_options(struct options *o, const bool init_gc)
> o->tls_timeout = 2;
> o->renegotiate_bytes = -1;
> o->renegotiate_seconds = 3600;
> + o->renegotiate_seconds_min = -1;
> o->handshake_window = 60;
> o->transition_window = 3600;
> o->ecdh_curve = NULL;
> @@ -7999,10 +8002,14 @@ add_option(struct options *options,
> VERIFY_PERMISSION(OPT_P_TLS_PARMS);
> options->renegotiate_packets = positive_atoi(p[1]);
> }
> - else if (streq(p[0], "reneg-sec") && p[1] && !p[2])
> + else if (streq(p[0], "reneg-sec") && p[1] && !p[3])
> {
> VERIFY_PERMISSION(OPT_P_TLS_PARMS);
> options->renegotiate_seconds = positive_atoi(p[1]);
> + if (p[2])
> + {
> + options->renegotiate_seconds_min = positive_atoi(p[2]);
> + }
> }
> else if (streq(p[0], "hand-window") && p[1] && !p[2])
> {
> diff --git a/src/openvpn/options.h b/src/openvpn/options.h
> index 496c1143..a74dc94d 100644
> --- a/src/openvpn/options.h
> +++ b/src/openvpn/options.h
> @@ -548,6 +548,7 @@ struct options
> int renegotiate_bytes;
> int renegotiate_packets;
> int renegotiate_seconds;
> + int renegotiate_seconds_min;
>
> /* Data channel key handshake must finalize
> * within n seconds of handshake initiation. */
> diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
> index cb94229a..174f13cb 100644
> --- a/src/openvpn/ssl.c
> +++ b/src/openvpn/ssl.c
> @@ -2732,9 +2732,9 @@ tls_process(struct tls_multi *multi,
> && ks->n_packets >= session->opt->renegotiate_packets)
> ||
> (packet_id_close_to_wrapping(&ks->crypto_options.packet_id.send))))
> {
> - msg(D_TLS_DEBUG_LOW,
> - "TLS: soft reset sec=%d bytes=" counter_format "/%d pkts="
> counter_format "/%d",
> - (int)(ks->established + session->opt->renegotiate_seconds -
> now),
> + msg(D_TLS_DEBUG_LOW, "TLS: soft reset sec=%lld/%d bytes="
> counter_format
> + "/%d pkts=" counter_format "/%d",
> + (now - ks->established), session->opt->renegotiate_seconds,
> ks->n_bytes, session->opt->renegotiate_bytes,
> ks->n_packets, session->opt->renegotiate_packets);
> key_state_soft_reset(session);
> --
> 2.14.1
>
diff -Naur openvpn-2.4.4.orig/doc/openvpn.8 openvpn-2.4.4/doc/openvpn.8
--- openvpn-2.4.4.orig/doc/openvpn.8 2017-09-26 11:27:37.000000000 +0200
+++ openvpn-2.4.4/doc/openvpn.8 2017-11-14 09:10:35.000000000 +0100
@@ -33,7 +33,7 @@
.\" .ft -- normal face
.\" .in +|-{n} -- indent
.\"
-.TH openvpn 8 "25 August 2016"
+.TH openvpn 8 "04 April 2017"
.\"*********************************************************
.SH NAME
openvpn \- secure IP tunnel daemon.
@@ -4958,10 +4958,26 @@
packets sent and received (disabled by default).
.\"*********************************************************
.TP
-.B \-\-reneg\-sec n
-Renegotiate data channel key after
-.B n
-seconds (default=3600).
+.B \-\-reneg\-sec max [min]
+Renegotiate data channel key after at most
+.B max
+seconds (default=3600) and at least
+.B min
+seconds (default is 90% of
+.B max
+for servers, and equal to
+.B max
+for clients).
+
+The effective
+.B reneg\-sec
+value used is per session pseudo-uniform-randomized between
+.B min
+and
+.B max\fR.
+
+With the default value of 3600 this results in an effective per session value
+in the range of 3240..3600 seconds for servers, or just 3600 for clients.
When using dual\-factor authentication, note that this default value may
cause the end user to be challenged to reauthorize once per hour.
diff -Naur openvpn-2.4.4.orig/src/openvpn/init.c openvpn-2.4.4/src/openvpn/init.c
--- openvpn-2.4.4.orig/src/openvpn/init.c 2017-09-26 11:27:37.000000000 +0200
+++ openvpn-2.4.4/src/openvpn/init.c 2017-11-14 09:10:35.000000000 +0100
@@ -2706,7 +2706,20 @@
to.packet_timeout = options->tls_timeout;
to.renegotiate_bytes = options->renegotiate_bytes;
to.renegotiate_packets = options->renegotiate_packets;
- to.renegotiate_seconds = options->renegotiate_seconds;
+ if (options->renegotiate_seconds_min < 0)
+ {
+ /* Add 10% jitter to the reneg-sec of each server connection by default */
+ int auto_jitter = options->mode != MODE_SERVER ? 0 :
+ get_random() % max_int(options->renegotiate_seconds / 10, 1);
+ to.renegotiate_seconds = options->renegotiate_seconds - auto_jitter;
+ }
+ else
+ {
+ /* Add user-specific jitter to the reneg-sec of each connection */
+ to.renegotiate_seconds = options->renegotiate_seconds -
+ (get_random() % max_int(options->renegotiate_seconds
+ - options->renegotiate_seconds_min, 1));
+ }
to.single_session = options->single_session;
to.mode = options->mode;
to.pull = options->pull;
diff -Naur openvpn-2.4.4.orig/src/openvpn/options.c openvpn-2.4.4/src/openvpn/options.c
--- openvpn-2.4.4.orig/src/openvpn/options.c 2017-09-26 11:27:37.000000000 +0200
+++ openvpn-2.4.4/src/openvpn/options.c 2017-11-14 09:10:35.000000000 +0100
@@ -604,7 +604,9 @@
" if no ACK from remote within n seconds (default=%d).\n"
"--reneg-bytes n : Renegotiate data chan. key after n bytes sent and recvd.\n"
"--reneg-pkts n : Renegotiate data chan. key after n packets sent and recvd.\n"
- "--reneg-sec n : Renegotiate data chan. key after n seconds (default=%d).\n"
+ "--reneg-sec max [min] : Renegotiate data chan. key after at most max (default=%d)\n"
+ " and at least min (defaults to 90%% of max on servers and equal\n"
+ " to max on clients).\n"
"--hand-window n : Data channel key exchange must finalize within n seconds\n"
" of handshake initiation by any peer (default=%d).\n"
"--tran-window n : Transition window -- old key can live this many seconds\n"
@@ -872,6 +874,7 @@
o->tls_timeout = 2;
o->renegotiate_bytes = -1;
o->renegotiate_seconds = 3600;
+ o->renegotiate_seconds_min = -1;
o->handshake_window = 60;
o->transition_window = 3600;
o->ecdh_curve = NULL;
@@ -8018,10 +8021,14 @@
VERIFY_PERMISSION(OPT_P_TLS_PARMS);
options->renegotiate_packets = positive_atoi(p[1]);
}
- else if (streq(p[0], "reneg-sec") && p[1] && !p[2])
+ else if (streq(p[0], "reneg-sec") && p[1] && !p[3])
{
VERIFY_PERMISSION(OPT_P_TLS_PARMS);
options->renegotiate_seconds = positive_atoi(p[1]);
+ if (p[2])
+ {
+ options->renegotiate_seconds_min = positive_atoi(p[2]);
+ }
}
else if (streq(p[0], "hand-window") && p[1] && !p[2])
{
diff -Naur openvpn-2.4.4.orig/src/openvpn/options.h openvpn-2.4.4/src/openvpn/options.h
--- openvpn-2.4.4.orig/src/openvpn/options.h 2017-09-26 11:27:37.000000000 +0200
+++ openvpn-2.4.4/src/openvpn/options.h 2017-11-14 09:10:35.000000000 +0100
@@ -549,6 +549,7 @@
int renegotiate_bytes;
int renegotiate_packets;
int renegotiate_seconds;
+ int renegotiate_seconds_min;
/* Data channel key handshake must finalize
* within n seconds of handshake initiation. */
diff -Naur openvpn-2.4.4.orig/src/openvpn/ssl.c openvpn-2.4.4/src/openvpn/ssl.c
--- openvpn-2.4.4.orig/src/openvpn/ssl.c 2017-09-26 11:27:37.000000000 +0200
+++ openvpn-2.4.4/src/openvpn/ssl.c 2017-11-14 09:19:03.000000000 +0100
@@ -2733,8 +2733,8 @@
|| (packet_id_close_to_wrapping(&ks->crypto_options.packet_id.send))))
{
msg(D_TLS_DEBUG_LOW,
- "TLS: soft reset sec=%d bytes=" counter_format "/%d pkts=" counter_format "/%d",
- (int)(ks->established + session->opt->renegotiate_seconds - now),
+ "TLS: soft reset sec=%d/%d bytes=" counter_format "/%d pkts=" counter_format "/%d",
+ (int)(now - ks->established), session->opt->renegotiate_seconds,
ks->n_bytes, session->opt->renegotiate_bytes,
ks->n_packets, session->opt->renegotiate_packets);
key_state_soft_reset(session);
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
Hi, On 15 November 2017 at 07:50, Simon Matter <simon.matter@invoca.ch> wrote: > Hi Steffan, > > While running your v3 version of the patch I found an issue with the > modified logging. It gives the following error while building > > gcc -DHAVE_CONFIG_H -I. -I../.. -I../../include -I../../include > -I../../src/compat -DPLUGIN_LIBDIR=\"/usr/lib64/openvpn/plugins\" > -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions > -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches > -m64 -mtune=generic -std=c99 -c -o ssl.o ssl.c > ssl.c: In function 'tls_process': > ssl.c:2735:9: warning: format '%lld' expects argument of type 'long long > int', but argument 3 has type 'time_t' [-Wformat=] > msg(D_TLS_DEBUG_LOW, "TLS: soft reset sec=%lld/%d bytes=" > counter_format > ^ > and the log output is also corrupted > > TLS: soft reset sec=14774687501680/336605974 > bytes=18446744069414584320/581335 pkts=0/0 > TLS: soft reset sec=14787572403571/77375 bytes=18446744069414584320/885 > pkts=0/-1080308296 > TLS: soft reset sec=14164802145506/6746662 > bytes=18446744069414584320/86778 pkts=0/0 > TLS: soft reset sec=15264313773538/186529 bytes=18446744069414584320/1108 > pkts=0/13935244 > > Please have a look at the attached v4 patch which fixes it for me. The > output is now > > TLS: soft reset sec=3474/3474 bytes=8470454/-1 pkts=108673/0 > TLS: soft reset sec=3489/3489 bytes=429623769/-1 pkts=656033/0 > TLS: soft reset sec=3517/3517 bytes=89365/-1 pkts=877/0 > TLS: soft reset sec=3537/3537 bytes=206142/-1 pkts=1123/0 > > which seems reasonable to me. > In the patch I've modified the lines below: > > msg(D_TLS_DEBUG_LOW, > - "TLS: soft reset sec=%d bytes=" counter_format "/%d pkts=" > counter_format "/%d", > - (int)(ks->established + session->opt->renegotiate_seconds - > now), > + "TLS: soft reset sec=%d/%d bytes=" counter_format "/%d pkts=" > counter_format "/%d", > + (int)(now - ks->established), session->opt->renegotiate_seconds, > ks->n_bytes, session->opt->renegotiate_bytes, > > I'm not a developer and not a git user, so please accept my hand crafted > patch work :-) Uch. Good find. Since we recently decided that the right way to print a time_t is to cast to long long and use the %lld format specifier, I wanted to do that here too. I did the latter, but forgot the first and didn't notice because on my x64 system time_t actually *is* a long long (so no compiler warnings). I'll send a follow-up version that incorporates the comments of both Simon's, probably tomorrow. -Steffan ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot
diff --git a/doc/openvpn.8 b/doc/openvpn.8 index a4189ac2..eb5258f9 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -33,7 +33,7 @@ .\" .ft -- normal face .\" .in +|-{n} -- indent .\" -.TH openvpn 8 "25 August 2016" +.TH openvpn 8 "04 April 2017" .\"********************************************************* .SH NAME openvpn \- secure IP tunnel daemon. @@ -4957,10 +4957,26 @@ Renegotiate data channel key after packets sent and received (disabled by default). .\"********************************************************* .TP -.B \-\-reneg\-sec n -Renegotiate data channel key after -.B n -seconds (default=3600). +.B \-\-reneg\-sec max [min] +Renegotiate data channel key after at most +.B max +seconds (default=3600) and at least +.B min +seconds (default is 90% of +.B max +for servers, and equal to +.B max +for clients). + +The effective +.B reneg\-sec +value used is per session pseudo-uniform-randomized between +.B min +and +.B max\fR. + +With the default value of 3600 this results in an effective per session value +in the range of 3240..3600 seconds for servers, or just 3600 for clients. When using dual\-factor authentication, note that this default value may cause the end user to be challenged to reauthorize once per hour. diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 1ed2c55e..0b64930e 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2693,7 +2693,20 @@ do_init_crypto_tls(struct context *c, const unsigned int flags) to.packet_timeout = options->tls_timeout; to.renegotiate_bytes = options->renegotiate_bytes; to.renegotiate_packets = options->renegotiate_packets; - to.renegotiate_seconds = options->renegotiate_seconds; + if (options->renegotiate_seconds_min < 0) + { + /* Add 10% jitter to the reneg-sec of each connection by default */ + int auto_jitter = options->mode != MODE_SERVER ? 0 : + get_random() % max_int(options->renegotiate_seconds / 10, 1); + to.renegotiate_seconds = options->renegotiate_seconds - auto_jitter; + } + else + { + /* Add user-specific jitter to the renge-sec of each connection */ + to.renegotiate_seconds = options->renegotiate_seconds - + (get_random() % max_int(options->renegotiate_seconds + - options->renegotiate_seconds_min, 1)); + } to.single_session = options->single_session; to.mode = options->mode; to.pull = options->pull; diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 641a26e2..7fe22064 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -603,7 +603,9 @@ static const char usage_message[] = " if no ACK from remote within n seconds (default=%d).\n" "--reneg-bytes n : Renegotiate data chan. key after n bytes sent and recvd.\n" "--reneg-pkts n : Renegotiate data chan. key after n packets sent and recvd.\n" - "--reneg-sec n : Renegotiate data chan. key after n seconds (default=%d).\n" + "--reneg-sec max [min] : Renegotiate data chan. key after at most max (default=%d)\n" + " and at least min (defaults to 90%% of max on servers and equal\n" + " to max on clients).\n" "--hand-window n : Data channel key exchange must finalize within n seconds\n" " of handshake initiation by any peer (default=%d).\n" "--tran-window n : Transition window -- old key can live this many seconds\n" @@ -870,6 +872,7 @@ init_options(struct options *o, const bool init_gc) o->tls_timeout = 2; o->renegotiate_bytes = -1; o->renegotiate_seconds = 3600; + o->renegotiate_seconds_min = -1; o->handshake_window = 60; o->transition_window = 3600; o->ecdh_curve = NULL; @@ -7999,10 +8002,14 @@ add_option(struct options *options, VERIFY_PERMISSION(OPT_P_TLS_PARMS); options->renegotiate_packets = positive_atoi(p[1]); } - else if (streq(p[0], "reneg-sec") && p[1] && !p[2]) + else if (streq(p[0], "reneg-sec") && p[1] && !p[3]) { VERIFY_PERMISSION(OPT_P_TLS_PARMS); options->renegotiate_seconds = positive_atoi(p[1]); + if (p[2]) + { + options->renegotiate_seconds_min = positive_atoi(p[2]); + } } else if (streq(p[0], "hand-window") && p[1] && !p[2]) { diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 496c1143..a74dc94d 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -548,6 +548,7 @@ struct options int renegotiate_bytes; int renegotiate_packets; int renegotiate_seconds; + int renegotiate_seconds_min; /* Data channel key handshake must finalize * within n seconds of handshake initiation. */ diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index cb94229a..174f13cb 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2732,9 +2732,9 @@ tls_process(struct tls_multi *multi, && ks->n_packets >= session->opt->renegotiate_packets) || (packet_id_close_to_wrapping(&ks->crypto_options.packet_id.send)))) { - msg(D_TLS_DEBUG_LOW, - "TLS: soft reset sec=%d bytes=" counter_format "/%d pkts=" counter_format "/%d", - (int)(ks->established + session->opt->renegotiate_seconds - now), + msg(D_TLS_DEBUG_LOW, "TLS: soft reset sec=%lld/%d bytes=" counter_format + "/%d pkts=" counter_format "/%d", + (now - ks->established), session->opt->renegotiate_seconds, ks->n_bytes, session->opt->renegotiate_bytes, ks->n_packets, session->opt->renegotiate_packets); key_state_soft_reset(session);