From 3e3e9b32519a38f9316986b877163d37557b4f70 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Iniesta Date: Thu, 22 Jun 2017 17:25:13 +0200 Subject: Import Debian changes 2.3.4-5+deb8u2 openvpn (2.3.4-5+deb8u2) jessie-security; urgency=high * SECURITY UPDATE: authenticated remote DoS vulnerability due to packet ID rollover. CVE-2017-7479. Kudos to Steve Beattie for doing all the backporting work for this patch. - debian/patches/CVE-2017-7479-prereq.patch: merge packet_id_alloc_outgoing() into packet_id_write() - debian/patches/CVE-2017-7479.patch: do not assert when packet ID rollover occurs * SECURITY UPDATE: (Closes: #865480) - CVE-2017-7508.patch. Fix remotely-triggerable ASSERT() on malformed IPv6 packet. - CVE-2017-7520.patch. Prevent two kinds of stack buffer OOB reads and a crash for invalid input data. - CVE-2017-7521.patch. Fix potential double-free in --x509-alt-username. - CVE-2017-7521bis.patch. Fix remote-triggerable memory leaks. --- debian/changelog | 20 ++ debian/patches/CVE-2017-7479-prereq.patch | 518 ++++++++++++++++++++++++++++++ debian/patches/CVE-2017-7479.patch | 162 ++++++++++ debian/patches/CVE-2017-7508.patch | 57 ++++ debian/patches/CVE-2017-7520.patch | 55 ++++ debian/patches/CVE-2017-7521.patch | 48 +++ debian/patches/CVE-2017-7521bis.patch | 74 +++++ debian/patches/series | 6 + 8 files changed, 940 insertions(+) create mode 100644 debian/patches/CVE-2017-7479-prereq.patch create mode 100644 debian/patches/CVE-2017-7479.patch create mode 100644 debian/patches/CVE-2017-7508.patch create mode 100644 debian/patches/CVE-2017-7520.patch create mode 100644 debian/patches/CVE-2017-7521.patch create mode 100644 debian/patches/CVE-2017-7521bis.patch diff --git a/debian/changelog b/debian/changelog index 05e193c..6bc3fa9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,23 @@ +openvpn (2.3.4-5+deb8u2) jessie-security; urgency=high + + * SECURITY UPDATE: authenticated remote DoS vulnerability due to + packet ID rollover. CVE-2017-7479. + Kudos to Steve Beattie for doing all the backporting + work for this patch. + - debian/patches/CVE-2017-7479-prereq.patch: merge + packet_id_alloc_outgoing() into packet_id_write() + - debian/patches/CVE-2017-7479.patch: do not assert when packet ID + rollover occurs + * SECURITY UPDATE: (Closes: #865480) + - CVE-2017-7508.patch. Fix remotely-triggerable ASSERT() on malformed IPv6 + packet. + - CVE-2017-7520.patch. Prevent two kinds of stack buffer OOB reads and a + crash for invalid input data. + - CVE-2017-7521.patch. Fix potential double-free in --x509-alt-username. + - CVE-2017-7521bis.patch. Fix remote-triggerable memory leaks. + + -- Alberto Gonzalez Iniesta Thu, 22 Jun 2017 17:25:13 +0200 + openvpn (2.3.4-5+deb8u1) stable; urgency=medium * Add --no-block to if-up.d script to avoid hanging boot on diff --git a/debian/patches/CVE-2017-7479-prereq.patch b/debian/patches/CVE-2017-7479-prereq.patch new file mode 100644 index 0000000..4408185 --- /dev/null +++ b/debian/patches/CVE-2017-7479-prereq.patch @@ -0,0 +1,518 @@ +From 5d747770efa0611cc6cfeb6b3a5853bf51046d53 Mon Sep 17 00:00:00 2001 +From: Steffan Karger +Date: Tue, 9 May 2017 21:10:36 +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. + +This patch was cherry-picked from a87e1431 (master). + +Signed-off-by: Steffan Karger +Acked-by: David Sommerseth +Message-Id: <1494357036-3529-1-git-send-email-steffan.karger@fox-it.com> +URL: http://www.mail-archive.com/search?l=mid&q=1494357036-3529-1-git-send-email-steffan.karger@fox-it.com +Signed-off-by: David Sommerseth + +[Ubuntu note: prereq for CVE-2017-7479 issue. Disabled all testscases, + as the infrastructure for that wasn't introduced until 2.3.12. -- sbeattie] + +--- + configure.ac | 1 + + src/openvpn/crypto.c | 12 +-- + src/openvpn/packet_id.c | 24 ++++- + src/openvpn/packet_id.h | 34 +++--- + tests/unit_tests/Makefile.am | 2 +- + tests/unit_tests/openvpn/Makefile.am | 24 +++++ + tests/unit_tests/openvpn/mock_msg.c | 98 +++++++++++++++++ + tests/unit_tests/openvpn/mock_msg.h | 35 +++++++ + tests/unit_tests/openvpn/test_packet_id.c | 169 ++++++++++++++++++++++++++++++ + 9 files changed, 365 insertions(+), 34 deletions(-) + create mode 100644 tests/unit_tests/openvpn/Makefile.am + create mode 100644 tests/unit_tests/openvpn/mock_msg.c + create mode 100644 tests/unit_tests/openvpn/mock_msg.h + create mode 100644 tests/unit_tests/openvpn/test_packet_id.c + +Index: openvpn-2.3.4/src/openvpn/crypto.c +=================================================================== +--- openvpn-2.3.4.orig/src/openvpn/crypto.c ++++ openvpn-2.3.4/src/openvpn/crypto.c +@@ -114,23 +114,19 @@ openvpn_encrypt (struct buffer *buf, str + /* Put packet ID in plaintext buffer or IV, depending on cipher mode */ + if (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)); + } + } + else if (mode == OPENVPN_MODE_CFB || mode == OPENVPN_MODE_OFB) + { +- struct packet_id_net pin; + struct buffer b; + + ASSERT (opt->flags & CO_USE_IV); /* IV and packet-ID required */ + ASSERT (opt->packet_id); /* for this mode. */ + +- packet_id_alloc_outgoing (&opt->packet_id->send, &pin, true); + memset (iv_buf, 0, iv_size); + 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 */ + { +@@ -188,9 +184,7 @@ openvpn_encrypt (struct buffer *buf, str + { + if (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)); + } + work = *buf; + } +Index: openvpn-2.3.4/src/openvpn/packet_id.c +=================================================================== +--- openvpn-2.3.4.orig/src/openvpn/packet_id.c ++++ openvpn-2.3.4/src/openvpn/packet_id.c +@@ -294,12 +294,30 @@ packet_id_read (struct packet_id_net *pi + 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.3.4/src/openvpn/packet_id.h +=================================================================== +--- openvpn-2.3.4.orig/src/openvpn/packet_id.h ++++ openvpn-2.3.4/src/openvpn/packet_id.h +@@ -252,7 +252,19 @@ const char *packet_id_persist_print (con + */ + + 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. +@@ -294,26 +306,6 @@ packet_id_close_to_wrapping (const struc + 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.3.4/tests/unit_tests/openvpn/Makefile.am +=================================================================== +--- /dev/null ++++ openvpn-2.3.4/tests/unit_tests/openvpn/Makefile.am +@@ -0,0 +1,24 @@ ++AUTOMAKE_OPTIONS = foreign ++ ++check_PROGRAMS= ++ ++if ENABLE_CRYPTO ++check_PROGRAMS += packet_id_testdriver ++endif ++ ++TESTS = $(check_PROGRAMS) ++ ++openvpn_includedir = $(top_srcdir)/include ++openvpn_srcdir = $(top_srcdir)/src/openvpn ++compat_srcdir = $(top_srcdir)/src/compat ++ ++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 +Index: openvpn-2.3.4/tests/unit_tests/openvpn/mock_msg.c +=================================================================== +--- /dev/null ++++ openvpn-2.3.4/tests/unit_tests/openvpn/mock_msg.c +@@ -0,0 +1,98 @@ ++/* ++ * 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-2017 Fox Crypto B.V. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include "errlevel.h" ++#include "error.h" ++ ++#include "mock_msg.h" ++ ++unsigned int x_debug_level = 0; /* Default to (almost) no debugging output */ ++bool fatal_error_triggered = false; ++ ++void ++mock_set_debug_level(int level) ++{ ++ x_debug_level = level; ++} ++ ++void ++x_msg_va(const unsigned int flags, const char *format, ++ va_list arglist) ++{ ++ if (flags & M_FATAL) ++ { ++ fatal_error_triggered = true; ++ printf("FATAL ERROR:"); ++ } ++ vprintf(format, arglist); ++ printf("\n"); ++} ++ ++void ++x_msg(const unsigned int flags, const char *format, ...) ++{ ++ va_list arglist; ++ va_start(arglist, format); ++ x_msg_va(flags, format, arglist); ++ va_end(arglist); ++} ++ ++void ++assert_failed(const char *filename, int line, const char *condition) ++{ ++ mock_assert(false, condition ? condition : "", filename, line); ++ /* Keep compiler happy. Should not happen, mock_assert() does not return */ ++ exit(1); ++} ++ ++/* ++ * Fail memory allocation. Don't use msg() because it tries ++ * to allocate memory as part of its operation. ++ */ ++void ++out_of_memory(void) ++{ ++ fprintf(stderr, "Out of Memory\n"); ++ exit(1); ++} ++ ++bool ++dont_mute(unsigned int flags) ++{ ++ return true; ++} +Index: openvpn-2.3.4/tests/unit_tests/openvpn/mock_msg.h +=================================================================== +--- /dev/null ++++ openvpn-2.3.4/tests/unit_tests/openvpn/mock_msg.h +@@ -0,0 +1,35 @@ ++/* ++ * 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-2017 Fox Crypto B.V. ++ * ++ * 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 ++ */ ++ ++#ifndef MOCK_MSG_H ++#define MOCK_MSG_H ++ ++/** ++ * Mock debug level defaults to 0, which gives clean(-ish) test reports. Call ++ * this function from your test driver to increase debug output when you ++ * need debug output. ++ */ ++void mock_set_debug_level(int level); ++ ++#endif /* MOCK_MSG */ +Index: openvpn-2.3.4/tests/unit_tests/openvpn/test_packet_id.c +=================================================================== +--- /dev/null ++++ openvpn-2.3.4/tests/unit_tests/openvpn/test_packet_id.c +@@ -0,0 +1,169 @@ ++/* ++ * 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. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++ ++#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..5cbc1ee --- /dev/null +++ b/debian/patches/CVE-2017-7479.patch @@ -0,0 +1,162 @@ +From ac08b27cfa693d9be592bb2597c260635aee9e68 Mon Sep 17 00:00:00 2001 +From: Steffan Karger +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 + +CVE-2017-7479 + +[Ubuntu note: 2.3.x does not support tlscrypt, so that portion of patch +was dropped; other backporting to 2.3.x]. --sbeattie + +--- + 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.3.2/src/openvpn/crypto.c +=================================================================== +--- openvpn-2.3.2.orig/src/openvpn/crypto.c ++++ openvpn-2.3.2/src/openvpn/crypto.c +@@ -112,9 +112,13 @@ openvpn_encrypt (struct buffer *buf, str + prng_bytes (iv_buf, iv_size); + + /* Put packet ID in plaintext buffer or IV, depending on cipher mode */ +- if (opt->packet_id) ++ if (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; + } + } + else if (mode == OPENVPN_MODE_CFB || mode == OPENVPN_MODE_OFB) +@@ -182,9 +186,12 @@ openvpn_encrypt (struct buffer *buf, str + } + else /* No Encryption */ + { +- if (opt->packet_id) ++ if (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; + } + work = *buf; + } +Index: openvpn-2.3.2/src/openvpn/packet_id.c +=================================================================== +--- openvpn-2.3.2.orig/src/openvpn/packet_id.c ++++ openvpn-2.3.2/src/openvpn/packet_id.c +@@ -294,27 +294,37 @@ packet_id_read (struct packet_id_net *pi + 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.3.2/src/openvpn/packet_id.h +=================================================================== +--- openvpn-2.3.2.orig/src/openvpn/packet_id.h ++++ openvpn-2.3.2/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.3.2/tests/unit_tests/openvpn/test_packet_id.c +=================================================================== +--- openvpn-2.3.2.orig/tests/unit_tests/openvpn/test_packet_id.c ++++ openvpn-2.3.2/tests/unit_tests/openvpn/test_packet_id.c +@@ -130,8 +130,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 +@@ -140,8 +139,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/CVE-2017-7508.patch b/debian/patches/CVE-2017-7508.patch new file mode 100644 index 0000000..f096553 --- /dev/null +++ b/debian/patches/CVE-2017-7508.patch @@ -0,0 +1,57 @@ +commit fc61d1bda112ffc669dbde961fab19f60b3c7439 +Author: Gert Doering +Date: Tue Jun 13 22:08:32 2017 +0200 + + Fix remotely-triggerable ASSERT() on malformed IPv6 packet. + + Correct sanity checks on IPv6 packet length in mss_fixup_ipv6(), + and change the ASSERT() check in mss_fixup_dowork() into a simple + "return" (= the TCP header will simply not be inspected further). + + CVE-2017-7508 has been assigned due to the serious nature of the + bug: it can be used to remotely shutdown an openvpn server or + client, if IPv6 and --mssfix are enabled and the IPv6 networks used + inside the VPN are known. + + Found by Guido Vranken . + + v2: style changes + + CVE: 2017-7508 + Signed-off-by: Gert Doering + Acked-by: Steffan Karger + Message-Id: <20170613200832.15027-1-gert@greenie.muc.de> + URL: https://www.mail-archive.com/search?l=mid&q=20170613200832.15027-1-gert@greenie.muc.de + Signed-off-by: Gert Doering + (cherry picked from commit c3f47077a7756de5929094569421a95aa66f2022) + +diff --git a/src/openvpn/mss.c b/src/openvpn/mss.c +index f930942a..c91751d1 100644 +--- a/src/openvpn/mss.c ++++ b/src/openvpn/mss.c +@@ -110,8 +110,12 @@ mss_fixup_ipv6 (struct buffer *buf, int maxmss) + if ( pip6->nexthdr != OPENVPN_IPPROTO_TCP ) + return; + ++ /* skip IPv6 header (40 bytes), ++ * verify remainder is large enough to contain a full TCP header ++ */ + newbuf = *buf; +- if ( buf_advance( &newbuf, 40 ) ) ++ if (buf_advance( &newbuf, 40 ) ++ && BLEN(&newbuf) >= (int) sizeof(struct openvpn_tcphdr)) + { + struct openvpn_tcphdr *tc = (struct openvpn_tcphdr *) BPTR (&newbuf); + if (tc->flags & OPENVPN_TCPH_SYN_MASK) +@@ -133,7 +137,10 @@ mss_fixup_dowork (struct buffer *buf, uint16_t maxmss) + int accumulate; + struct openvpn_tcphdr *tc; + +- ASSERT (BLEN (buf) >= (int) sizeof (struct openvpn_tcphdr)); ++ if (BLEN(buf) < (int) sizeof(struct openvpn_tcphdr)) ++ { ++ return; ++ } + + verify_align_4 (buf); + tc = (struct openvpn_tcphdr *) BPTR (buf); diff --git a/debian/patches/CVE-2017-7520.patch b/debian/patches/CVE-2017-7520.patch new file mode 100644 index 0000000..e74cec0 --- /dev/null +++ b/debian/patches/CVE-2017-7520.patch @@ -0,0 +1,55 @@ +commit f38a4a105979b87ebebe9be1c3d323116d3fb924 +Author: Guido Vranken +Date: Fri May 19 14:04:25 2017 +0200 + + Prevent two kinds of stack buffer OOB reads and a crash for invalid input data + + Pre-authentication remote crash/information disclosure for clients + + If clients use a HTTP proxy with NTLM authentication (i.e. + "--http-proxy [|'auto'|'auto-nct'] ntlm2"), + a man-in-the-middle attacker between the client and the proxy can + cause the client to crash or disclose at most 96 bytes of stack + memory. The disclosed stack memory is likely to contain the proxy + password. + + If the proxy password is not reused, this is unlikely to compromise + the security of the OpenVPN tunnel itself. Clients who do not use + the --http-proxy option with ntlm2 authentication are not affected. + + CVE: 2017-7520 + Signed-off-by: Guido Vranken + Acked-by: Gert Doering + Message-Id: + URL: https://www.mail-archive.com/search?l=mid&q=CAO5O-EJvHKid-zTj+hmFG_3Gv78ixqCayE9=C62DZaxN32WNtQ@mail.gmail.com + Signed-off-by: Gert Doering + (cherry picked from commit 7718c8984f04b507c1885f363970e2124e3c6c77) + +Index: openvpn-2.3.4/src/openvpn/ntlm.c +=================================================================== +--- openvpn-2.3.4.orig/src/openvpn/ntlm.c ++++ openvpn-2.3.4/src/openvpn/ntlm.c +@@ -193,7 +193,7 @@ ntlm_phase_3 (const struct http_proxy_in + */ + + char pwbuf[sizeof (p->up.password) * 2]; /* for unicode password */ +- char buf2[128]; /* decoded reply from proxy */ ++ unsigned char buf2[128]; /* decoded reply from proxy */ + unsigned char phase3[464]; + + char md4_hash[MD4_DIGEST_LENGTH+5]; +@@ -282,7 +282,13 @@ ntlm_phase_3 (const struct http_proxy_in + tib_len = buf2[0x28];/* Get Target Information block size */ + if (tib_len > 96) tib_len = 96; + { +- char *tib_ptr = buf2 + buf2[0x2c]; /* Get Target Information block pointer */ ++ char *tib_ptr; ++ int tib_pos = buf2[0x2c]; ++ if (tib_pos + tib_len > sizeof(buf2)) ++ { ++ return NULL; ++ } ++ tib_ptr = buf2 + tib_pos; /* Get Target Information block pointer */ + memcpy(&ntlmv2_blob[0x1c], tib_ptr, tib_len); /* Copy Target Information block into the blob */ + } + } else { diff --git a/debian/patches/CVE-2017-7521.patch b/debian/patches/CVE-2017-7521.patch new file mode 100644 index 0000000..085550c --- /dev/null +++ b/debian/patches/CVE-2017-7521.patch @@ -0,0 +1,48 @@ +commit 1dde0cd6e5e6a0f2f45ec9969b7ff1b6537514ad +Author: Steffan Karger +Date: Mon Jun 19 11:28:40 2017 +0200 + + Fix potential double-free in --x509-alt-username (CVE-2017-7521) + + We didn't check the return value of ASN1_STRING_to_UTF8() in + extract_x509_extension(). Ignoring such a failure could result in buf + being free'd twice. An error in ASN1_STRING_to_UTF8() can be caused + remotely if the peer can make the local process run out of memory. + + The problem can only be triggered for configurations that use the + --x509-alt-username option with an x509 extension (i.e. the option + parameter starts with "ext:"). + + This issue was discovered, analysed and reported to the OpenVPN team by + Guido Vranken. + + Extensive testing by Guido Vranken gives confidence that this function + is very unlikely to fail in real-world usage (using subjectAltName or + issuerAltName extensions) for other reasons than memory exhaustion. + + CVE: 2017-7521 + Signed-off-by: Steffan Karger + Acked-by: Gert Doering + Acked-by: David Sommerseth + Acked-by: Guido Vranken + Message-Id: <1497864520-12219-6-git-send-email-steffan.karger@fox-it.com> + URL: https://www.mail-archive.com/search?l=mid&q=1497864520-12219-6-git-send-email-steffan.karger@fox-it.com + Signed-off-by: Gert Doering + (cherry picked from commit cb4e35ece4a5b70b10ef9013be3bff263d82f32b) + +Index: openvpn-2.3.4/src/openvpn/ssl_verify_openssl.c +=================================================================== +--- openvpn-2.3.4.orig/src/openvpn/ssl_verify_openssl.c ++++ openvpn-2.3.4/src/openvpn/ssl_verify_openssl.c +@@ -124,7 +124,10 @@ bool extract_x509_extension(X509 *cert, + switch (name->type) + { + case GEN_EMAIL: +- ASN1_STRING_to_UTF8((unsigned char**)&buf, name->d.ia5); ++ if (ASN1_STRING_to_UTF8((unsigned char **)&buf, name->d.ia5) < 0) ++ { ++ continue; ++ } + if ( strlen (buf) != name->d.ia5->length ) + { + msg (D_TLS_ERRORS, "ASN1 ERROR: string contained terminating zero"); diff --git a/debian/patches/CVE-2017-7521bis.patch b/debian/patches/CVE-2017-7521bis.patch new file mode 100644 index 0000000..a986ef0 --- /dev/null +++ b/debian/patches/CVE-2017-7521bis.patch @@ -0,0 +1,74 @@ +commit 84e1775961de1c9d2ab32159fc03f758591f5238 +Author: Steffan Karger +Date: Mon Jun 19 11:28:38 2017 +0200 + + Fix remote-triggerable memory leaks (CVE-2017-7521) + + Several of our OpenSSL-specific certificate-parsing code paths did not + always clear all allocated memory. Since a client can cause a few bytes + of memory to be leaked for each connection attempt, a client can cause a + server to run out of memory and thereby kill the server. That makes this + a (quite inefficient) DoS attack. + + When using the --x509-alt-username option on openssl builds with an + extension (argument prefixed with "ext:", e.g. "ext:subjectAltName"), the + code would not free all allocated memory. Fix this by using the proper + free function. + + If ASN1_STRING_to_UTF8() returns 0, it didn't fail and *did* allocate + memory. So also free the returned buffer if it returns 0. + + These issues were found, analysed and reported to the OpenVPN team by Guido + Vranken. + + CVE: 2017-7521 + Signed-off-by: Steffan Karger + Acked-by: Gert Doering + Acked-by: David Sommerseth + Acked-by: Guido Vranken + Message-Id: <1497864520-12219-4-git-send-email-steffan.karger@fox-it.com> + URL: https://www.mail-archive.com/search?l=mid&q=1497864520-12219-4-git-send-email-steffan.karger@fox-it.com + Signed-off-by: Gert Doering + (cherry picked from commit 2d032c7fcdfd692c851ea2fa858b4c2d9ea7d52d) + +Index: openvpn-2.3.4/src/openvpn/ssl_verify_openssl.c +=================================================================== +--- openvpn-2.3.4.orig/src/openvpn/ssl_verify_openssl.c ++++ openvpn-2.3.4/src/openvpn/ssl_verify_openssl.c +@@ -144,7 +144,7 @@ bool extract_x509_extension(X509 *cert, + break; + } + } +- sk_GENERAL_NAME_free (extensions); ++ GENERAL_NAMES_free(extensions); + } + return retval; + } +@@ -191,8 +191,7 @@ extract_x509_field_ssl (X509_NAME *x509, + asn1 = X509_NAME_ENTRY_get_data(x509ne); + if (!asn1) + return FAILURE; +- tmp = ASN1_STRING_to_UTF8(&buf, asn1); +- if (tmp <= 0) ++ if (ASN1_STRING_to_UTF8(&buf, asn1) < 0) + return FAILURE; + + strncpynt(out, (char *)buf, size); +@@ -364,7 +363,7 @@ x509_setenv_track (const struct x509_tra + ASN1_STRING *val = X509_NAME_ENTRY_get_data (ent); + unsigned char *buf; + buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ +- if (ASN1_STRING_to_UTF8 (&buf, val) > 0) ++ if (ASN1_STRING_to_UTF8 (&buf, val) >= 0) + { + do_setenv_x509(es, xt->name, (char *)buf, depth); + OPENSSL_free (buf); +@@ -440,7 +439,7 @@ x509_setenv (struct env_set *es, int cer + if (!objbuf) + continue; + buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ +- if (ASN1_STRING_to_UTF8 (&buf, val) <= 0) ++ if (ASN1_STRING_to_UTF8 (&buf, val) < 0) + continue; + name_expand_size = 64 + strlen (objbuf); + name_expand = (char *) malloc (name_expand_size); diff --git a/debian/patches/series b/debian/patches/series index 22a08e6..dcff610 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -10,3 +10,9 @@ better_systemd_detection.patch client_connect_tmp_files.patch 0001-Drop-too-short-control-channel-packets-instead-of-as.patch update_sample_certs.patch +CVE-2017-7479-prereq.patch +CVE-2017-7479.patch +CVE-2017-7521.patch +CVE-2017-7521bis.patch +CVE-2017-7520.patch +CVE-2017-7508.patch -- cgit v1.2.3