From 610b109241f9f8cbad08560e737549f1cc9b0e00 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Mon, 4 May 2026 23:29:26 -0500 Subject: [PATCH 1/2] fixes for fips#379 and related: linuxkm/Makefile, linuxkm/linuxkm-fips-hash-wrapper.sh, linuxkm/linuxkm_memory.c: refactor coreKey extraction to use ELF tools rather than WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE and user_settings.h. linuxkm/module_hooks.c: add stack measurement for wc_RunAllCast_fips(). tests/api/test_slhdsa.c: frivolous initialization to work around a false positive -Wmaybe-uninitialized in slhdsa_der_roundtrip_one(). wolfcrypt/src/wc_slhdsa.c, wolfssl/wolfcrypt/wc_slhdsa.h: * refactor lifecycle management for SHA-2 objects to fix a leak via wc_SlhDsaKey_CheckKey(). * add support for WC_SLHDSA_NO_ASM. * add WOLFSSL_SLHDSA_VERIFY_ONLY gates around prototypes, to get compile-time failures for misuse. wolfcrypt/test/test.c: * clean up myFipsCb() and restore usability of TEST_ALWAYS_RUN_TO_END with bad FIPS hash (useful test coverage). * add wc_RunAllCast_fips() to wolfcrypt_test(). * when WOLFSSL_KERNEL_MODE or BENCH_EMBEDDED, force on WOLFSSL_SLHDSA_VERIFY_ONLY unless WOLFSSL_SLHDSA_FORCE_FULL_TESTS is defined. wolfssl/wolfcrypt/settings.h: * add WC_MLKEM_NO_ASM to WOLFSSL_LINUXKM section to work around asm bug. * remove clause in WOLFSSL_KERNEL_MODE section that forced on WOLFSSL_SLHDSA_VERIFY_ONLY. --- .wolfssl_known_macro_extras | 3 + linuxkm/Makefile | 6 +- linuxkm/linuxkm-fips-hash-wrapper.sh | 21 +++- linuxkm/linuxkm_memory.c | 6 +- linuxkm/module_hooks.c | 18 +++ tests/api/test_slhdsa.c | 2 +- wolfcrypt/src/wc_slhdsa.c | 165 +++++++++++++++++---------- wolfcrypt/test/test.c | 59 +++++----- wolfssl/wolfcrypt/settings.h | 13 +-- wolfssl/wolfcrypt/sha3.h | 5 +- wolfssl/wolfcrypt/wc_slhdsa.h | 25 +++- 11 files changed, 211 insertions(+), 112 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 99e5990666b..2764c6e1452 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -656,6 +656,7 @@ WC_FORCE_LINUXKM_FORTIFY_SOURCE WC_HASH_CUSTOM_MAX_BLOCK_SIZE WC_HASH_CUSTOM_MAX_DIGEST_SIZE WC_HASH_CUSTOM_MIN_DIGEST_SIZE +WC_MLKEM_KERNEL_ASM WC_NO_ASYNC_SLEEP WC_NO_RNG_SIMPLE WC_NO_STATIC_ASSERT @@ -671,6 +672,8 @@ WC_RSA_NONBLOCK_TIME WC_RSA_NO_FERMAT_CHECK WC_RWLOCK_OPS_INLINE WC_SKIP_INCLUDED_C_FILES +WC_SLHDSA_KERNEL_ASM +WC_SLHDSA_NO_ASM WC_SLHDSA_VERBOSE_DEBUG WC_SSIZE_TYPE WC_STRICT_SIG diff --git a/linuxkm/Makefile b/linuxkm/Makefile index 0c1cdfaa110..24a867b9356 100644 --- a/linuxkm/Makefile +++ b/linuxkm/Makefile @@ -401,15 +401,11 @@ $(MODULE_TOP)/libwolfssl-user-build/src/.libs/libwolfssl.so: $(LIBWOLFSSL_NAME). @ for file in "$${srcfiles[@]}"; do if [[ ! -e "$$file" ]]; then mkdir -p "$$(dirname "$$file")" && cp --no-dereference --symbolic-link --no-clobber '$(SRC_TOP)'/"$$file" "$$file"; fi; done @ echo ' done.' @fi - @if [[ ! -f user_settings.h ]]; then - @ echo '__attribute__ ((visibility("default"))) extern const char coreKey[];' > user_settings.h - @ echo > user_settings_asm.h - @fi @if [[ -f Makefile ]]; then @ echo 'Using existing Makefile for libwolfssl.so.' @else @ echo -n 'Configuring user libwolfssl.so...' - @ $(FRESH_ENV) ./configure $(QFLAG) $(VFLAG) --disable-jobserver --enable-cryptonly --enable-fips="$$FIPS_FLAVOR" CFLAGS='-DWC_SYM_RELOC_TABLES_SUPPORT -DWOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE -DWOLFSSL_USER_SETTINGS -DWOLFSSL_USER_SETTINGS_ASM -DDEBUG_LINUXKM_PIE_SUPPORT' $(if $(HOSTCC),CC='$(HOSTCC)') + @ $(FRESH_ENV) ./configure $(QFLAG) $(VFLAG) --disable-jobserver --enable-cryptonly --enable-fips="$$FIPS_FLAVOR" CFLAGS='-DWC_SYM_RELOC_TABLES_SUPPORT -DDEBUG_LINUXKM_PIE_SUPPORT -DWOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE_SUPPORT' $(if $(HOSTCC),CC='$(HOSTCC)') @ echo ' done.' @fi @echo -n 'Building user libwolfssl.so...' diff --git a/linuxkm/linuxkm-fips-hash-wrapper.sh b/linuxkm/linuxkm-fips-hash-wrapper.sh index 1018d30c154..eac6954e905 100755 --- a/linuxkm/linuxkm-fips-hash-wrapper.sh +++ b/linuxkm/linuxkm-fips-hash-wrapper.sh @@ -45,6 +45,25 @@ if ! "$AWK" --version 2>&1 | grep -F -q 'GNU Awk'; then exit 1 fi +if [[ ! -v COREKEY ]]; then + if [[ ! -v LIBWOLFSSL ]]; then + LIBWOLFSSL=./libwolfssl-user-build/src/.libs/libwolfssl.so + fi + read -a coreKey_a < <("${READELF-readelf}" --symbols --wide "$LIBWOLFSSL" | grep --max-count=1 -E -e '[[:space:]]coreKey$') || exit $? + if [[ ${#coreKey_a[@]} != 8 || "${coreKey_a[2]}" != "65" ]]; then + echo "unexpected readelf output: \"${coreKey_a[*]}\" (${#coreKey_a[@]})" >&2 + exit 1 + fi + coreKey_offset=$((0x${coreKey_a[1]})) + COREKEY=$(dd if="$LIBWOLFSSL" bs=64 iflag=skip_bytes,count_bytes skip="$coreKey_offset" count=64 status=none) || exit $? + if [[ "$COREKEY" =~ ^[0-9A-Fa-f]{64}$ ]]; then + : + else + echo "unexpected value for coreKey \"${COREKEY}\"." >&2 + exit 1 + fi +fi + # shellcheck disable=SC2016 # using $AWK instead of awk confuses shellcheck. readarray -t fenceposts < <(readelf --wide --sections --symbols "$mod_path" | "$AWK" ' BEGIN { @@ -110,4 +129,4 @@ BEGIN { } }') -./linuxkm-fips-hash "${fenceposts[@]}" --mod-path "$mod_path" --in-place "$@" +./linuxkm-fips-hash "${fenceposts[@]}" --mod-path "$mod_path" --in-place --core-key="$COREKEY" "$@" diff --git a/linuxkm/linuxkm_memory.c b/linuxkm/linuxkm_memory.c index 27814207e60..ecdc89c2a93 100644 --- a/linuxkm/linuxkm_memory.c +++ b/linuxkm/linuxkm_memory.c @@ -505,7 +505,8 @@ ssize_t wc_reloc_normalize_segment( #ifdef HAVE_FIPS -#ifdef WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE +#if defined(WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE) || \ + defined(WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE_SUPPORT) #include #ifndef MAX_FIPS_DATA_SZ @@ -969,6 +970,7 @@ int wc_fips_generate_hash( return ret; } -#endif /* WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE */ +#endif /* WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE || */ + /* WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE_SUPPORT */ #endif /* HAVE_FIPS */ diff --git a/linuxkm/module_hooks.c b/linuxkm/module_hooks.c index 1cbde5a6ee1..8ef3ea0029f 100644 --- a/linuxkm/module_hooks.c +++ b/linuxkm/module_hooks.c @@ -882,7 +882,25 @@ static int wolfssl_init(void) #endif #if defined(HAVE_FIPS) && FIPS_VERSION3_GT(5,2,0) + + #ifdef WC_LINUXKM_HAVE_STACK_DEBUG + { + unsigned long stack_usage; + stack_usage = wc_linuxkm_stack_current(); + pr_info("STACK INFO: usage at call to wc_RunAllCast_fips(): %lu of %lu total\n", stack_usage, THREAD_SIZE); + wc_linuxkm_stack_hwm_prepare(0xee); + #endif + ret = wc_RunAllCast_fips(); + +#ifdef WC_LINUXKM_HAVE_STACK_DEBUG + stack_usage = wc_linuxkm_stack_hwm_measure_rel(0xee); + pr_info("STACK INFO: rel usage by wc_RunAllCast_fips(): %lu\n", stack_usage); + /* shush up false stack HWM reading by kernel: */ + wc_linuxkm_stack_hwm_prepare(0); + } +#endif + if (ret != 0) { pr_err("ERROR: wc_RunAllCast_fips() failed with return value %d\n", ret); return -ECANCELED; diff --git a/tests/api/test_slhdsa.c b/tests/api/test_slhdsa.c index 646123f4729..ca32d2cf32d 100644 --- a/tests/api/test_slhdsa.c +++ b/tests/api/test_slhdsa.c @@ -1351,7 +1351,7 @@ static int slhdsa_der_roundtrip_one(enum SlhDsaParam param) byte* derBuf = NULL; byte* sig = NULL; const word32 derBufSz = 16 * 1024; - word32 derLen; + word32 derLen = 0; /* initialize to suppress false -Wmaybe-uninitialized */ word32 idx; word32 sigLen; enum SlhDsaParam placeholder = param; diff --git a/wolfcrypt/src/wc_slhdsa.c b/wolfcrypt/src/wc_slhdsa.c index 3909bbb653a..066daf2965b 100644 --- a/wolfcrypt/src/wc_slhdsa.c +++ b/wolfcrypt/src/wc_slhdsa.c @@ -47,6 +47,12 @@ #include #endif +#ifdef WC_SLHDSA_NO_ASM + #undef USE_INTEL_SPEEDUP + #undef WOLFSSL_ARMASM + #undef WOLFSSL_RISCV_ASM +#endif + #if defined(USE_INTEL_SPEEDUP) /* CPU information for Intel. */ static cpuid_flags_t cpuid_flags = WC_CPUID_INITIALIZER; @@ -677,7 +683,7 @@ static void HA_Encode_Compressed(const word32* adrs, byte* address) */ static int slhdsakey_precompute_sha2_midstates(SlhDsaKey* key) { - int ret; + int ret = 0; byte n = key->params->n; const byte* pk_seed = key->sk + 2 * n; byte block[WC_SHA512_BLOCK_SIZE]; @@ -685,8 +691,13 @@ static int slhdsakey_precompute_sha2_midstates(SlhDsaKey* key) /* SHA-256 midstate: PK.seed || zeros to fill 64-byte block. */ XMEMSET(block, 0, WC_SHA256_BLOCK_SIZE); XMEMCPY(block, pk_seed, n); + if (key->hash.sha2.sha256_mid_inited) { + wc_Sha256Free(&key->hash.sha2.sha256_mid); + key->hash.sha2.sha256_mid_inited = 0; + } ret = wc_InitSha256(&key->hash.sha2.sha256_mid); if (ret == 0) { + key->hash.sha2.sha256_mid_inited = 1; ret = wc_Sha256Update(&key->hash.sha2.sha256_mid, block, WC_SHA256_BLOCK_SIZE); } @@ -696,8 +707,13 @@ static int slhdsakey_precompute_sha2_midstates(SlhDsaKey* key) if ((ret == 0) && (n > 16)) { XMEMSET(block, 0, WC_SHA512_BLOCK_SIZE); XMEMCPY(block, pk_seed, n); + if (key->hash.sha2.sha512_mid_inited) { + wc_Sha512Free(&key->hash.sha2.sha512_mid); + key->hash.sha2.sha512_mid_inited = 0; + } ret = wc_InitSha512(&key->hash.sha2.sha512_mid); if (ret == 0) { + key->hash.sha2.sha512_mid_inited = 1; ret = wc_Sha512Update(&key->hash.sha2.sha512_mid, block, WC_SHA512_BLOCK_SIZE); } @@ -727,7 +743,6 @@ static int slhdsakey_hash_f_sha2(SlhDsaKey* key, const byte* pk_seed, int ret; byte address[SLHDSA_HAC_SZ]; byte digest[WC_SHA256_DIGEST_SIZE]; - int copy_succeeded = 0; (void)pk_seed; @@ -736,9 +751,13 @@ static int slhdsakey_hash_f_sha2(SlhDsaKey* key, const byte* pk_seed, /* Restore SHA-256 midstate. */ + if (key->hash.sha2.sha256_inited) { + wc_Sha256Free(&key->hash.sha2.sha256); + key->hash.sha2.sha256_inited = 0; + } ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, &key->hash.sha2.sha256); if (ret == 0) { - copy_succeeded = 1; + key->hash.sha2.sha256_inited = 1; /* Update with compressed ADRS and message. */ ret = wc_Sha256Update(&key->hash.sha2.sha256, address, SLHDSA_HAC_SZ); } @@ -752,9 +771,6 @@ static int slhdsakey_hash_f_sha2(SlhDsaKey* key, const byte* pk_seed, /* Truncate to n bytes. */ XMEMCPY(hash, digest, n); } - if (copy_succeeded) { - wc_Sha256Free(&key->hash.sha2.sha256); - } return ret; } @@ -788,12 +804,15 @@ static int slhdsakey_hash_h_sha2(SlhDsaKey* key, const byte* pk_seed, if (n == WC_SLHDSA_N_128) { /* Category 1: use SHA-256. */ byte digest[WC_SHA256_DIGEST_SIZE]; - int copy_succeeded = 0; + if (key->hash.sha2.sha256_inited) { + wc_Sha256Free(&key->hash.sha2.sha256); + key->hash.sha2.sha256_inited = 0; + } ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, &key->hash.sha2.sha256); if (ret == 0) { - copy_succeeded = 1; + key->hash.sha2.sha256_inited = 1; ret = wc_Sha256Update(&key->hash.sha2.sha256, address, SLHDSA_HAC_SZ); } @@ -806,19 +825,19 @@ static int slhdsakey_hash_h_sha2(SlhDsaKey* key, const byte* pk_seed, if (ret == 0) { XMEMCPY(hash, digest, n); } - if (copy_succeeded) { - wc_Sha256Free(&key->hash.sha2.sha256); - } } else { /* Categories 3, 5: use SHA-512. */ byte digest[WC_SHA512_DIGEST_SIZE]; - int copy_succeeded = 0; + if (key->hash.sha2.sha512_inited) { + wc_Sha512Free(&key->hash.sha2.sha512); + key->hash.sha2.sha512_inited = 0; + } ret = wc_Sha512Copy(&key->hash.sha2.sha512_mid, &key->hash.sha2.sha512); if (ret == 0) { - copy_succeeded = 1; + key->hash.sha2.sha512_inited = 1; ret = wc_Sha512Update(&key->hash.sha2.sha512, address, SLHDSA_HAC_SZ); } @@ -831,9 +850,6 @@ static int slhdsakey_hash_h_sha2(SlhDsaKey* key, const byte* pk_seed, if (ret == 0) { XMEMCPY(hash, digest, n); } - if (copy_succeeded) { - wc_Sha512Free(&key->hash.sha2.sha512); - } } return ret; @@ -867,12 +883,15 @@ static int slhdsakey_hash_h_2_sha2(SlhDsaKey* key, const byte* pk_seed, if (n == WC_SLHDSA_N_128) { /* Category 1: use SHA-256. */ byte digest[WC_SHA256_DIGEST_SIZE]; - int copy_succeeded = 0; + if (key->hash.sha2.sha256_inited) { + wc_Sha256Free(&key->hash.sha2.sha256); + key->hash.sha2.sha256_inited = 0; + } ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, &key->hash.sha2.sha256); if (ret == 0) { - copy_succeeded = 1; + key->hash.sha2.sha256_inited = 1; ret = wc_Sha256Update(&key->hash.sha2.sha256, address, SLHDSA_HAC_SZ); } @@ -888,19 +907,19 @@ static int slhdsakey_hash_h_2_sha2(SlhDsaKey* key, const byte* pk_seed, if (ret == 0) { XMEMCPY(hash, digest, n); } - if (copy_succeeded) { - wc_Sha256Free(&key->hash.sha2.sha256); - } } else { /* Categories 3, 5: use SHA-512. */ byte digest[WC_SHA512_DIGEST_SIZE]; - int copy_succeeded = 0; + if (key->hash.sha2.sha512_inited) { + wc_Sha512Free(&key->hash.sha2.sha512); + key->hash.sha2.sha512_inited = 0; + } ret = wc_Sha512Copy(&key->hash.sha2.sha512_mid, &key->hash.sha2.sha512); if (ret == 0) { - copy_succeeded = 1; + key->hash.sha2.sha512_inited = 1; ret = wc_Sha512Update(&key->hash.sha2.sha512, address, SLHDSA_HAC_SZ); } @@ -916,9 +935,6 @@ static int slhdsakey_hash_h_2_sha2(SlhDsaKey* key, const byte* pk_seed, if (ret == 0) { XMEMCPY(hash, digest, n); } - if (copy_succeeded) { - wc_Sha512Free(&key->hash.sha2.sha512); - } } return ret; @@ -945,7 +961,6 @@ static int slhdsakey_hash_prf_sha2(SlhDsaKey* key, const byte* pk_seed, int ret; byte address[SLHDSA_HAC_SZ]; byte digest[WC_SHA256_DIGEST_SIZE]; - int copy_succeeded = 0; (void)pk_seed; @@ -953,9 +968,13 @@ static int slhdsakey_hash_prf_sha2(SlhDsaKey* key, const byte* pk_seed, HA_Encode_Compressed(adrs, address); /* Restore SHA-256 midstate. */ + if (key->hash.sha2.sha256_inited) { + wc_Sha256Free(&key->hash.sha2.sha256); + key->hash.sha2.sha256_inited = 0; + } ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, &key->hash.sha2.sha256); if (ret == 0) { - copy_succeeded = 1; + key->hash.sha2.sha256_inited = 1; ret = wc_Sha256Update(&key->hash.sha2.sha256, address, SLHDSA_HAC_SZ); } if (ret == 0) { @@ -967,9 +986,6 @@ static int slhdsakey_hash_prf_sha2(SlhDsaKey* key, const byte* pk_seed, if (ret == 0) { XMEMCPY(hash, digest, n); } - if (copy_succeeded) { - wc_Sha256Free(&key->hash.sha2.sha256); - } return ret; } @@ -998,9 +1014,14 @@ static int slhdsakey_hash_start_addr_sha2(SlhDsaKey* key, if (n == WC_SLHDSA_N_128) { /* Category 1: SHA-256 -- use sha256_2 (T_l must not collide with * sha256 which is used by F and H). */ + if (key->hash.sha2.sha256_2_inited) { + wc_Sha256Free(&key->hash.sha2.sha256_2); + key->hash.sha2.sha256_2_inited = 0; + } ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, &key->hash.sha2.sha256_2); if (ret == 0) { + key->hash.sha2.sha256_2_inited = 1; ret = wc_Sha256Update(&key->hash.sha2.sha256_2, address, SLHDSA_HAC_SZ); } @@ -1008,9 +1029,14 @@ static int slhdsakey_hash_start_addr_sha2(SlhDsaKey* key, else { /* Categories 3, 5: SHA-512 -- use sha512_2 (T_l must not collide * with sha512 which is used by H). */ + if (key->hash.sha2.sha512_2_inited) { + wc_Sha512Free(&key->hash.sha2.sha512_2); + key->hash.sha2.sha512_2_inited = 0; + } ret = wc_Sha512Copy(&key->hash.sha2.sha512_mid, &key->hash.sha2.sha512_2); if (ret == 0) { + key->hash.sha2.sha512_2_inited = 1; ret = wc_Sha512Update(&key->hash.sha2.sha512_2, address, SLHDSA_HAC_SZ); } @@ -1077,9 +1103,11 @@ static void slhdsakey_hash_free_sha2(SlhDsaKey* key) if (n == WC_SLHDSA_N_128) { wc_Sha256Free(&key->hash.sha2.sha256_2); + key->hash.sha2.sha256_2_inited = 0; } else { wc_Sha512Free(&key->hash.sha2.sha512_2); + key->hash.sha2.sha512_2_inited = 0; } return; @@ -1117,11 +1145,13 @@ static int slhdsakey_mgf1_sha2(SlhDsaKey* key, const byte* seed, byte digest[WC_SHA256_DIGEST_SIZE]; word32 cpLen = (left < WC_SHA256_DIGEST_SIZE) ? left : WC_SHA256_DIGEST_SIZE; - int hash_inited = 0; - ret = wc_InitSha256(&key->hash.sha2.sha256_2); + if (! key->hash.sha2.sha256_2_inited) { + ret = wc_InitSha256(&key->hash.sha2.sha256_2); + if (ret == 0) + key->hash.sha2.sha256_2_inited = 1; + } if (ret == 0) { - hash_inited = 1; ret = wc_Sha256Update(&key->hash.sha2.sha256_2, seed, seedLen); } if (ret == 0) { @@ -1130,9 +1160,6 @@ static int slhdsakey_mgf1_sha2(SlhDsaKey* key, const byte* seed, if (ret == 0) { ret = wc_Sha256Final(&key->hash.sha2.sha256_2, digest); } - if (hash_inited) { - wc_Sha256Free(&key->hash.sha2.sha256_2); - } if (ret == 0) { XMEMCPY(out + done, digest, cpLen); done += cpLen; @@ -1143,11 +1170,13 @@ static int slhdsakey_mgf1_sha2(SlhDsaKey* key, const byte* seed, byte digest[WC_SHA512_DIGEST_SIZE]; word32 cpLen = (left < WC_SHA512_DIGEST_SIZE) ? left : WC_SHA512_DIGEST_SIZE; - int hash_inited = 0; - ret = wc_InitSha512(&key->hash.sha2.sha512_2); + if (! key->hash.sha2.sha512_2_inited) { + ret = wc_InitSha512(&key->hash.sha2.sha512_2); + if (ret == 0) + key->hash.sha2.sha512_2_inited = 1; + } if (ret == 0) { - hash_inited = 1; ret = wc_Sha512Update(&key->hash.sha2.sha512_2, seed, seedLen); } if (ret == 0) { @@ -1156,9 +1185,6 @@ static int slhdsakey_mgf1_sha2(SlhDsaKey* key, const byte* seed, if (ret == 0) { ret = wc_Sha512Final(&key->hash.sha2.sha512_2, digest); } - if (hash_inited) { - wc_Sha512Free(&key->hash.sha2.sha512_2); - } if (ret == 0) { XMEMCPY(out + done, digest, cpLen); done += cpLen; @@ -1255,7 +1281,7 @@ static int slhdsakey_h_msg_sha2(SlhDsaKey* key, const byte* r, const byte* hdr, const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz, byte* md, word32 mdLen) { - int ret; + int ret = 0; byte n = key->params->n; const byte* pk_seed = key->sk + 2 * n; const byte* pk_root = key->sk + 3 * n; @@ -1265,12 +1291,14 @@ static int slhdsakey_h_msg_sha2(SlhDsaKey* key, const byte* r, byte innerHash[WC_SHA256_DIGEST_SIZE]; /* Seed for MGF1: R || PK.seed || innerHash. */ byte mgfSeed[32 + 16 + WC_SHA256_DIGEST_SIZE]; - int sha_inited = 0; /* Step 1: innerHash = SHA-256(R || PK.seed || PK.root || M). */ - ret = wc_InitSha256(&key->hash.sha2.sha256_2); + if (! key->hash.sha2.sha256_2_inited) { + ret = wc_InitSha256(&key->hash.sha2.sha256_2); + if (ret == 0) + key->hash.sha2.sha256_2_inited = 1; + } if (ret == 0) { - sha_inited = 1; ret = wc_Sha256Update(&key->hash.sha2.sha256_2, r, n); } if (ret == 0) { @@ -1291,9 +1319,6 @@ static int slhdsakey_h_msg_sha2(SlhDsaKey* key, const byte* r, if (ret == 0) { ret = wc_Sha256Final(&key->hash.sha2.sha256_2, innerHash); } - if (sha_inited) { - wc_Sha256Free(&key->hash.sha2.sha256_2); - } /* Step 2: MGF1-SHA-256(R || PK.seed || innerHash, mdLen). */ if (ret == 0) { @@ -1309,12 +1334,14 @@ static int slhdsakey_h_msg_sha2(SlhDsaKey* key, const byte* r, byte innerHash[WC_SHA512_DIGEST_SIZE]; /* Seed for MGF1: R || PK.seed || innerHash. */ byte mgfSeed[32 + 32 + WC_SHA512_DIGEST_SIZE]; - int sha_inited = 0; /* Step 1: innerHash = SHA-512(R || PK.seed || PK.root || M). */ - ret = wc_InitSha512(&key->hash.sha2.sha512_2); + if (! key->hash.sha2.sha512_2_inited) { + ret = wc_InitSha512(&key->hash.sha2.sha512_2); + if (ret == 0) + key->hash.sha2.sha512_2_inited = 1; + } if (ret == 0) { - sha_inited = 1; ret = wc_Sha512Update(&key->hash.sha2.sha512_2, r, n); } if (ret == 0) { @@ -1335,9 +1362,6 @@ static int slhdsakey_h_msg_sha2(SlhDsaKey* key, const byte* r, if (ret == 0) { ret = wc_Sha512Final(&key->hash.sha2.sha512_2, innerHash); } - if (sha_inited) { - wc_Sha512Free(&key->hash.sha2.sha512_2); - } /* Step 2: MGF1-SHA-512(R || PK.seed || innerHash, mdLen). */ if (ret == 0) { @@ -6523,8 +6547,12 @@ int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param, void* heap, if (SLHDSA_IS_SHA2(param)) { /* Initialize SHA2 hash objects. */ ret = wc_InitSha256(&key->hash.sha2.sha256); + if (ret == 0) + key->hash.sha2.sha256_inited = 1; if ((ret == 0) && (key->params->n > 16)) { ret = wc_InitSha512(&key->hash.sha2.sha512); + if (ret == 0) + key->hash.sha2.sha512_inited = 1; } } else @@ -6562,13 +6590,29 @@ void wc_SlhDsaKey_Free(SlhDsaKey* key) #ifdef WOLFSSL_SLHDSA_SHA2 if (SLHDSA_IS_SHA2(key->params->param)) { /* Dispose of the SHA2 hash objects. */ - wc_Sha256Free(&key->hash.sha2.sha256); - wc_Sha256Free(&key->hash.sha2.sha256_2); - wc_Sha256Free(&key->hash.sha2.sha256_mid); - if (key->params->n > 16) { + if (key->hash.sha2.sha256_inited) { + wc_Sha256Free(&key->hash.sha2.sha256); + key->hash.sha2.sha256_inited = 0; + } + if (key->hash.sha2.sha256_2_inited) { + wc_Sha256Free(&key->hash.sha2.sha256_2); + key->hash.sha2.sha256_2_inited = 0; + } + if (key->hash.sha2.sha256_mid_inited) { + wc_Sha256Free(&key->hash.sha2.sha256_mid); + key->hash.sha2.sha256_mid_inited = 0; + } + if (key->hash.sha2.sha512_inited) { wc_Sha512Free(&key->hash.sha2.sha512); + key->hash.sha2.sha512_inited = 0; + } + if (key->hash.sha2.sha512_2_inited) { wc_Sha512Free(&key->hash.sha2.sha512_2); + key->hash.sha2.sha512_2_inited = 0; + } + if (key->hash.sha2.sha512_mid_inited) { wc_Sha512Free(&key->hash.sha2.sha512_mid); + key->hash.sha2.sha512_mid_inited = 0; } } else @@ -9018,4 +9062,3 @@ int wc_SlhDsaKey_PrivateKeyToDer(SlhDsaKey* key, byte* output, word32 inLen) #endif /* WC_ENABLE_ASYM_KEY_EXPORT */ #endif /* WOLFSSL_HAVE_SLHDSA */ - diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 361f16d6319..0a323e7c624 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -1231,40 +1231,23 @@ typedef struct func_args { /* Kernel modules implement and install their own FIPS callback with similar * functionality. */ -#ifdef REALLY_LONG_DRBG_CONTINUOUS_TEST - int only_run_cb_once = 1; -#endif #if defined(HAVE_FIPS) && !defined(WOLFSSL_KERNEL_MODE) static void myFipsCb(int ok, int err, const char* hash) { -#ifdef REALLY_LONG_DRBG_CONTINUOUS_TEST - if (only_run_cb_once == 1) { -#endif - printf("in my Fips callback, ok = %d, err = %d\n", ok, err); - printf("message = %s\n", wc_GetErrorString(err)); - printf("hash = %s\n", hash); + static int rendered_fips_message = 0; - if (err == WC_NO_ERR_TRACE(IN_CORE_FIPS_E)) { - printf("In core integrity hash check failure, copy above hash\n"); - printf("into verifyCore[] in fips_test.c and rebuild\n"); -#ifdef TEST_ALWAYS_RUN_TO_END - /* When TEST_ALWAYS_RUN_TO_END is defined, testwolfcrypt tries to - * run every test even after failures. But with a wrong integrity - * hash the FIPS module is in FAILED state and every API call will - * fail, fire this callback, and produce millions of lines of - * redundant output. Exit now -- the hash has been printed for - * fips-hash.sh to extract, and no test can possibly pass. */ - exit(IN_CORE_FIPS_E); /* NOLINT(concurrency-mt-unsafe) */ -#endif - } -#ifdef REALLY_LONG_DRBG_CONTINUOUS_TEST - only_run_cb_once = 0; - } else { - (void) ok; - (void) err; - (void) hash; + if (rendered_fips_message == 0) { + rendered_fips_message = 1; + + printf("in my Fips callback, ok = %d, err = %d\n", ok, err); + printf("message = %s\n", wc_GetErrorString(err)); + printf("hash = %s\n", hash); + + if (err == WC_NO_ERR_TRACE(IN_CORE_FIPS_E)) { + printf("In core integrity hash check failure, copy above hash\n"); + printf("into verifyCore[] in fips_test.c and rebuild\n"); + } } -#endif } #endif /* HAVE_FIPS && !WOLFSSL_KERNEL_MODE */ @@ -2389,6 +2372,14 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ TEST_PASS("CAVP selftest passed!\n"); #endif +#if defined(HAVE_FIPS) && FIPS_VERSION3_GT(5,2,0) + ret = wc_RunAllCast_fips(); + if (ret != 0) + TEST_FAIL("wc_RunAllCast_fips failed.\n", ret); + else + TEST_PASS("wc_RunAllCast_fips passed.\n"); +#endif + if ( (ret = macro_test()) != 0) TEST_FAIL("macro test failed!\n", ret); else @@ -53979,6 +53970,16 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test_verify_only(void) #if defined(WOLFSSL_HAVE_SLHDSA) +/* If kernel or embedded, test with verify-only so that overly lengthy keygen + * and siggen tests are omitted, leaning on the FIPS KATs. + */ +#if (defined(WOLFSSL_KERNEL_MODE) || \ + defined(BENCH_EMBEDDED)) && \ + !defined(WOLFSSL_SLHDSA_FORCE_FULL_TESTS) && \ + !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) + #define WOLFSSL_SLHDSA_VERIFY_ONLY +#endif + #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY /* KeyGen KAT: deterministic key generation cross-validated against NIST CAVP * vectors. Verifies that MakeKeyWithRandom produces the expected sk and pk diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index ca74b140a82..fb68377da74 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -3917,6 +3917,11 @@ extern void uITRON4_free(void *p) ; #if defined(__aarch64__) && !defined(WOLFSSL_AARCH64_PRIVILEGE_MODE) #define WOLFSSL_AARCH64_PRIVILEGE_MODE #endif + + /* USE_INTEL_SPEEDUP currently gives wrong results for ML-KEM in linuxkm. */ + #if !defined(WC_MLKEM_NO_ASM) && !defined(WC_MLKEM_KERNEL_ASM) + #define WC_MLKEM_NO_ASM + #endif #endif /* WOLFSSL_LINUXKM */ /* FreeBSD Kernel Module */ @@ -4051,14 +4056,6 @@ extern void uITRON4_free(void *p) ; #undef WOLFSSL_GENERAL_ALIGNMENT #define WOLFSSL_GENERAL_ALIGNMENT SIZEOF_LONG #endif - - /* SLH-DSA signature generation is too computationally intensive to be - * appropriate in typical kernel deployments. - */ - #if !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ - !defined(WOLFSSL_SLHDSA_NO_VERIFY_ONLY) - #define WOLFSSL_SLHDSA_VERIFY_ONLY - #endif #endif /* WOLFSSL_KERNEL_MODE */ #if defined(WC_SYM_RELOC_TABLES) && defined(HAVE_FIPS) && \ diff --git a/wolfssl/wolfcrypt/sha3.h b/wolfssl/wolfcrypt/sha3.h index 3039137ef0b..cfa699146b0 100644 --- a/wolfssl/wolfcrypt/sha3.h +++ b/wolfssl/wolfcrypt/sha3.h @@ -244,8 +244,9 @@ WOLFSSL_LOCAL void BlockSha3(word64 *s); #ifdef WC_SHA3_NO_ASM /* asm speedups disabled */ - #if defined(USE_INTEL_SPEEDUP) && !defined(WC_MLKEM_NO_ASM) - /* native ML-KEM uses this directly. */ + #if defined(USE_INTEL_SPEEDUP) && \ + !(defined(WC_MLKEM_NO_ASM) && defined(WC_SLHDSA_NO_ASM)) + /* native ML-KEM and SLH-DSA use this directly. */ WOLFSSL_LOCAL void sha3_blocksx4_avx2(word64* s); #endif #elif defined(USE_INTEL_SPEEDUP) diff --git a/wolfssl/wolfcrypt/wc_slhdsa.h b/wolfssl/wolfcrypt/wc_slhdsa.h index 715b9af80b5..15e32368b09 100644 --- a/wolfssl/wolfcrypt/wc_slhdsa.h +++ b/wolfssl/wolfcrypt/wc_slhdsa.h @@ -628,6 +628,12 @@ typedef struct SlhDsaKey { wc_Sha256 sha256_mid; /* Pre-computed midstate: PK.seed || pad(128 - n). */ wc_Sha512 sha512_mid; + WC_BITFIELD sha256_inited:1; + WC_BITFIELD sha256_2_inited:1; + WC_BITFIELD sha256_mid_inited:1; + WC_BITFIELD sha512_inited:1; + WC_BITFIELD sha512_2_inited:1; + WC_BITFIELD sha512_mid_inited:1; } sha2; #endif } hash; @@ -637,6 +643,8 @@ WOLFSSL_API int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param, void* heap, int devId); WOLFSSL_API void wc_SlhDsaKey_Free(SlhDsaKey* key); +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY + WOLFSSL_API int wc_SlhDsaKey_MakeKey(SlhDsaKey* key, WC_RNG* rng); WOLFSSL_API int wc_SlhDsaKey_MakeKeyWithRandom(SlhDsaKey* key, const byte* sk_seed, word32 sk_seed_len, @@ -651,18 +659,24 @@ WOLFSSL_API int wc_SlhDsaKey_SignWithRandom(SlhDsaKey* key, const byte* ctx, WOLFSSL_API int wc_SlhDsaKey_Sign(SlhDsaKey* key, const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz, byte* sig, word32* sigSz, WC_RNG* rng); + +#endif /* WOLFSSL_SLHDSA_VERIFY_ONLY */ + WOLFSSL_API int wc_SlhDsaKey_Verify(SlhDsaKey* key, const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz, const byte* sig, word32 sigSz); +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY /* Internal interface: M' provided directly (no M' construction). */ WOLFSSL_API int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key, const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz); WOLFSSL_API int wc_SlhDsaKey_SignMsgWithRandom(SlhDsaKey* key, const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz, const byte* addRnd); +#endif /* WOLFSSL_SLHDSA_VERIFY_ONLY */ WOLFSSL_API int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime, word32 mprimeSz, const byte* sig, word32 sigSz); +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY WOLFSSL_API int wc_SlhDsaKey_SignHashDeterministic(SlhDsaKey* key, const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType, byte* sig, word32* sigSz); @@ -672,25 +686,30 @@ WOLFSSL_API int wc_SlhDsaKey_SignHashWithRandom(SlhDsaKey* key, WOLFSSL_API int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType, byte* sig, word32* sigSz, WC_RNG* rng); +#endif /* WOLFSSL_SLHDSA_VERIFY_ONLY */ WOLFSSL_API int wc_SlhDsaKey_VerifyHash(SlhDsaKey* key, const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType, const byte* sig, word32 sigSz); +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY WOLFSSL_API int wc_SlhDsaKey_ImportPrivate(SlhDsaKey* key, const byte* in, word32 inLen); -WOLFSSL_API int wc_SlhDsaKey_ImportPublic(SlhDsaKey* key, const byte* in, - word32 inLen); WOLFSSL_API int wc_SlhDsaKey_CheckKey(SlhDsaKey* key); - WOLFSSL_API int wc_SlhDsaKey_ExportPrivate(SlhDsaKey* key, byte* out, word32* outLen); +#endif /* WOLFSSL_SLHDSA_VERIFY_ONLY */ + +WOLFSSL_API int wc_SlhDsaKey_ImportPublic(SlhDsaKey* key, const byte* in, + word32 inLen); WOLFSSL_API int wc_SlhDsaKey_ExportPublic(SlhDsaKey* key, byte* out, word32* outLen); WOLFSSL_API int wc_SlhDsaKey_PrivateSize(SlhDsaKey* key); WOLFSSL_API int wc_SlhDsaKey_PublicSize(SlhDsaKey* key); WOLFSSL_API int wc_SlhDsaKey_SigSize(SlhDsaKey* key); +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY WOLFSSL_API int wc_SlhDsaKey_PrivateSizeFromParam(enum SlhDsaParam param); +#endif WOLFSSL_API int wc_SlhDsaKey_PublicSizeFromParam(enum SlhDsaParam param); WOLFSSL_API int wc_SlhDsaKey_SigSizeFromParam(enum SlhDsaParam param); From d93a5ee194b33334c2d2a4f520ad1c99aeaa339b Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 5 May 2026 11:01:51 -0500 Subject: [PATCH 2/2] linuxkm/linuxkm-fips-hash-wrapper.sh: fix whitespace. --- .wolfssl_known_macro_extras | 2 +- linuxkm/linuxkm-fips-hash-wrapper.sh | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 2764c6e1452..5c624e5d735 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -684,7 +684,7 @@ WIFI_101 WIFI_AVAILABLE WIFI_NINA WIN_REUSE_CRYPT_HANDLE -WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE_SUPPORT +WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE WOLFSENTRY_H WOLFSENTRY_NO_JSON WOLFSSL_32BIT_MILLI_TIME diff --git a/linuxkm/linuxkm-fips-hash-wrapper.sh b/linuxkm/linuxkm-fips-hash-wrapper.sh index eac6954e905..8be522e4707 100755 --- a/linuxkm/linuxkm-fips-hash-wrapper.sh +++ b/linuxkm/linuxkm-fips-hash-wrapper.sh @@ -47,20 +47,20 @@ fi if [[ ! -v COREKEY ]]; then if [[ ! -v LIBWOLFSSL ]]; then - LIBWOLFSSL=./libwolfssl-user-build/src/.libs/libwolfssl.so + LIBWOLFSSL=./libwolfssl-user-build/src/.libs/libwolfssl.so fi read -a coreKey_a < <("${READELF-readelf}" --symbols --wide "$LIBWOLFSSL" | grep --max-count=1 -E -e '[[:space:]]coreKey$') || exit $? if [[ ${#coreKey_a[@]} != 8 || "${coreKey_a[2]}" != "65" ]]; then - echo "unexpected readelf output: \"${coreKey_a[*]}\" (${#coreKey_a[@]})" >&2 - exit 1 + echo "unexpected readelf output: \"${coreKey_a[*]}\" (${#coreKey_a[@]})" >&2 + exit 1 fi coreKey_offset=$((0x${coreKey_a[1]})) COREKEY=$(dd if="$LIBWOLFSSL" bs=64 iflag=skip_bytes,count_bytes skip="$coreKey_offset" count=64 status=none) || exit $? if [[ "$COREKEY" =~ ^[0-9A-Fa-f]{64}$ ]]; then - : + : else - echo "unexpected value for coreKey \"${COREKEY}\"." >&2 - exit 1 + echo "unexpected value for coreKey \"${COREKEY}\"." >&2 + exit 1 fi fi