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 <walter.openvpn@wjd.nu>
Tested-By: Walter Doekes <walter.openvpn@wjd.nu>
Change-Id: I6752dcd5aff3e5cea2b439366479e86751a1c403
Signed-off-by: Arne Schwabe <arne@rfc2549.org>
Acked-by: MaxF <max@max-fillinger.net>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1184
Message-Id: <20250916155258.6864-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg32990.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
(backported from commit 518e122b42739b0dbb54e7169a8a3aadb4773125)
| ... | ... |
@@ -153,7 +153,8 @@ do_pre_decrypt_check(struct multi_context *m, |
| 153 | 153 |
* need to contain the peer id */ |
| 154 | 154 |
struct gc_arena gc = gc_new(); |
| 155 | 155 |
|
| 156 |
- bool ret = check_session_id_hmac(state, from, hmac, handwindow); |
|
| 156 |
+ bool pkt_is_ack = (verdict == VERDICT_VALID_ACK_V1); |
|
| 157 |
+ bool ret = check_session_hmac_and_pkt_id(state, from, hmac, handwindow, pkt_is_ack); |
|
| 157 | 158 |
|
| 158 | 159 |
const char *peer = print_link_socket_actual(&m->top.c2.from, &gc); |
| 159 | 160 |
uint8_t pkt_firstbyte = *BPTR( &m->top.c2.buf); |
| ... | ... |
@@ -161,7 +162,8 @@ do_pre_decrypt_check(struct multi_context *m, |
| 161 | 161 |
|
| 162 | 162 |
if (!ret) |
| 163 | 163 |
{
|
| 164 |
- msg(D_MULTI_MEDIUM, "Packet (%s) with invalid or missing SID from %s", |
|
| 164 |
+ msg(D_MULTI_MEDIUM, "Packet (%s) with invalid or missing SID from" |
|
| 165 |
+ " %s or wrong packet id", |
|
| 165 | 166 |
packet_opcode_name(op), peer); |
| 166 | 167 |
} |
| 167 | 168 |
else |
| ... | ... |
@@ -527,10 +527,11 @@ calculate_session_id_hmac(struct session_id client_sid, |
| 527 | 527 |
} |
| 528 | 528 |
|
| 529 | 529 |
bool |
| 530 |
-check_session_id_hmac(struct tls_pre_decrypt_state *state, |
|
| 531 |
- const struct openvpn_sockaddr *from, |
|
| 532 |
- hmac_ctx_t *hmac, |
|
| 533 |
- int handwindow) |
|
| 530 |
+check_session_hmac_and_pkt_id(struct tls_pre_decrypt_state *state, |
|
| 531 |
+ const struct openvpn_sockaddr *from, |
|
| 532 |
+ hmac_ctx_t *hmac, |
|
| 533 |
+ int handwindow, |
|
| 534 |
+ bool pkt_is_ack) |
|
| 534 | 535 |
{
|
| 535 | 536 |
if (!from) |
| 536 | 537 |
{
|
| ... | ... |
@@ -545,6 +546,36 @@ check_session_id_hmac(struct tls_pre_decrypt_state *state, |
| 545 | 545 |
return false; |
| 546 | 546 |
} |
| 547 | 547 |
|
| 548 |
+ /* Check if the packet ID of the packet or ACKED packet is <= 1 */ |
|
| 549 |
+ for (int i = 0; i < ack.len; i++) |
|
| 550 |
+ {
|
|
| 551 |
+ /* This packet ACKs a packet that has a higher packet id than the |
|
| 552 |
+ * ones expected in the three-way handshake, consider it as invalid |
|
| 553 |
+ * for the session */ |
|
| 554 |
+ if (ack.packet_id[i] > 1) |
|
| 555 |
+ {
|
|
| 556 |
+ return false; |
|
| 557 |
+ } |
|
| 558 |
+ } |
|
| 559 |
+ |
|
| 560 |
+ if (!pkt_is_ack) |
|
| 561 |
+ {
|
|
| 562 |
+ packet_id_type message_id; |
|
| 563 |
+ /* Extract the packet ID from the packet */ |
|
| 564 |
+ if (!reliable_ack_read_packet_id(&buf, &message_id)) |
|
| 565 |
+ {
|
|
| 566 |
+ return false; |
|
| 567 |
+ } |
|
| 568 |
+ |
|
| 569 |
+ /* similar check. Anything larger than 1 is not considered part of the |
|
| 570 |
+ * three-way handshake */ |
|
| 571 |
+ if (message_id > 1) |
|
| 572 |
+ {
|
|
| 573 |
+ return false; |
|
| 574 |
+ } |
|
| 575 |
+ } |
|
| 576 |
+ |
|
| 577 |
+ |
|
| 548 | 578 |
/* check adjacent timestamps too */ |
| 549 | 579 |
for (int offset = -2; offset <= 1; offset++) |
| 550 | 580 |
{
|
| ... | ... |
@@ -182,17 +182,20 @@ calculate_session_id_hmac(struct session_id client_sid, |
| 182 | 182 |
/** |
| 183 | 183 |
* Checks if a control packet has a correct HMAC server session id |
| 184 | 184 |
* |
| 185 |
- * @param client_sid session id of the client |
|
| 185 |
+ * This will also consider packets that have a packet id higher |
|
| 186 |
+ * than 1 or ack packets higher than 1 to be invalid as they are |
|
| 187 |
+ * not part of the initial three way handshake of OpenVPN and should |
|
| 188 |
+ * not create a new connection. |
|
| 189 |
+ * |
|
| 190 |
+ * @param state session information |
|
| 186 | 191 |
* @param from link_socket from the client |
| 187 | 192 |
* @param hmac the hmac context to use for the calculation |
| 188 | 193 |
* @param handwindow the quantisation of the current time |
| 194 |
+ * @param pkt_is_ack the packet being checked is a P_ACK_V1 |
|
| 189 | 195 |
* @return the expected server session id |
| 190 | 196 |
*/ |
| 191 |
-bool |
|
| 192 |
-check_session_id_hmac(struct tls_pre_decrypt_state *state, |
|
| 193 |
- const struct openvpn_sockaddr *from, |
|
| 194 |
- hmac_ctx_t *hmac, |
|
| 195 |
- int handwindow); |
|
| 197 |
+bool check_session_hmac_and_pkt_id(struct tls_pre_decrypt_state *state, const struct openvpn_sockaddr *from, |
|
| 198 |
+ hmac_ctx_t *hmac, int handwindow, bool pkt_is_ack); |
|
| 196 | 199 |
|
| 197 | 200 |
/* |
| 198 | 201 |
* Write a control channel authentication record. |
| ... | ... |
@@ -174,6 +174,27 @@ const uint8_t client_ack_none_random_id[] = {
|
| 174 | 174 |
0x85, 0xdb, 0x53, 0x56, 0x23, 0xb0, 0x2e |
| 175 | 175 |
}; |
| 176 | 176 |
|
| 177 |
+/* no tls-auth, P_ACK_V1, acks 0,1, and 2 */ |
|
| 178 |
+const uint8_t client_ack_123_none_random_id[] = {
|
|
| 179 |
+ 0x28, |
|
| 180 |
+ 0xae, 0xb9, 0xaf, 0xe1, 0xf0, 0x1d, 0x79, 0xc8, |
|
| 181 |
+ 0x03, |
|
| 182 |
+ 0x00, 0x00, 0x00, 0x00, |
|
| 183 |
+ 0x00, 0x00, 0x00, 0x01, |
|
| 184 |
+ 0x00, 0x00, 0x00, 0x02, |
|
| 185 |
+ 0xdd, 0x85, 0xdb, 0x53, 0x56, 0x23, 0xb0, 0x2e |
|
| 186 |
+}; |
|
| 187 |
+ |
|
| 188 |
+/* no tls-auth, P_CONTROL_V1, acks 0, msg-id 2 */ |
|
| 189 |
+const uint8_t client_control_none_random_id[] = {
|
|
| 190 |
+ 0x20, |
|
| 191 |
+ 0xae, 0xb9, 0xaf, 0xe1, 0xf0, 0x1d, 0x79, 0xc8, |
|
| 192 |
+ 0x01, |
|
| 193 |
+ 0x00, 0x00, 0x00, 0x00, |
|
| 194 |
+ 0x02 |
|
| 195 |
+}; |
|
| 196 |
+ |
|
| 197 |
+ |
|
| 177 | 198 |
struct tls_auth_standalone |
| 178 | 199 |
init_tas_auth(int key_direction) |
| 179 | 200 |
{
|
| ... | ... |
@@ -294,12 +315,10 @@ test_tls_decrypt_lite_auth(void **ut_state) |
| 294 | 294 |
assert_int_equal(verdict, VERDICT_VALID_RESET_V2); |
| 295 | 295 |
free_tls_pre_decrypt_state(&state); |
| 296 | 296 |
|
| 297 |
- free_tls_pre_decrypt_state(&state); |
|
| 298 | 297 |
/* The pre decrypt function should not modify the buffer, so calling it |
| 299 | 298 |
* again should have the same result */ |
| 300 | 299 |
verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf); |
| 301 | 300 |
assert_int_equal(verdict, VERDICT_VALID_RESET_V2); |
| 302 |
- free_tls_pre_decrypt_state(&state); |
|
| 303 | 301 |
|
| 304 | 302 |
/* and buf memory should be equal */ |
| 305 | 303 |
assert_memory_equal(BPTR(&buf), client_reset_v2_tls_auth, sizeof(client_reset_v2_tls_auth)); |
| ... | ... |
@@ -317,7 +336,6 @@ test_tls_decrypt_lite_auth(void **ut_state) |
| 317 | 317 |
assert_int_equal(verdict, VERDICT_INVALID); |
| 318 | 318 |
free_tls_pre_decrypt_state(&state); |
| 319 | 319 |
|
| 320 |
- free_tls_pre_decrypt_state(&state); |
|
| 321 | 320 |
/* Wrong key direction gives a wrong hmac key and should not validate */ |
| 322 | 321 |
free_key_ctx_bi(&tas.tls_wrap.opt.key_ctx_bi); |
| 323 | 322 |
free_tas(&tas); |
| ... | ... |
@@ -357,15 +375,12 @@ test_tls_decrypt_lite_none(void **ut_state) |
| 357 | 357 |
assert_int_equal(verdict, VERDICT_VALID_RESET_V2); |
| 358 | 358 |
free_tls_pre_decrypt_state(&state); |
| 359 | 359 |
|
| 360 |
- free_tls_pre_decrypt_state(&state); |
|
| 361 | 360 |
buf_reset_len(&buf); |
| 362 | 361 |
buf_write(&buf, client_reset_v2_tls_crypt, sizeof(client_reset_v2_none)); |
| 363 | 362 |
verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf); |
| 364 | 363 |
assert_int_equal(verdict, VERDICT_VALID_RESET_V2); |
| 365 | 364 |
free_tls_pre_decrypt_state(&state); |
| 366 | 365 |
|
| 367 |
- free_tls_pre_decrypt_state(&state); |
|
| 368 |
- |
|
| 369 | 366 |
/* This is not a reset packet and should trigger the other response */ |
| 370 | 367 |
buf_reset_len(&buf); |
| 371 | 368 |
buf_write(&buf, client_ack_tls_auth_randomid, sizeof(client_ack_tls_auth_randomid)); |
| ... | ... |
@@ -443,7 +458,7 @@ test_verify_hmac_tls_auth(void **ut_state) |
| 443 | 443 |
assert_int_equal(verdict, VERDICT_VALID_CONTROL_V1); |
| 444 | 444 |
|
| 445 | 445 |
/* This is a valid packet but containing a random id instead of an HMAC id*/ |
| 446 |
- bool valid = check_session_id_hmac(&state, &from.dest, hmac, 30); |
|
| 446 |
+ bool valid = check_session_hmac_and_pkt_id(&state, &from.dest, hmac, 30, false); |
|
| 447 | 447 |
assert_false(valid); |
| 448 | 448 |
|
| 449 | 449 |
free_tls_pre_decrypt_state(&state); |
| ... | ... |
@@ -474,7 +489,7 @@ test_verify_hmac_none(void **ut_state) |
| 474 | 474 |
verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf); |
| 475 | 475 |
assert_int_equal(verdict, VERDICT_VALID_ACK_V1); |
| 476 | 476 |
|
| 477 |
- bool valid = check_session_id_hmac(&state, &from.dest, hmac, 30); |
|
| 477 |
+ bool valid = check_session_hmac_and_pkt_id(&state, &from.dest, hmac, 30, true); |
|
| 478 | 478 |
assert_true(valid); |
| 479 | 479 |
|
| 480 | 480 |
free_tls_pre_decrypt_state(&state); |
| ... | ... |
@@ -483,6 +498,51 @@ test_verify_hmac_none(void **ut_state) |
| 483 | 483 |
hmac_ctx_free(hmac); |
| 484 | 484 |
} |
| 485 | 485 |
|
| 486 |
+static void |
|
| 487 |
+test_verify_hmac_none_out_of_range_ack(void **ut_state) |
|
| 488 |
+{
|
|
| 489 |
+ hmac_ctx_t *hmac = session_id_hmac_init(); |
|
| 490 |
+ |
|
| 491 |
+ struct link_socket_actual from = { 0 };
|
|
| 492 |
+ from.dest.addr.sa.sa_family = AF_INET; |
|
| 493 |
+ |
|
| 494 |
+ struct tls_auth_standalone tas = { 0 };
|
|
| 495 |
+ struct tls_pre_decrypt_state state = { 0 };
|
|
| 496 |
+ |
|
| 497 |
+ struct buffer buf = alloc_buf(1024); |
|
| 498 |
+ enum first_packet_verdict verdict; |
|
| 499 |
+ |
|
| 500 |
+ tas.tls_wrap.mode = TLS_WRAP_NONE; |
|
| 501 |
+ |
|
| 502 |
+ buf_reset_len(&buf); |
|
| 503 |
+ buf_write(&buf, client_ack_123_none_random_id, sizeof(client_ack_123_none_random_id)); |
|
| 504 |
+ |
|
| 505 |
+ |
|
| 506 |
+ verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf); |
|
| 507 |
+ assert_int_equal(verdict, VERDICT_VALID_ACK_V1); |
|
| 508 |
+ |
|
| 509 |
+ /* should fail because it acks 2 */ |
|
| 510 |
+ bool valid = check_session_hmac_and_pkt_id(&state, &from.dest, hmac, 30, true); |
|
| 511 |
+ assert_false(valid); |
|
| 512 |
+ free_tls_pre_decrypt_state(&state); |
|
| 513 |
+ |
|
| 514 |
+ /* Try test with the control with a too high message id now */ |
|
| 515 |
+ buf_reset_len(&buf); |
|
| 516 |
+ buf_write(&buf, client_control_none_random_id, sizeof(client_control_none_random_id)); |
|
| 517 |
+ |
|
| 518 |
+ verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf); |
|
| 519 |
+ assert_int_equal(verdict, VERDICT_VALID_CONTROL_V1); |
|
| 520 |
+ |
|
| 521 |
+ /* should fail because it has message id 2 */ |
|
| 522 |
+ valid = check_session_hmac_and_pkt_id(&state, &from.dest, hmac, 30, true); |
|
| 523 |
+ assert_false(valid); |
|
| 524 |
+ |
|
| 525 |
+ free_tls_pre_decrypt_state(&state); |
|
| 526 |
+ free_buf(&buf); |
|
| 527 |
+ hmac_ctx_cleanup(hmac); |
|
| 528 |
+ hmac_ctx_free(hmac); |
|
| 529 |
+} |
|
| 530 |
+ |
|
| 486 | 531 |
static hmac_ctx_t * |
| 487 | 532 |
init_static_hmac(void) |
| 488 | 533 |
{
|
| ... | ... |
@@ -670,6 +730,7 @@ main(void) |
| 670 | 670 |
cmocka_unit_test(test_calc_session_id_hmac_static), |
| 671 | 671 |
cmocka_unit_test(test_verify_hmac_none), |
| 672 | 672 |
cmocka_unit_test(test_verify_hmac_tls_auth), |
| 673 |
+ cmocka_unit_test(test_verify_hmac_none_out_of_range_ack), |
|
| 673 | 674 |
cmocka_unit_test(test_generate_reset_packet_plain), |
| 674 | 675 |
cmocka_unit_test(test_generate_reset_packet_tls_auth), |
| 675 | 676 |
cmocka_unit_test(test_extract_control_message) |