From ebbab7ac45ff6d6020a8f54581a4f6c6178f1170 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 14 Apr 2026 23:07:44 -0500 Subject: [PATCH 1/7] src/crl.c: fix sequence in FreeCRL(): First decrement the refcount, then shut down the CRL monitor, then deallocate resources (fixes ASAN-detected read-after-free). --- src/crl.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/crl.c b/src/crl.c index 62c207de526..cecc0461c0b 100644 --- a/src/crl.c +++ b/src/crl.c @@ -316,10 +316,28 @@ void FreeCRL(WOLFSSL_CRL* crl, int dynamic) WOLFSSL_MSG("Couldn't lock x509 mutex"); if (!doFree) return; - wolfSSL_RefFree(&crl->ref); } #endif +#ifdef HAVE_CRL_MONITOR + if (crl->tid != INVALID_THREAD_VAL) { + WOLFSSL_MSG("stopping monitor thread"); + if (StopMonitor(crl->mfd) == 0) { + if (wolfSSL_JoinThread(crl->tid) != 0) + WOLFSSL_MSG("stop monitor failed in wolfSSL_JoinThread"); + } + else { + WOLFSSL_MSG("stop monitor failed"); + } + } + if (wolfSSL_CondFree(&crl->cond) != 0) + WOLFSSL_MSG("wolfSSL_CondFree failed in FreeCRL"); +#endif + +#ifdef OPENSSL_ALL + wolfSSL_RefFree(&crl->ref); +#endif + tmp = crl->crlList; #ifdef HAVE_CRL_MONITOR if (crl->monitors[0].path) @@ -343,20 +361,6 @@ void FreeCRL(WOLFSSL_CRL* crl, int dynamic) tmp = next; } -#ifdef HAVE_CRL_MONITOR - if (crl->tid != INVALID_THREAD_VAL) { - WOLFSSL_MSG("stopping monitor thread"); - if (StopMonitor(crl->mfd) == 0) { - if (wolfSSL_JoinThread(crl->tid) != 0) - WOLFSSL_MSG("stop monitor failed in wolfSSL_JoinThread"); - } - else { - WOLFSSL_MSG("stop monitor failed"); - } - } - if (wolfSSL_CondFree(&crl->cond) != 0) - WOLFSSL_MSG("wolfSSL_CondFree failed in FreeCRL"); -#endif wc_FreeRwLock(&crl->crlLock); if (dynamic) /* free self */ XFREE(crl, crl->heap, DYNAMIC_TYPE_CRL); From 96199467f971e182541978c64f301afc0609daaa Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 14 Apr 2026 23:08:03 -0500 Subject: [PATCH 2/7] scripts/*.test: delay reaping servers in cleanup handlers to allow sanitizers to finish rendering backtraces. --- scripts/benchmark.test | 4 +++- scripts/crl-revoked.test | 4 +++- scripts/dtls.test | 4 ++++ scripts/openssl.test | 11 +++++++++-- scripts/pkcallbacks.test | 8 ++++++-- scripts/psk.test | 4 +++- scripts/resume.test | 4 +++- scripts/tls13.test | 4 +++- scripts/trusted_peer.test | 4 +++- 9 files changed, 37 insertions(+), 10 deletions(-) diff --git a/scripts/benchmark.test b/scripts/benchmark.test index 7762b54f54b..5b6ed89e654 100755 --- a/scripts/benchmark.test +++ b/scripts/benchmark.test @@ -60,8 +60,10 @@ remove_ready_file() { do_cleanup() { echo "in cleanup" - if [ $server_pid != $no_pid ] + if [ $server_pid != $no_pid ] && kill -0 $server_pid then + # sleep to give sanitizers time to dump backtraces. + sleep 1 echo "killing server" kill -9 $server_pid fi diff --git a/scripts/crl-revoked.test b/scripts/crl-revoked.test index 95a8d1470e7..119e651dd90 100755 --- a/scripts/crl-revoked.test +++ b/scripts/crl-revoked.test @@ -63,8 +63,10 @@ remove_ready_file() { abort_trap() { echo "script aborted" - if [ $server_pid != $no_pid ] + if [ $server_pid != $no_pid ] && kill -0 $server_pid then + # sleep to give sanitizers time to dump backtraces. + sleep 1 echo "killing server" kill -9 $server_pid fi diff --git a/scripts/dtls.test b/scripts/dtls.test index 1aa0f78c6d2..d1a461b6292 100755 --- a/scripts/dtls.test +++ b/scripts/dtls.test @@ -39,8 +39,12 @@ if [ "${AM_BWRAPPED-}" != "yes" ]; then fi kill_server() { + sleepseconds=1 for i in $(jobs -pr); do if [ "$i" != "$TCPDUMP_PID" ]; then + # sleep to give sanitizers time to dump backtraces. + sleep $sleepseconds + sleepseconds=0 kill -9 $i fi done diff --git a/scripts/openssl.test b/scripts/openssl.test index b41d4499af8..ff4e01e61c9 100755 --- a/scripts/openssl.test +++ b/scripts/openssl.test @@ -141,14 +141,21 @@ do_cleanup() { echo "in cleanup" IFS=$OIFS #restore separator + sleepseconds=1 for s in $servers do f2=${s%:*} sname=${f2%:*} pid=${f2##*:} port=${s##*:} - echo "killing server: $sname ($port)" - kill -9 "$pid" + if kill -0 "$pid" + then + # sleep to give sanitizers time to dump backtraces. + sleep $sleepseconds + sleepseconds=0 + echo "killing server: $sname ($port)" + kill -9 "$pid" + fi done } diff --git a/scripts/pkcallbacks.test b/scripts/pkcallbacks.test index 0a6fb2d7b52..a46dddea899 100755 --- a/scripts/pkcallbacks.test +++ b/scripts/pkcallbacks.test @@ -54,8 +54,10 @@ remove_ready_file() { do_cleanup() { echo "in cleanup" - if [ $server_pid != $no_pid ] + if [ $server_pid != $no_pid ] && kill -0 $server_pid then + # sleep to give sanitizers time to dump backtraces. + sleep 1 echo "killing server" kill -9 $server_pid fi @@ -67,8 +69,10 @@ do_cleanup() { abort_trap() { echo "script aborted" - if [ $server_pid != $no_pid ] + if [ $server_pid != $no_pid ] && kill -0 $server_pid then + # sleep to give sanitizers time to dump backtraces. + sleep 1 echo "killing server" kill -9 $server_pid fi diff --git a/scripts/psk.test b/scripts/psk.test index 10efe2ecfb8..c6469e6c7a2 100755 --- a/scripts/psk.test +++ b/scripts/psk.test @@ -63,8 +63,10 @@ remove_ready_file() { do_cleanup() { echo "in cleanup" - if [ $server_pid != $no_pid ] + if [ $server_pid != $no_pid ] && kill -0 $server_pid then + # sleep to give sanitizers time to dump backtraces. + sleep 1 echo "killing server" kill -9 $server_pid fi diff --git a/scripts/resume.test b/scripts/resume.test index 06f25be0034..07488f10b86 100755 --- a/scripts/resume.test +++ b/scripts/resume.test @@ -44,8 +44,10 @@ remove_ready_file() { do_cleanup() { echo "in cleanup" - if [ $server_pid != $no_pid ] + if [ $server_pid != $no_pid ] && kill -0 $server_pid then + # sleep to give sanitizers time to dump backtraces. + sleep 1 echo "killing server" kill -9 $server_pid fi diff --git a/scripts/tls13.test b/scripts/tls13.test index 085ffc18064..e2ef3c91227 100755 --- a/scripts/tls13.test +++ b/scripts/tls13.test @@ -74,8 +74,10 @@ remove_ready_file() { do_cleanup() { echo "in cleanup" - if [ $server_pid != $no_pid ] + if [ $server_pid != $no_pid ] && kill -0 $server_pid then + # sleep to give sanitizers time to dump backtraces. + sleep 1 echo "killing server" kill -9 $server_pid 2>/dev/null server_pid=$no_pid diff --git a/scripts/trusted_peer.test b/scripts/trusted_peer.test index f616a5ee999..46d73428686 100755 --- a/scripts/trusted_peer.test +++ b/scripts/trusted_peer.test @@ -87,8 +87,10 @@ remove_ready_file() { do_cleanup() { echo "in cleanup" - if [ $server_pid != $no_pid ] + if [ $server_pid != $no_pid ] && kill -0 $server_pid then + # sleep to give sanitizers time to dump backtraces. + sleep 1 echo "killing server" kill -9 $server_pid fi From 1df26161a7e01bcb9f4557ffc344aebbce201e86 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 14 Apr 2026 23:08:26 -0500 Subject: [PATCH 3/7] configure.ac: exclude AES-EAX from --enable-all-crypto when --enable-afalg. --- configure.ac | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 542151e22c6..962e7bdaf97 100644 --- a/configure.ac +++ b/configure.ac @@ -1546,7 +1546,8 @@ then test "$enable_ed448" = "" && enable_ed448=yes test "$enable_ed448_stream" = "" && test "$enable_ed448" != "no" && enable_ed448_stream=yes test "$enable_aessiv" = "" && enable_aessiv=yes - test "$enable_aeseax" = "" && enable_aeseax=yes + # AFALG lacks AES-EAX + test "$enable_aeseax" = "" && test "$enable_afalg" != "yes" && enable_aeseax=yes if test "$KERNEL_MODE_DEFAULTS" != "yes" then From 9bc221bfecfae1e60caa4d0ef93aa7921bebd9b6 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 14 Apr 2026 23:08:42 -0500 Subject: [PATCH 4/7] wolfcrypt/test/test.c: skip the "reject authTagSz below WOLFSSL_MIN_AUTH_TAG_SZ" test on FIPS <7.0.0. --- wolfcrypt/test/test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 5f846fcc7e8..d8f62b73b3b 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -18362,6 +18362,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aesgcm_test(void) ERROR_OUT(WC_TEST_RET_ENC_NC, out); #endif +#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) /* Regression test: wc_AesGcmDecryptFinal must reject authTagSz below * WOLFSSL_MIN_AUTH_TAG_SZ, consistent with wc_AesGcmDecrypt and * wc_AesGcmEncryptFinal. */ @@ -18376,6 +18377,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aesgcm_test(void) if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); #endif /* HAVE_AES_DECRYPT && WOLFSSL_MIN_AUTH_TAG_SZ > 1 */ +#endif /* !HAVE_FIPS || FIPS_VERSION3_GE(7,0,0) */ /* alen is the size to pass in with each update. */ for (alen = 1; alen < WC_AES_BLOCK_SIZE + 1; alen++) { From 575ac48664bcbb22c258a57be22a587e821e8b47 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 14 Apr 2026 23:08:59 -0500 Subject: [PATCH 5/7] wolfssl/wolfcrypt/aes.h and wolfssl/wolfcrypt/cmac.h: fix circular dependency mitigation for struct AesEax more robustly. --- wolfssl/wolfcrypt/aes.h | 39 ++++++++++++++++++++++++--------------- wolfssl/wolfcrypt/cmac.h | 7 ++++++- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/wolfssl/wolfcrypt/aes.h b/wolfssl/wolfcrypt/aes.h index d1ab4baf521..c64f8b658ea 100644 --- a/wolfssl/wolfcrypt/aes.h +++ b/wolfssl/wolfcrypt/aes.h @@ -821,22 +821,11 @@ WOLFSSL_LOCAL int wc_local_CmacUpdateAes(struct Cmac *cmac, const byte* in, #ifdef WOLFSSL_AES_EAX -/* Because of the circular dependency between AES and CMAC, we need to prevent - * inclusion of AES EAX from CMAC to avoid a recursive inclusion */ -#ifndef WOLF_CRYPT_CMAC_H -#include -struct AesEax { - Aes aes; - Cmac nonceCmac; - Cmac aadCmac; - Cmac ciphertextCmac; - byte nonceCmacFinal[WC_AES_BLOCK_SIZE]; - byte aadCmacFinal[WC_AES_BLOCK_SIZE]; - byte ciphertextCmacFinal[WC_AES_BLOCK_SIZE]; - byte prefixBuf[WC_AES_BLOCK_SIZE]; -}; -#endif /* !defined(WOLF_CRYPT_CMAC_H) */ +/* Note that struct AesEax is defined at the end of this file, to work around + * circular dependency between AES and CMAC. + */ +struct AesEax; typedef struct AesEax AesEax; /* One-shot API */ @@ -1120,3 +1109,23 @@ WOLFSSL_LOCAL void AES_XTS_decrypt_AARCH32(const byte* in, byte* out, #endif /* NO_AES */ #endif /* WOLF_CRYPT_AES_H */ + +/* Because of the circular dependency between AES and CMAC, we need to define + * struct AesEax here, with careful gating. + */ +#if defined(WOLFSSL_AES_EAX) && !defined(WC_AES_INCLUDE_FOR_CMAC_H) && \ + !defined(WC_AESEAX_STRUCT_DEFINED) +#include +struct AesEax { + Aes aes; + Cmac nonceCmac; + Cmac aadCmac; + Cmac ciphertextCmac; + byte nonceCmacFinal[WC_AES_BLOCK_SIZE]; + byte aadCmacFinal[WC_AES_BLOCK_SIZE]; + byte ciphertextCmacFinal[WC_AES_BLOCK_SIZE]; + byte prefixBuf[WC_AES_BLOCK_SIZE]; +}; +#define WC_AESEAX_STRUCT_DEFINED +#endif /* WOLFSSL_AES_EAX && !WC_AES_INCLUDE_FOR_CMAC_H && */ + /* !WC_AESEAX_STRUCT_DEFINED */ diff --git a/wolfssl/wolfcrypt/cmac.h b/wolfssl/wolfcrypt/cmac.h index e64ab322b1c..13998f6f06b 100644 --- a/wolfssl/wolfcrypt/cmac.h +++ b/wolfssl/wolfcrypt/cmac.h @@ -28,7 +28,12 @@ #ifdef WOLFSSL_CMAC #ifndef NO_AES -#include + /* Inhibit definition of struct AesEax, with its circular dependency on the + * below definition of struct Cmac. + */ + #define WC_AES_INCLUDE_FOR_CMAC_H + #include + #undef WC_AES_INCLUDE_FOR_CMAC_H #endif #if defined(HAVE_FIPS) && \ From 48b763a5d1d7baa7b276c634bac6945e8b1ae48c Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 14 Apr 2026 23:10:48 -0500 Subject: [PATCH 6/7] .wolfssl_known_macro_extras: remove WOLF_CRYPTO_CB_FIND (now covered by .github/workflows/os-check.yml). --- .wolfssl_known_macro_extras | 1 - 1 file changed, 1 deletion(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 0e58d4f11b0..46355fff435 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -945,7 +945,6 @@ WOLFSSL_XMSS_LARGE_SECRET_KEY WOLFSSL_ZEPHYR WOLF_ALLOW_BUILTIN WOLF_CRYPTO_CB_CMD -WOLF_CRYPTO_CB_FIND WOLF_CRYPTO_CB_ONLY_ECC WOLF_CRYPTO_CB_ONLY_RSA WOLF_CRYPTO_DEV From e4fab909384ea9eb853c5051057fddd8e8897061 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 14 Apr 2026 23:23:53 -0500 Subject: [PATCH 7/7] scripts/*.test: in kill -0 PID existence tests, close stderr to silence noise. --- scripts/benchmark.test | 2 +- scripts/crl-revoked.test | 2 +- scripts/openssl.test | 2 +- scripts/pkcallbacks.test | 4 ++-- scripts/psk.test | 2 +- scripts/resume.test | 2 +- scripts/tls13.test | 2 +- scripts/trusted_peer.test | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/benchmark.test b/scripts/benchmark.test index 5b6ed89e654..09cb74cf94c 100755 --- a/scripts/benchmark.test +++ b/scripts/benchmark.test @@ -60,7 +60,7 @@ remove_ready_file() { do_cleanup() { echo "in cleanup" - if [ $server_pid != $no_pid ] && kill -0 $server_pid + if [ $server_pid != $no_pid ] && kill -0 $server_pid 2>&- then # sleep to give sanitizers time to dump backtraces. sleep 1 diff --git a/scripts/crl-revoked.test b/scripts/crl-revoked.test index 119e651dd90..99ea9b9b912 100755 --- a/scripts/crl-revoked.test +++ b/scripts/crl-revoked.test @@ -63,7 +63,7 @@ remove_ready_file() { abort_trap() { echo "script aborted" - if [ $server_pid != $no_pid ] && kill -0 $server_pid + if [ $server_pid != $no_pid ] && kill -0 $server_pid 2>&- then # sleep to give sanitizers time to dump backtraces. sleep 1 diff --git a/scripts/openssl.test b/scripts/openssl.test index ff4e01e61c9..2bd049ae13f 100755 --- a/scripts/openssl.test +++ b/scripts/openssl.test @@ -148,7 +148,7 @@ do_cleanup() { sname=${f2%:*} pid=${f2##*:} port=${s##*:} - if kill -0 "$pid" + if kill -0 "$pid" 2>&- then # sleep to give sanitizers time to dump backtraces. sleep $sleepseconds diff --git a/scripts/pkcallbacks.test b/scripts/pkcallbacks.test index a46dddea899..aa7b783981e 100755 --- a/scripts/pkcallbacks.test +++ b/scripts/pkcallbacks.test @@ -54,7 +54,7 @@ remove_ready_file() { do_cleanup() { echo "in cleanup" - if [ $server_pid != $no_pid ] && kill -0 $server_pid + if [ $server_pid != $no_pid ] && kill -0 $server_pid 2>&- then # sleep to give sanitizers time to dump backtraces. sleep 1 @@ -69,7 +69,7 @@ do_cleanup() { abort_trap() { echo "script aborted" - if [ $server_pid != $no_pid ] && kill -0 $server_pid + if [ $server_pid != $no_pid ] && kill -0 $server_pid 2>&- then # sleep to give sanitizers time to dump backtraces. sleep 1 diff --git a/scripts/psk.test b/scripts/psk.test index c6469e6c7a2..0810e385f5a 100755 --- a/scripts/psk.test +++ b/scripts/psk.test @@ -63,7 +63,7 @@ remove_ready_file() { do_cleanup() { echo "in cleanup" - if [ $server_pid != $no_pid ] && kill -0 $server_pid + if [ $server_pid != $no_pid ] && kill -0 $server_pid 2>&- then # sleep to give sanitizers time to dump backtraces. sleep 1 diff --git a/scripts/resume.test b/scripts/resume.test index 07488f10b86..38af600e916 100755 --- a/scripts/resume.test +++ b/scripts/resume.test @@ -44,7 +44,7 @@ remove_ready_file() { do_cleanup() { echo "in cleanup" - if [ $server_pid != $no_pid ] && kill -0 $server_pid + if [ $server_pid != $no_pid ] && kill -0 $server_pid 2>&- then # sleep to give sanitizers time to dump backtraces. sleep 1 diff --git a/scripts/tls13.test b/scripts/tls13.test index e2ef3c91227..d0f02004de9 100755 --- a/scripts/tls13.test +++ b/scripts/tls13.test @@ -74,7 +74,7 @@ remove_ready_file() { do_cleanup() { echo "in cleanup" - if [ $server_pid != $no_pid ] && kill -0 $server_pid + if [ $server_pid != $no_pid ] && kill -0 $server_pid 2>&- then # sleep to give sanitizers time to dump backtraces. sleep 1 diff --git a/scripts/trusted_peer.test b/scripts/trusted_peer.test index 46d73428686..c3260b8f005 100755 --- a/scripts/trusted_peer.test +++ b/scripts/trusted_peer.test @@ -87,7 +87,7 @@ remove_ready_file() { do_cleanup() { echo "in cleanup" - if [ $server_pid != $no_pid ] && kill -0 $server_pid + if [ $server_pid != $no_pid ] && kill -0 $server_pid 2>&- then # sleep to give sanitizers time to dump backtraces. sleep 1