Skip to content

Commit 518e122

Browse files
schwabecron2
authored andcommitted
Check message id/acked ids too when doing sessionid cookie checks
This fixes that control packets on a floating client can trigger creating a new session in special circumstances: To trigger this circumstance a connection needs to - starts on IP A - successfully floats to IP B by data packet - then has a control packet from IP A before any data packet can trigger the float back to IP A and all of this needs to happen in the 60s time that hmac cookie is valid in the default configuration. In this scenario we would trigger a new connection as the HMAC session id would be valid. This patch adds checking also of the message-id and acked ids to discern packet from the initial three-way handshake where these ids are 0 or 1 from any later packet. This will now trigger (at verb 4 or higher) a messaged like: Packet (P_ACK_V1) with invalid or missing SID instead. Also remove a few duplicated free_tls_pre_decrypt_state in test_ssl. Reported-By: Walter Doekes <[email protected]> Tested-By: Walter Doekes <[email protected]> Change-Id: I6752dcd5aff3e5cea2b439366479e86751a1c403 Signed-off-by: Arne Schwabe <[email protected]> Acked-by: MaxF <[email protected]> Message-Id: <[email protected]> URL: https://www.mail-archive.com/[email protected]/msg32626.html Signed-off-by: Gert Doering <[email protected]>
1 parent 5c4744f commit 518e122

File tree

4 files changed

+129
-24
lines changed

4 files changed

+129
-24
lines changed

src/openvpn/mudp.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,15 +151,17 @@ do_pre_decrypt_check(struct multi_context *m, struct tls_pre_decrypt_state *stat
151151
* need to contain the peer id */
152152
struct gc_arena gc = gc_new();
153153

154-
bool ret = check_session_id_hmac(state, from, hmac, handwindow);
154+
bool pkt_is_ack = (verdict == VERDICT_VALID_ACK_V1);
155+
bool ret = check_session_hmac_and_pkt_id(state, from, hmac, handwindow, pkt_is_ack);
155156

156157
const char *peer = print_link_socket_actual(&m->top.c2.from, &gc);
157158
uint8_t pkt_firstbyte = *BPTR(&m->top.c2.buf);
158159
int op = pkt_firstbyte >> P_OPCODE_SHIFT;
159160

160161
if (!ret)
161162
{
162-
msg(D_MULTI_MEDIUM, "Packet (%s) with invalid or missing SID from %s",
163+
msg(D_MULTI_MEDIUM, "Packet (%s) with invalid or missing SID from"
164+
" %s or wrong packet id",
163165
packet_opcode_name(op), peer);
164166
}
165167
else

src/openvpn/ssl_pkt.c

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -496,8 +496,11 @@ calculate_session_id_hmac(struct session_id client_sid, const struct openvpn_soc
496496
}
497497

498498
bool
499-
check_session_id_hmac(struct tls_pre_decrypt_state *state, const struct openvpn_sockaddr *from,
500-
hmac_ctx_t *hmac, int handwindow)
499+
check_session_hmac_and_pkt_id(struct tls_pre_decrypt_state *state,
500+
const struct openvpn_sockaddr *from,
501+
hmac_ctx_t *hmac,
502+
int handwindow,
503+
bool pkt_is_ack)
501504
{
502505
if (!from)
503506
{
@@ -512,6 +515,36 @@ check_session_id_hmac(struct tls_pre_decrypt_state *state, const struct openvpn_
512515
return false;
513516
}
514517

518+
/* Check if the packet ID of the packet or ACKED packet is <= 1 */
519+
for (int i = 0; i < ack.len; i++)
520+
{
521+
/* This packet ACKs a packet that has a higher packet id than the
522+
* ones expected in the three-way handshake, consider it as invalid
523+
* for the session */
524+
if (ack.packet_id[i] > 1)
525+
{
526+
return false;
527+
}
528+
}
529+
530+
if (!pkt_is_ack)
531+
{
532+
packet_id_type message_id;
533+
/* Extract the packet ID from the packet */
534+
if (!reliable_ack_read_packet_id(&buf, &message_id))
535+
{
536+
return false;
537+
}
538+
539+
/* similar check. Anything larger than 1 is not considered part of the
540+
* three-way handshake */
541+
if (message_id > 1)
542+
{
543+
return false;
544+
}
545+
}
546+
547+
515548
/* check adjacent timestamps too */
516549
for (int offset = -2; offset <= 1; offset++)
517550
{

src/openvpn/ssl_pkt.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,20 @@ struct session_id calculate_session_id_hmac(struct session_id client_sid,
178178
/**
179179
* Checks if a control packet has a correct HMAC server session id
180180
*
181+
* This will also consider packets that have a packet id higher
182+
* than 1 or ack packets higher than 1 to be invalid as they are
183+
* not part of the initial three way handshake of OpenVPN and should
184+
* not create a new connection.
185+
*
181186
* @param state session information
182187
* @param from link_socket from the client
183188
* @param hmac the hmac context to use for the calculation
184189
* @param handwindow the quantisation of the current time
190+
* @param pkt_is_ack the packet being checked is a P_ACK_V1
185191
* @return the expected server session id
186192
*/
187-
bool check_session_id_hmac(struct tls_pre_decrypt_state *state, const struct openvpn_sockaddr *from,
188-
hmac_ctx_t *hmac, int handwindow);
193+
bool check_session_hmac_and_pkt_id(struct tls_pre_decrypt_state *state, const struct openvpn_sockaddr *from,
194+
hmac_ctx_t *hmac, int handwindow, bool pkt_is_ack);
189195

190196
/*
191197
* Write a control channel authentication record.

tests/unit_tests/openvpn/test_pkt.c

Lines changed: 82 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,27 @@ const uint8_t client_ack_none_random_id[] = { 0x28, 0xae, 0xb9, 0xaf, 0xe1, 0xf0
139139
0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x85,
140140
0xdb, 0x53, 0x56, 0x23, 0xb0, 0x2e };
141141

142+
/* no tls-auth, P_ACK_V1, acks 0,1, and 2 */
143+
const uint8_t client_ack_123_none_random_id[] = {
144+
0x28,
145+
0xae, 0xb9, 0xaf, 0xe1, 0xf0, 0x1d, 0x79, 0xc8,
146+
0x03,
147+
0x00, 0x00, 0x00, 0x00,
148+
0x00, 0x00, 0x00, 0x01,
149+
0x00, 0x00, 0x00, 0x02,
150+
0xdd, 0x85, 0xdb, 0x53, 0x56, 0x23, 0xb0, 0x2e
151+
};
152+
153+
/* no tls-auth, P_CONTROL_V1, acks 0, msg-id 2 */
154+
const uint8_t client_control_none_random_id[] = {
155+
0x20,
156+
0xae, 0xb9, 0xaf, 0xe1, 0xf0, 0x1d, 0x79, 0xc8,
157+
0x01,
158+
0x00, 0x00, 0x00, 0x00,
159+
0x02
160+
};
161+
162+
142163
struct tls_auth_standalone
143164
init_tas_auth(int key_direction)
144165
{
@@ -256,12 +277,10 @@ test_tls_decrypt_lite_auth(void **ut_state)
256277
assert_int_equal(verdict, VERDICT_VALID_RESET_V2);
257278
free_tls_pre_decrypt_state(&state);
258279

259-
free_tls_pre_decrypt_state(&state);
260280
/* The pre decrypt function should not modify the buffer, so calling it
261281
* again should have the same result */
262282
verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf);
263283
assert_int_equal(verdict, VERDICT_VALID_RESET_V2);
264-
free_tls_pre_decrypt_state(&state);
265284

266285
/* and buf memory should be equal */
267286
assert_memory_equal(BPTR(&buf), client_reset_v2_tls_auth, sizeof(client_reset_v2_tls_auth));
@@ -279,7 +298,6 @@ test_tls_decrypt_lite_auth(void **ut_state)
279298
assert_int_equal(verdict, VERDICT_INVALID);
280299
free_tls_pre_decrypt_state(&state);
281300

282-
free_tls_pre_decrypt_state(&state);
283301
/* Wrong key direction gives a wrong hmac key and should not validate */
284302
free_key_ctx_bi(&tas.tls_wrap.opt.key_ctx_bi);
285303
free_tas(&tas);
@@ -319,15 +337,12 @@ test_tls_decrypt_lite_none(void **ut_state)
319337
assert_int_equal(verdict, VERDICT_VALID_RESET_V2);
320338
free_tls_pre_decrypt_state(&state);
321339

322-
free_tls_pre_decrypt_state(&state);
323340
buf_reset_len(&buf);
324341
buf_write(&buf, client_reset_v2_tls_crypt, sizeof(client_reset_v2_none));
325342
verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf);
326343
assert_int_equal(verdict, VERDICT_VALID_RESET_V2);
327344
free_tls_pre_decrypt_state(&state);
328345

329-
free_tls_pre_decrypt_state(&state);
330-
331346
/* This is not a reset packet and should trigger the other response */
332347
buf_reset_len(&buf);
333348
buf_write(&buf, client_ack_tls_auth_randomid, sizeof(client_ack_tls_auth_randomid));
@@ -405,7 +420,7 @@ test_verify_hmac_tls_auth(void **ut_state)
405420
assert_int_equal(verdict, VERDICT_VALID_CONTROL_V1);
406421

407422
/* This is a valid packet but containing a random id instead of an HMAC id*/
408-
bool valid = check_session_id_hmac(&state, &from.dest, hmac, 30);
423+
bool valid = check_session_hmac_and_pkt_id(&state, &from.dest, hmac, 30, false);
409424
assert_false(valid);
410425

411426
free_tls_pre_decrypt_state(&state);
@@ -436,7 +451,7 @@ test_verify_hmac_none(void **ut_state)
436451
verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf);
437452
assert_int_equal(verdict, VERDICT_VALID_ACK_V1);
438453

439-
bool valid = check_session_id_hmac(&state, &from.dest, hmac, 30);
454+
bool valid = check_session_hmac_and_pkt_id(&state, &from.dest, hmac, 30, true);
440455
assert_true(valid);
441456

442457
free_tls_pre_decrypt_state(&state);
@@ -445,6 +460,51 @@ test_verify_hmac_none(void **ut_state)
445460
hmac_ctx_free(hmac);
446461
}
447462

463+
static void
464+
test_verify_hmac_none_out_of_range_ack(void **ut_state)
465+
{
466+
hmac_ctx_t *hmac = session_id_hmac_init();
467+
468+
struct link_socket_actual from = { 0 };
469+
from.dest.addr.sa.sa_family = AF_INET;
470+
471+
struct tls_auth_standalone tas = { 0 };
472+
struct tls_pre_decrypt_state state = { 0 };
473+
474+
struct buffer buf = alloc_buf(1024);
475+
enum first_packet_verdict verdict;
476+
477+
tas.tls_wrap.mode = TLS_WRAP_NONE;
478+
479+
buf_reset_len(&buf);
480+
buf_write(&buf, client_ack_123_none_random_id, sizeof(client_ack_123_none_random_id));
481+
482+
483+
verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf);
484+
assert_int_equal(verdict, VERDICT_VALID_ACK_V1);
485+
486+
/* should fail because it acks 2 */
487+
bool valid = check_session_hmac_and_pkt_id(&state, &from.dest, hmac, 30, true);
488+
assert_false(valid);
489+
free_tls_pre_decrypt_state(&state);
490+
491+
/* Try test with the control with a too high message id now */
492+
buf_reset_len(&buf);
493+
buf_write(&buf, client_control_none_random_id, sizeof(client_control_none_random_id));
494+
495+
verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf);
496+
assert_int_equal(verdict, VERDICT_VALID_CONTROL_V1);
497+
498+
/* should fail because it has message id 2 */
499+
valid = check_session_hmac_and_pkt_id(&state, &from.dest, hmac, 30, true);
500+
assert_false(valid);
501+
502+
free_tls_pre_decrypt_state(&state);
503+
free_buf(&buf);
504+
hmac_ctx_cleanup(hmac);
505+
hmac_ctx_free(hmac);
506+
}
507+
448508
static hmac_ctx_t *
449509
init_static_hmac(void)
450510
{
@@ -634,16 +694,20 @@ int
634694
main(void)
635695
{
636696
openvpn_unit_test_setup();
637-
const struct CMUnitTest tests[] = { cmocka_unit_test(test_tls_decrypt_lite_none),
638-
cmocka_unit_test(test_tls_decrypt_lite_auth),
639-
cmocka_unit_test(test_tls_decrypt_lite_crypt),
640-
cmocka_unit_test(test_parse_ack),
641-
cmocka_unit_test(test_calc_session_id_hmac_static),
642-
cmocka_unit_test(test_verify_hmac_none),
643-
cmocka_unit_test(test_verify_hmac_tls_auth),
644-
cmocka_unit_test(test_generate_reset_packet_plain),
645-
cmocka_unit_test(test_generate_reset_packet_tls_auth),
646-
cmocka_unit_test(test_extract_control_message) };
697+
698+
const struct CMUnitTest tests[] = {
699+
cmocka_unit_test(test_tls_decrypt_lite_none),
700+
cmocka_unit_test(test_tls_decrypt_lite_auth),
701+
cmocka_unit_test(test_tls_decrypt_lite_crypt),
702+
cmocka_unit_test(test_parse_ack),
703+
cmocka_unit_test(test_calc_session_id_hmac_static),
704+
cmocka_unit_test(test_verify_hmac_none),
705+
cmocka_unit_test(test_verify_hmac_tls_auth),
706+
cmocka_unit_test(test_verify_hmac_none_out_of_range_ack),
707+
cmocka_unit_test(test_generate_reset_packet_plain),
708+
cmocka_unit_test(test_generate_reset_packet_tls_auth),
709+
cmocka_unit_test(test_extract_control_message)
710+
};
647711

648712
#if defined(ENABLE_CRYPTO_OPENSSL)
649713
OpenSSL_add_all_algorithms();

0 commit comments

Comments
 (0)