diff options
Diffstat (limited to 'debian/patches/CVE-2017-7479.patch')
-rw-r--r-- | debian/patches/CVE-2017-7479.patch | 193 |
1 files changed, 193 insertions, 0 deletions
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)); |