From 1d56f96f6ab5034d677136b9d50b5a75dff0faf5 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Tue, 18 Nov 2025 13:17:55 +0900 Subject: [PATCH] pkcs11: avoid stack overwrite when initializing a token If gnutls_pkcs11_token_init is called with label longer than 32 characters, the internal storage used to blank-fill it would overflow. This adds a guard to prevent that. Signed-off-by: Daiki Ueno CVE: CVE-2025-9820 Upstream-Status: Backport [https://gitlab.com/gnutls/gnutls/-/commit/1d56f96f6ab5034d677136b9d50b5a75dff0faf5] Signed-off-by: Peter Marko --- NEWS | 4 + lib/pkcs11_write.c | 5 +- tests/Makefile.am | 2 +- tests/pkcs11/long-label.c | 164 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 tests/pkcs11/long-label.c diff --git a/NEWS b/NEWS index 0ae3c9991..d6df70ee6 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,10 @@ Copyright (C) 2000-2016 Free Software Foundation, Inc. Copyright (C) 2013-2019 Nikos Mavrogiannopoulos See the end for copying conditions. +** libgnutls: Fix stack overwrite in gnutls_pkcs11_token_init + Reported by Luigino Camastra from Aisle Research. [GNUTLS-SA-2025-11-18, + CVSS: low] [CVE-2025-9820] + ** libgnutls: Fix NULL pointer dereference when 2nd Client Hello omits PSK Reported by Stefan Bühler. [GNUTLS-SA-2025-07-07-4, CVSS: medium] [CVE-2025-6395] diff --git a/lib/pkcs11_write.c b/lib/pkcs11_write.c index f5e9058e0..64b85a2df 100644 --- a/lib/pkcs11_write.c +++ b/lib/pkcs11_write.c @@ -28,6 +28,7 @@ #include "pkcs11x.h" #include #include "pk.h" +#include "minmax.h" static const ck_bool_t tval = 1; static const ck_bool_t fval = 0; @@ -1199,7 +1200,7 @@ int gnutls_pkcs11_delete_url(const char *object_url, unsigned int flags) * gnutls_pkcs11_token_init: * @token_url: A PKCS #11 URL specifying a token * @so_pin: Security Officer's PIN - * @label: A name to be used for the token + * @label: A name to be used for the token, at most 32 characters * * This function will initialize (format) a token. If the token is * at a factory defaults state the security officer's PIN given will be @@ -1238,7 +1239,7 @@ gnutls_pkcs11_token_init(const char *token_url, /* so it seems memset has other uses than zeroing! */ memset(flabel, ' ', sizeof(flabel)); if (label != NULL) - memcpy(flabel, label, strlen(label)); + memcpy(flabel, label, MIN(sizeof(flabel), strlen(label))); rv = pkcs11_init_token(module, slot, (uint8_t *) so_pin, strlen(so_pin), (uint8_t *) flabel); diff --git a/tests/Makefile.am b/tests/Makefile.am index be4966f4b..8327c90ca 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -485,7 +485,7 @@ buffer_CPPFLAGS = $(AM_CPPFLAGS) \ if ENABLE_PKCS11 if !WINDOWS ctests += tls13/post-handshake-with-cert-pkcs11 pkcs11/tls-neg-pkcs11-no-key \ - global-init-override + global-init-override pkcs11/long-label tls13_post_handshake_with_cert_pkcs11_DEPENDENCIES = libpkcs11mock2.la libutils.la tls13_post_handshake_with_cert_pkcs11_LDADD = $(LDADD) $(LIBDL) pkcs11_tls_neg_pkcs11_no_key_DEPENDENCIES = libpkcs11mock2.la libutils.la diff --git a/tests/pkcs11/long-label.c b/tests/pkcs11/long-label.c new file mode 100644 index 000000000..a70bc9728 --- /dev/null +++ b/tests/pkcs11/long-label.c @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2025 Red Hat, Inc. + * + * Author: Daiki Ueno + * + * This file is part of GnuTLS. + * + * GnuTLS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#if defined(_WIN32) + +int main(void) +{ + exit(77); +} + +#else + +#include +#include +#include + +#include "cert-common.h" +#include "pkcs11/softhsm.h" +#include "utils.h" + +/* This program tests that a token can be initialized with + * a label longer than 32 characters. + */ + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "server|<%d>| %s", level, str); +} + +#define PIN "1234" + +#define CONFIG_NAME "softhsm-long-label" +#define CONFIG CONFIG_NAME ".config" + +static int pin_func(void *userdata, int attempt, const char *url, + const char *label, unsigned flags, char *pin, + size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +static void test(const char *provider) +{ + int ret; + size_t i; + + gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + + success("test with %s\n", provider); + + if (debug) { + gnutls_global_set_log_function(tls_log_func); + gnutls_global_set_log_level(4711); + } + + /* point to SoftHSM token that libpkcs11mock4.so internally uses */ + setenv(SOFTHSM_ENV, CONFIG, 1); + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + + ret = gnutls_pkcs11_add_provider(provider, "trusted"); + if (ret != 0) { + fail("gnutls_pkcs11_add_provider: %s\n", gnutls_strerror(ret)); + } + + /* initialize softhsm token */ + ret = gnutls_pkcs11_token_init( + SOFTHSM_URL, PIN, + "this is a very long label whose length exceeds 32"); + if (ret < 0) { + fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret)); + } + + for (i = 0;; i++) { + char *url = NULL; + + ret = gnutls_pkcs11_token_get_url(i, 0, &url); + if (ret < 0) + break; + if (strstr(url, + "token=this%20is%20a%20very%20long%20label%20whose")) + break; + } + if (ret < 0) + fail("gnutls_pkcs11_token_get_url: %s\n", gnutls_strerror(ret)); + + gnutls_pkcs11_deinit(); +} + +void doit(void) +{ + const char *bin; + const char *lib; + char buf[128]; + + if (gnutls_fips140_mode_enabled()) + exit(77); + + /* this must be called once in the program */ + global_init(); + + /* we call gnutls_pkcs11_init manually */ + gnutls_pkcs11_deinit(); + + /* check if softhsm module is loadable */ + lib = softhsm_lib(); + + /* initialize SoftHSM token that libpkcs11mock4.so internally uses */ + bin = softhsm_bin(); + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), + "%s --init-token --slot 0 --label test --so-pin " PIN + " --pin " PIN, + bin); + system(buf); + + test(lib); + + lib = getenv("P11MOCKLIB4"); + if (lib == NULL) { + fail("P11MOCKLIB4 is not set\n"); + } + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), + "%s --init-token --slot 0 --label test --so-pin " PIN + " --pin " PIN, + bin); + system(buf); + + test(lib); +} +#endif /* _WIN32 */