openvpn: patch CVE-2025-13086

Details https://nvd.nist.gov/vuln/detail/CVE-2025-13086

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
Ankur Tyagi 2025-12-16 12:45:37 +05:30 committed by Anuj Mittal
parent c42bfd596e
commit 86abe3d5de
No known key found for this signature in database
GPG Key ID: 4340AEFE69F5085C
2 changed files with 158 additions and 0 deletions

View File

@ -0,0 +1,157 @@
From c56eb06a59ce8ccd601f1d58aa71cbd1211ee8d6 Mon Sep 17 00:00:00 2001
From: Arne Schwabe <arne@rfc2549.org>
Date: Mon, 27 Oct 2025 10:05:55 +0100
Subject: [PATCH] Fix memcmp check for the hmac verification in the 3way
handshake being inverted
This is a stupid mistake but causes all hmac cookies to be accepted,
thus breaking source IP address validation. As a consequence, TLS
sessions can be openend and state can be consumed in the server from
IP addresses that did not initiate an initial connection.
While at it, fix check to only allow [t-2;t] timeslots, disallowing
HMACs coming in from a future timeslot.
Github: OpenVPN/openvpn-private-issues#56
CVE: 2025-13086
Reported-By: Joshua Rogers <contact@joshua.hu>
Found-by: ZeroPath (https://zeropath.com/)
Reported-By: stefan@srlabs.de
Change-Id: I9cbe2bf535575b47ddd7f34e985c5c1c6953a6fc
Signed-off-by: Arne Schwabe <arne@rfc2549.org>
Acked-by: Max Fillinger <max@max-fillinger.net>
(cherry picked from commit 68ec931e7fb4af11d5ba0d4283df0350083fd373)
CVE: CVE-2025-13086
Upstream-Status: Backport [https://github.com/OpenVPN/openvpn/commit/fa6a1824b0f37bff137204156a74ca28cf5b6f83]
Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
src/openvpn/ssl_pkt.c | 7 ++--
tests/unit_tests/openvpn/test_pkt.c | 57 ++++++++++++++++++++++++++++-
2 files changed, 60 insertions(+), 4 deletions(-)
diff --git a/src/openvpn/ssl_pkt.c b/src/openvpn/ssl_pkt.c
index 41299f46..e820dc93 100644
--- a/src/openvpn/ssl_pkt.c
+++ b/src/openvpn/ssl_pkt.c
@@ -545,13 +545,14 @@ check_session_id_hmac(struct tls_pre_decrypt_state *state,
return false;
}
- /* check adjacent timestamps too */
- for (int offset = -2; offset <= 1; offset++)
+ /* check adjacent timestamps too, the handwindow is split in 2 for the
+ * offset, so we check the current timeslot and the two before that */
+ for (int offset = -2; offset <= 0; offset++)
{
struct session_id expected_id =
calculate_session_id_hmac(state->peer_session_id, from, hmac, handwindow, offset);
- if (memcmp_constant_time(&expected_id, &state->server_session_id, SID_SIZE))
+ if (memcmp_constant_time(&expected_id, &state->server_session_id, SID_SIZE) == 0)
{
return true;
}
diff --git a/tests/unit_tests/openvpn/test_pkt.c b/tests/unit_tests/openvpn/test_pkt.c
index 74d7311f..4e97384d 100644
--- a/tests/unit_tests/openvpn/test_pkt.c
+++ b/tests/unit_tests/openvpn/test_pkt.c
@@ -429,6 +429,8 @@ test_verify_hmac_tls_auth(void **ut_state)
hmac_ctx_t *hmac = session_id_hmac_init();
struct link_socket_actual from = { 0 };
+ from.dest.addr.sa.sa_family = AF_INET;
+ from.dest.addr.in4.sin_addr.s_addr = ntohl(0x01020304);
struct tls_auth_standalone tas = { 0 };
struct tls_pre_decrypt_state state = { 0 };
@@ -456,10 +458,12 @@ test_verify_hmac_tls_auth(void **ut_state)
static void
test_verify_hmac_none(void **ut_state)
{
+ now = 1000;
hmac_ctx_t *hmac = session_id_hmac_init();
struct link_socket_actual from = { 0 };
from.dest.addr.sa.sa_family = AF_INET;
+ from.dest.addr.in4.sin_addr.s_addr = ntohl(0x01020304);
struct tls_auth_standalone tas = { 0 };
struct tls_pre_decrypt_state state = { 0 };
@@ -475,8 +479,59 @@ test_verify_hmac_none(void **ut_state)
assert_int_equal(verdict, VERDICT_VALID_ACK_V1);
bool valid = check_session_id_hmac(&state, &from.dest, hmac, 30);
+ assert_false(valid);
+
+ struct session_id client_id = { { 0xae, 0xb9, 0xaf, 0xe1, 0xf0, 0x1d, 0x79, 0xc8 } };
+ assert_memory_equal(&client_id, &state.peer_session_id, sizeof(struct session_id));
+
+ struct session_id expected_id = calculate_session_id_hmac(client_id, &from.dest, hmac, 30, 0);
+
+ free_tls_pre_decrypt_state(&state);
+ buf_reset_len(&buf);
+
+ /* Write the packet again into the buffer but this time, replacing the peer packet
+ * id with the expected one */
+ buf_write(&buf, client_ack_none_random_id, sizeof(client_ack_none_random_id) - 8);
+ buf_write(&buf, expected_id.id, 8);
+
+ verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf);
+ assert_int_equal(verdict, VERDICT_VALID_ACK_V1);
+ valid = check_session_id_hmac(&state, &from.dest, hmac, 30);
+
assert_true(valid);
+ /* Our handwindow is 30 so the slices are half of that, so they are
+ * (975,990), (990, 1005), (1005, 1020), (1020, 1035), (1035, 1050)
+ * So setting time to the two future ones should work
+ */
+ now = 980;
+ assert_false(check_session_id_hmac(&state, &from.dest, hmac, 30));
+ now = 1040;
+ assert_false(check_session_id_hmac(&state, &from.dest, hmac, 30));
+ now = 1002;
+ assert_true(check_session_id_hmac(&state, &from.dest, hmac, 30));
+ now = 1022;
+ assert_true(check_session_id_hmac(&state, &from.dest, hmac, 30));
+ now = 1010;
+ assert_true(check_session_id_hmac(&state, &from.dest, hmac, 30));
+
+ /* Changing the IP address should make this invalid */
+ from.dest.addr.in4.sin_addr.s_addr = ntohl(0x01020305);
+ assert_false(check_session_id_hmac(&state, &from.dest, hmac, 30));
+
+ /* Change to the correct one again */
+ from.dest.addr.in4.sin_addr.s_addr = ntohl(0x01020304);
+ assert_true(check_session_id_hmac(&state, &from.dest, hmac, 30));
+
+ /* Modify the peer id, should now fail hmac verification */
+ buf_inc_len(&buf, -4);
+ buf_write_u32(&buf, 0x12345678);
+
+ free_tls_pre_decrypt_state(&state);
+ verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf);
+ assert_int_equal(verdict, VERDICT_VALID_ACK_V1);
+ assert_false(check_session_id_hmac(&state, &from.dest, hmac, 30));
+
free_tls_pre_decrypt_state(&state);
free_buf(&buf);
hmac_ctx_cleanup(hmac);
@@ -663,12 +718,12 @@ int
main(void)
{
const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_verify_hmac_none),
cmocka_unit_test(test_tls_decrypt_lite_none),
cmocka_unit_test(test_tls_decrypt_lite_auth),
cmocka_unit_test(test_tls_decrypt_lite_crypt),
cmocka_unit_test(test_parse_ack),
cmocka_unit_test(test_calc_session_id_hmac_static),
- cmocka_unit_test(test_verify_hmac_none),
cmocka_unit_test(test_verify_hmac_tls_auth),
cmocka_unit_test(test_generate_reset_packet_plain),
cmocka_unit_test(test_generate_reset_packet_tls_auth),

View File

@ -10,6 +10,7 @@ inherit autotools systemd update-rc.d pkgconfig
SRC_URI = "http://swupdate.openvpn.org/community/releases/${BP}.tar.gz \
file://0001-configure.ac-eliminate-build-path-from-openvpn-versi.patch \
file://openvpn \
file://CVE-2025-13086.patch \
"
UPSTREAM_CHECK_URI = "https://openvpn.net/community-downloads"