Hi,

unlike normal "patch on the list (directly or via gerrit), ACK/+2 in
public, commit + merge info on the list", patches that carry a CVE
tag are handled privately.  Whether or not this is always necessary
could certainly be debated, but however, in the last releases 
(2.7.2, 2.6.20, and master) we had two of them.

To enable verification that the source has what was discussed and
approved, I'll attach the patches plus the relevant commit IDs.

commit 64fae9d82989ede6c92e230c594ab9335c05df8d (master)
commit 4a2c827c2536aa03a1d6c7cc916689a46c067187 (release/2.7)
commit 4472265ea2d18b88bb5f59fb30d4067a0323aff5 (release/2.6)
Author: Arne Schwabe <[email protected]>
Date:   Fri Apr 10 16:59:53 2026 +0200

    Ensure that buffer of freed session are not used
    CVE: 2026-40215

commit fa129d7153f7292f7b6f7341601ae97d5c47e36e (master)
commit 607e2fcb9cbcff785abfa372c7a59029767b5ed9 (release/2.7)
commit 0dc820fe1d0de369d101702151fa06fff0eb360c (release/2.6)
Author: Steffan Karger <[email protected]>
Date:   Sun Apr 12 13:37:56 2026 +0200

    tls-crypt-v2: Avoid interpreting opcode as part of WKc
    CVE: 2026-35058

Details in the commit logs, and on the web

https://community.openvpn.net/Security%20Announcements/CVE-2026-40215
https://community.openvpn.net/Security%20Announcements/CVE-2026-35058


both are not of the "the world will end" category, but the ASSERT() one
is nasty as you can make a remote server stop itself *iff* tls-crypt-v2
is used, and you can create a sufficiently-malformed packet, signed with
a valid tls-crypt-v2 client key.

So, you should see that you upgrade *your servers*.

Clients are not affected.

gert
-- 
"If was one thing all people took for granted, was conviction that if you 
 feed honest figures into a computer, honest figures come out. Never doubted 
 it myself till I met a computer with a sense of humor."
                             Robert A. Heinlein, The Moon is a Harsh Mistress

Gert Doering - Munich, Germany                             [email protected]
From fa129d7153f7292f7b6f7341601ae97d5c47e36e Mon Sep 17 00:00:00 2001
From: Steffan Karger <[email protected]>
Date: Sun, 12 Apr 2026 13:37:56 +0200
Subject: [PATCH 1/2] tls-crypt-v2: Avoid interpreting opcode as part of WKc

The buffer we pass to tls_crypt_v2_extract_client_key contains the
entire received control channel packet. We should skip the opcode before
trying to read WKC.

This logic error is a second bug behind the XlabAI finding, next too the
too-strict ASSERT in tls_crypt_unwrap.

Also remove a too strict ASSERT in tls_crypt_unwrap.  We already check
a few lines later for a too short packet and return a proper error
("packet too short").

XlabAI found a way of triggering this ASSERT that requires a tls-crypt-v2
client key that has a specific property (a specific byte need to have a
specific value, about 1/256 probability). If an attacker can get hold of
such a tls-crypt-v2 client key or observe a handshake using such a key,
the attacker can trigger the ASSERT, crashing the server. Setups that do
not use tls-crypt-v2 are not affected.

Independently, Cisco Talos reported a way to trigger this ASSERT with any
tls-crypt-v2 key but this requires the attacker to be also in possession
of the private key part of the tls-crypt-v2 client key or to inject packet
into a live session of a client session.

CVE: 2026-35058
Reported-By: XlabAI Team of Tencent Xuanwu Lab ([email protected])
Reported-By: Guannan Wang ([email protected]
Reported-By: Zhanpeng Liu ([email protected])
Reported-By: Guancheng Li ([email protected])
Reported-By: Emma Reuter of Cisco ASIG (TALOS-2026-2381)
Signed-off-by: Steffan Karger <[email protected]>
Signed-off-by: Arne Schwabe <[email protected]>

Change-Id: I623733c0476c98f436d19009ee8990693c1579b5
Private-URL: https://github.com/OpenVPN/openvpn-private-issues/issues/111
Acked-by: Gert Doering <[email protected]>
Signed-off-by: Gert Doering <[email protected]>
---
 src/openvpn/tls_crypt.c                   |  4 ++--
 tests/unit_tests/openvpn/test_tls_crypt.c | 11 ++++++++++-
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/openvpn/tls_crypt.c b/src/openvpn/tls_crypt.c
index 70889dcf..e91f80cf 100644
--- a/src/openvpn/tls_crypt.c
+++ b/src/openvpn/tls_crypt.c
@@ -216,7 +216,6 @@ tls_crypt_unwrap(const struct buffer *src, struct buffer *dst, struct crypto_opt
     gc_init(&gc);
 
     ASSERT(opt);
-    ASSERT(src->len > 0);
     ASSERT(ctx->cipher);
     ASSERT(packet_id_initialized(&opt->packet_id) || (opt->flags & CO_IGNORE_PACKET_ID));
 
@@ -619,7 +618,8 @@ tls_crypt_v2_extract_client_key(struct buffer *buf, struct tls_wrap_ctx *ctx,
     struct buffer wrapped_client_key = *buf;
     uint16_t net_len = 0;
 
-    if (BLENZ(&wrapped_client_key) < sizeof(net_len))
+    if (!buf_advance(&wrapped_client_key, 1)
+        || BLENZ(&wrapped_client_key) < 1 + sizeof(net_len))
     {
         msg(D_TLS_ERRORS, "Can not read tls-crypt-v2 client key length");
         return false;
diff --git a/tests/unit_tests/openvpn/test_tls_crypt.c b/tests/unit_tests/openvpn/test_tls_crypt.c
index 1776d71c..161ee908 100644
--- a/tests/unit_tests/openvpn/test_tls_crypt.c
+++ b/tests/unit_tests/openvpn/test_tls_crypt.c
@@ -518,7 +518,16 @@ tls_crypt_v2_wrap_unwrap_max_metadata(void **state)
         .mode = TLS_WRAP_CRYPT,
         .tls_crypt_v2_server_key = ctx->server_keys.encrypt,
     };
-    assert_true(tls_crypt_v2_extract_client_key(&ctx->wkc, &wrap_ctx, NULL, true));
+
+    /* a buffer that only contains the wrapped key should fail */
+    assert_false(tls_crypt_v2_extract_client_key(&ctx->wkc, &wrap_ctx, NULL, true));
+
+    /* add a opcode in front of the key to make it valid to extract */
+    struct buffer wkcop = alloc_buf_gc(buf_len(&ctx->wkc) + 1, &ctx->gc);
+    buf_write_u8(&wkcop, 0x50);
+    buf_copy(&wkcop, &ctx->wkc);
+    assert_true(tls_crypt_v2_extract_client_key(&wkcop, &wrap_ctx, NULL, true));
+
     tls_wrap_free(&wrap_ctx);
 }
 
-- 
2.53.0

From 64fae9d82989ede6c92e230c594ab9335c05df8d Mon Sep 17 00:00:00 2001
From: Arne Schwabe <[email protected]>
Date: Fri, 10 Apr 2026 16:59:53 +0200
Subject: [PATCH 2/2] Ensure that buffer of freed session are not used

In a race condition an old TLS session could still try to send a packet but
also get replaced by a new session. In this case, the buffer of the new
session is still referenced. Add the check_session_buf_not_used function
to mitigate this problem.

Also make the check if the to_link pointer is in one of the memory
regions a bit better even though this not make a difference with the
way we use these structs. But better safe than sorry.

A better solution to remove the TM_INITIAL state and handle reconnecting
session in their own complete tls_multi is a more involved fix that requires
a lot more refactoring.

CVE: 2026-40215
Reported-By: XlabAI Team of Tencent Xuanwu Lab ([email protected])
Reported-By: Guannan Wang ([email protected]
Reported-By: Zhanpeng Liu ([email protected])
Reported-By: Guancheng Li ([email protected])
Signed-off-by: Arne Schwabe <[email protected]>

Change-Id: I7c5fa2a7a2563b7a8955d386411f3ceffe5b092f
Private-URL: https://github.com/OpenVPN/openvpn-private-issues/issues/112
Acked-by: Gert Doering <[email protected]>
Signed-off-by: Gert Doering <[email protected]>
---
 src/openvpn/ssl.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index 5868d531..d332359c 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -3290,6 +3290,7 @@ tls_multi_process(struct tls_multi *multi, struct buffer *to_link,
                 if (i == TM_ACTIVE && ks_lame->state >= S_GENERATED_KEYS
                     && !multi->opt.single_session)
                 {
+                    check_session_buf_not_used(to_link, session);
                     move_session(multi, TM_LAME_DUCK, TM_ACTIVE, true);
                 }
                 else
@@ -3363,6 +3364,7 @@ tls_multi_process(struct tls_multi *multi, struct buffer *to_link,
      */
     if (TLS_AUTHENTICATED(multi, &multi->session[TM_INITIAL].key[KS_PRIMARY]))
     {
+        check_session_buf_not_used(to_link, &multi->session[TM_ACTIVE]);
         move_session(multi, TM_ACTIVE, TM_INITIAL, true);
         tas = tls_authentication_status(multi);
         msg(D_TLS_DEBUG_LOW,
-- 
2.53.0

Attachment: signature.asc
Description: PGP signature

_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to