Skip to content

Commit 591a4e5

Browse files
syzzerdsommers
authored andcommitted
Drop packets instead of assert out if packet id rolls over (CVE-2017-7479)
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). This is a fix for finding 5.2 from the OSTIF / Quarkslab audit. CVE: 2017-7479 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: <1494358209-4568-3-git-send-email-steffan.karger@fox-it.com> URL: http://www.mail-archive.com/search?l=mid&q=1494358209-4568-3-git-send-email-steffan.karger@fox-it.com Signed-off-by: David Sommerseth <davids@openvpn.net> (cherry picked from commit e498cb0)
1 parent 66b99a0 commit 591a4e5

File tree

6 files changed

+51
-18
lines changed

6 files changed

+51
-18
lines changed

Changes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,3 +335,7 @@ Security
335335
to hit an ASSERT() and stop the process. If ``--tls-auth`` or ``--tls-crypt``
336336
is used, only attackers that have the ``--tls-auth`` or ``--tls-crypt`` key
337337
can mount an attack. (OSTIF/Quarkslab audit finding 5.1, CVE-2017-7478)
338+
- Fix an authenticated remote DoS vulnerability that could be triggered by
339+
causing a packet id roll over. An attack is rather inefficient; a peer
340+
would need to get us to send at least about 196 GB of data.
341+
(OSTIF/Quarkslab audit finding 5.2, CVE-2017-7479)

src/openvpn/crypto.c

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,11 @@ openvpn_encrypt_aead(struct buffer *buf, struct buffer work,
9494
buf_set_write(&iv_buffer, iv, iv_len);
9595

9696
/* IV starts with packet id to make the IV unique for packet */
97-
ASSERT(packet_id_write(&opt->packet_id.send, &iv_buffer, false, false));
97+
if (!packet_id_write(&opt->packet_id.send, &iv_buffer, false, false))
98+
{
99+
msg(D_CRYPT_ERRORS, "ENCRYPT ERROR: packet ID roll over");
100+
goto err;
101+
}
98102

99103
/* Remainder of IV consists of implicit part (unique per session) */
100104
ASSERT(buf_write(&iv_buffer, ctx->implicit_iv, ctx->implicit_iv_len));
@@ -195,11 +199,13 @@ openvpn_encrypt_v1(struct buffer *buf, struct buffer work,
195199
}
196200

197201
/* Put packet ID in plaintext buffer */
198-
if (packet_id_initialized(&opt->packet_id))
202+
if (packet_id_initialized(&opt->packet_id)
203+
&& !packet_id_write(&opt->packet_id.send, buf,
204+
opt->flags & CO_PACKET_ID_LONG_FORM,
205+
true))
199206
{
200-
ASSERT(packet_id_write(&opt->packet_id.send, buf,
201-
opt->flags & CO_PACKET_ID_LONG_FORM,
202-
true));
207+
msg(D_CRYPT_ERRORS, "ENCRYPT ERROR: packet ID roll over");
208+
goto err;
203209
}
204210
}
205211
else if (cipher_kt_mode_ofb_cfb(cipher_kt))
@@ -259,11 +265,12 @@ openvpn_encrypt_v1(struct buffer *buf, struct buffer work,
259265
}
260266
else /* No Encryption */
261267
{
262-
if (packet_id_initialized(&opt->packet_id))
268+
if (packet_id_initialized(&opt->packet_id)
269+
&& !packet_id_write(&opt->packet_id.send, buf,
270+
opt->flags & CO_PACKET_ID_LONG_FORM, true))
263271
{
264-
ASSERT(packet_id_write(&opt->packet_id.send, buf,
265-
BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM),
266-
true));
272+
msg(D_CRYPT_ERRORS, "ENCRYPT ERROR: packet ID roll over");
273+
goto err;
267274
}
268275
if (ctx->hmac)
269276
{

src/openvpn/packet_id.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -325,27 +325,37 @@ packet_id_read(struct packet_id_net *pin, struct buffer *buf, bool long_form)
325325
return true;
326326
}
327327

328-
static void
328+
static bool
329329
packet_id_send_update(struct packet_id_send *p, bool long_form)
330330
{
331331
if (!p->time)
332332
{
333333
p->time = now;
334334
}
335-
p->id++;
336-
if (!p->id)
335+
if (p->id == PACKET_ID_MAX)
337336
{
338-
ASSERT(long_form);
337+
/* Packet ID only allowed to roll over if using long form and time has
338+
* moved forward since last roll over.
339+
*/
340+
if (!long_form || now <= p->time)
341+
{
342+
return false;
343+
}
339344
p->time = now;
340-
p->id = 1;
345+
p->id = 0;
341346
}
347+
p->id++;
348+
return true;
342349
}
343350

344351
bool
345352
packet_id_write(struct packet_id_send *p, struct buffer *buf, bool long_form,
346353
bool prepend)
347354
{
348-
packet_id_send_update(p, long_form);
355+
if (!packet_id_send_update(p, long_form))
356+
{
357+
return false;
358+
}
349359

350360
const packet_id_type net_id = htonpid(p->id);
351361
const net_time_t net_time = htontime(p->time);

src/openvpn/packet_id.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
* to for network transmission.
5151
*/
5252
typedef uint32_t packet_id_type;
53+
#define PACKET_ID_MAX UINT32_MAX
5354
typedef uint32_t net_time_t;
5455

5556
/*

src/openvpn/tls_crypt.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,11 @@ tls_crypt_wrap(const struct buffer *src, struct buffer *dst,
9898
format_hex(BPTR(src), BLEN(src), 80, &gc));
9999

100100
/* Get packet ID */
101-
ASSERT(packet_id_write(&opt->packet_id.send, dst, true, false));
101+
if (!packet_id_write(&opt->packet_id.send, dst, true, false))
102+
{
103+
msg(D_CRYPT_ERRORS, "TLS-CRYPT ERROR: packet ID roll over.");
104+
goto err;
105+
}
102106

103107
dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP AD: %s",
104108
format_hex(BPTR(dst), BLEN(dst), 0, &gc));

tests/unit_tests/openvpn/test_packet_id.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,7 @@ test_packet_id_write_short_wrap(void **state)
129129
struct test_packet_id_write_data *data = *state;
130130

131131
data->pis.id = ~0;
132-
expect_assert_failure(
133-
packet_id_write(&data->pis, &data->test_buf, false, false));
132+
assert_false(packet_id_write(&data->pis, &data->test_buf, false, false));
134133
}
135134

136135
static void
@@ -139,8 +138,16 @@ test_packet_id_write_long_wrap(void **state)
139138
struct test_packet_id_write_data *data = *state;
140139

141140
data->pis.id = ~0;
141+
data->pis.time = 5006;
142+
143+
/* Write fails if time did not change */
144+
now = 5006;
145+
assert_false(packet_id_write(&data->pis, &data->test_buf, true, false));
146+
147+
/* Write succeeds if time moved forward */
142148
now = 5010;
143149
assert_true(packet_id_write(&data->pis, &data->test_buf, true, false));
150+
144151
assert(data->pis.id == 1);
145152
assert(data->pis.time == now);
146153
assert_true(data->test_buf_data.buf_id == htonl(1));

0 commit comments

Comments
 (0)