diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2017-06-27 13:56:16 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2017-06-27 13:56:16 +0200 |
commit | 749384a154025e268b53cf3cc79eaeddde2b3ceb (patch) | |
tree | 27baa9e6aec76635d750405d90cd461440a656d1 /debian/patches | |
parent | db4f04c584f7d4e828b5d317cf40962b9d854ac5 (diff) |
initial stretch branch release 2.4.0-6
Diffstat (limited to 'debian/patches')
-rw-r--r-- | debian/patches/CVE-2017-7478.patch | 55 | ||||
-rw-r--r-- | debian/patches/CVE-2017-7479-prereq.patch | 443 | ||||
-rw-r--r-- | debian/patches/CVE-2017-7479.patch | 193 | ||||
-rw-r--r-- | debian/patches/kfreebsd_support.patch | 44 | ||||
-rw-r--r-- | debian/patches/match-manpage-and-command-help.patch | 13 | ||||
-rw-r--r-- | debian/patches/openvpn-pkcs11warn.patch | 6 | ||||
-rw-r--r-- | debian/patches/series | 5 | ||||
-rw-r--r-- | debian/patches/upstream-issue-879.patch | 87 | ||||
-rw-r--r-- | debian/patches/wipe_tokens_on_de-auth.patch | 118 |
9 files changed, 934 insertions, 30 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/kfreebsd_support.patch b/debian/patches/kfreebsd_support.patch index 4445e0d..0c8165b 100644 --- a/debian/patches/kfreebsd_support.patch +++ b/debian/patches/kfreebsd_support.patch @@ -3,9 +3,9 @@ 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 2017-06-22 13:17:05.754630908 +0200 -+++ openvpn/src/openvpn/route.c 2017-06-22 13:17:05.750630880 +0200 -@@ -1689,7 +1689,7 @@ +--- 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"); @@ -14,7 +14,7 @@ Index: openvpn/src/openvpn/route.c argv_printf(&argv, "%s add", ROUTE_PATH); -@@ -1875,7 +1875,7 @@ +@@ -1856,7 +1856,7 @@ network = print_in6_addr( r6->network, 0, &gc); gateway = print_in6_addr( r6->gateway, 0, &gc); @@ -23,7 +23,7 @@ Index: openvpn/src/openvpn/route.c || defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \ || defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) -@@ -2043,7 +2043,7 @@ +@@ -2032,7 +2032,7 @@ argv_msg(D_ROUTE, &argv); status = openvpn_execve_check(&argv, es, 0, "ERROR: Solaris route add -inet6 command failed"); @@ -32,7 +32,7 @@ Index: openvpn/src/openvpn/route.c argv_printf(&argv, "%s add -inet6 %s/%d", ROUTE_PATH, -@@ -2227,7 +2227,7 @@ +@@ -2216,7 +2216,7 @@ argv_msg(D_ROUTE, &argv); openvpn_execve_check(&argv, es, 0, "ERROR: Solaris route delete command failed"); @@ -41,7 +41,7 @@ Index: openvpn/src/openvpn/route.c argv_printf(&argv, "%s delete -net %s %s %s", ROUTE_PATH, -@@ -2334,7 +2334,7 @@ +@@ -2323,7 +2323,7 @@ network = print_in6_addr( r6->network, 0, &gc); gateway = print_in6_addr( r6->gateway, 0, &gc); @@ -50,7 +50,7 @@ Index: openvpn/src/openvpn/route.c || defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \ || defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) -@@ -2469,7 +2469,7 @@ +@@ -2458,7 +2458,7 @@ argv_msg(D_ROUTE, &argv); openvpn_execve_check(&argv, es, 0, "ERROR: Solaris route delete -inet6 command failed"); @@ -59,7 +59,7 @@ Index: openvpn/src/openvpn/route.c argv_printf(&argv, "%s delete -inet6 %s/%d", ROUTE_PATH, -@@ -3514,7 +3514,8 @@ +@@ -3499,7 +3499,8 @@ #elif defined(TARGET_DARWIN) || defined(TARGET_SOLARIS) \ || defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \ @@ -71,9 +71,9 @@ Index: openvpn/src/openvpn/route.c #include <sys/socket.h> Index: openvpn/src/openvpn/tun.c =================================================================== ---- openvpn.orig/src/openvpn/tun.c 2017-06-22 13:17:05.754630908 +0200 -+++ openvpn/src/openvpn/tun.c 2017-06-22 13:17:05.750630880 +0200 -@@ -843,7 +843,7 @@ +--- 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) \ @@ -82,7 +82,7 @@ Index: openvpn/src/openvpn/tun.c /* 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" -@@ -1412,7 +1412,7 @@ +@@ -1408,7 +1408,7 @@ add_route_connected_v6_net(tt, es); } @@ -91,7 +91,7 @@ Index: openvpn/src/openvpn/tun.c in_addr_t remote_end; /* for "virtual" subnet topology */ -@@ -2770,7 +2770,7 @@ +@@ -2762,7 +2762,7 @@ } } @@ -102,8 +102,8 @@ Index: openvpn/src/openvpn/tun.c freebsd_modify_read_write_return(int len) Index: openvpn/src/openvpn/lladdr.c =================================================================== ---- openvpn.orig/src/openvpn/lladdr.c 2017-06-22 13:17:05.754630908 +0200 -+++ openvpn/src/openvpn/lladdr.c 2017-06-22 13:17:05.750630880 +0200 +--- 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, @@ -115,9 +115,9 @@ Index: openvpn/src/openvpn/lladdr.c IFCONFIG_PATH, Index: openvpn/src/openvpn/syshead.h =================================================================== ---- openvpn.orig/src/openvpn/syshead.h 2017-06-22 13:17:05.754630908 +0200 -+++ openvpn/src/openvpn/syshead.h 2017-06-22 13:17:05.750630880 +0200 -@@ -297,7 +297,7 @@ +--- 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 */ @@ -128,9 +128,9 @@ Index: openvpn/src/openvpn/syshead.h #include <sys/uio.h> Index: openvpn/src/openvpn/ssl.c =================================================================== ---- openvpn.orig/src/openvpn/ssl.c 2017-06-22 13:17:05.754630908 +0200 -+++ openvpn/src/openvpn/ssl.c 2017-06-22 13:17:05.750630880 +0200 -@@ -2269,7 +2269,7 @@ +--- 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"); diff --git a/debian/patches/match-manpage-and-command-help.patch b/debian/patches/match-manpage-and-command-help.patch index 39b899c..34ed3cd 100644 --- a/debian/patches/match-manpage-and-command-help.patch +++ b/debian/patches/match-manpage-and-command-help.patch @@ -7,11 +7,11 @@ Subject: [PATCH] Change command help to match man page and implementation src/openvpn/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -Index: openvpn/src/openvpn/options.c -=================================================================== ---- openvpn.orig/src/openvpn/options.c 2017-06-22 13:17:12.806680520 +0200 -+++ openvpn/src/openvpn/options.c 2017-06-22 13:17:12.802680492 +0200 -@@ -197,7 +197,7 @@ +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" @@ -20,3 +20,6 @@ Index: openvpn/src/openvpn/options.c "--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 index 1fabddd..0ec934f 100644 --- a/debian/patches/openvpn-pkcs11warn.patch +++ b/debian/patches/openvpn-pkcs11warn.patch @@ -3,9 +3,9 @@ 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 2017-06-22 13:16:58.862582114 +0200 -+++ openvpn/src/openvpn/options.c 2017-06-22 13:16:58.862582114 +0200 -@@ -6818,6 +6818,20 @@ +--- 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]; } diff --git a/debian/patches/series b/debian/patches/series index 50b527d..907dc15 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -3,3 +3,8 @@ 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"); |