Skip to content

Commit b727643

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-1-git-send-email-steffan.karger@fox-it.com> URL: http://www.mail-archive.com/search?l=mid&q=1494358209-4568-1-git-send-email-steffan.karger@fox-it.com Signed-off-by: David Sommerseth <davids@openvpn.net>
1 parent e80c659 commit b727643

File tree

5 files changed

+49
-13
lines changed

5 files changed

+49
-13
lines changed

Changes.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,16 @@ Behavioral changes
104104

105105
- Do not randomize resolving of IP addresses in getaddr()
106106

107+
Version 2.3.15
108+
==============
109+
110+
Security fixes
111+
--------------
112+
- Fix an authenticated remote DoS vulnerability that could be triggered by
113+
causing a packet id roll over. An attack is rather inefficient; a peer
114+
would need to get us to send at least about 196 GB of data.
115+
(OSTIF/Quarkslab audit finding 5.2, CVE-2017-7479)
116+
107117
Version 2.3.14
108118
==============
109119

src/openvpn/crypto.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,11 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
110110
prng_bytes (iv_buf, iv_size);
111111

112112
/* Put packet ID in plaintext buffer or IV, depending on cipher mode */
113-
if (opt->packet_id)
113+
if (opt->packet_id
114+
&& !packet_id_write (&opt->packet_id->send, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true))
114115
{
115-
ASSERT (packet_id_write (&opt->packet_id->send, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true));
116+
msg (D_CRYPT_ERRORS, "ENCRYPT ERROR: packet ID roll over");
117+
goto err;
116118
}
117119
}
118120
else if (cipher_kt_mode_ofb_cfb(cipher_kt))
@@ -123,7 +125,11 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
123125
ASSERT (opt->packet_id); /* for this mode. */
124126

125127
buf_set_write (&b, iv_buf, iv_size);
126-
ASSERT (packet_id_write (&opt->packet_id->send, &b, true, false));
128+
if (!packet_id_write (&opt->packet_id->send, &b, true, false))
129+
{
130+
msg (D_CRYPT_ERRORS, "ENCRYPT ERROR: packet ID roll over");
131+
goto err;
132+
}
127133
}
128134
else /* We only support CBC, CFB, or OFB modes right now */
129135
{
@@ -182,9 +188,11 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
182188
}
183189
else /* No Encryption */
184190
{
185-
if (opt->packet_id)
191+
if (opt->packet_id
192+
&& !packet_id_write (&opt->packet_id->send, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true))
186193
{
187-
ASSERT (packet_id_write (&opt->packet_id->send, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true));
194+
msg (D_CRYPT_ERRORS, "ENCRYPT ERROR: packet ID roll over");
195+
goto err;
188196
}
189197
work = *buf;
190198
}

src/openvpn/packet_id.c

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

297-
static void
297+
static bool
298298
packet_id_send_update(struct packet_id_send *p, bool long_form)
299299
{
300300
if (!p->time)
301301
{
302302
p->time = now;
303303
}
304-
p->id++;
305-
if (!p->id)
304+
if (p->id == PACKET_ID_MAX)
306305
{
307-
ASSERT(long_form);
306+
/* Packet ID only allowed to roll over if using long form and time has
307+
* moved forward since last roll over.
308+
*/
309+
if (!long_form || now <= p->time)
310+
{
311+
return false;
312+
}
308313
p->time = now;
309-
p->id = 1;
314+
p->id = 0;
310315
}
316+
p->id++;
317+
return true;
311318
}
312319

313320
bool
314321
packet_id_write (struct packet_id_send *p, struct buffer *buf, bool long_form,
315322
bool prepend)
316323
{
317-
packet_id_send_update(p, long_form);
324+
if (!packet_id_send_update(p, long_form))
325+
{
326+
return false;
327+
}
318328

319329
const packet_id_type net_id = htonpid(p->id);
320330
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
/*

tests/unit_tests/openvpn/test_packet_id.c

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

132132
data->pis.id = ~0;
133-
expect_assert_failure(
134-
packet_id_write(&data->pis, &data->test_buf, false, false));
133+
assert_false(packet_id_write(&data->pis, &data->test_buf, false, false));
135134
}
136135

137136
static void
@@ -140,8 +139,16 @@ test_packet_id_write_long_wrap(void **state)
140139
struct test_packet_id_write_data *data = *state;
141140

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

0 commit comments

Comments
 (0)