]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
pkcs11: avoid stack overwrite when initializing a token
authorDaiki Ueno <ueno@gnu.org>
Tue, 18 Nov 2025 04:17:55 +0000 (13:17 +0900)
committerDaiki Ueno <ueno@gnu.org>
Wed, 19 Nov 2025 11:47:00 +0000 (20:47 +0900)
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 <ueno@gnu.org>
.gitignore
NEWS
lib/pkcs11_write.c
tests/Makefile.am
tests/pkcs11/long-label.c [new file with mode: 0644]

index 6d1f8a3285a696d8e87f3ce3a5c50748dc379c8c..0c24e010c93c31c88573db95eb2574616ffd8731 100644 (file)
@@ -582,6 +582,7 @@ tests/pkcs11/gnutls_pcert_list_import_x509_file
 tests/pkcs11/gnutls_x509_crt_list_import_url
 tests/pkcs11/list-objects
 tests/pkcs11/list-tokens
+tests/pkcs11/long-label
 tests/pkcs11/os-locking-ok
 tests/pkcs11/pkcs11-chainverify
 tests/pkcs11/pkcs11-combo
@@ -752,6 +753,7 @@ tests/slow/keygen
 tests/slow/mac-override
 tests/softhsm-*.db/
 tests/softhsm-distrust-after.config
+tests/softhsm-long-label.config
 tests/softhsm-neg-no-key.config
 tests/softhsm-post-handshake-with-cert-pkcs11.config
 tests/spki
diff --git a/NEWS b/NEWS
index 0ae3c999199a88be18480ffe6974a4c614b4afa9..d6df70ee65b1db3300c436e1496c653c68d0f3c8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,10 @@ See the end for copying conditions.
 
 * Version 3.8.11 (unreleased)
 
+** 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: MAC algorithms for PSK binders is now configurable
    The previous implementation assumed HMAC-SHA256 to calculate the
    PSK binders. With the new gnutls_psk_allocate_client_credentials2()
index f5e9058e05346a9dcaa19f1f3283b88aed107324..64b85a2dfc31f86c3e36ee5cc25e09ab6cbcbf34 100644 (file)
@@ -28,6 +28,7 @@
 #include "pkcs11x.h"
 #include "x509/common.h"
 #include "pk.h"
+#include "minmax.h"
 
 static const ck_bool_t tval = 1;
 static const ck_bool_t fval = 0;
@@ -1172,7 +1173,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
@@ -1210,7 +1211,7 @@ int gnutls_pkcs11_token_init(const char *token_url, const char *so_pin,
        /* 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);
index be4966f4b52673077e5125e2dcb340d729132c53..8327c90ca6a3bf3d298a05883f668f339200bb01 100644 (file)
@@ -508,7 +508,7 @@ pathbuf_CPPFLAGS = $(AM_CPPFLAGS) \
 if ENABLE_PKCS11
 if !WINDOWS
 ctests += tls13/post-handshake-with-cert-pkcs11 pkcs11/tls-neg-pkcs11-no-key \
-       global-init-override pkcs11/distrust-after pkcs11/os-locking-ok
+       global-init-override pkcs11/distrust-after pkcs11/os-locking-ok 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 (file)
index 0000000..a70bc97
--- /dev/null
@@ -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 <https://www.gnu.org/licenses/>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(_WIN32)
+
+int main(void)
+{
+       exit(77);
+}
+
+#else
+
+#include <string.h>
+#include <unistd.h>
+#include <gnutls/gnutls.h>
+
+#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 */