From: "Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco)" <devanshp@cisco.com>
To: openembedded-core@lists.openembedded.org
Subject: [OE-core][scarthgap][PATCH 6/8] curl: fix CVE-2026-8932
Date: Wed, 7 Oct 2026 04:24:01 -0700 [thread overview]
Message-ID: <20261007112403.486499-6-devanshp@cisco.com> (raw)
In-Reply-To: <20261007112403.486499-1-devanshp@cisco.com>
From: Devansh Patel <devanshp@cisco.com>
This patch applies the upstream fix as referenced in [2], using the
commit shown in [1].
[1] https://github.com/curl/curl/commit/7541ae569d82fb308a5e2d94916027da4fa3ba3e
[2] https://curl.se/docs/CVE-2026-8932.html
Signed-off-by: Devansh Patel <devanshp@cisco.com>
---
.../curl/curl/CVE-2026-8932.patch | 427 ++++++++++++++++++
meta/recipes-support/curl/curl_8.7.1.bb | 1 +
2 files changed, 428 insertions(+)
create mode 100644 meta/recipes-support/curl/curl/CVE-2026-8932.patch
diff --git a/meta/recipes-support/curl/curl/CVE-2026-8932.patch b/meta/recipes-support/curl/curl/CVE-2026-8932.patch
new file mode 100644
index 0000000000..0b539c54ab
--- /dev/null
+++ b/meta/recipes-support/curl/curl/CVE-2026-8932.patch
@@ -0,0 +1,427 @@
+From c25faf128bba57a64da636f126773b858b35bc27 Mon Sep 17 00:00:00 2001
+From: Joshua Rogers <MegaManSec@users.noreply.github.com>
+Date: Tue, 19 May 2026 11:47:50 +0200
+Subject: [PATCH] tls: fix incomplete mTLS config in conn reuse and session
+ cache
+
+cert_type, key, key_type, key_passwd and key_blob lived in
+ssl_config_data but not in ssl_primary_config, so they were invisible to
+match_ssl_primary_config() and to the TLS session cache peer key.
+
+Two easy handles sharing a connection pool could reuse each other's
+authenticated connections when they differed only on SSLKEY, SSLKEYTYPE,
+KEYPASSWD, SSLCERTTYPE or SSLKEYBLOB. The second handle would silently
+inherit the first handle's authenticated identity.
+
+Promote all five fields into ssl_primary_config so the conn-reuse
+predicate and session cache key cover the complete client credential
+set. Also replace the fixed ":CCERT" session cache marker with the
+actual clientcert path so sessions are not shared across different
+client certificates.
+
+Verified by test 3303 and 3304
+
+Reported-By: Joshua Rogers (AISLE Research)
+Closes #21667
+
+CVE: CVE-2026-8932
+Upstream-Status: Backport [https://github.com/curl/curl/commit/7541ae569d82fb308a5e2d94916027da4fa3ba3e]
+
+Backport Changes:
+- curl 8.7.1 keeps the session cache in vtls.c and stores backend key
+ properties outside ssl_primary_config. Duplicate those pointers into
+ the primary configuration so matching and cloning cover reuse.
+- Keep the old backend members as aliases, so omit backend-only access
+ moves in ldap.c, vssh, and the TLS backend files.
+- Adapt unit3303 to the curl 8.7.1 harness and allocation helpers.
+ Include memdebug.h last so cleanup uses the debug allocator's free()
+ hook. Fold unit3304's case-insensitive cert_type and key_type checks
+ into it.
+- Extend unit3303 with key_blob deep-copy, connection reuse, and TLS
+ session cache matching checks.
+- Omit vtls_scache.c, vtls_scache.h, and unit3304 because their peer
+ key API does not exist in curl 8.7.1. The vtls.c cache uses the
+ updated clone and match functions exercised by unit3303.
+
+(cherry picked from commit 7541ae569d82fb308a5e2d94916027da4fa3ba3e)
+Signed-off-by: Devansh Patel <devanshp@cisco.com>
+---
+ lib/urldata.h | 5 +
+ lib/vtls/vtls.c | 25 +++++
+ tests/data/Makefile.inc | 3 +-
+ tests/data/test3303 | 23 +++++
+ tests/unit/Makefile.inc | 4 +-
+ tests/unit/unit3303.c | 210 ++++++++++++++++++++++++++++++++++++++++
+ 6 files changed, 268 insertions(+), 2 deletions(-)
+ create mode 100644 tests/data/test3303
+ create mode 100644 tests/unit/unit3303.c
+
+diff --git a/lib/urldata.h b/lib/urldata.h
+index d2d9424197..9015515e17 100644
+--- a/lib/urldata.h
++++ b/lib/urldata.h
+@@ -286,6 +286,11 @@ struct ssl_primary_config {
+ char *CAfile; /* certificate to verify peer against */
+ char *issuercert; /* optional issuer certificate filename */
+ char *clientcert;
++ char *cert_type; /* format for certificate (default: PEM) */
++ char *key; /* private key file name */
++ struct curl_blob *key_blob;
++ char *key_type; /* format for private key (default: PEM) */
++ char *key_passwd; /* plain text private key password */
+ char *cipher_list; /* list of ciphers to use */
+ char *cipher_list13; /* list of TLS 1.3 cipher suites to use */
+ char *pinned_key;
+diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
+index d13a3cb1b7..c89e8abcc6 100644
+--- a/lib/vtls/vtls.c
++++ b/lib/vtls/vtls.c
+@@ -187,10 +187,15 @@ match_ssl_primary_config(struct Curl_easy *data,
+ blobcmp(c1->cert_blob, c2->cert_blob) &&
+ blobcmp(c1->ca_info_blob, c2->ca_info_blob) &&
+ blobcmp(c1->issuercert_blob, c2->issuercert_blob) &&
++ blobcmp(c1->key_blob, c2->key_blob) &&
+ Curl_safecmp(c1->CApath, c2->CApath) &&
+ Curl_safecmp(c1->CAfile, c2->CAfile) &&
+ Curl_safecmp(c1->issuercert, c2->issuercert) &&
+ Curl_safecmp(c1->clientcert, c2->clientcert) &&
++ curl_strequal(c1->cert_type, c2->cert_type) &&
++ Curl_safecmp(c1->key, c2->key) &&
++ curl_strequal(c1->key_type, c2->key_type) &&
++ !Curl_timestrcmp(c1->key_passwd, c2->key_passwd) &&
+ #ifdef USE_TLS_SRP
+ !Curl_timestrcmp(c1->username, c2->username) &&
+ !Curl_timestrcmp(c1->password, c2->password) &&
+@@ -234,10 +239,15 @@ static bool clone_ssl_primary_config(struct ssl_primary_config *source,
+ CLONE_BLOB(cert_blob);
+ CLONE_BLOB(ca_info_blob);
+ CLONE_BLOB(issuercert_blob);
++ CLONE_BLOB(key_blob);
+ CLONE_STRING(CApath);
+ CLONE_STRING(CAfile);
+ CLONE_STRING(issuercert);
+ CLONE_STRING(clientcert);
++ CLONE_STRING(cert_type);
++ CLONE_STRING(key);
++ CLONE_STRING(key_type);
++ CLONE_STRING(key_passwd);
+ CLONE_STRING(cipher_list);
+ CLONE_STRING(cipher_list13);
+ CLONE_STRING(pinned_key);
+@@ -257,12 +267,17 @@ static void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
+ Curl_safefree(sslc->CAfile);
+ Curl_safefree(sslc->issuercert);
+ Curl_safefree(sslc->clientcert);
++ Curl_safefree(sslc->cert_type);
++ Curl_safefree(sslc->key);
++ Curl_safefree(sslc->key_type);
++ Curl_safefree(sslc->key_passwd);
+ Curl_safefree(sslc->cipher_list);
+ Curl_safefree(sslc->cipher_list13);
+ Curl_safefree(sslc->pinned_key);
+ Curl_safefree(sslc->cert_blob);
+ Curl_safefree(sslc->ca_info_blob);
+ Curl_safefree(sslc->issuercert_blob);
++ Curl_safefree(sslc->key_blob);
+ Curl_safefree(sslc->curves);
+ Curl_safefree(sslc->CRLfile);
+ #ifdef USE_TLS_SRP
+@@ -297,6 +312,11 @@ CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data)
+ data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD];
+ data->set.ssl.primary.clientcert = data->set.str[STRING_CERT];
+ data->set.ssl.key_blob = data->set.blobs[BLOB_KEY];
++ data->set.ssl.primary.cert_type = data->set.ssl.cert_type;
++ data->set.ssl.primary.key = data->set.ssl.key;
++ data->set.ssl.primary.key_type = data->set.ssl.key_type;
++ data->set.ssl.primary.key_passwd = data->set.ssl.key_passwd;
++ data->set.ssl.primary.key_blob = data->set.ssl.key_blob;
+
+ #ifndef CURL_DISABLE_PROXY
+ data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
+@@ -322,6 +342,11 @@ CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data)
+ data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
+ data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY];
+ data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY];
++ data->set.proxy_ssl.primary.cert_type = data->set.proxy_ssl.cert_type;
++ data->set.proxy_ssl.primary.key = data->set.proxy_ssl.key;
++ data->set.proxy_ssl.primary.key_type = data->set.proxy_ssl.key_type;
++ data->set.proxy_ssl.primary.key_passwd = data->set.proxy_ssl.key_passwd;
++ data->set.proxy_ssl.primary.key_blob = data->set.proxy_ssl.key_blob;
+ #ifdef USE_TLS_SRP
+ data->set.proxy_ssl.primary.username =
+ data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
+diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
+index f420a8a4f5..27b1b52a10 100644
+--- a/tests/data/Makefile.inc
++++ b/tests/data/Makefile.inc
+@@ -264,4 +264,5 @@ test3024 test3025 test3026 test3027 test3028 test3029 test3030 \
+ \
+ test3100 test3101 test3102 test3103 \
+ test3200 \
+-test3201 test3202
++test3201 test3202 \
++test3303
+diff --git a/tests/data/test3303 b/tests/data/test3303
+new file mode 100644
+index 0000000000..9b52bcb817
+--- /dev/null
++++ b/tests/data/test3303
+@@ -0,0 +1,23 @@
++<?xml version="1.0" encoding="US-ASCII"?>
++<testcase>
++<info>
++<keywords>
++unittest
++TLS
++mTLS
++</keywords>
++</info>
++
++# Client-side
++<client>
++<server>
++none
++</server>
++<features>
++unittest
++</features>
++<name>
++conn-reuse match distinguishes mTLS key, cert_type, key_type and key_passwd fields
++</name>
++</client>
++</testcase>
+diff --git a/tests/unit/Makefile.inc b/tests/unit/Makefile.inc
+index 1926b49b3a..afbe29d2b7 100644
+--- a/tests/unit/Makefile.inc
++++ b/tests/unit/Makefile.inc
+@@ -39,7 +39,7 @@ UNITPROGS = unit1300 unit1302 unit1303 unit1304 unit1305 unit1307 \
+ unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 unit1656 \
+ unit1660 unit1661 \
+ unit2600 unit2601 unit2602 unit2603 \
+- unit3200
++ unit3200 unit3303
+
+ unit1300_SOURCES = unit1300.c $(UNITFILES)
+
+@@ -134,3 +134,5 @@ unit2602_SOURCES = unit2602.c $(UNITFILES)
+ unit2603_SOURCES = unit2603.c $(UNITFILES)
+
+ unit3200_SOURCES = unit3200.c $(UNITFILES)
++
++unit3303_SOURCES = unit3303.c $(UNITFILES)
+diff --git a/tests/unit/unit3303.c b/tests/unit/unit3303.c
+new file mode 100644
+index 0000000000..f9928b638a
+--- /dev/null
++++ b/tests/unit/unit3303.c
+@@ -0,0 +1,210 @@
++/***************************************************************************
++ * _ _ ____ _
++ * Project ___| | | | _ \| |
++ * / __| | | | |_) | |
++ * | (__| |_| | _ <| |___
++ * \___|\___/|_| \_\_____|
++ *
++ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
++ *
++ * This software is licensed as described in the file COPYING, which
++ * you should have received as part of this distribution. The terms
++ * are also available at https://curl.se/docs/copyright.html.
++ *
++ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
++ * copies of the Software, and permit persons to whom the Software is
++ * furnished to do so, under the terms of the COPYING file.
++ *
++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
++ * KIND, either express or implied.
++ *
++ * SPDX-License-Identifier: curl
++ *
++ ***************************************************************************/
++#include "curlcheck.h"
++#include "cfilters.h"
++#include "http.h"
++#include "urldata.h"
++
++#ifdef USE_SSL
++#include "vtls/vtls.h"
++#include "vtls/vtls_int.h"
++#endif
++#include "memdebug.h" /* LAST include file */
++
++static CURLcode unit_setup(void)
++{
++ return curl_global_init(CURL_GLOBAL_ALL);
++}
++
++static void unit_stop(void)
++{
++ curl_global_cleanup();
++}
++
++UNITTEST_START
++#ifdef USE_SSL
++{
++ CURL *curl;
++ struct Curl_easy *data;
++ struct connectdata *conn;
++ struct Curl_cfilter cf;
++ struct ssl_connect_data sslctx;
++ struct ssl_primary_config *primary;
++ struct curl_blob key_blob;
++ struct curl_blob alt_key_blob;
++ struct curl_blob *saved_blob;
++ struct curl_blob *saved_conn_blob;
++ void *sessionid;
++ size_t idsize = 0;
++ bool added = FALSE;
++ char fake_session;
++ char *saved;
++ static char alt_passwd[] = "wrong";
++ static char alt_key[] = "other.key";
++ static char alt_ktype[] = "DER";
++ static char alt_ctype[] = "P12";
++ static char lc_ctype[] = "pem";
++ static char lc_ktype[] = "pem";
++
++ curl = curl_easy_init();
++ abort_unless(curl, "curl_easy_init failed");
++ data = (struct Curl_easy *)curl;
++
++ key_blob.data = (void *)"first private key";
++ key_blob.len = sizeof("first private key") - 1;
++ key_blob.flags = CURL_BLOB_COPY;
++ alt_key_blob.data = (void *)"second private key";
++ alt_key_blob.len = sizeof("second private key") - 1;
++ alt_key_blob.flags = CURL_BLOB_NOCOPY;
++
++ curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem");
++ curl_easy_setopt(curl, CURLOPT_SSLKEY, "client.key");
++ curl_easy_setopt(curl, CURLOPT_SSLKEY_BLOB, &key_blob);
++ curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "secret");
++ curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
++ curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
++
++ abort_unless(!Curl_ssl_easy_config_complete(data),
++ "Curl_ssl_easy_config_complete failed");
++
++ conn = calloc(1, sizeof(*conn));
++ abort_unless(conn, "connection allocation failed");
++ abort_unless(!Curl_ssl_conn_config_init(data, conn),
++ "Curl_ssl_conn_config_init failed");
++
++ fail_unless(Curl_ssl_conn_config_match(data, conn, FALSE),
++ "identical mTLS config should match");
++
++ primary = &data->set.ssl.primary;
++
++ fail_unless(conn->ssl_config.key_blob &&
++ conn->ssl_config.key_blob != primary->key_blob &&
++ conn->ssl_config.key_blob->len == primary->key_blob->len &&
++ !memcmp(conn->ssl_config.key_blob->data,
++ primary->key_blob->data, primary->key_blob->len),
++ "key_blob must be cloned into the connection config");
++
++ saved_blob = primary->key_blob;
++ primary->key_blob = &alt_key_blob;
++ fail_unless(!Curl_ssl_conn_config_match(data, conn, FALSE),
++ "different key_blob must not reuse conn");
++ primary->key_blob = saved_blob;
++
++ saved = primary->key_passwd;
++ primary->key_passwd = alt_passwd;
++ fail_unless(!Curl_ssl_conn_config_match((struct Curl_easy *)curl, conn,
++ FALSE),
++ "different key_passwd must not reuse conn");
++ primary->key_passwd = saved;
++
++ saved = primary->key;
++ primary->key = alt_key;
++ fail_unless(!Curl_ssl_conn_config_match((struct Curl_easy *)curl, conn,
++ FALSE),
++ "different key must not reuse conn");
++ primary->key = saved;
++
++ saved = primary->key_type;
++ primary->key_type = alt_ktype;
++ fail_unless(!Curl_ssl_conn_config_match((struct Curl_easy *)curl, conn,
++ FALSE),
++ "different key_type must not reuse conn");
++ primary->key_type = saved;
++
++ saved = primary->cert_type;
++ primary->cert_type = alt_ctype;
++ fail_unless(!Curl_ssl_conn_config_match((struct Curl_easy *)curl, conn,
++ FALSE),
++ "different cert_type must not reuse conn");
++ primary->cert_type = saved;
++
++ primary->cert_type = lc_ctype;
++ fail_unless(Curl_ssl_conn_config_match((struct Curl_easy *)curl, conn,
++ FALSE),
++ "cert_type comparison must be case-insensitive");
++ primary->cert_type = saved;
++
++ primary->key_type = lc_ktype;
++ fail_unless(Curl_ssl_conn_config_match((struct Curl_easy *)curl, conn,
++ FALSE),
++ "key_type comparison must be case-insensitive");
++ primary->key_type = saved;
++
++ fail_unless(Curl_ssl_conn_config_match((struct Curl_easy *)curl, conn,
++ FALSE),
++ "restored mTLS config should match");
++
++ memset(&cf, 0, sizeof(cf));
++ memset(&sslctx, 0, sizeof(sslctx));
++ conn->handler = &Curl_handler_https;
++ sslctx.peer.hostname = "example.com";
++ sslctx.port = 443;
++ cf.cft = &Curl_cft_ssl;
++ cf.ctx = &sslctx;
++ cf.conn = conn;
++
++ abort_unless(!Curl_ssl_initsessions(data, 1),
++ "Curl_ssl_initsessions failed");
++ abort_unless(!Curl_ssl_addsessionid(&cf, data, &fake_session, 1,
++ &added),
++ "Curl_ssl_addsessionid failed");
++ fail_unless(added, "session was not added to the cache");
++ fail_unless(data->state.session[0].ssl_config.key_blob &&
++ data->state.session[0].ssl_config.key_blob !=
++ conn->ssl_config.key_blob,
++ "key_blob must be cloned into the session cache");
++
++ sessionid = NULL;
++ fail_unless(!Curl_ssl_getsessionid(&cf, data, &sessionid, &idsize) &&
++ sessionid == &fake_session,
++ "identical key_blob should reuse the TLS session");
++
++ saved_conn_blob = conn->ssl_config.key_blob;
++ conn->ssl_config.key_blob = &alt_key_blob;
++ sessionid = NULL;
++ fail_unless(Curl_ssl_getsessionid(&cf, data, &sessionid, &idsize) &&
++ !sessionid,
++ "different key_blob must not reuse the TLS session");
++ conn->ssl_config.key_blob = saved_conn_blob;
++
++ sessionid = NULL;
++ fail_unless(!Curl_ssl_getsessionid(&cf, data, &sessionid, &idsize) &&
++ sessionid == &fake_session,
++ "restored key_blob should reuse the TLS session");
++
++ Curl_ssl_conn_config_cleanup(conn);
++ conn->ssl_config = data->state.session[0].ssl_config;
++ memset(&data->state.session[0].ssl_config, 0,
++ sizeof(data->state.session[0].ssl_config));
++ free(data->state.session[0].name);
++ data->state.session[0].name = NULL;
++ free(data->state.session[0].conn_to_host);
++ data->state.session[0].conn_to_host = NULL;
++ data->state.session[0].sessionid = NULL;
++ Curl_ssl_conn_config_cleanup(conn);
++ free(conn);
++ curl_easy_cleanup(curl);
++}
++#endif /* USE_SSL */
++UNITTEST_STOP
diff --git a/meta/recipes-support/curl/curl_8.7.1.bb b/meta/recipes-support/curl/curl_8.7.1.bb
index 9f261955ff..6f9a814457 100644
--- a/meta/recipes-support/curl/curl_8.7.1.bb
+++ b/meta/recipes-support/curl/curl_8.7.1.bb
@@ -45,6 +45,7 @@ SRC_URI = " \
file://CVE-2026-8286.patch \
file://CVE-2026-8927-dependent.patch \
file://CVE-2026-8927.patch \
+ file://CVE-2026-8932.patch \
"
SRC_URI:append:class-nativesdk = " \
--
2.35.6
next prev parent reply other threads:[~2026-10-07 11:24 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-07 11:23 [OE-core][scarthgap][PATCH 1/8] curl: set CVE_STATUS for CVE-2026-9547 Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-10-07 11:23 ` [OE-core][scarthgap][PATCH 2/8] curl: deferred CVE-2026-12064 Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-10-07 11:23 ` [OE-core][scarthgap][PATCH 3/8] curl: fix CVE-2026-8286 Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-10-07 11:23 ` [OE-core][scarthgap][PATCH 4/8] curl: ignore CVE-2026-8924 Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-10-07 11:24 ` [OE-core][scarthgap][PATCH 5/8] curl: fix CVE-2026-8927 Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-10-07 11:24 ` Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco) [this message]
2026-10-07 11:24 ` [OE-core][scarthgap][PATCH 7/8] curl: fix CVE-2026-6429 Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-10-07 11:24 ` [OE-core][scarthgap][PATCH 8/8] curl: fix CVE-2026-7168 Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261007112403.486499-6-devanshp@cisco.com \
--to=devanshp@cisco.com \
--cc=openembedded-core@lists.openembedded.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.