From 81f276fd62876d31cdecd838627b65591b89814a Mon Sep 17 00:00:00 2001 From: kaleb-himes Date: Wed, 14 Oct 2026 10:08:09 -0600 Subject: [PATCH] Zero the SLH-DSA key before the parameter lookup in wc_SlhDsaKey_Init --- doc/dox_comments/header_files/wc_slhdsa.h | 4 +++- src/internal.c | 4 ++-- src/ssl_load.c | 4 ++-- wolfcrypt/src/wc_slhdsa.c | 7 ++++--- wolfcrypt/test/test.c | 25 +++++++++++++++++++++++ 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/doc/dox_comments/header_files/wc_slhdsa.h b/doc/dox_comments/header_files/wc_slhdsa.h index fd9cce316c..004990f90c 100644 --- a/doc/dox_comments/header_files/wc_slhdsa.h +++ b/doc/dox_comments/header_files/wc_slhdsa.h @@ -11,7 +11,9 @@ f = fast signing). \return 0 on success. - \return BAD_FUNC_ARG if key is NULL or param is invalid. + \return BAD_FUNC_ARG if key is NULL. + \return NOT_COMPILED_IN if param is not a parameter set built in. The key + is zeroed first, so wc_SlhDsaKey_Free() is safe after any failure. \param [in,out] key Pointer to the SlhDsaKey to initialize. \param [in] param Parameter set to use. One of: SLHDSA_SHAKE128S, diff --git a/src/internal.c b/src/internal.c index c77accd243..65f1ebe245 100644 --- a/src/internal.c +++ b/src/internal.c @@ -9885,8 +9885,8 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey) case DYNAMIC_TYPE_SLHDSA: /* SLH-DSA requires the parameter set at init; use an always-present * placeholder here and re-init with the real one once known. - * wc_SlhDsaKey_Init can fail before it zeroes the object, so clear - * it first, or the caller's FreeKey would run over raw memory. */ + * Clear it first so the caller's FreeKey is well defined whatever + * wc_SlhDsaKey_Init returns. */ XMEMSET(*pKey, 0, sizeof(SlhDsaKey)); ret = wc_SlhDsaKey_Init((SlhDsaKey*)*pKey, WC_SLHDSA_DEFAULT_PARAM, ssl->heap, ssl->devId); diff --git a/src/ssl_load.c b/src/ssl_load.c index 10d03d0979..3ab831d626 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -1097,8 +1097,8 @@ static int ProcessBufferTryDecodeSlhDsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl, return MEMORY_E; } - /* wc_SlhDsaKey_Init returns NOT_COMPILED_IN before it zeroes the key, so - * clear it here to keep the unconditional Free below well defined. */ + /* Clear the key so the unconditional Free below is well defined whatever + * wc_SlhDsaKey_Init returns. */ XMEMSET(key, 0, sizeof(SlhDsaKey)); /* Initialise with an always-present placeholder parameter set; diff --git a/wolfcrypt/src/wc_slhdsa.c b/wolfcrypt/src/wc_slhdsa.c index 000ab6d987..964a2f14b4 100644 --- a/wolfcrypt/src/wc_slhdsa.c +++ b/wolfcrypt/src/wc_slhdsa.c @@ -8584,6 +8584,10 @@ int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param, void* heap, if (key == NULL) { ret = BAD_FUNC_ARG; } + else { + /* Zeroize key first so wc_SlhDsaKey_Free() is safe on any failure. */ + XMEMSET(key, 0, sizeof(SlhDsaKey)); + } if (ret == 0) { int i; @@ -8600,9 +8604,6 @@ int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param, void* heap, } } if (ret == 0) { - /* Zeroize key. */ - XMEMSET(key, 0, sizeof(SlhDsaKey)); - /* Set the parameters into key early so SLHDSA_IS_SHA2 works. */ key->params = &SlhDsaParams[idx]; /* Set heap hint to use with all allocations. */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 3411564a39..6821f13ec0 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -77778,6 +77778,26 @@ static wc_test_ret_t slhdsa_id_label_test(void) } #endif /* WOLF_PRIVATE_KEY_ID && (SHAKE128S|F || SHA2_128S|F) */ +#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) +#define SLHDSA_TEST_INIT_FAIL_FREE +/* Free must be safe after Init fails on uninitialized memory. */ +static wc_test_ret_t slhdsa_init_fail_free_test(void) +{ + wc_test_ret_t ret; + WC_DECLARE_VAR(key, SlhDsaKey, 1, HEAP_HINT); + + WC_ALLOC_VAR_EX(key, SlhDsaKey, 1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER, + return WC_TEST_RET_ENC_EC(MEMORY_E)); + XMEMSET(key, 0xA5, sizeof(SlhDsaKey)); + ret = wc_SlhDsaKey_Init(key, (enum SlhDsaParam)0x7f, HEAP_HINT, devId); + wc_SlhDsaKey_Free(key); + WC_FREE_VAR_EX(key, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (ret != WC_NO_ERR_TRACE(NOT_COMPILED_IN)) + return WC_TEST_RET_ENC_EC(ret); + return 0; +} +#endif + wc_test_ret_t slhdsa_test(void) { int ret = 0; @@ -79682,6 +79702,11 @@ out: #endif #endif /* WOLFSSL_SLHDSA_PARAM_128S */ +#ifdef SLHDSA_TEST_INIT_FAIL_FREE + if (ret == 0) + ret = (int)slhdsa_init_fail_free_test(); +#endif + return ret; } #endif