Browse code

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 <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)

Arne Schwabe authored on 2025/09/17 00:52:50
Showing 4 changed files
... ...
@@ -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)