|
| 1 | +From 1d56f96f6ab5034d677136b9d50b5a75dff0faf5 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Daiki Ueno <ueno@gnu.org> |
| 3 | +Date: Tue, 18 Nov 2025 13:17:55 +0900 |
| 4 | +Subject: [PATCH] pkcs11: avoid stack overwrite when initializing a token |
| 5 | + |
| 6 | +If gnutls_pkcs11_token_init is called with label longer than 32 |
| 7 | +characters, the internal storage used to blank-fill it would |
| 8 | +overflow. This adds a guard to prevent that. |
| 9 | + |
| 10 | +Signed-off-by: Daiki Ueno <ueno@gnu.org> |
| 11 | + |
| 12 | +Upstream Patch reference: https://gitlab.com/gnutls/gnutls/-/commit/1d56f96f6ab5034d677136b9d50b5a75dff0faf5.patch |
| 13 | +--- |
| 14 | + lib/pkcs11_write.c | 5 +- |
| 15 | + tests/Makefile.am | 2 +- |
| 16 | + tests/pkcs11/long-label.c | 164 ++++++++++++++++++++++++++++++++++++++ |
| 17 | + 3 files changed, 168 insertions(+), 3 deletions(-) |
| 18 | + create mode 100644 tests/pkcs11/long-label.c |
| 19 | + |
| 20 | +diff --git a/lib/pkcs11_write.c b/lib/pkcs11_write.c |
| 21 | +index 3ce794b..5685411 100644 |
| 22 | +--- a/lib/pkcs11_write.c |
| 23 | ++++ b/lib/pkcs11_write.c |
| 24 | +@@ -28,6 +28,7 @@ |
| 25 | + #include "pkcs11x.h" |
| 26 | + #include <x509/common.h> |
| 27 | + #include "pk.h" |
| 28 | ++#include "minmax.h" |
| 29 | + |
| 30 | + static const ck_bool_t tval = 1; |
| 31 | + static const ck_bool_t fval = 0; |
| 32 | +@@ -1199,7 +1200,7 @@ int gnutls_pkcs11_delete_url(const char *object_url, unsigned int flags) |
| 33 | + * gnutls_pkcs11_token_init: |
| 34 | + * @token_url: A PKCS #11 URL specifying a token |
| 35 | + * @so_pin: Security Officer's PIN |
| 36 | +- * @label: A name to be used for the token |
| 37 | ++ * @label: A name to be used for the token, at most 32 characters |
| 38 | + * |
| 39 | + * This function will initialize (format) a token. If the token is |
| 40 | + * at a factory defaults state the security officer's PIN given will be |
| 41 | +@@ -1238,7 +1239,7 @@ gnutls_pkcs11_token_init(const char *token_url, |
| 42 | + /* so it seems memset has other uses than zeroing! */ |
| 43 | + memset(flabel, ' ', sizeof(flabel)); |
| 44 | + if (label != NULL) |
| 45 | +- memcpy(flabel, label, strlen(label)); |
| 46 | ++ memcpy(flabel, label, MIN(sizeof(flabel), strlen(label))); |
| 47 | + |
| 48 | + rv = pkcs11_init_token(module, slot, (uint8_t *) so_pin, |
| 49 | + strlen(so_pin), (uint8_t *) flabel); |
| 50 | +diff --git a/tests/Makefile.am b/tests/Makefile.am |
| 51 | +index 0b3a218..79222ea 100644 |
| 52 | +--- a/tests/Makefile.am |
| 53 | ++++ b/tests/Makefile.am |
| 54 | +@@ -483,7 +483,7 @@ buffer_CPPFLAGS = $(AM_CPPFLAGS) \ |
| 55 | + if ENABLE_PKCS11 |
| 56 | + if !WINDOWS |
| 57 | + ctests += tls13/post-handshake-with-cert-pkcs11 pkcs11/tls-neg-pkcs11-no-key \ |
| 58 | +- global-init-override |
| 59 | ++ global-init-override pkcs11/long-label |
| 60 | + tls13_post_handshake_with_cert_pkcs11_DEPENDENCIES = libpkcs11mock2.la libutils.la |
| 61 | + tls13_post_handshake_with_cert_pkcs11_LDADD = $(LDADD) $(LIBDL) |
| 62 | + pkcs11_tls_neg_pkcs11_no_key_DEPENDENCIES = libpkcs11mock2.la libutils.la |
| 63 | +diff --git a/tests/pkcs11/long-label.c b/tests/pkcs11/long-label.c |
| 64 | +new file mode 100644 |
| 65 | +index 0000000..a70bc97 |
| 66 | +--- /dev/null |
| 67 | ++++ b/tests/pkcs11/long-label.c |
| 68 | +@@ -0,0 +1,164 @@ |
| 69 | ++/* |
| 70 | ++ * Copyright (C) 2025 Red Hat, Inc. |
| 71 | ++ * |
| 72 | ++ * Author: Daiki Ueno |
| 73 | ++ * |
| 74 | ++ * This file is part of GnuTLS. |
| 75 | ++ * |
| 76 | ++ * GnuTLS is free software; you can redistribute it and/or modify it |
| 77 | ++ * under the terms of the GNU General Public License as published by |
| 78 | ++ * the Free Software Foundation; either version 3 of the License, or |
| 79 | ++ * (at your option) any later version. |
| 80 | ++ * |
| 81 | ++ * GnuTLS is distributed in the hope that it will be useful, but |
| 82 | ++ * WITHOUT ANY WARRANTY; without even the implied warranty of |
| 83 | ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 84 | ++ * General Public License for more details. |
| 85 | ++ * |
| 86 | ++ * You should have received a copy of the GNU Lesser General Public License |
| 87 | ++ * along with this program. If not, see <https://www.gnu.org/licenses/> |
| 88 | ++ */ |
| 89 | ++ |
| 90 | ++#ifdef HAVE_CONFIG_H |
| 91 | ++#include "config.h" |
| 92 | ++#endif |
| 93 | ++ |
| 94 | ++#include <stdbool.h> |
| 95 | ++#include <stdio.h> |
| 96 | ++#include <stdlib.h> |
| 97 | ++ |
| 98 | ++#if defined(_WIN32) |
| 99 | ++ |
| 100 | ++int main(void) |
| 101 | ++{ |
| 102 | ++ exit(77); |
| 103 | ++} |
| 104 | ++ |
| 105 | ++#else |
| 106 | ++ |
| 107 | ++#include <string.h> |
| 108 | ++#include <unistd.h> |
| 109 | ++#include <gnutls/gnutls.h> |
| 110 | ++ |
| 111 | ++#include "cert-common.h" |
| 112 | ++#include "pkcs11/softhsm.h" |
| 113 | ++#include "utils.h" |
| 114 | ++ |
| 115 | ++/* This program tests that a token can be initialized with |
| 116 | ++ * a label longer than 32 characters. |
| 117 | ++ */ |
| 118 | ++ |
| 119 | ++static void tls_log_func(int level, const char *str) |
| 120 | ++{ |
| 121 | ++ fprintf(stderr, "server|<%d>| %s", level, str); |
| 122 | ++} |
| 123 | ++ |
| 124 | ++#define PIN "1234" |
| 125 | ++ |
| 126 | ++#define CONFIG_NAME "softhsm-long-label" |
| 127 | ++#define CONFIG CONFIG_NAME ".config" |
| 128 | ++ |
| 129 | ++static int pin_func(void *userdata, int attempt, const char *url, |
| 130 | ++ const char *label, unsigned flags, char *pin, |
| 131 | ++ size_t pin_max) |
| 132 | ++{ |
| 133 | ++ if (attempt == 0) { |
| 134 | ++ strcpy(pin, PIN); |
| 135 | ++ return 0; |
| 136 | ++ } |
| 137 | ++ return -1; |
| 138 | ++} |
| 139 | ++ |
| 140 | ++static void test(const char *provider) |
| 141 | ++{ |
| 142 | ++ int ret; |
| 143 | ++ size_t i; |
| 144 | ++ |
| 145 | ++ gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); |
| 146 | ++ |
| 147 | ++ success("test with %s\n", provider); |
| 148 | ++ |
| 149 | ++ if (debug) { |
| 150 | ++ gnutls_global_set_log_function(tls_log_func); |
| 151 | ++ gnutls_global_set_log_level(4711); |
| 152 | ++ } |
| 153 | ++ |
| 154 | ++ /* point to SoftHSM token that libpkcs11mock4.so internally uses */ |
| 155 | ++ setenv(SOFTHSM_ENV, CONFIG, 1); |
| 156 | ++ |
| 157 | ++ gnutls_pkcs11_set_pin_function(pin_func, NULL); |
| 158 | ++ |
| 159 | ++ ret = gnutls_pkcs11_add_provider(provider, "trusted"); |
| 160 | ++ if (ret != 0) { |
| 161 | ++ fail("gnutls_pkcs11_add_provider: %s\n", gnutls_strerror(ret)); |
| 162 | ++ } |
| 163 | ++ |
| 164 | ++ /* initialize softhsm token */ |
| 165 | ++ ret = gnutls_pkcs11_token_init( |
| 166 | ++ SOFTHSM_URL, PIN, |
| 167 | ++ "this is a very long label whose length exceeds 32"); |
| 168 | ++ if (ret < 0) { |
| 169 | ++ fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret)); |
| 170 | ++ } |
| 171 | ++ |
| 172 | ++ for (i = 0;; i++) { |
| 173 | ++ char *url = NULL; |
| 174 | ++ |
| 175 | ++ ret = gnutls_pkcs11_token_get_url(i, 0, &url); |
| 176 | ++ if (ret < 0) |
| 177 | ++ break; |
| 178 | ++ if (strstr(url, |
| 179 | ++ "token=this%20is%20a%20very%20long%20label%20whose")) |
| 180 | ++ break; |
| 181 | ++ } |
| 182 | ++ if (ret < 0) |
| 183 | ++ fail("gnutls_pkcs11_token_get_url: %s\n", gnutls_strerror(ret)); |
| 184 | ++ |
| 185 | ++ gnutls_pkcs11_deinit(); |
| 186 | ++} |
| 187 | ++ |
| 188 | ++void doit(void) |
| 189 | ++{ |
| 190 | ++ const char *bin; |
| 191 | ++ const char *lib; |
| 192 | ++ char buf[128]; |
| 193 | ++ |
| 194 | ++ if (gnutls_fips140_mode_enabled()) |
| 195 | ++ exit(77); |
| 196 | ++ |
| 197 | ++ /* this must be called once in the program */ |
| 198 | ++ global_init(); |
| 199 | ++ |
| 200 | ++ /* we call gnutls_pkcs11_init manually */ |
| 201 | ++ gnutls_pkcs11_deinit(); |
| 202 | ++ |
| 203 | ++ /* check if softhsm module is loadable */ |
| 204 | ++ lib = softhsm_lib(); |
| 205 | ++ |
| 206 | ++ /* initialize SoftHSM token that libpkcs11mock4.so internally uses */ |
| 207 | ++ bin = softhsm_bin(); |
| 208 | ++ |
| 209 | ++ set_softhsm_conf(CONFIG); |
| 210 | ++ snprintf(buf, sizeof(buf), |
| 211 | ++ "%s --init-token --slot 0 --label test --so-pin " PIN |
| 212 | ++ " --pin " PIN, |
| 213 | ++ bin); |
| 214 | ++ system(buf); |
| 215 | ++ |
| 216 | ++ test(lib); |
| 217 | ++ |
| 218 | ++ lib = getenv("P11MOCKLIB4"); |
| 219 | ++ if (lib == NULL) { |
| 220 | ++ fail("P11MOCKLIB4 is not set\n"); |
| 221 | ++ } |
| 222 | ++ |
| 223 | ++ set_softhsm_conf(CONFIG); |
| 224 | ++ snprintf(buf, sizeof(buf), |
| 225 | ++ "%s --init-token --slot 0 --label test --so-pin " PIN |
| 226 | ++ " --pin " PIN, |
| 227 | ++ bin); |
| 228 | ++ system(buf); |
| 229 | ++ |
| 230 | ++ test(lib); |
| 231 | ++} |
| 232 | ++#endif /* _WIN32 */ |
| 233 | +-- |
| 234 | +2.43.0 |
| 235 | + |
0 commit comments