summaryrefslogtreecommitdiff
path: root/debian/patches
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches')
-rw-r--r--debian/patches/CVE-2017-7478.patch55
-rw-r--r--debian/patches/CVE-2017-7479-prereq.patch443
-rw-r--r--debian/patches/CVE-2017-7479.patch193
-rw-r--r--debian/patches/auth-pam_libpam_so_filename.patch16
-rw-r--r--debian/patches/debian_nogroup_for_sample_files.patch81
-rw-r--r--debian/patches/kfreebsd_support.patch141
-rw-r--r--debian/patches/match-manpage-and-command-help.patch25
-rw-r--r--debian/patches/openvpn-pkcs11warn.patch28
-rw-r--r--debian/patches/series10
-rw-r--r--debian/patches/upstream-issue-879.patch87
-rw-r--r--debian/patches/wipe_tokens_on_de-auth.patch118
11 files changed, 1197 insertions, 0 deletions
diff --git a/debian/patches/CVE-2017-7478.patch b/debian/patches/CVE-2017-7478.patch
new file mode 100644
index 0000000..e301cf1
--- /dev/null
+++ b/debian/patches/CVE-2017-7478.patch
@@ -0,0 +1,55 @@
+From be66408610a52f81c9c895a8973958ead55a4e57 Mon Sep 17 00:00:00 2001
+From: Steffan Karger <steffan.karger@fox-it.com>
+Date: Tue, 9 May 2017 15:40:25 +0300
+Subject: [PATCH] Don't assert out on receiving too-large control packets
+ (CVE-2017-xxx)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Commit 3c1b19e0 changed the maximum size of accepted control channel
+packets. This was needed for crypto negotiation (which is needed for a
+nice transition to a new default cipher), but exposed a DoS
+vulnerability. The vulnerability was found during the OpenVPN 2.4 code
+audit by Quarkslab (commisioned by OSTIF).
+
+To fix the issue, we should not ASSERT() on external input (in this case
+the received packet size), but instead gracefully error out and drop the
+invalid packet.
+
+Signed-off-by: Steffan Karger <steffan.karger@fox-it.com>
+Signed-off-by: Samuli Seppänen <samuli@openvpn.net>
+
+CVE-2017-7478
+
+ Security
+ --------
+ - This release fixes a pre-authentication denial-of-service attack on both
+ clients and servers. By sending a too-large control packet, OpenVPN 2.4.0 or
+ 2.4.1 can be forced to hit an ASSERT() and stop the process. If
+ ``--tls-auth`` or ``--tls-crypt`` is used, only attackers that have the
+ ``--tls-auth`` or ``--tls-crypt`` key can mount an attack. (CVE-2017-xxx)
+
+---
+ Changes.rst | 8 ++++++++
+ src/openvpn/ssl.c | 7 ++++++-
+ 2 files changed, 14 insertions(+), 1 deletion(-)
+
+Index: openvpn-2.4.0/src/openvpn/ssl.c
+===================================================================
+--- openvpn-2.4.0.orig/src/openvpn/ssl.c
++++ openvpn-2.4.0/src/openvpn/ssl.c
+@@ -3708,7 +3708,12 @@ tls_pre_decrypt(struct tls_multi *multi,
+ /* Save incoming ciphertext packet to reliable buffer */
+ struct buffer *in = reliable_get_buf(ks->rec_reliable);
+ ASSERT(in);
+- ASSERT(buf_copy(in, buf));
++ if(!buf_copy(in, buf))
++ {
++ msg(D_MULTI_DROPPED,
++ "Incoming control channel packet too big, dropping.");
++ goto error;
++ }
+ reliable_mark_active_incoming(ks->rec_reliable, in, id, op);
+ }
+
diff --git a/debian/patches/CVE-2017-7479-prereq.patch b/debian/patches/CVE-2017-7479-prereq.patch
new file mode 100644
index 0000000..e3c94d7
--- /dev/null
+++ b/debian/patches/CVE-2017-7479-prereq.patch
@@ -0,0 +1,443 @@
+From a87e1431baccd49a9344cfc63ab7446c4317fa2f Mon Sep 17 00:00:00 2001
+From: Steffan Karger <steffan.karger@fox-it.com>
+Date: Fri, 5 May 2017 19:44:51 +0200
+Subject: [PATCH] cleanup: merge packet_id_alloc_outgoing() into
+ packet_id_write()
+
+The functions packet_id_alloc_outgoing() and packet_id_write() were
+always called in tandem. Instead of forcing the caller to allocate a
+packet_id_net to do so, merge the two functions. This simplifies the API
+and reduces the chance on mistakes in the future.
+
+This patch adds unit tests to verify the behaviour of packet_id_write().
+Verifying that we assert out correctly required the change to mock_msg.c.
+
+Signed-off-by: Steffan Karger <steffan.karger@fox-it.com>
+Acked-by: Gert Doering <gert@greenie.muc.de>
+Acked-by: David Sommerseth <davids@openvpn.net>
+Message-Id: <1494006291-3522-1-git-send-email-steffan.karger@fox-it.com>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14541.html
+Signed-off-by: Gert Doering <gert@greenie.muc.de>
+
+[prerequisite for CVE-2017-7479. Adjusted to apply to 2.4.0 release -- sbeattie]
+
+---
+ src/openvpn/crypto.c | 20 ++--
+ src/openvpn/packet_id.c | 24 ++++-
+ src/openvpn/packet_id.h | 35 +++----
+ src/openvpn/tls_crypt.c | 6 +-
+ tests/unit_tests/openvpn/Makefile.am | 13 ++-
+ tests/unit_tests/openvpn/mock_msg.c | 15 ++-
+ tests/unit_tests/openvpn/test_packet_id.c | 168 ++++++++++++++++++++++++++++++
+ 7 files changed, 228 insertions(+), 53 deletions(-)
+ create mode 100644 tests/unit_tests/openvpn/test_packet_id.c
+
+Index: openvpn-2.4.0/src/openvpn/crypto.c
+===================================================================
+--- openvpn-2.4.0.orig/src/openvpn/crypto.c
++++ openvpn-2.4.0/src/openvpn/crypto.c
+@@ -85,7 +85,6 @@ openvpn_encrypt_aead(struct buffer *buf,
+ /* Prepare IV */
+ {
+ struct buffer iv_buffer;
+- struct packet_id_net pin;
+ uint8_t iv[OPENVPN_MAX_IV_LENGTH] = {0};
+ const int iv_len = cipher_ctx_iv_length(ctx->cipher);
+
+@@ -94,8 +93,7 @@ openvpn_encrypt_aead(struct buffer *buf,
+ buf_set_write(&iv_buffer, iv, iv_len);
+
+ /* IV starts with packet id to make the IV unique for packet */
+- packet_id_alloc_outgoing(&opt->packet_id.send, &pin, false);
+- ASSERT(packet_id_write(&pin, &iv_buffer, false, false));
++ ASSERT(packet_id_write(&opt->packet_id.send, &iv_buffer, false, false));
+
+ /* Remainder of IV consists of implicit part (unique per session) */
+ ASSERT(buf_write(&iv_buffer, ctx->implicit_iv, ctx->implicit_iv_len));
+@@ -198,23 +196,21 @@ openvpn_encrypt_v1(struct buffer *buf, s
+ /* Put packet ID in plaintext buffer */
+ if (packet_id_initialized(&opt->packet_id))
+ {
+- struct packet_id_net pin;
+- packet_id_alloc_outgoing(&opt->packet_id.send, &pin, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM));
+- ASSERT(packet_id_write(&pin, buf, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM), true));
++ ASSERT(packet_id_write(&opt->packet_id.send, buf,
++ opt->flags & CO_PACKET_ID_LONG_FORM,
++ true));
+ }
+ }
+ else if (cipher_kt_mode_ofb_cfb(cipher_kt))
+ {
+- struct packet_id_net pin;
+ struct buffer b;
+
+ /* IV and packet-ID required for this mode. */
+ ASSERT(opt->flags & CO_USE_IV);
+ ASSERT(packet_id_initialized(&opt->packet_id));
+
+- packet_id_alloc_outgoing(&opt->packet_id.send, &pin, true);
+ buf_set_write(&b, iv_buf, iv_size);
+- ASSERT(packet_id_write(&pin, &b, true, false));
++ ASSERT(packet_id_write(&opt->packet_id.send, &b, true, false));
+ }
+ else /* We only support CBC, CFB, or OFB modes right now */
+ {
+@@ -264,9 +260,9 @@ openvpn_encrypt_v1(struct buffer *buf, s
+ {
+ if (packet_id_initialized(&opt->packet_id))
+ {
+- struct packet_id_net pin;
+- packet_id_alloc_outgoing(&opt->packet_id.send, &pin, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM));
+- ASSERT(packet_id_write(&pin, buf, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM), true));
++ ASSERT(packet_id_write(&opt->packet_id.send, buf,
++ BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM),
++ true));
+ }
+ if (ctx->hmac)
+ {
+Index: openvpn-2.4.0/src/openvpn/packet_id.c
+===================================================================
+--- openvpn-2.4.0.orig/src/openvpn/packet_id.c
++++ openvpn-2.4.0/src/openvpn/packet_id.c
+@@ -325,12 +325,30 @@ packet_id_read(struct packet_id_net *pin
+ return true;
+ }
+
++static void
++packet_id_send_update(struct packet_id_send *p, bool long_form)
++{
++ if (!p->time)
++ {
++ p->time = now;
++ }
++ p->id++;
++ if (!p->id)
++ {
++ ASSERT(long_form);
++ p->time = now;
++ p->id = 1;
++ }
++}
++
+ bool
+-packet_id_write(const struct packet_id_net *pin, struct buffer *buf, bool long_form, bool prepend)
++packet_id_write(struct packet_id_send *p, struct buffer *buf, bool long_form,
++ bool prepend)
+ {
+- packet_id_type net_id = htonpid(pin->id);
+- net_time_t net_time = htontime(pin->time);
++ packet_id_send_update(p, long_form);
+
++ const packet_id_type net_id = htonpid(p->id);
++ const net_time_t net_time = htontime(p->time);
+ if (prepend)
+ {
+ if (long_form)
+Index: openvpn-2.4.0/src/openvpn/packet_id.h
+===================================================================
+--- openvpn-2.4.0.orig/src/openvpn/packet_id.h
++++ openvpn-2.4.0/src/openvpn/packet_id.h
+@@ -254,7 +254,18 @@ const char *packet_id_persist_print(cons
+
+ bool packet_id_read(struct packet_id_net *pin, struct buffer *buf, bool long_form);
+
+-bool packet_id_write(const struct packet_id_net *pin, struct buffer *buf, bool long_form, bool prepend);
++/**
++ * Write a packet ID to buf, and update the packet ID state.
++ *
++ * @param p Packet ID state.
++ * @param buf Buffer to write the packet ID too
++ * @param long_form If true, also update and write time_t to buf
++ * @param prepend If true, prepend to buffer, otherwise apppend.
++ *
++ * @return true if successful, false otherwise.
++ */
++bool packet_id_write(struct packet_id_send *p, struct buffer *buf,
++ bool long_form, bool prepend);
+
+ /*
+ * Inline functions.
+@@ -304,28 +315,6 @@ packet_id_close_to_wrapping(const struct
+ return p->id >= PACKET_ID_WRAP_TRIGGER;
+ }
+
+-/*
+- * Allocate an outgoing packet id.
+- * Sequence number ranges from 1 to 2^32-1.
+- * In long_form, a time_t is added as well.
+- */
+-static inline void
+-packet_id_alloc_outgoing(struct packet_id_send *p, struct packet_id_net *pin, bool long_form)
+-{
+- if (!p->time)
+- {
+- p->time = now;
+- }
+- pin->id = ++p->id;
+- if (!pin->id)
+- {
+- ASSERT(long_form);
+- p->time = now;
+- pin->id = p->id = 1;
+- }
+- pin->time = p->time;
+-}
+-
+ static inline bool
+ check_timestamp_delta(time_t remote, unsigned int max_delta)
+ {
+Index: openvpn-2.4.0/src/openvpn/tls_crypt.c
+===================================================================
+--- openvpn-2.4.0.orig/src/openvpn/tls_crypt.c
++++ openvpn-2.4.0/src/openvpn/tls_crypt.c
+@@ -95,11 +95,7 @@ tls_crypt_wrap(const struct buffer *src,
+ format_hex(BPTR(src), BLEN(src), 80, &gc));
+
+ /* Get packet ID */
+- {
+- struct packet_id_net pin;
+- packet_id_alloc_outgoing(&opt->packet_id.send, &pin, true);
+- packet_id_write(&pin, dst, true, false);
+- }
++ ASSERT(packet_id_write(&opt->packet_id.send, dst, true, false));
+
+ dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP AD: %s",
+ format_hex(BPTR(dst), BLEN(dst), 0, &gc));
+Index: openvpn-2.4.0/tests/unit_tests/openvpn/Makefile.am
+===================================================================
+--- openvpn-2.4.0.orig/tests/unit_tests/openvpn/Makefile.am
++++ openvpn-2.4.0/tests/unit_tests/openvpn/Makefile.am
+@@ -1,6 +1,6 @@
+ AUTOMAKE_OPTIONS = foreign
+
+-check_PROGRAMS = argv_testdriver buffer_testdriver
++check_PROGRAMS = argv_testdriver buffer_testdriver packet_id_testdriver
+
+ if ENABLE_CRYPTO
+ check_PROGRAMS += tls_crypt_testdriver
+@@ -27,6 +27,17 @@ buffer_testdriver_SOURCES = test_buffer.
+ $(openvpn_srcdir)/buffer.c \
+ $(openvpn_srcdir)/platform.c
+
++packet_id_testdriver_CFLAGS = @TEST_CFLAGS@ \
++ -I$(openvpn_includedir) -I$(compat_srcdir) -I$(openvpn_srcdir) \
++ $(OPTIONAL_CRYPTO_CFLAGS)
++packet_id_testdriver_LDFLAGS = @TEST_LDFLAGS@ \
++ $(OPTIONAL_CRYPTO_LIBS)
++packet_id_testdriver_SOURCES = test_packet_id.c mock_msg.c \
++ $(openvpn_srcdir)/buffer.c \
++ $(openvpn_srcdir)/otime.c \
++ $(openvpn_srcdir)/packet_id.c \
++ $(openvpn_srcdir)/platform.c
++
+ tls_crypt_testdriver_CFLAGS = @TEST_CFLAGS@ \
+ -I$(openvpn_includedir) -I$(compat_srcdir) -I$(openvpn_srcdir) \
+ $(OPTIONAL_CRYPTO_CFLAGS)
+Index: openvpn-2.4.0/tests/unit_tests/openvpn/mock_msg.c
+===================================================================
+--- openvpn-2.4.0.orig/tests/unit_tests/openvpn/mock_msg.c
++++ openvpn-2.4.0/tests/unit_tests/openvpn/mock_msg.c
+@@ -29,9 +29,12 @@
+ #endif
+
+ #include <stdarg.h>
+-#include <stdbool.h>
++#include <stddef.h>
+ #include <stdio.h>
+ #include <stdlib.h>
++#include <setjmp.h>
++#include <cmocka.h>
++
+
+ #include "errlevel.h"
+ #include "error.h"
+@@ -70,14 +73,8 @@ x_msg(const unsigned int flags, const ch
+ void
+ assert_failed(const char *filename, int line, const char *condition)
+ {
+- if (condition)
+- {
+- printf("Assertion failed at %s:%d (%s)", filename, line, condition);
+- }
+- else
+- {
+- printf("Assertion failed at %s:%d", filename, line);
+- }
++ mock_assert(false, condition ? condition : "", filename, line);
++ /* Keep compiler happy. Should not happen, mock_assert() does not return */
+ exit(1);
+ }
+
+Index: openvpn-2.4.0/tests/unit_tests/openvpn/test_packet_id.c
+===================================================================
+--- /dev/null
++++ openvpn-2.4.0/tests/unit_tests/openvpn/test_packet_id.c
+@@ -0,0 +1,168 @@
++/*
++ * OpenVPN -- An application to securely tunnel IP networks
++ * over a single UDP port, with support for SSL/TLS-based
++ * session authentication and key exchange,
++ * packet encryption, packet authentication, and
++ * packet compression.
++ *
++ * Copyright (C) 2016 Fox Crypto B.V. <openvpn@fox-it.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program (see the file COPYING included with this
++ * distribution); if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#elif defined(_MSC_VER)
++#include "config-msvc.h"
++#endif
++
++#include "syshead.h"
++
++#include <stdarg.h>
++#include <stddef.h>
++#include <setjmp.h>
++#include <cmocka.h>
++
++#include "packet_id.h"
++
++#include "mock_msg.h"
++
++struct test_packet_id_write_data {
++ struct {
++ uint32_t buf_id;
++ uint32_t buf_time;
++ } test_buf_data;
++ struct buffer test_buf;
++ struct packet_id_send pis;
++};
++
++static int
++test_packet_id_write_setup(void **state) {
++ struct test_packet_id_write_data *data =
++ calloc(1, sizeof(struct test_packet_id_write_data));
++
++ if (!data)
++ {
++ return -1;
++ }
++
++ data->test_buf.data = (void *) &data->test_buf_data;
++ data->test_buf.capacity = sizeof(data->test_buf_data);
++
++ *state = data;
++ return 0;
++}
++
++static int
++test_packet_id_write_teardown(void **state) {
++ free(*state);
++ return 0;
++}
++
++static void
++test_packet_id_write_short(void **state)
++{
++ struct test_packet_id_write_data *data = *state;
++
++ now = 5010;
++ assert_true(packet_id_write(&data->pis, &data->test_buf, false, false));
++ assert_true(data->pis.id == 1);
++ assert_true(data->test_buf_data.buf_id == htonl(1));
++ assert_true(data->test_buf_data.buf_time == 0);
++}
++
++static void
++test_packet_id_write_long(void **state)
++{
++ struct test_packet_id_write_data *data = *state;
++
++ now = 5010;
++ assert_true(packet_id_write(&data->pis, &data->test_buf, true, false));
++ assert(data->pis.id == 1);
++ assert(data->pis.time == now);
++ assert_true(data->test_buf_data.buf_id == htonl(1));
++ assert_true(data->test_buf_data.buf_time == htonl(now));
++}
++
++static void
++test_packet_id_write_short_prepend(void **state)
++{
++ struct test_packet_id_write_data *data = *state;
++
++ data->test_buf.offset = sizeof(packet_id_type);
++ now = 5010;
++ assert_true(packet_id_write(&data->pis, &data->test_buf, false, true));
++ assert_true(data->pis.id == 1);
++ assert_true(data->test_buf_data.buf_id == htonl(1));
++ assert_true(data->test_buf_data.buf_time == 0);
++}
++
++static void
++test_packet_id_write_long_prepend(void **state)
++{
++ struct test_packet_id_write_data *data = *state;
++
++ data->test_buf.offset = sizeof(data->test_buf_data);
++ now = 5010;
++ assert_true(packet_id_write(&data->pis, &data->test_buf, true, true));
++ assert(data->pis.id == 1);
++ assert(data->pis.time == now);
++ assert_true(data->test_buf_data.buf_id == htonl(1));
++ assert_true(data->test_buf_data.buf_time == htonl(now));
++}
++
++static void
++test_packet_id_write_short_wrap(void **state)
++{
++ struct test_packet_id_write_data *data = *state;
++
++ data->pis.id = ~0;
++ expect_assert_failure(
++ packet_id_write(&data->pis, &data->test_buf, false, false));
++}
++
++static void
++test_packet_id_write_long_wrap(void **state)
++{
++ struct test_packet_id_write_data *data = *state;
++
++ data->pis.id = ~0;
++ now = 5010;
++ assert_true(packet_id_write(&data->pis, &data->test_buf, true, false));
++ assert(data->pis.id == 1);
++ assert(data->pis.time == now);
++ assert_true(data->test_buf_data.buf_id == htonl(1));
++ assert_true(data->test_buf_data.buf_time == htonl(now));
++}
++
++int
++main(void) {
++ const struct CMUnitTest tests[] = {
++ cmocka_unit_test_setup_teardown(test_packet_id_write_short,
++ test_packet_id_write_setup, test_packet_id_write_teardown),
++ cmocka_unit_test_setup_teardown(test_packet_id_write_long,
++ test_packet_id_write_setup, test_packet_id_write_teardown),
++ cmocka_unit_test_setup_teardown(test_packet_id_write_short_prepend,
++ test_packet_id_write_setup, test_packet_id_write_teardown),
++ cmocka_unit_test_setup_teardown(test_packet_id_write_long_prepend,
++ test_packet_id_write_setup, test_packet_id_write_teardown),
++ cmocka_unit_test_setup_teardown(test_packet_id_write_short_wrap,
++ test_packet_id_write_setup, test_packet_id_write_teardown),
++ cmocka_unit_test_setup_teardown(test_packet_id_write_long_wrap,
++ test_packet_id_write_setup, test_packet_id_write_teardown),
++ };
++
++ return cmocka_run_group_tests_name("packet_id tests", tests, NULL, NULL);
++}
diff --git a/debian/patches/CVE-2017-7479.patch b/debian/patches/CVE-2017-7479.patch
new file mode 100644
index 0000000..9f75d31
--- /dev/null
+++ b/debian/patches/CVE-2017-7479.patch
@@ -0,0 +1,193 @@
+From ac08b27cfa693d9be592bb2597c260635aee9e68 Mon Sep 17 00:00:00 2001
+From: Steffan Karger <steffan.karger@fox-it.com>
+Date: Tue, 25 Apr 2017 10:00:44 +0200
+Subject: [PATCH 2/2] Drop packets instead of asserting out if packet id rolls
+ over
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Previously, if a mode was selected where packet ids are not allowed to roll
+over, but renegotiation does not succeed for some reason (e.g. no password
+entered in time, certificate expired or a malicious peer that refuses the
+renegotiaion on purpose) we would continue to use the old keys. Until the
+packet ID would roll over and we would ASSERT() out.
+
+Given that this can be triggered on purpose by an authenticated peer, this
+is a fix for an authenticated remote DoS vulnerability. An attack is
+rather inefficient though; a peer would need to get us to send 2^32
+packets (min-size packet is IP+UDP+OPCODE+PID+TAG (no payload), results in
+(20+8+1+4+16)×2^32 bytes, or approx. 196 GB).
+
+Signed-off-by: Steffan Karger <steffan.karger@fox-it.com>
+
+CVE-2017-7479
+
+---
+ src/openvpn/crypto.c | 25 ++++++++++++++++---------
+ src/openvpn/packet_id.c | 22 ++++++++++++++++------
+ src/openvpn/packet_id.h | 1 +
+ src/openvpn/tls_crypt.c | 6 +++++-
+ tests/unit_tests/openvpn/test_packet_id.c | 11 +++++++++--
+ 5 files changed, 47 insertions(+), 18 deletions(-)
+
+Index: openvpn-2.4.0/src/openvpn/crypto.c
+===================================================================
+--- openvpn-2.4.0.orig/src/openvpn/crypto.c
++++ openvpn-2.4.0/src/openvpn/crypto.c
+@@ -93,7 +93,11 @@ openvpn_encrypt_aead(struct buffer *buf,
+ buf_set_write(&iv_buffer, iv, iv_len);
+
+ /* IV starts with packet id to make the IV unique for packet */
+- ASSERT(packet_id_write(&opt->packet_id.send, &iv_buffer, false, false));
++ if (!packet_id_write(&opt->packet_id.send, &iv_buffer, false, false))
++ {
++ msg(D_CRYPT_ERRORS, "ENCRYPT ERROR: packet ID roll over");
++ goto err;
++ }
+
+ /* Remainder of IV consists of implicit part (unique per session) */
+ ASSERT(buf_write(&iv_buffer, ctx->implicit_iv, ctx->implicit_iv_len));
+@@ -194,11 +198,13 @@ openvpn_encrypt_v1(struct buffer *buf, s
+ }
+
+ /* Put packet ID in plaintext buffer */
+- if (packet_id_initialized(&opt->packet_id))
++ if (packet_id_initialized(&opt->packet_id)
++ && !packet_id_write(&opt->packet_id.send, buf,
++ opt->flags & CO_PACKET_ID_LONG_FORM,
++ true))
+ {
+- ASSERT(packet_id_write(&opt->packet_id.send, buf,
+- opt->flags & CO_PACKET_ID_LONG_FORM,
+- true));
++ msg(D_CRYPT_ERRORS, "ENCRYPT ERROR: packet ID roll over");
++ goto err;
+ }
+ }
+ else if (cipher_kt_mode_ofb_cfb(cipher_kt))
+@@ -258,11 +264,12 @@ openvpn_encrypt_v1(struct buffer *buf, s
+ }
+ else /* No Encryption */
+ {
+- if (packet_id_initialized(&opt->packet_id))
++ if (packet_id_initialized(&opt->packet_id)
++ && !packet_id_write(&opt->packet_id.send, buf,
++ opt->flags & CO_PACKET_ID_LONG_FORM, true))
+ {
+- ASSERT(packet_id_write(&opt->packet_id.send, buf,
+- BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM),
+- true));
++ msg(D_CRYPT_ERRORS, "ENCRYPT ERROR: packet ID roll over");
++ goto err;
+ }
+ if (ctx->hmac)
+ {
+Index: openvpn-2.4.0/src/openvpn/packet_id.c
+===================================================================
+--- openvpn-2.4.0.orig/src/openvpn/packet_id.c
++++ openvpn-2.4.0/src/openvpn/packet_id.c
+@@ -325,27 +325,37 @@ packet_id_read(struct packet_id_net *pin
+ return true;
+ }
+
+-static void
++static bool
+ packet_id_send_update(struct packet_id_send *p, bool long_form)
+ {
+ if (!p->time)
+ {
+ p->time = now;
+ }
+- p->id++;
+- if (!p->id)
++ if (p->id == PACKET_ID_MAX)
+ {
+- ASSERT(long_form);
++ /* Packet ID only allowed to roll over if using long form and time has
++ * moved forward since last roll over.
++ */
++ if (!long_form || now <= p->time)
++ {
++ return false;
++ }
+ p->time = now;
+- p->id = 1;
++ p->id = 0;
+ }
++ p->id++;
++ return true;
+ }
+
+ bool
+ packet_id_write(struct packet_id_send *p, struct buffer *buf, bool long_form,
+ bool prepend)
+ {
+- packet_id_send_update(p, long_form);
++ if (!packet_id_send_update(p, long_form))
++ {
++ return false;
++ }
+
+ const packet_id_type net_id = htonpid(p->id);
+ const net_time_t net_time = htontime(p->time);
+Index: openvpn-2.4.0/src/openvpn/packet_id.h
+===================================================================
+--- openvpn-2.4.0.orig/src/openvpn/packet_id.h
++++ openvpn-2.4.0/src/openvpn/packet_id.h
+@@ -50,6 +50,7 @@
+ * to for network transmission.
+ */
+ typedef uint32_t packet_id_type;
++#define PACKET_ID_MAX UINT32_MAX
+ typedef uint32_t net_time_t;
+
+ /*
+Index: openvpn-2.4.0/src/openvpn/tls_crypt.c
+===================================================================
+--- openvpn-2.4.0.orig/src/openvpn/tls_crypt.c
++++ openvpn-2.4.0/src/openvpn/tls_crypt.c
+@@ -95,7 +95,11 @@ tls_crypt_wrap(const struct buffer *src,
+ format_hex(BPTR(src), BLEN(src), 80, &gc));
+
+ /* Get packet ID */
+- ASSERT(packet_id_write(&opt->packet_id.send, dst, true, false));
++ if (!packet_id_write(&opt->packet_id.send, dst, true, false))
++ {
++ msg(D_CRYPT_ERRORS, "TLS-CRYPT ERROR: packet ID roll over.");
++ goto err;
++ }
+
+ dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP AD: %s",
+ format_hex(BPTR(dst), BLEN(dst), 0, &gc));
+Index: openvpn-2.4.0/tests/unit_tests/openvpn/test_packet_id.c
+===================================================================
+--- openvpn-2.4.0.orig/tests/unit_tests/openvpn/test_packet_id.c
++++ openvpn-2.4.0/tests/unit_tests/openvpn/test_packet_id.c
+@@ -129,8 +129,7 @@ test_packet_id_write_short_wrap(void **s
+ struct test_packet_id_write_data *data = *state;
+
+ data->pis.id = ~0;
+- expect_assert_failure(
+- packet_id_write(&data->pis, &data->test_buf, false, false));
++ assert_false(packet_id_write(&data->pis, &data->test_buf, false, false));
+ }
+
+ static void
+@@ -139,8 +138,16 @@ test_packet_id_write_long_wrap(void **st
+ struct test_packet_id_write_data *data = *state;
+
+ data->pis.id = ~0;
++ data->pis.time = 5006;
++
++ /* Write fails if time did not change */
++ now = 5006;
++ assert_false(packet_id_write(&data->pis, &data->test_buf, true, false));
++
++ /* Write succeeds if time moved forward */
+ now = 5010;
+ assert_true(packet_id_write(&data->pis, &data->test_buf, true, false));
++
+ assert(data->pis.id == 1);
+ assert(data->pis.time == now);
+ assert_true(data->test_buf_data.buf_id == htonl(1));
diff --git a/debian/patches/auth-pam_libpam_so_filename.patch b/debian/patches/auth-pam_libpam_so_filename.patch
new file mode 100644
index 0000000..cfa9047
--- /dev/null
+++ b/debian/patches/auth-pam_libpam_so_filename.patch
@@ -0,0 +1,16 @@
+Description: Fix libpam.so filename to /lib/libpam.so.0 in pam plugin
+Author: Alberto Gonzalez Iniesta <agi@inittab.org>
+Bug-Debian: http://bugs.debian.org/306335
+Index: openvpn/src/plugins/auth-pam/auth-pam.c
+===================================================================
+--- openvpn.orig/src/plugins/auth-pam/auth-pam.c 2016-12-27 18:45:37.638198402 +0100
++++ openvpn/src/plugins/auth-pam/auth-pam.c 2016-12-27 18:45:37.638198402 +0100
+@@ -698,7 +698,7 @@
+ struct user_pass up;
+ int command;
+ #ifdef USE_PAM_DLOPEN
+- static const char pam_so[] = "libpam.so";
++ static const char pam_so[] = "libpam.so.0";
+ #endif
+
+ /*
diff --git a/debian/patches/debian_nogroup_for_sample_files.patch b/debian/patches/debian_nogroup_for_sample_files.patch
new file mode 100644
index 0000000..f7dcaaa
--- /dev/null
+++ b/debian/patches/debian_nogroup_for_sample_files.patch
@@ -0,0 +1,81 @@
+Description: Unpriviledged group in Debian is called nogroup instead of nobody
+Author: Alberto Gonzalez Iniesta <agi@inittab.org>
+Bug-Debian: http://bugs.debian.org/317987
+Index: openvpn/sample/sample-config-files/server.conf
+===================================================================
+--- openvpn.orig/sample/sample-config-files/server.conf 2016-11-21 09:53:43.608863207 +0100
++++ openvpn/sample/sample-config-files/server.conf 2016-11-21 09:53:43.604863188 +0100
+@@ -272,7 +272,7 @@
+ # You can uncomment this out on
+ # non-Windows systems.
+ ;user nobody
+-;group nobody
++;group nogroup
+
+ # The persist options will try to avoid
+ # accessing certain resources on restart
+Index: openvpn/sample/sample-config-files/tls-home.conf
+===================================================================
+--- openvpn.orig/sample/sample-config-files/tls-home.conf 2016-11-21 09:53:43.608863207 +0100
++++ openvpn/sample/sample-config-files/tls-home.conf 2016-11-21 09:53:43.608863207 +0100
+@@ -51,7 +51,7 @@
+ # "nobody" after initialization
+ # for extra security.
+ ; user nobody
+-; group nobody
++; group nogroup
+
+ # If you built OpenVPN with
+ # LZO compression, uncomment
+Index: openvpn/sample/sample-config-files/static-home.conf
+===================================================================
+--- openvpn.orig/sample/sample-config-files/static-home.conf 2016-11-21 09:53:43.608863207 +0100
++++ openvpn/sample/sample-config-files/static-home.conf 2016-11-21 09:53:43.608863207 +0100
+@@ -43,7 +43,7 @@
+ # "nobody" after initialization
+ # for extra security.
+ ; user nobody
+-; group nobody
++; group nogroup
+
+ # If you built OpenVPN with
+ # LZO compression, uncomment
+Index: openvpn/sample/sample-config-files/static-office.conf
+===================================================================
+--- openvpn.orig/sample/sample-config-files/static-office.conf 2016-11-21 09:53:43.608863207 +0100
++++ openvpn/sample/sample-config-files/static-office.conf 2016-11-21 09:53:43.608863207 +0100
+@@ -40,7 +40,7 @@
+ # "nobody" after initialization
+ # for extra security.
+ ; user nobody
+-; group nobody
++; group nogroup
+
+ # If you built OpenVPN with
+ # LZO compression, uncomment
+Index: openvpn/sample/sample-config-files/client.conf
+===================================================================
+--- openvpn.orig/sample/sample-config-files/client.conf 2016-11-21 09:53:43.608863207 +0100
++++ openvpn/sample/sample-config-files/client.conf 2016-11-21 09:53:43.608863207 +0100
+@@ -59,7 +59,7 @@
+
+ # Downgrade privileges after initialization (non-Windows only)
+ ;user nobody
+-;group nobody
++;group nogroup
+
+ # Try to preserve some state across restarts.
+ persist-key
+Index: openvpn/sample/sample-config-files/tls-office.conf
+===================================================================
+--- openvpn.orig/sample/sample-config-files/tls-office.conf 2016-11-21 09:53:43.608863207 +0100
++++ openvpn/sample/sample-config-files/tls-office.conf 2016-11-21 09:53:43.608863207 +0100
+@@ -51,7 +51,7 @@
+ # "nobody" after initialization
+ # for extra security.
+ ; user nobody
+-; group nobody
++; group nogroup
+
+ # If you built OpenVPN with
+ # LZO compression, uncomment
diff --git a/debian/patches/kfreebsd_support.patch b/debian/patches/kfreebsd_support.patch
new file mode 100644
index 0000000..0c8165b
--- /dev/null
+++ b/debian/patches/kfreebsd_support.patch
@@ -0,0 +1,141 @@
+Description: Improve kFreeBSD support
+Author: Gonéri Le Bouder <goneri@rulezlan.org>
+Bug-Debian: http://bugs.debian.org/626062
+Index: openvpn/src/openvpn/route.c
+===================================================================
+--- openvpn.orig/src/openvpn/route.c 2016-12-27 19:01:52.704942715 +0100
++++ openvpn/src/openvpn/route.c 2016-12-27 19:08:24.717996310 +0100
+@@ -1670,7 +1670,7 @@
+ argv_msg(D_ROUTE, &argv);
+ status = openvpn_execve_check(&argv, es, 0, "ERROR: Solaris route add command failed");
+
+-#elif defined(TARGET_FREEBSD)
++#elif defined(TARGET_FREEBSD) || defined(__FreeBSD_kernel__)
+
+ argv_printf(&argv, "%s add",
+ ROUTE_PATH);
+@@ -1856,7 +1856,7 @@
+ network = print_in6_addr( r6->network, 0, &gc);
+ gateway = print_in6_addr( r6->gateway, 0, &gc);
+
+-#if defined(TARGET_DARWIN) \
++#if defined(TARGET_DARWIN) || defined(__FreeBSD_kernel__) \
+ || defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \
+ || defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)
+
+@@ -2032,7 +2032,7 @@
+ argv_msg(D_ROUTE, &argv);
+ status = openvpn_execve_check(&argv, es, 0, "ERROR: Solaris route add -inet6 command failed");
+
+-#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY)
++#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) || defined(__FreeBSD_kernel__)
+
+ argv_printf(&argv, "%s add -inet6 %s/%d",
+ ROUTE_PATH,
+@@ -2216,7 +2216,7 @@
+ argv_msg(D_ROUTE, &argv);
+ openvpn_execve_check(&argv, es, 0, "ERROR: Solaris route delete command failed");
+
+-#elif defined(TARGET_FREEBSD)
++#elif defined(TARGET_FREEBSD) || defined(__FreeBSD_kernel__)
+
+ argv_printf(&argv, "%s delete -net %s %s %s",
+ ROUTE_PATH,
+@@ -2323,7 +2323,7 @@
+ network = print_in6_addr( r6->network, 0, &gc);
+ gateway = print_in6_addr( r6->gateway, 0, &gc);
+
+-#if defined(TARGET_DARWIN) \
++#if defined(TARGET_DARWIN) || defined(__FreeBSD_kernel__) \
+ || defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \
+ || defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)
+
+@@ -2458,7 +2458,7 @@
+ argv_msg(D_ROUTE, &argv);
+ openvpn_execve_check(&argv, es, 0, "ERROR: Solaris route delete -inet6 command failed");
+
+-#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY)
++#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) || defined(__FreeBSD_kernel__)
+
+ argv_printf(&argv, "%s delete -inet6 %s/%d",
+ ROUTE_PATH,
+@@ -3499,7 +3499,8 @@
+
+ #elif defined(TARGET_DARWIN) || defined(TARGET_SOLARIS) \
+ || defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \
+- || defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)
++ || defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) \
++ || defined(__FreeBSD_kernel__)
+
+ #include <sys/types.h>
+ #include <sys/socket.h>
+Index: openvpn/src/openvpn/tun.c
+===================================================================
+--- openvpn.orig/src/openvpn/tun.c 2016-12-27 19:01:52.704942715 +0100
++++ openvpn/src/openvpn/tun.c 2016-12-27 19:05:14.585486719 +0100
+@@ -840,7 +840,7 @@
+ #endif /* if defined(_WIN32) || defined(TARGET_DARWIN) || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD) */
+
+ #if defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \
+- || defined(TARGET_OPENBSD)
++ || defined(TARGET_OPENBSD) || defined(__FreeBSD_kernel__)
+ /* we can't use true subnet mode on tun on all platforms, as that
+ * conflicts with IPv6 (wants to use ND then, which we don't do),
+ * but the OSes want "a remote address that is different from ours"
+@@ -1408,7 +1408,7 @@
+ add_route_connected_v6_net(tt, es);
+ }
+
+-#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY)
++#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) || defined(__FreeBSD_kernel__)
+
+ in_addr_t remote_end; /* for "virtual" subnet topology */
+
+@@ -2762,7 +2762,7 @@
+ }
+ }
+
+-#elif defined(TARGET_FREEBSD)
++#elif defined(TARGET_FREEBSD)||defined(__FreeBSD_kernel__)
+
+ static inline int
+ freebsd_modify_read_write_return(int len)
+Index: openvpn/src/openvpn/lladdr.c
+===================================================================
+--- openvpn.orig/src/openvpn/lladdr.c 2016-12-27 19:01:52.704942715 +0100
++++ openvpn/src/openvpn/lladdr.c 2016-12-27 19:09:07.286110127 +0100
+@@ -50,7 +50,7 @@
+ "%s %s lladdr %s",
+ IFCONFIG_PATH,
+ ifname, lladdr);
+-#elif defined(TARGET_FREEBSD)
++#elif defined(TARGET_FREEBSD) || defined(__FreeBSD_kernel__)
+ argv_printf(&argv,
+ "%s %s ether %s",
+ IFCONFIG_PATH,
+Index: openvpn/src/openvpn/syshead.h
+===================================================================
+--- openvpn.orig/src/openvpn/syshead.h 2016-12-27 19:01:52.704942715 +0100
++++ openvpn/src/openvpn/syshead.h 2016-12-27 19:01:52.700942705 +0100
+@@ -294,7 +294,7 @@
+
+ #endif /* TARGET_OPENBSD */
+
+-#ifdef TARGET_FREEBSD
++#if defined(TARGET_FREEBSD) || defined(__FreeBSD_kernel__)
+
+ #ifdef HAVE_SYS_UIO_H
+ #include <sys/uio.h>
+Index: openvpn/src/openvpn/ssl.c
+===================================================================
+--- openvpn.orig/src/openvpn/ssl.c 2016-12-27 19:01:52.704942715 +0100
++++ openvpn/src/openvpn/ssl.c 2016-12-27 19:03:13.433160691 +0100
+@@ -2247,7 +2247,7 @@
+ buf_printf(&out, "IV_PLAT=mac\n");
+ #elif defined(TARGET_NETBSD)
+ buf_printf(&out, "IV_PLAT=netbsd\n");
+-#elif defined(TARGET_FREEBSD)
++#elif defined(TARGET_FREEBSD) || defined(__FreeBSD_kernel__)
+ buf_printf(&out, "IV_PLAT=freebsd\n");
+ #elif defined(TARGET_ANDROID)
+ buf_printf(&out, "IV_PLAT=android\n");
diff --git a/debian/patches/match-manpage-and-command-help.patch b/debian/patches/match-manpage-and-command-help.patch
new file mode 100644
index 0000000..34ed3cd
--- /dev/null
+++ b/debian/patches/match-manpage-and-command-help.patch
@@ -0,0 +1,25 @@
+From a88d8ba3e81ca34fc2675805a273cd85875c8973 Mon Sep 17 00:00:00 2001
+From: Arne Schwabe <arne@rfc2549.org>
+Date: Wed, 4 Jan 2017 19:18:46 +0100
+Subject: [PATCH] Change command help to match man page and implementation
+
+---
+ src/openvpn/options.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/openvpn/options.c b/src/openvpn/options.c
+index bfedb6a..80143e6 100644
+--- a/src/openvpn/options.c
++++ b/src/openvpn/options.c
+@@ -198,7 +198,7 @@ static const char usage_message[] =
+ " is established. Multiple routes can be specified.\n"
+ " netmask default: 255.255.255.255\n"
+ " gateway default: taken from --route-gateway or --ifconfig\n"
+- " Specify default by leaving blank or setting to \"nil\".\n"
++ " Specify default by leaving blank or setting to \"default\".\n"
+ "--route-ipv6 network/bits [gateway] [metric] :\n"
+ " Add IPv6 route to routing table after connection\n"
+ " is established. Multiple routes can be specified.\n"
+--
+2.10.1 (Apple Git-78)
+
diff --git a/debian/patches/openvpn-pkcs11warn.patch b/debian/patches/openvpn-pkcs11warn.patch
new file mode 100644
index 0000000..0ec934f
--- /dev/null
+++ b/debian/patches/openvpn-pkcs11warn.patch
@@ -0,0 +1,28 @@
+Description: Warn users about deprecated pkcs11 options
+Author: Florian Kulzer <florian.kulzer+debian@icfo.es>
+Bug-Debian: http://bugs.debian.org/475353
+Index: openvpn/src/openvpn/options.c
+===================================================================
+--- openvpn.orig/src/openvpn/options.c 2016-12-27 18:46:18.362320774 +0100
++++ openvpn/src/openvpn/options.c 2016-12-27 18:46:18.362320774 +0100
+@@ -6789,6 +6789,20 @@
+ options->port_share_port = p[2];
+ options->port_share_journal_dir = p[3];
+ }
++ else if (streq (p[0], "pkcs11-id-type") ||
++ streq (p[0], "pkcs11-sign-mode") ||
++ streq (p[0], "pkcs11-slot") ||
++ streq (p[0], "pkcs11-slot-type") ||
++ streq (p[0], "show-pkcs11-objects") ||
++ streq (p[0], "show-pkcs11-slots"))
++ {
++ if (file)
++ msg (msglevel, "You are using an obsolete parameter in %s:%d: %s (%s).\nPlease see /usr/share/doc/openvpn/NEWS.Debian.gz for details.",
++ file, line, p[0], PACKAGE_VERSION);
++ else
++ msg (msglevel, "You are using an obsolete parameter: --%s (%s).\nPlease see /usr/share/doc/openvpn/NEWS.Debian.gz for details.",
++ p[0], PACKAGE_VERSION);
++ }
+ #endif
+ else if (streq(p[0], "client-to-client") && !p[1])
+ {
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..907dc15
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,10 @@
+auth-pam_libpam_so_filename.patch
+debian_nogroup_for_sample_files.patch
+openvpn-pkcs11warn.patch
+kfreebsd_support.patch
+match-manpage-and-command-help.patch
+CVE-2017-7478.patch
+CVE-2017-7479-prereq.patch
+CVE-2017-7479.patch
+wipe_tokens_on_de-auth.patch
+upstream-issue-879.patch
diff --git a/debian/patches/upstream-issue-879.patch b/debian/patches/upstream-issue-879.patch
new file mode 100644
index 0000000..2139afc
--- /dev/null
+++ b/debian/patches/upstream-issue-879.patch
@@ -0,0 +1,87 @@
+Index: openvpn/src/openvpn/forward.c
+===================================================================
+--- openvpn.orig/src/openvpn/forward.c 2017-05-22 14:59:09.634938195 +0200
++++ openvpn/src/openvpn/forward.c 2017-05-22 14:59:09.630937170 +0200
+@@ -866,9 +866,16 @@
+ * will load crypto_options with the correct encryption key
+ * and return false.
+ */
++ uint8_t opcode = *BPTR(&c->c2.buf) >> P_OPCODE_SHIFT;
+ if (tls_pre_decrypt(c->c2.tls_multi, &c->c2.from, &c->c2.buf, &co,
+ floated, &ad_start))
+ {
++ /* Restore pre-NCP frame parameters */
++ if (is_hard_reset(opcode, c->options.key_method))
++ {
++ c->c2.frame = c->c2.frame_initial;
++ }
++
+ interval_action(&c->c2.tmp_int);
+
+ /* reset packet received timer if TLS packet */
+Index: openvpn/src/openvpn/init.c
+===================================================================
+--- openvpn.orig/src/openvpn/init.c 2017-05-22 14:59:09.634938195 +0200
++++ openvpn/src/openvpn/init.c 2017-05-22 14:59:09.634938195 +0200
+@@ -4055,6 +4055,8 @@
+ c->c2.did_open_tun = do_open_tun(c);
+ }
+
++ c->c2.frame_initial = c->c2.frame;
++
+ /* print MTU info */
+ do_print_data_channel_mtu_parms(c);
+
+Index: openvpn/src/openvpn/openvpn.h
+===================================================================
+--- openvpn.orig/src/openvpn/openvpn.h 2017-05-22 14:59:09.634938195 +0200
++++ openvpn/src/openvpn/openvpn.h 2017-05-22 14:59:09.634938195 +0200
+@@ -263,7 +263,8 @@
+ struct link_socket_actual from; /* address of incoming datagram */
+
+ /* MTU frame parameters */
+- struct frame frame;
++ struct frame frame; /* Active frame parameters */
++ struct frame frame_initial; /* Restored on new session */
+
+ #ifdef ENABLE_FRAGMENT
+ /* Object to handle advanced MTU negotiation and datagram fragmentation */
+Index: openvpn/src/openvpn/ssl.c
+===================================================================
+--- openvpn.orig/src/openvpn/ssl.c 2017-05-22 14:59:09.634938195 +0200
++++ openvpn/src/openvpn/ssl.c 2017-05-22 14:59:09.634938195 +0200
+@@ -830,14 +830,7 @@
+ return BSTR(&out);
+ }
+
+-/*
+- * Given a key_method, return true if op
+- * represents the required form of hard_reset.
+- *
+- * If key_method = 0, return true if any
+- * form of hard reset is used.
+- */
+-static bool
++bool
+ is_hard_reset(int op, int key_method)
+ {
+ if (!key_method || key_method == 1)
+Index: openvpn/src/openvpn/ssl.h
+===================================================================
+--- openvpn.orig/src/openvpn/ssl.h 2017-05-22 14:59:09.634938195 +0200
++++ openvpn/src/openvpn/ssl.h 2017-05-22 14:59:09.634938195 +0200
+@@ -591,6 +591,14 @@
+ /*#define EXTRACT_X509_FIELD_TEST*/
+ void extract_x509_field_test(void);
+
++/**
++ * Given a key_method, return true if opcode represents the required form of
++ * hard_reset.
++ *
++ * If key_method == 0, return true if any form of hard reset is used.
++ */
++bool is_hard_reset(int op, int key_method);
++
+ #endif /* ENABLE_CRYPTO */
+
+ #endif /* ifndef OPENVPN_SSL_H */
diff --git a/debian/patches/wipe_tokens_on_de-auth.patch b/debian/patches/wipe_tokens_on_de-auth.patch
new file mode 100644
index 0000000..8db560f
--- /dev/null
+++ b/debian/patches/wipe_tokens_on_de-auth.patch
@@ -0,0 +1,118 @@
+From daab0a9fa8ff4f40e8a34707db0ac156d49fbfcb Mon Sep 17 00:00:00 2001
+From: David Sommerseth <davids@openvpn.net>
+Date: Tue, 28 Mar 2017 22:53:46 +0200
+Subject: [PATCH] auth-token: Ensure tokens are always wiped on de-auth
+
+If tls_deauthenticate() was called, it could in some scenarios leave the
+authentication token for a session in memory. This change just ensures
+auth-tokens are always wiped as soon as a TLS session is considered
+broken.
+
+Signed-off-by: David Sommerseth <davids@openvpn.net>
+
+Acked-by: Steffan Karger <steffan@karger.me>
+Message-Id: <20170328205346.18844-1-davids@openvpn.net>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14344.html
+Signed-off-by: David Sommerseth <davids@openvpn.net>
+---
+ src/openvpn/ssl_verify.c | 47 +++++++++++++++++++++++++++--------------------
+ 1 file changed, 27 insertions(+), 20 deletions(-)
+
+Index: openvpn-2.4.0/src/openvpn/ssl_verify.c
+===================================================================
+--- openvpn-2.4.0.orig/src/openvpn/ssl_verify.c
++++ openvpn-2.4.0/src/openvpn/ssl_verify.c
+@@ -80,6 +80,28 @@ setenv_untrusted(struct tls_session *ses
+ setenv_link_socket_actual(session->opt->es, "untrusted", &session->untrusted_addr, SA_IP_PORT);
+ }
+
++
++/**
++ * Wipes the authentication token out of the memory, frees and cleans up related buffers and flags
++ *
++ * @param multi Pointer to a multi object holding the auth_token variables
++ */
++static void
++wipe_auth_token(struct tls_multi *multi)
++{
++ if(multi)
++ {
++ if (multi->auth_token)
++ {
++ secure_memzero(multi->auth_token, AUTH_TOKEN_SIZE);
++ free(multi->auth_token);
++ }
++ multi->auth_token = NULL;
++ multi->auth_token_sent = false;
++ }
++}
++
++
+ /*
+ * Remove authenticated state from all sessions in the given tunnel
+ */
+@@ -88,10 +110,14 @@ tls_deauthenticate(struct tls_multi *mul
+ {
+ if (multi)
+ {
+- int i, j;
+- for (i = 0; i < TM_SIZE; ++i)
+- for (j = 0; j < KS_SIZE; ++j)
++ wipe_auth_token(multi);
++ for (int i = 0; i < TM_SIZE; ++i)
++ {
++ for (int j = 0; j < KS_SIZE; ++j)
++ {
+ multi->session[i].key[j].authenticated = false;
++ }
++ }
+ }
+ }
+
+@@ -1213,21 +1239,6 @@ verify_user_pass_management(struct tls_s
+ }
+ #endif /* ifdef MANAGEMENT_DEF_AUTH */
+
+-/**
+- * Wipes the authentication token out of the memory, frees and cleans up related buffers and flags
+- *
+- * @param multi Pointer to a multi object holding the auth_token variables
+- */
+-static void
+-wipe_auth_token(struct tls_multi *multi)
+-{
+- secure_memzero(multi->auth_token, AUTH_TOKEN_SIZE);
+- free(multi->auth_token);
+- multi->auth_token = NULL;
+- multi->auth_token_sent = false;
+-}
+-
+-
+ /*
+ * Main username/password verification entry point
+ */
+@@ -1279,7 +1290,7 @@ verify_user_pass(struct user_pass *up, s
+ /* Ensure that the username has not changed */
+ if (!tls_lock_username(multi, up->username))
+ {
+- wipe_auth_token(multi);
++ /* auth-token cleared in tls_lock_username() on failure */
+ ks->authenticated = false;
+ goto done;
+ }
+@@ -1300,7 +1311,6 @@ verify_user_pass(struct user_pass *up, s
+ if (memcmp_constant_time(multi->auth_token, up->password,
+ strlen(multi->auth_token)) != 0)
+ {
+- wipe_auth_token(multi);
+ ks->authenticated = false;
+ tls_deauthenticate(multi);
+
+@@ -1472,6 +1482,7 @@ verify_final_auth_checks(struct tls_mult
+ if (!cn || !strcmp(cn, CCD_DEFAULT) || !test_file(path))
+ {
+ ks->authenticated = false;
++ wipe_auth_token(multi);
+ msg(D_TLS_ERRORS, "TLS Auth Error: --client-config-dir authentication failed for common name '%s' file='%s'",
+ session->common_name,
+ path ? path : "UNDEF");