From 40623dada06221e90c15d3849ebe535ff85c1a05 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 14 Jul 2026 17:19:13 -0500 Subject: [PATCH 01/18] Implement FIPS shimming for wc_AesGcmEncrypt(): wolfssl/wolfcrypt/aes.h: if HAVE_FIPS && !WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED, make wc_AesGcmEncrypt() a WOLFSSL_LOCAL, and if !_WC_BUILDING_AES_C, add a WC_DEPRECATED() attribute to it. wolfssl/wolfcrypt/wc_compat.h, wolfssl/wolfcrypt/include.am, .wolfssl_known_macro_extras: add wc_compat.h: when HAVE_FIPS and !WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED, shim wc_AesGcmEncrypt() to remap it to FIPS-allowed APIs. wolfssl/wolfcrypt/types.h: at the end, #ifndef BUILDING_WOLFSSL, #include , to assure transparent shimming of wc_AesGcmEncrypt() for all outside callers. wolfcrypt/src/evp.c, wolfcrypt/src/hpke.c, wolfcrypt/src/pkcs7.c, wolfcrypt/benchmark/benchmark.c, wolfcrypt/test/test.c, wolfssl/ssl.h: #include to shim in-library/in-module calls to wc_AesGcmEncrypt(). src/internal.c: in TicketEncDec(), add const attributes to constable input args, and fix swapped out/in in calls to wc_AesGcmEncrypt(). tests/api/test_aes.c: in test_wc_AesGcmEncryptDecrypt(), skip longIV test if WC_TEST_AES_GCM_ENCRYPT_NO_NONSTD_IV (defined by wc_compat.h when needed). wolfssl/wolfcrypt/error-crypt.h, wolfssl/error-ssl.h, wolfcrypt/src/error.c, src/internal.c: * add FIPS_WRONG_API_E; * put several error codes back into sequence in wc_GetErrorString() switch(). * move wc_static_assert()s from headers to corresponding .c files, to eliminate dependency on wolfcrypt/types.h; * remove unneeded #include from error-crypt.h. --- .wolfssl_known_macro_extras | 1 + src/internal.c | 10 +-- tests/api/test_aes.c | 3 +- wolfcrypt/benchmark/benchmark.c | 1 + wolfcrypt/src/error.c | 63 +++++++++-------- wolfcrypt/src/evp.c | 2 + wolfcrypt/src/hpke.c | 2 + wolfcrypt/src/pkcs7.c | 2 + wolfcrypt/test/test.c | 2 + wolfssl/error-ssl.h | 2 - wolfssl/ssl.h | 1 + wolfssl/wolfcrypt/aes.h | 18 +++-- wolfssl/wolfcrypt/error-crypt.h | 11 +-- wolfssl/wolfcrypt/include.am | 3 +- wolfssl/wolfcrypt/types.h | 4 ++ wolfssl/wolfcrypt/wc_compat.h | 120 ++++++++++++++++++++++++++++++++ 16 files changed, 196 insertions(+), 49 deletions(-) create mode 100644 wolfssl/wolfcrypt/wc_compat.h diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index b506fe1987e..224fe57c88c 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -719,6 +719,7 @@ WC_ASYNC_THREAD_BIND WC_BLINDING_NO_RNG_ACKNOWLEDGE_WEAKNESS WC_CACHE_RESISTANT_BASE64_TABLE WC_DISABLE_RADIX_ZERO_PAD +WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED WC_FLAG_DONT_USE_AESNI WC_FORCE_LINUXKM_FORTIFY_SOURCE WC_HASH_CUSTOM_MAX_BLOCK_SIZE diff --git a/src/internal.c b/src/internal.c index 0ea1b04f2b7..5d6af2a7e7a 100644 --- a/src/internal.c +++ b/src/internal.c @@ -28447,6 +28447,8 @@ static const char* wolfSSL_ERR_reason_error_string_OpenSSL(unsigned long e) } #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL || HAVE_WEBSERVER || HAVE_MEMCACHED */ +wc_static_assert((int)WC_LAST_E <= (int)WOLFSSL_LAST_E); + const char* wolfSSL_ERR_reason_error_string(unsigned long e) { #ifdef NO_ERROR_STRINGS @@ -42275,8 +42277,8 @@ static int TicketEncDec(byte* key, int keyLen, byte* iv, byte* aad, int aadSz, * @return MEMORY_E when dynamic memory allocation fails. * @return Other value when encryption/decryption fails. */ -static int TicketEncDec(byte* key, int keyLen, byte* iv, byte* aad, int aadSz, - byte* in, int inLen, byte* out, int* outLen, byte* tag, +static int TicketEncDec(const byte* key, int keyLen, const byte* iv, const byte* aad, int aadSz, + const byte* in, int inLen, byte* out, int* outLen, byte* tag, void* heap, int enc) { int ret; @@ -42293,7 +42295,7 @@ static int TicketEncDec(byte* key, int keyLen, byte* iv, byte* aad, int aadSz, ret = wc_AesGcmSetKey(aes, key, keyLen); } if (ret == 0) { - ret = wc_AesGcmEncrypt(aes, in, out, inLen, iv, GCM_NONCE_MID_SZ, + ret = wc_AesGcmEncrypt(aes, out, in, inLen, iv, GCM_NONCE_MID_SZ, tag, WC_AES_BLOCK_SIZE, aad, aadSz); } wc_AesFree(aes); @@ -42304,7 +42306,7 @@ static int TicketEncDec(byte* key, int keyLen, byte* iv, byte* aad, int aadSz, ret = wc_AesGcmSetKey(aes, key, keyLen); } if (ret == 0) { - ret = wc_AesGcmDecrypt(aes, in, out, inLen, iv, GCM_NONCE_MID_SZ, + ret = wc_AesGcmDecrypt(aes, out, in, inLen, iv, GCM_NONCE_MID_SZ, tag, WC_AES_BLOCK_SIZE, aad, aadSz); } wc_AesFree(aes); diff --git a/tests/api/test_aes.c b/tests/api/test_aes.c index f879f6e06b2..f7fe62b0c27 100644 --- a/tests/api/test_aes.c +++ b/tests/api/test_aes.c @@ -3399,7 +3399,8 @@ int test_wc_AesGcmEncryptDecrypt(void) * bound on the IV length. */ #if (!defined(HAVE_FIPS) || \ (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) && \ - !defined(WOLFSSL_AES_GCM_FIXED_IV_AAD) + !defined(WOLFSSL_AES_GCM_FIXED_IV_AAD) && \ + !defined(WC_TEST_AES_GCM_ENCRYPT_NO_NONSTD_IV) ExpectIntEQ(wc_AesGcmEncrypt(&aes, enc, vector, sizeof(vector), longIV, sizeof(longIV)/sizeof(byte), resultT, sizeof(resultT), a, sizeof(a)), 0); diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 85ae3beca74..a0973c76160 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -80,6 +80,7 @@ #include #include #include +#include #ifdef WOLFSSL_LINUXKM /* remap current_time() -- collides with a function in kernel linux/fs.h */ diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index dbece3d4e37..62a67470bb6 100644 --- a/wolfcrypt/src/error.c +++ b/wolfcrypt/src/error.c @@ -32,6 +32,10 @@ #include #endif +wc_static_assert((int)WC_LAST_E <= (int)WC_SPAN2_LAST_E); +wc_static_assert((int)MIN_CODE_E <= (int)WC_LAST_E); +wc_static_assert((int)MIN_CODE_E <= (int)WC_SPAN2_MIN_CODE_E); + WOLFSSL_ABI const char* wc_GetErrorString(int error) { @@ -620,6 +624,9 @@ const char* wc_GetErrorString(int error) case KEY_EXHAUSTED_E: return "Key no longer usable for operation"; + case ML_KEM_KAT_FIPS_E: + return "wolfCrypt FIPS ML-KEM Known Answer Test Failure"; + case FIPS_INVALID_VER_E: return "Invalid FIPS version defined, check length"; @@ -644,6 +651,15 @@ const char* wc_GetErrorString(int error) case WC_KEY_MISMATCH_E: return "key values mismatch"; + case ML_DSA_KAT_FIPS_E: + return "wolfCrypt FIPS ML-DSA Known Answer Test Failure"; + + case LMS_KAT_FIPS_E: + return "wolfCrypt FIPS LMS Known Answer Test Failure"; + + case XMSS_KAT_FIPS_E: + return "wolfCrypt FIPS XMSS Known Answer Test Failure"; + case DEADLOCK_AVERTED_E: return "Deadlock averted -- retry the call"; @@ -668,17 +684,26 @@ const char* wc_GetErrorString(int error) case ALREADY_E: return "Operation was redundant or preempted"; - case ML_KEM_KAT_FIPS_E: - return "wolfCrypt FIPS ML-KEM Known Answer Test Failure"; + case SEQ_OVERFLOW_E: + return "Sequence counter would overflow"; - case ML_DSA_KAT_FIPS_E: - return "wolfCrypt FIPS ML-DSA Known Answer Test Failure"; + case PUF_INIT_E: + return "PUF initialization failed"; - case LMS_KAT_FIPS_E: - return "wolfCrypt FIPS LMS Known Answer Test Failure"; + case PUF_READ_E: + return "PUF SRAM read failed"; - case XMSS_KAT_FIPS_E: - return "wolfCrypt FIPS XMSS Known Answer Test Failure"; + case PUF_ENROLL_E: + return "PUF enrollment failed"; + + case PUF_RECONSTRUCT_E: + return "PUF reconstruction failed"; + + case PUF_DERIVE_KEY_E: + return "PUF key derivation failed"; + + case PUF_IDENTITY_E: + return "PUF identity retrieval failed"; case ML_KEM_PCT_E: return "wolfcrypt ML-KEM Pairwise Consistency Test Failure"; @@ -710,26 +735,8 @@ const char* wc_GetErrorString(int error) case AES_KW_KAT_FIPS_E: return "wolfCrypt FIPS AES Key Wrap Known Answer Test Failure"; - case SEQ_OVERFLOW_E: - return "Sequence counter would overflow"; - - case PUF_INIT_E: - return "PUF initialization failed"; - - case PUF_READ_E: - return "PUF SRAM read failed"; - - case PUF_ENROLL_E: - return "PUF enrollment failed"; - - case PUF_RECONSTRUCT_E: - return "PUF reconstruction failed"; - - case PUF_DERIVE_KEY_E: - return "PUF key derivation failed"; - - case PUF_IDENTITY_E: - return "PUF identity retrieval failed"; + case FIPS_WRONG_API_E: + return "Requested API is not allowed in FIPS mode"; case MAX_CODE_E: case WC_SPAN1_MIN_CODE_E: diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 23f576781b7..ced8033430f 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -54,6 +54,8 @@ #include #endif +#include + static const struct s_ent { const enum wc_HashType macType; const int nid; diff --git a/wolfcrypt/src/hpke.c b/wolfcrypt/src/hpke.c index e117e9e813a..ff74e1cd932 100644 --- a/wolfcrypt/src/hpke.c +++ b/wolfcrypt/src/hpke.c @@ -45,6 +45,8 @@ #include #endif +#include + static const char* KEM_STR = "KEM"; static const int KEM_STR_LEN = 3; diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 858b5c1baab..f76afe6f988 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -101,6 +101,8 @@ #include #endif +#include + /* direction for processing, encoding or decoding */ typedef enum { WC_PKCS7_ENCODE, diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 3177be665ca..feed8d31c6a 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -57,6 +57,8 @@ #include #endif +#include + #if defined(HAVE_WOLFCRYPT_TEST_OPTIONS) #include #define err_sys err_sys_remap /* remap err_sys */ diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 2783f00813b..68e952cdc99 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -255,8 +255,6 @@ enum wolfSSL_ErrorCodes { /* codes -1000 to -1999 are reserved for wolfCrypt. */ }; -wc_static_assert((int)WC_LAST_E <= (int)WOLFSSL_LAST_E); - #ifndef WOLFSSL_NO_DILITHIUM_LEGACY_NAMES /* Legacy alias for code written against the pre-standardization * Dilithium name. Will be removed alongside the dilithium.h shim. */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index b5a0fb4a07a..9d92c273b0a 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -38,6 +38,7 @@ #include #include #include +#include #if defined(HAVE_OCSP) || defined(HAVE_CRL) || (defined(WOLFSSL_CUSTOM_OID) && \ defined(WOLFSSL_ASN_TEMPLATE) && defined(HAVE_OID_DECODING)) || \ diff --git a/wolfssl/wolfcrypt/aes.h b/wolfssl/wolfcrypt/aes.h index 51986b4ba54..183aad072f8 100644 --- a/wolfssl/wolfcrypt/aes.h +++ b/wolfssl/wolfcrypt/aes.h @@ -621,11 +621,19 @@ WOLFSSL_LOCAL int wc_local_AesGcmCheckTagSz(word32 authTagSz); word32 kup); #endif WOLFSSL_API int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len); - WOLFSSL_API int wc_AesGcmEncrypt(Aes* aes, byte* out, - const byte* in, word32 sz, - const byte* iv, word32 ivSz, - byte* authTag, word32 authTagSz, - const byte* authIn, word32 authInSz); +#if defined(HAVE_FIPS) && !defined(WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED) +#ifndef _WC_BUILDING_AES_C + WC_DEPRECATED("wc_AesGcmEncrypt() is not approved for FIPS usage.") +#endif + WOLFSSL_LOCAL +#else + WOLFSSL_API +#endif + int wc_AesGcmEncrypt(Aes* aes, byte* out, + const byte* in, word32 sz, + const byte* iv, word32 ivSz, + byte* authTag, word32 authTagSz, + const byte* authIn, word32 authInSz); WOLFSSL_API WARN_UNUSED_RESULT int wc_AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz, const byte* iv, word32 ivSz, diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index f0172ed8c45..d524bd71a26 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -31,8 +31,6 @@ the error status. #ifndef WOLF_CRYPT_ERROR_H #define WOLF_CRYPT_ERROR_H -#include - #ifdef __cplusplus extern "C" { #endif @@ -340,9 +338,10 @@ enum wolfCrypt_ErrorCodes { * so fips.c can report it as retired rather * than unknown. */ AES_KW_KAT_FIPS_E = -1024, /* AES Key Wrap KAT failure */ + FIPS_WRONG_API_E = -1025, /* Requested API is not allowed in FIPS mode */ - WC_SPAN2_LAST_E = -1024, /* Update to indicate last used error code */ - WC_LAST_E = -1024, /* the last code used either here or in + WC_SPAN2_LAST_E = -1025, /* Update to indicate last used error code */ + WC_LAST_E = -1025, /* the last code used either here or in * error-ssl.h */ WC_SPAN2_MIN_CODE_E = -1999, /* Last usable code in span 2 */ @@ -354,10 +353,6 @@ enum wolfCrypt_ErrorCodes { wolfcrypt/src/error.c !!! */ }; -wc_static_assert((int)WC_LAST_E <= (int)WC_SPAN2_LAST_E); -wc_static_assert((int)MIN_CODE_E <= (int)WC_LAST_E); -wc_static_assert((int)MIN_CODE_E <= (int)WC_SPAN2_MIN_CODE_E); - #ifdef NO_ERROR_STRINGS #define wc_GetErrorString(error) "no support for error strings built in" #define wc_ErrorString(err, buf) \ diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index 1841813f4fe..e49082f6ae4 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/wolfssl/wolfcrypt/include.am @@ -88,7 +88,8 @@ nobase_include_HEADERS+= \ wolfssl/wolfcrypt/wc_xmss.h \ wolfssl/wolfcrypt/wc_slhdsa.h \ wolfssl/wolfcrypt/puf.h \ - wolfssl/wolfcrypt/oid_sum.h + wolfssl/wolfcrypt/oid_sum.h \ + wolfssl/wolfcrypt/wc_compat.h noinst_HEADERS+= \ wolfssl/wolfcrypt/port/aria/aria-crypt.h \ diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 010ebcb7e69..af98e43ba30 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -2566,4 +2566,8 @@ enum Max_ASN { } /* extern "C" */ #endif +#ifndef BUILDING_WOLFSSL + #include +#endif + #endif /* WOLF_CRYPT_TYPES_H */ diff --git a/wolfssl/wolfcrypt/wc_compat.h b/wolfssl/wolfcrypt/wc_compat.h new file mode 100644 index 00000000000..4472158ba01 --- /dev/null +++ b/wolfssl/wolfcrypt/wc_compat.h @@ -0,0 +1,120 @@ +/* wolfcrypt/wc_compat.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +/*! + \file ../wolfssl/wolfcrypt/wc_compat.h + \brief Header file containing wolfCrypt compatibility shims +*/ + +#if (defined(WOLF_CRYPT_SHA256_H) && !defined(NO_SHA256) && \ + !defined(WC_SHA256_TYPE_DEFINED)) || \ + (defined(WOLF_CRYPT_SHA512_H) && \ + (defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384)) && \ + (!defined(WC_SHA512_TYPE_DEFINED) || !defined(WC_SHA384_TYPE_DEFINED))) ||\ + (defined(WOLF_CRYPT_AES_H) && !defined(NO_AES) && \ + !defined(WC_AES_TYPE_DEFINED)) || \ + (defined(WOLF_CRYPT_RANDOM_H) && !defined(WC_RNG_TYPE_DEFINED)) + + /* Inhibit wc_compat.h during inclusion of sha256.h, sha512.h, aes.h, and + * random.h, to mitigate circular dependencies via aes.h included below. + */ + +#else /* Circular dependency deferral check passed */ + +#ifndef wolfSSL_WOLFCRYPT_WC_COMPAT_H +#define wolfSSL_WOLFCRYPT_WC_COMPAT_H + +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + +#if defined(HAVE_FIPS) && defined(HAVE_AESGCM) && \ + !defined(WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED) + + /* Unless WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED, wc_AesGcmEncrypt() is a + * non-FIPS API hardwired to FIPS_WRONG_API_E in fips.c. But we can emulate + * it with FIPS calls as below. + */ + + #undef wc_AesGcmEncrypt + #include + #undef wc_AesGcmEncrypt + + #define wc_AesGcmEncrypt wc_AesGcmEncrypt_compat_shim + + #ifdef WOLFSSL_AESGCM_STREAM + + static WC_INLINE int wc_AesGcmEncrypt_compat_shim(Aes* aes, byte* out, const byte* in, word32 sz, + const byte* iv, word32 ivSz, + byte* authTag, word32 authTagSz, + const byte* authIn, word32 authInSz) + { + int ret; + + #if FIPS_VERSION3_EQ(6,0,0) + /* FIPS v6 doesn't robustly validate authTagSz in wc_AesGcmEncryptFinal(). */ + if (authTagSz < WOLFSSL_MIN_AUTH_TAG_SZ) + return BAD_FUNC_ARG; + #endif + ret = wc_AesGcmInit(aes, NULL /* key */, 0 /* len */, iv, ivSz); + if (ret) + return ret; + ret = wc_AesGcmEncryptUpdate(aes, out, in, sz, authIn, authInSz); + if (ret) + return ret; + return wc_AesGcmEncryptFinal(aes, authTag, authTagSz); + } + + #else /* ! WOLFSSL_AESGCM_STREAM */ + + /* Note this variant of the shim can't handle nonstandard-size IVs. */ + #define WC_TEST_AES_GCM_ENCRYPT_NO_NONSTD_IV + + static WC_INLINE int wc_AesGcmEncrypt_compat_shim(Aes* aes, byte* out, const byte* in, word32 sz, + const byte* iv, word32 ivSz, + byte* authTag, word32 authTagSz, + const byte* authIn, word32 authInSz) + { + int ret; + byte scratch[GCM_NONCE_MAX_SZ]; + + if (ivSz > GCM_NONCE_MAX_SZ) + return BAD_LENGTH_E; + + ret = wc_AesGcmSetExtIV(aes, iv, ivSz); + if (ret != 0) + return ret; + return wc_AesGcmEncrypt_ex(aes, out, in, sz, scratch, ivSz, authTag, + authTagSz, authIn, authInSz); + } + #endif /* ! WOLFSSL_AESGCM_STREAM */ +#endif /* HAVE_FIPS && HAVE_AESGCM && */ + /* !WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED */ + +#ifdef __cplusplus + } +#endif + +#endif /* !wolfSSL_WOLFCRYPT_WC_COMPAT_H */ + +#endif /* Circular dependency deferral check passed */ From 9b304432880d81f5630645ab6dece1f93350bd77 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 14 Jul 2026 17:19:38 -0500 Subject: [PATCH 02/18] linuxkm/lkcapi_aes_glue.c: in the inner streaming loops for AES-GCM and AES-XTS (AesGcmCrypt_1(), km_AesXtsEncrypt(), and km_AesXtsDecrypt()), bypass FIPS wrappers to avoid frivolous overhead, with decisive check after looping by the Final function. --- linuxkm/lkcapi_aes_glue.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/linuxkm/lkcapi_aes_glue.c b/linuxkm/lkcapi_aes_glue.c index bd2776365d0..bd362226242 100644 --- a/linuxkm/lkcapi_aes_glue.c +++ b/linuxkm/lkcapi_aes_glue.c @@ -1121,6 +1121,16 @@ static int km_AesGcmSetAuthsize_Rfc4106(struct crypto_aead *tfm, unsigned int au #ifdef WOLFSSL_AESGCM_STREAM +/* Don't incur the FIPS check overhead inside the loop -- the Final() call will + * check and error if the module entered degraded state during the loop. + */ +#if defined(HAVE_FIPS) && !defined(FIPS_NO_WRAPPERS) + #undef wc_AesGcmDecryptUpdate + #undef wc_AesGcmEncryptUpdate + typeof(wc_AesGcmDecryptUpdate_fips) wc_AesGcmDecryptUpdate; + typeof(wc_AesGcmEncryptUpdate_fips) wc_AesGcmEncryptUpdate; +#endif + static int AesGcmCrypt_1(struct aead_request *req, int decrypt_p, int rfc4106_p) { struct crypto_aead * tfm = NULL; @@ -1340,6 +1350,11 @@ static int AesGcmCrypt_1(struct aead_request *req, int decrypt_p, int rfc4106_p) return err; } +#if defined(HAVE_FIPS) && !defined(FIPS_NO_WRAPPERS) + #define wc_AesGcmDecryptUpdate wc_AesGcmDecryptUpdate_fips + #define wc_AesGcmEncryptUpdate wc_AesGcmEncryptUpdate_fips +#endif + #else /* !WOLFSSL_AESGCM_STREAM */ static int AesGcmCrypt_1(struct aead_request *req, int decrypt_p, int rfc4106_p) @@ -2205,6 +2220,16 @@ static int km_AesXtsSetKey(struct crypto_skcipher *tfm, const u8 *in_key, /* see /usr/src/linux/drivers/md/dm-crypt.c */ +/* Don't incur the FIPS check overhead inside the loop -- the Final() call will + * check and error if the module entered degraded state during the loop. + */ +#if defined(HAVE_FIPS) && !defined(FIPS_NO_WRAPPERS) + #undef wc_AesXtsDecryptUpdate + #undef wc_AesXtsEncryptUpdate + typeof(wc_AesXtsDecryptUpdate_fips) wc_AesXtsDecryptUpdate; + typeof(wc_AesXtsEncryptUpdate_fips) wc_AesXtsEncryptUpdate; +#endif + static int km_AesXtsEncrypt(struct skcipher_request *req) { int err; @@ -2507,6 +2532,11 @@ static int km_AesXtsDecrypt(struct skcipher_request *req) return err; } +#if defined(HAVE_FIPS) && !defined(FIPS_NO_WRAPPERS) + #define wc_AesXtsDecryptUpdate wc_AesXtsDecryptUpdate_fips + #define wc_AesXtsEncryptUpdate wc_AesXtsEncryptUpdate_fips +#endif + static struct skcipher_alg xtsAesAlg = { .base.cra_name = WOLFKM_AESXTS_NAME, .base.cra_driver_name = WOLFKM_AESXTS_DRIVER, From 6f1e5a93d4cebe3a3f899b1cb12015a749325289 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 14 Jul 2026 17:19:52 -0500 Subject: [PATCH 03/18] wolfcrypt/src/aes.c: revert atomic refactor of checkedAESNI, haveAESNI, and intel_flags (3f3ebcac58 / #10871) to avoid frivolous atomic access overhead. Also use regular int, not cpuid_flags_atomic_t, for cpuid_flags in the WOLFSSL_ARMASM path, and similarly use a regular int for aes_ppc64_use_crypto in the WOLFSSL_PPC64_ASM_CRYPTO path. --- wolfcrypt/src/aes.c | 54 ++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index b04fa23c6d3..46a89a6ad80 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -671,16 +671,18 @@ block cipher mechanism that uses n-bit binary string parameter key with 128-bits #define AESNI_ALIGN 16 #endif - /* Accessed with the wolfSSL atomic APIs so the one-time detection is free of - * data races. Writes are also idempotent (all callers compute the same - * value), so a benign concurrent double-write is harmless. */ - static wolfSSL_Atomic_Uint checkedAESNI = WOLFSSL_ATOMIC_INITIALIZER(0); - static wolfSSL_Atomic_Uint haveAESNI = WOLFSSL_ATOMIC_INITIALIZER(0); - static cpuid_flags_atomic_t intel_flags = WC_CPUID_ATOMIC_INITIALIZER; + /* Note that all write access to these static variables must be idempotent, + * as arranged by Check_CPU_support_AES(), else they will be susceptible to + * data races. Don't use wolfSSL_Atomic_Uint here, to avoid atomic access + * overhead on subsequent calls. + */ + static int checkedAESNI = 0; + static int haveAESNI = 0; + static cpuid_flags_t intel_flags = WC_CPUID_INITIALIZER; static WARN_UNUSED_RESULT int Check_CPU_support_AES(void) { - cpuid_get_flags_atomic(&intel_flags); + cpuid_get_flags_ex(&intel_flags); return IS_INTEL_AESNI(intel_flags) != 0; } @@ -1084,11 +1086,12 @@ block cipher mechanism that uses n-bit binary string parameter key with 128-bits #elif defined(WOLFSSL_ARMASM) #if defined(__aarch64__) && !defined(WOLFSSL_ARMASM_NO_HW_CRYPTO) -static cpuid_flags_atomic_t cpuid_flags = WC_CPUID_ATOMIC_INITIALIZER; +static cpuid_flags_t cpuid_flags = WC_CPUID_INITIALIZER; static void Check_CPU_support_HwCrypto(Aes* aes) { - cpuid_get_flags_atomic(&cpuid_flags); + if (cpuid_flags == WC_CPUID_INITIALIZER) + cpuid_get_flags_ex(&cpuid_flags); aes->use_aes_hw_crypto = IS_AARCH64_AES(cpuid_flags); #ifdef HAVE_AESGCM aes->use_pmull_hw_crypto = IS_AARCH64_PMULL(cpuid_flags); @@ -1175,21 +1178,22 @@ static WARN_UNUSED_RESULT int wc_AesDecrypt(Aes* aes, const byte* inBlock, * branches that also call these names are #if'd out, so only the live PPC call * sites are redirected. */ -/* Resolved dispatch decision (0 = base, 1 = vector-crypto), accessed with the - * wolfSSL atomic APIs so the one-time detection is free of data races. The - * master cpuid flags read by cpuid_get_flags() are themselves atomic; the write - * here is idempotent so a benign concurrent double-write is harmless. */ -static wolfSSL_Atomic_Uint aes_ppc64_use_crypto = WOLFSSL_ATOMIC_INITIALIZER(0); +/* Resolved dispatch decision (0 = base, 1 = vector-crypto). The write here is + * idempotent so a benign concurrent double-write is harmless. Avoid atomic for + * this, as for intel_flags above, to avoid unnecessary expensive reads. */ +static int aes_ppc64_use_crypto = 0; /* True when the CPU supports the vector-crypto instructions. */ -#define AES_PPC64_USE_CRYPTO() (WOLFSSL_ATOMIC_LOAD(aes_ppc64_use_crypto) != 0) +#define AES_PPC64_USE_CRYPTO() (aes_ppc64_use_crypto != 0) /* Check and set the decision together (as Check_CPU_support_AES/HwCrypto do); * called from the key-setup path before any AES_*_crypto use. */ static void Aes_SetCrypto(void) { - WOLFSSL_ATOMIC_STORE(aes_ppc64_use_crypto, - (unsigned int)(IS_PPC64_VEC_CRYPTO(cpuid_get_flags()) != 0)); + static cpuid_flags_t cpu_flags = WC_CPUID_INITIALIZER; + if (cpu_flags == WC_CPUID_INITIALIZER) + cpuid_get_flags_ex(&cpu_flags); + aes_ppc64_use_crypto = (IS_PPC64_VEC_CRYPTO(cpu_flags) != 0); } #define AES_set_encrypt_key(key, len, ks) \ @@ -5674,11 +5678,11 @@ static void AesSetKey_C(Aes* aes, const byte* key, word32 keySz, int dir) * function correctly with default build settings. */ - if (WOLFSSL_ATOMIC_LOAD(checkedAESNI) == 0) { - WOLFSSL_ATOMIC_STORE(haveAESNI, Check_CPU_support_AES()); - WOLFSSL_ATOMIC_STORE(checkedAESNI, 1); + if (checkedAESNI == 0) { + haveAESNI = Check_CPU_support_AES(); + checkedAESNI = 1; } - if (WOLFSSL_ATOMIC_LOAD(haveAESNI) + if (haveAESNI #if defined(WC_FLAG_DONT_USE_VECTOR_OPS) && !defined(WC_C_DYNAMIC_FALLBACK) && (aes->use_aesni != WC_FLAG_DONT_USE_VECTOR_OPS) #endif @@ -19464,7 +19468,7 @@ static AesGcmSivPolyvalFn AesGcmSivPolyvalAsm(void) static AesGcmSivPolyvalFn AesGcmSivPolyvalAsm(void) { #ifndef WOLFSSL_ARMASM_NO_HW_CRYPTO - cpuid_get_flags_atomic(&cpuid_flags); + cpuid_get_flags_ex(&cpuid_flags); if (IS_AARCH64_PMULL(cpuid_flags)) { return &AES_GCMSIV_polyval_pmull; } @@ -19483,7 +19487,7 @@ static AesGcmSivPolyvalFn AesGcmSivPolyvalAsm(void) * AES-NI gates the base path (matching wolfSSL's AES-GCM). */ static AesGcmSivPolyvalFn AesGcmSivPolyvalAsm(void) { - cpuid_get_flags_atomic(&intel_flags); + cpuid_get_flags_ex(&intel_flags); if (!IS_INTEL_AESNI(intel_flags)) { return NULL; } @@ -19528,7 +19532,7 @@ static AesGcmSivCtrFn AesGcmSivCtrAsm(void) static AesGcmSivCtrFn AesGcmSivCtrAsm(void) { #ifndef WOLFSSL_ARMASM_NO_HW_CRYPTO - cpuid_get_flags_atomic(&cpuid_flags); + cpuid_get_flags_ex(&cpuid_flags); if (IS_AARCH64_AES(cpuid_flags)) { return &AES_GCMSIV_ctr_aarch64; } @@ -19546,7 +19550,7 @@ static AesGcmSivCtrFn AesGcmSivCtrAsm(void) * the base; AVX1/VAES/AVX512 are progressively wider pipelines. */ static AesGcmSivCtrFn AesGcmSivCtrAsm(void) { - cpuid_get_flags_atomic(&intel_flags); + cpuid_get_flags_ex(&intel_flags); if (!IS_INTEL_AESNI(intel_flags)) { return NULL; } From 2628676b285e18268b068b7c89788d21080e9bdb Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Wed, 15 Jul 2026 10:09:31 -0500 Subject: [PATCH 04/18] wolfssl/wolfcrypt/wc_compat.h, wolfssl/wolfcrypt/fips_test.h, .wolfssl_known_macro_extras: * also inhibit recursive evaluation midway through random.h, fips.h, and fips_test.h (circular dependencies). * add WC_FIPS_ENUM_CAST_ID_DEFINED to allow detection of fips_test.h incomplete evaluation. --- .wolfssl_known_macro_extras | 2 ++ wolfssl/wolfcrypt/fips_test.h | 1 + wolfssl/wolfcrypt/wc_compat.h | 17 +++++++++++------ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 224fe57c88c..425f640b62d 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -1069,12 +1069,14 @@ WOLFSSL_ZEPHYR WOLF_ALLOW_BUILTIN WOLF_CRYPTO_CB_CMD WOLF_CRYPTO_DEV +WOLF_CRYPT_FIPS_H WOLF_NO_TRAILING_ENUM_COMMAS WindowsCE XGETPASSWD XMSS_CALL_PRF_KEYGEN XPAR_VERSAL_CIPS_0_PSPMC_0_PSV_CORTEXA72_0_TIMESTAMP_CLK_FREQ XSECURE_CACHE_DISABLE +fipsCastStatus_get _ABI64 _ABIO64 _ARCH_PPC64 diff --git a/wolfssl/wolfcrypt/fips_test.h b/wolfssl/wolfcrypt/fips_test.h index 67a703059ed..dc247b272bd 100644 --- a/wolfssl/wolfcrypt/fips_test.h +++ b/wolfssl/wolfcrypt/fips_test.h @@ -100,6 +100,7 @@ enum FipsCastId { FIPS_CAST_AES_KW = 28, FIPS_CAST_COUNT = 29 }; +#define WC_FIPS_ENUM_CAST_ID_DEFINED enum FipsCastStateId { FIPS_CAST_STATE_INIT = 0, diff --git a/wolfssl/wolfcrypt/wc_compat.h b/wolfssl/wolfcrypt/wc_compat.h index 4472158ba01..ae946f90fc3 100644 --- a/wolfssl/wolfcrypt/wc_compat.h +++ b/wolfssl/wolfcrypt/wc_compat.h @@ -30,10 +30,12 @@ (!defined(WC_SHA512_TYPE_DEFINED) || !defined(WC_SHA384_TYPE_DEFINED))) ||\ (defined(WOLF_CRYPT_AES_H) && !defined(NO_AES) && \ !defined(WC_AES_TYPE_DEFINED)) || \ - (defined(WOLF_CRYPT_RANDOM_H) && !defined(WC_RNG_TYPE_DEFINED)) + (defined(WOLF_CRYPT_RANDOM_H) && !defined(WC_RNG_TYPE_DEFINED)) || \ + (defined(WOLF_CRYPT_FIPS_H) && !defined(fipsCastStatus_get)) || \ + (defined(WOLF_CRYPT_FIPS_TEST_H) && !defined(WC_FIPS_ENUM_CAST_ID_DEFINED)) - /* Inhibit wc_compat.h during inclusion of sha256.h, sha512.h, aes.h, and - * random.h, to mitigate circular dependencies via aes.h included below. + /* Inhibit wc_compat.h during inclusion of sha256.h, sha512.h, aes.h, + * random.h, fips.h, and fips_test.h, to mitigate circular dependencies. */ #else /* Circular dependency deferral check passed */ @@ -49,7 +51,8 @@ #endif #if defined(HAVE_FIPS) && defined(HAVE_AESGCM) && \ - !defined(WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED) + !defined(WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED) && \ + !defined(FIPS_NO_WRAPPERS) /* Unless WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED, wc_AesGcmEncrypt() is a * non-FIPS API hardwired to FIPS_WRONG_API_E in fips.c. But we can emulate @@ -108,8 +111,10 @@ authTagSz, authIn, authInSz); } #endif /* ! WOLFSSL_AESGCM_STREAM */ -#endif /* HAVE_FIPS && HAVE_AESGCM && */ - /* !WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED */ +#endif /* HAVE_FIPS && HAVE_AESGCM && */ + /* !WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED && */ + /* !FIPS_NO_WRAPPERS && !WOLF_CRYPT_FIPS_TEST_H */ + #ifdef __cplusplus } From 3db433a31ac2738a1d66284ddab4049cbca4c9f0 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Wed, 15 Jul 2026 10:09:54 -0500 Subject: [PATCH 05/18] wolfcrypt/src/ed25519.c, tests/api/test_ed25519.c: * add missing null key checks to wc_ed25519_verify_msg_init(), wc_ed25519_verify_msg_update(), and wc_ed25519_verify_msg_final(). * add WC_ARG_NOT_NULL() attributes to args of static functions as appropriate. * add FIPS >v6 gates to new null key tests and a new invalid hash size test in test_wc_ed25519_sign_verify_ctx_ph() and test_wc_ed25519_verify_streaming(). --- tests/api/test_ed25519.c | 8 ++++++++ wolfcrypt/src/ed25519.c | 23 +++++++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/tests/api/test_ed25519.c b/tests/api/test_ed25519.c index d9ff72b18e5..dcbca22902a 100644 --- a/tests/api/test_ed25519.c +++ b/tests/api/test_ed25519.c @@ -979,6 +979,7 @@ int test_wc_ed25519_sign_verify_ctx_ph(void) &verify_ok, &key, ctx, sizeof(ctx)), 0); ExpectIntEQ(verify_ok, 1); +#if !defined(HAVE_FIPS) || FIPS_VERSION3_GT(6,0,0) /* Ed25519ph length check true side: wrong-size "hash" input. */ sigLen = sizeof(sig); ExpectIntEQ(wc_ed25519_sign_msg_ex(hash, sizeof(hash) - 1, sig, &sigLen, @@ -988,6 +989,7 @@ int test_wc_ed25519_sign_verify_ctx_ph(void) ExpectIntEQ(wc_ed25519_verify_msg_ex(sig, sizeof(sig), hash, sizeof(hash) - 1, &verify_ok, &key, (byte)Ed25519ph, ctx, sizeof(ctx)), WC_NO_ERR_TRACE(BAD_LENGTH_E)); +#endif /* context==NULL && contextLen!=0 compound: TRUE side, direct low-level * calls (the ctx/ph wrappers above always pass a real, non-NULL @@ -1054,8 +1056,10 @@ int test_wc_ed25519_verify_streaming(void) /* init: NULL args. */ ExpectIntEQ(wc_ed25519_verify_msg_init(NULL, sigLen, &key, (byte)Ed25519, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); +#if !defined(HAVE_FIPS) || FIPS_VERSION3_GT(6,0,0) ExpectIntEQ(wc_ed25519_verify_msg_init(sig, sigLen, NULL, (byte)Ed25519, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); +#endif /* init: sigLen wrong. */ ExpectIntEQ(wc_ed25519_verify_msg_init(sig, sigLen - 1, &key, (byte)Ed25519, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); @@ -1069,8 +1073,10 @@ int test_wc_ed25519_verify_streaming(void) /* update: NULL msgSegment, then NULL key (independent operand). */ ExpectIntEQ(wc_ed25519_verify_msg_update(NULL, 4, &key), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); +#if !defined(HAVE_FIPS) || FIPS_VERSION3_GT(6,0,0) ExpectIntEQ(wc_ed25519_verify_msg_update(msg, 4, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); +#endif /* init: context==NULL/contextLen!=0 compound, explicit both-sides * pairing within this function (type left as plain Ed25519 so the @@ -1092,8 +1098,10 @@ int test_wc_ed25519_verify_streaming(void) WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_ed25519_verify_msg_final(sig, sigLen, NULL, &key), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); +#if !defined(HAVE_FIPS) || FIPS_VERSION3_GT(6,0,0) ExpectIntEQ(wc_ed25519_verify_msg_final(sig, sigLen, &verify_ok, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); +#endif /* final: sigLen wrong. */ ExpectIntEQ(wc_ed25519_verify_msg_final(sig, sigLen - 1, &verify_ok, &key), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); diff --git a/wolfcrypt/src/ed25519.c b/wolfcrypt/src/ed25519.c index cb7abcc9deb..fc9bd0f644f 100644 --- a/wolfcrypt/src/ed25519.c +++ b/wolfcrypt/src/ed25519.c @@ -86,7 +86,9 @@ static const byte ed25519Ctx[ED25519CTX_SIZE + 1] = ED25519CTX_SNC_MESSAGE; #endif -static int ed25519_hash_init(ed25519_key* key, wc_Sha512 *sha) +static int WC_ARG_NOT_NULL(1) WC_ARG_NOT_NULL(2) + ed25519_hash_init(ed25519_key* key, wc_Sha512 *sha) + { int ret; @@ -108,7 +110,7 @@ static int ed25519_hash_init(ed25519_key* key, wc_Sha512 *sha) } #ifdef WOLFSSL_ED25519_PERSISTENT_SHA -static int ed25519_hash_reset(ed25519_key* key) +static int WC_ARG_NOT_NULL(1) ed25519_hash_reset(ed25519_key* key) { int ret; @@ -132,8 +134,9 @@ static int ed25519_hash_reset(ed25519_key* key) } #endif /* WOLFSSL_ED25519_PERSISTENT_SHA */ -static int ed25519_hash_update(ed25519_key* key, wc_Sha512 *sha, - const byte* data, word32 len) +static int WC_ARG_NOT_NULL(1) + ed25519_hash_update(ed25519_key* key, wc_Sha512 *sha, + const byte* data, word32 len) { #ifdef WOLFSSL_ED25519_PERSISTENT_SHA if (key->sha_clean_flag) { @@ -145,7 +148,8 @@ static int ed25519_hash_update(ed25519_key* key, wc_Sha512 *sha, return wc_Sha512Update(sha, data, len); } -static int ed25519_hash_final(ed25519_key* key, wc_Sha512 *sha, byte* hash) +static int WC_ARG_NOT_NULL(1) + ed25519_hash_final(ed25519_key* key, wc_Sha512 *sha, byte* hash) { int ret = wc_Sha512Final(sha, hash); #ifdef WOLFSSL_ED25519_PERSISTENT_SHA @@ -158,7 +162,8 @@ static int ed25519_hash_final(ed25519_key* key, wc_Sha512 *sha, byte* hash) return ret; } -static void ed25519_hash_free(ed25519_key* key, wc_Sha512 *sha) +static void WC_ARG_NOT_NULL(1) + ed25519_hash_free(ed25519_key* key, wc_Sha512 *sha) { wc_Sha512Free(sha); #ifdef WOLFSSL_ED25519_PERSISTENT_SHA @@ -1002,18 +1007,24 @@ static int ed25519_verify_msg_final_with_sha(const byte* sig, word32 sigLen, int wc_ed25519_verify_msg_init(const byte* sig, word32 sigLen, ed25519_key* key, byte type, const byte* context, byte contextLen) { + if (key == NULL) + return BAD_FUNC_ARG; return ed25519_verify_msg_init_with_sha(sig, sigLen, key, &key->sha, type, context, contextLen); } int wc_ed25519_verify_msg_update(const byte* msgSegment, word32 msgSegmentLen, ed25519_key* key) { + if (key == NULL) + return BAD_FUNC_ARG; return ed25519_verify_msg_update_with_sha(msgSegment, msgSegmentLen, key, &key->sha); } int wc_ed25519_verify_msg_final(const byte* sig, word32 sigLen, int* res, ed25519_key* key) { + if (key == NULL) + return BAD_FUNC_ARG; return ed25519_verify_msg_final_with_sha(sig, sigLen, res, key, &key->sha); } From 08b5b65c267ca531f280ce94ed89d1ab3d220c34 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Wed, 15 Jul 2026 10:10:23 -0500 Subject: [PATCH 06/18] configure.ac: add --enable-all-quantum-crypto "Enable all quantum-resistant asymmetric algorithms (default: disabled)". --- configure.ac | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 4c231e5e400..265b5446d6d 100644 --- a/configure.ac +++ b/configure.ac @@ -1564,9 +1564,9 @@ fi # have dedicated streaming assembly (AES_GCM_*_RISCV64). (Previously disabled # here.) -# All wolfCrypt features: +# All wolfCrypt features except quantum-resistant asymmetric: AC_ARG_ENABLE([all-crypto], - [AS_HELP_STRING([--enable-all-crypto],[Enable all wolfcrypt algorithms (default: disabled)])], + [AS_HELP_STRING([--enable-all-crypto],[Enable all wolfcrypt algorithms except quantum-resistant asymmetric (default: disabled)])], [ ENABLED_ALL_CRYPT=$enableval ], [ ENABLED_ALL_CRYPT=no ] ) @@ -1708,6 +1708,21 @@ then AM_CFLAGS="$AM_CFLAGS -DWC_KDF_NIST_SP_800_56C" fi +# All native quantum-resistant asymmetric algorithms: +AC_ARG_ENABLE([all-quantum-crypto], + [AS_HELP_STRING([--enable-all-quantum-crypto],[Enable all quantum-resistant asymmetric algorithms (default: disabled)])], + [ ENABLED_ALL_QUANTUM_CRYPT=$enableval ], + [ ENABLED_ALL_QUANTUM_CRYPT=no ] + ) +if test "$ENABLED_ALL_QUANTUM_CRYPT" = "yes" +then + test "$enable_mlkem" = "" && enable_mlkem=yes + test "$enable_mldsa" = "" && enable_mldsa=yes + test "$enable_xmss" = "" && enable_xmss=yes + test "$enable_lms" = "" && enable_lms=yes + test "$enable_slhdsa" = "" && enable_slhdsa='yes,sha2' +fi + # kernel-appropriate settings, also in enable-all-crypto above: if test "$KERNEL_MODE_DEFAULTS" = "yes" && test "$ENABLED_ALL_CRYPT" != "yes" then From b4095f0578d129e05905a648ed5072f5a8f4204b Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Wed, 15 Jul 2026 13:27:14 -0500 Subject: [PATCH 07/18] wolfcrypt/src/ed25519.c: whitespace fix (from AI review). --- wolfcrypt/src/ed25519.c | 1 - 1 file changed, 1 deletion(-) diff --git a/wolfcrypt/src/ed25519.c b/wolfcrypt/src/ed25519.c index fc9bd0f644f..557ee1d6964 100644 --- a/wolfcrypt/src/ed25519.c +++ b/wolfcrypt/src/ed25519.c @@ -88,7 +88,6 @@ static int WC_ARG_NOT_NULL(1) WC_ARG_NOT_NULL(2) ed25519_hash_init(ed25519_key* key, wc_Sha512 *sha) - { int ret; From 00368d1cc460a1bb8f57701588c46a822810f873 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Wed, 15 Jul 2026 15:45:53 -0500 Subject: [PATCH 08/18] wolfssl/wolfcrypt/error-crypt.h: #include where previously #include , to retain standalone compilability without provoking circular dependencies via wc_compat.h. --- wolfssl/wolfcrypt/error-crypt.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index d524bd71a26..922102a6697 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -31,6 +31,11 @@ the error status. #ifndef WOLF_CRYPT_ERROR_H #define WOLF_CRYPT_ERROR_H +/* Avoid wolfcrypt/types.h here, to mitigate circular dependencies via + * wc_compat.h. + */ +#include + #ifdef __cplusplus extern "C" { #endif From 09bcd2f39194b9d839084a2b8baef4fc65e0e2da Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Wed, 15 Jul 2026 20:27:12 -0500 Subject: [PATCH 09/18] wolfssl/wolfcrypt/wc_compat.h: FIPS v2 compatibility. --- .wolfssl_known_macro_extras | 2 ++ wolfssl/wolfcrypt/wc_compat.h | 28 ++++++++++++++++------------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 425f640b62d..c3906b75695 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -218,6 +218,7 @@ CRYP_HEADERWIDTHUNIT_BYTE CRYP_KEYIVCONFIG_ONCE CRYP_KEYSIZE_192B CSM_UNSUPPORTED_ALGS +CTAO_CRYPT_AES_H CTYPE_USER CURVED448_SMALL CUSTOM_ENTROPY_TIMEHIRES @@ -1077,6 +1078,7 @@ XMSS_CALL_PRF_KEYGEN XPAR_VERSAL_CIPS_0_PSPMC_0_PSV_CORTEXA72_0_TIMESTAMP_CLK_FREQ XSECURE_CACHE_DISABLE fipsCastStatus_get +wc_Des3_SetKey _ABI64 _ABIO64 _ARCH_PPC64 diff --git a/wolfssl/wolfcrypt/wc_compat.h b/wolfssl/wolfcrypt/wc_compat.h index ae946f90fc3..41c8fb542d4 100644 --- a/wolfssl/wolfcrypt/wc_compat.h +++ b/wolfssl/wolfcrypt/wc_compat.h @@ -23,16 +23,20 @@ \brief Header file containing wolfCrypt compatibility shims */ -#if (defined(WOLF_CRYPT_SHA256_H) && !defined(NO_SHA256) && \ - !defined(WC_SHA256_TYPE_DEFINED)) || \ - (defined(WOLF_CRYPT_SHA512_H) && \ - (defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384)) && \ - (!defined(WC_SHA512_TYPE_DEFINED) || !defined(WC_SHA384_TYPE_DEFINED))) ||\ - (defined(WOLF_CRYPT_AES_H) && !defined(NO_AES) && \ - !defined(WC_AES_TYPE_DEFINED)) || \ - (defined(WOLF_CRYPT_RANDOM_H) && !defined(WC_RNG_TYPE_DEFINED)) || \ - (defined(WOLF_CRYPT_FIPS_H) && !defined(fipsCastStatus_get)) || \ - (defined(WOLF_CRYPT_FIPS_TEST_H) && !defined(WC_FIPS_ENUM_CAST_ID_DEFINED)) +#if (defined(WOLF_CRYPT_SHA256_H) && !defined(NO_SHA256) && \ + !defined(WC_SHA256_TYPE_DEFINED) && !defined(SHA256_NOINLINE)) || \ + (defined(WOLF_CRYPT_SHA512_H) && \ + (defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384)) && \ + !defined(WC_SHA512_TYPE_DEFINED) && !defined(WC_SHA384_TYPE_DEFINED) && \ + !defined(SHA512_NOINLINE)) || \ + (defined(WOLF_CRYPT_AES_H) && !defined(NO_AES) && \ + !defined(WC_AES_TYPE_DEFINED) && !defined(CTAO_CRYPT_AES_H)) || \ + (defined(WOLF_CRYPT_RANDOM_H) && !defined(WC_RNG_TYPE_DEFINED)) || \ + (defined(WOLF_CRYPT_FIPS_H) && \ + !defined(fipsCastStatus_get) && !defined(wc_Des3_SetKey) && \ + !defined(WC_DES3_TYPE_DEFINED)) || \ + (defined(WOLF_CRYPT_FIPS_TEST_H) && \ + !defined(WC_FIPS_ENUM_CAST_ID_DEFINED) && !defined(WOLF_CRYPT_FIPS_H)) /* Inhibit wc_compat.h during inclusion of sha256.h, sha512.h, aes.h, * random.h, fips.h, and fips_test.h, to mitigate circular dependencies. @@ -99,9 +103,9 @@ const byte* authIn, word32 authInSz) { int ret; - byte scratch[GCM_NONCE_MAX_SZ]; + byte scratch[16]; /* FIPS v2 doesn't have GCM_NONCE_MAX_SZ */ - if (ivSz > GCM_NONCE_MAX_SZ) + if (ivSz > sizeof(scratch)) return BAD_LENGTH_E; ret = wc_AesGcmSetExtIV(aes, iv, ivSz); From a7511940ff1d81f8f8d2873b1362a315f42bc9a6 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Wed, 15 Jul 2026 22:31:54 -0500 Subject: [PATCH 10/18] wolfssl/wolfcrypt/wc_compat.h: in non-streaming wc_AesGcmEncrypt_compat_shim(), restore aes->reg to the supplied IV after wc_AesGcmEncrypt_ex() increments it, supporting the EVP access pattern. --- wolfssl/wolfcrypt/wc_compat.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wolfssl/wolfcrypt/wc_compat.h b/wolfssl/wolfcrypt/wc_compat.h index 41c8fb542d4..9a820f49a91 100644 --- a/wolfssl/wolfcrypt/wc_compat.h +++ b/wolfssl/wolfcrypt/wc_compat.h @@ -111,8 +111,11 @@ ret = wc_AesGcmSetExtIV(aes, iv, ivSz); if (ret != 0) return ret; - return wc_AesGcmEncrypt_ex(aes, out, in, sz, scratch, ivSz, authTag, + ret = wc_AesGcmEncrypt_ex(aes, out, in, sz, scratch, ivSz, authTag, authTagSz, authIn, authInSz); + if (ret != 0) + return ret; + return wc_AesGcmSetExtIV(aes, iv, ivSz); } #endif /* ! WOLFSSL_AESGCM_STREAM */ #endif /* HAVE_FIPS && HAVE_AESGCM && */ From 7897c335e0d6d7ddf0ac05b8ece260f3bbd61783 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Sat, 18 Jul 2026 11:24:04 -0500 Subject: [PATCH 11/18] configure.ac: don't include CShake or KMAC in enable-all-crypto when building FIPS < v7. --- configure.ac | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 265b5446d6d..f153e0170d2 100644 --- a/configure.ac +++ b/configure.ac @@ -1674,13 +1674,17 @@ then test "$enable_aesxts_stream" = "" && test "$enable_aesxts" = "yes" && enable_aesxts_stream=yes test "$enable_shake128" = "" && enable_shake128=yes test "$enable_shake256" = "" && enable_shake256=yes - test "$enable_cshake" = "" && enable_cshake=yes - test "$enable_kmac" = "" && enable_kmac=yes test "$enable_compkey" = "" && enable_compkey=yes # AFALG lacks AES-ECB test "$enable_srtp_kdf" = "" && test "$enable_afalg" != "yes" && enable_srtp_kdf=yes fi + if test "$ENABLED_FIPS" = "no" || test "$HAVE_FIPS_VERSION" -ge 7 + then + test "$enable_cshake" = "" && enable_cshake=yes + test "$enable_kmac" = "" && enable_kmac=yes + fi + if test "$ENABLED_FIPS" = "no" || test "$HAVE_FIPS_VERSION" -lt 5; then test "$enable_des3" = "" && enable_des3=yes test "$enable_des3" != "no" && AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DES_ECB" From d49486496512e979b01cfc708aa8d99bddf28763 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Sat, 18 Jul 2026 11:30:04 -0500 Subject: [PATCH 12/18] wolfssl/wolfcrypt/settings.h: add assert that WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED isn't defined in old FIPS builds. --- wolfssl/wolfcrypt/settings.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index da911e6508d..0c1f32f4325 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -3892,6 +3892,15 @@ #endif #endif +#if defined(HAVE_FIPS) && defined(HAVE_AESGCM) && FIPS_VERSION3_LT(7,0,0) && \ + defined(WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED) && \ + !defined(WOLFSSL_EXPERIMENTAL_SETTINGS) + /* FIPS < v7 does not implement wc_AesGcmEncrypt() as a supported API, so it + * must be remapped to FIPS-supported APIs as arranged in wc_compat.h. + */ + #error WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED is forbidden for selected FIPS version. +#endif + /* sniffer requires: * static RSA cipher suites * session stats and peak stats From 755220792eea8c373676664baf27b2dbe0f28c5d Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Sat, 18 Jul 2026 13:50:00 -0500 Subject: [PATCH 13/18] wolfcrypt/src/kdf.c, wolfssl/wolfcrypt/kdf.h: use "hash_type", not "hash", for the hash type in wc_PRF_fips(), for clarity and consistency. --- wolfcrypt/src/kdf.c | 20 ++++++++++---------- wolfssl/wolfcrypt/kdf.h | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/wolfcrypt/src/kdf.c b/wolfcrypt/src/kdf.c index 4ae7d584f9a..6f6825b7409 100644 --- a/wolfcrypt/src/kdf.c +++ b/wolfcrypt/src/kdf.c @@ -73,8 +73,8 @@ /* Pseudo Random Function for MD5, SHA-1, SHA-256, SHA-384, or SHA-512 */ int wc_PRF(byte* result, word32 resLen, const byte* secret, - word32 secLen, const byte* seed, word32 seedLen, int hash, - void* heap, int devId) + word32 secLen, const byte* seed, word32 seedLen, + int hash_type, void* heap, int devId) { word32 len = P_HASH_MAX_SIZE; word32 times; @@ -89,45 +89,45 @@ int wc_PRF(byte* result, word32 resLen, const byte* secret, Hmac hmac[1]; #endif - switch (hash) { + switch (hash_type) { #ifndef NO_MD5 case md5_mac: - hash = WC_MD5; + hash_type = WC_MD5; len = WC_MD5_DIGEST_SIZE; break; #endif #ifndef NO_SHA256 case sha256_mac: - hash = WC_SHA256; + hash_type = WC_SHA256; len = WC_SHA256_DIGEST_SIZE; break; #endif #ifdef WOLFSSL_SHA384 case sha384_mac: - hash = WC_SHA384; + hash_type = WC_SHA384; len = WC_SHA384_DIGEST_SIZE; break; #endif #ifdef WOLFSSL_SHA512 case sha512_mac: - hash = WC_SHA512; + hash_type = WC_SHA512; len = WC_SHA512_DIGEST_SIZE; break; #endif #ifdef WOLFSSL_SM3 case sm3_mac: - hash = WC_SM3; + hash_type = WC_SM3; len = WC_SM3_DIGEST_SIZE; break; #endif #ifndef NO_SHA case sha_mac: - hash = WC_SHA; + hash_type = WC_SHA; len = WC_SHA_DIGEST_SIZE; break; #endif @@ -165,7 +165,7 @@ int wc_PRF(byte* result, word32 resLen, const byte* secret, ret = wc_HmacInit(hmac, heap, devId); if (ret == 0) { - ret = wc_HmacSetKey(hmac, hash, secret, secLen); + ret = wc_HmacSetKey(hmac, hash_type, secret, secLen); if (ret == 0) ret = wc_HmacUpdate(hmac, seed, seedLen); /* A0 = seed */ if (ret == 0) diff --git a/wolfssl/wolfcrypt/kdf.h b/wolfssl/wolfcrypt/kdf.h index 916b663bcbb..da5990e7793 100644 --- a/wolfssl/wolfcrypt/kdf.h +++ b/wolfssl/wolfcrypt/kdf.h @@ -63,8 +63,8 @@ enum max_prf { #ifdef WOLFSSL_HAVE_PRF WOLFSSL_API int wc_PRF(byte* result, word32 resLen, const byte* secret, - word32 secLen, const byte* seed, word32 seedLen, int hash, - void* heap, int devId); + word32 secLen, const byte* seed, word32 seedLen, + int hash_type, void* heap, int devId); WOLFSSL_API int wc_PRF_TLSv1(byte* digest, word32 digLen, const byte* secret, word32 secLen, const byte* label, word32 labLen, const byte* seed, word32 seedLen, void* heap, int devId); From b4a93268428402c2b8f63cb9a366b9471120a26c Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Sat, 18 Jul 2026 16:15:58 -0500 Subject: [PATCH 14/18] configure.ac: fix DH dependencies for FIPS v7 (implicit --disable-dh). --- configure.ac | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index f153e0170d2..547a6e04373 100644 --- a/configure.ac +++ b/configure.ac @@ -1620,7 +1620,6 @@ then test "$enable_md2" = "" && enable_md2=yes test "$enable_md4" = "" && enable_md4=yes test "$enable_md5" = "" && enable_md5=yes - test "$enable_anon" = "" && enable_anon=yes test "$enable_ssh" = "" && test "$enable_hmac" != "no" && enable_ssh=yes test "$enable_rng_bank" = "" && enable_rng_bank=yes @@ -1667,6 +1666,12 @@ then test "$enable_pkcallbacks" = "" && enable_pkcallbacks=yes fi + if test "$ENABLED_FIPS" = "no" || test "$HAVE_FIPS_VERSION" -lt 7 + then + # "Anonymous suite requires DH." + test "$enable_anon" = "" && enable_anon=yes + fi + if test "$ENABLED_FIPS" = "no" || test "$HAVE_FIPS_VERSION" -ge 6 then test "$enable_aesgcm_stream" = "" && test "$enable_aesgcm" = "yes" && enable_aesgcm_stream=yes @@ -6167,13 +6172,21 @@ then fi +if test "$ENABLED_FIPS" = "no" || test "$HAVE_FIPS_VERSION" -lt 7 +then + ENABLED_DH_DEFAULT=yes +else + ENABLED_DH_DEFAULT=no +fi + # DH AC_ARG_ENABLE([dh], [AS_HELP_STRING([--enable-dh],[Enable DH (default: enabled). Set to "nonblock" to enable non-blocking DH key agreement via SP small mod_exp_nb])], [ ENABLED_DH=$enableval ], - [ ENABLED_DH=yes ] + [ ENABLED_DH=$ENABLED_DH_DEFAULT ] ) +# note, this will be forced back off for FIPS v7+ below. if test "$ENABLED_OPENSSH" = "yes" && test "$ENABLED_DH" = "no" then ENABLED_DH="yes" @@ -6214,8 +6227,9 @@ AC_ARG_ENABLE([anon], [ ENABLED_ANON=no ] ) -if test "x$ENABLED_WPAS" = "xyes" || test "x$ENABLED_NGINX" = "xyes" || \ - test "x$ENABLED_HAPROXY" = "xyes" || test "$ENABLED_RSYSLOG" = "yes" +if (test "x$ENABLED_WPAS" = "xyes" || test "x$ENABLED_NGINX" = "xyes" || \ + test "x$ENABLED_HAPROXY" = "xyes" || test "$ENABLED_RSYSLOG" = "yes") && \ + (test "$ENABLED_FIPS" = "no" || test "$HAVE_FIPS_VERSION" -lt 7) then ENABLED_ANON=yes fi @@ -6817,6 +6831,10 @@ AS_CASE([$FIPS_VERSION], (test "$FIPS_VERSION" != "dev" || test "$enable_rsapss" != "no")], [ENABLED_RSAPSS="yes"; AM_CFLAGS="$AM_CFLAGS -DWC_RSA_PSS"]) + AS_IF([test "$ENABLED_DH" != "no" && + (test "$FIPS_VERSION" != "dev" || test "$enable_dh" != "yes")], + [enable_dh="no"; ENABLED_DH="no"; AM_CFLAGS="$AM_CFLAGS -DNO_DH"]) + AS_IF([test "$ENABLED_ECC" != "yes" && (test "$FIPS_VERSION" != "dev" || test "$enable_ecc" != "no")], [ENABLED_ECC="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_ECC -DTFM_ECC256" From ef070bf564be368abadc885d45b01761793a7918 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Sat, 18 Jul 2026 16:17:48 -0500 Subject: [PATCH 15/18] linuxkm/linuxkm-fips-hash-wrapper.sh: fix dependency on SHA-2 coreKey. --- linuxkm/linuxkm-fips-hash-wrapper.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/linuxkm/linuxkm-fips-hash-wrapper.sh b/linuxkm/linuxkm-fips-hash-wrapper.sh index 8be522e4707..04b3a980820 100755 --- a/linuxkm/linuxkm-fips-hash-wrapper.sh +++ b/linuxkm/linuxkm-fips-hash-wrapper.sh @@ -50,13 +50,14 @@ if [[ ! -v COREKEY ]]; 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 + if [[ ${#coreKey_a[@]} != 8 || ("${coreKey_a[2]}" != "65" && "${coreKey_a[2]}" != "257") ]]; then echo "unexpected readelf output: \"${coreKey_a[*]}\" (${#coreKey_a[@]})" >&2 exit 1 fi + corekey_length=$(( ${coreKey_a[2]} - 1)) 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 + COREKEY=$(dd if="$LIBWOLFSSL" bs="$corekey_length" iflag=skip_bytes,count_bytes skip="$coreKey_offset" count="$corekey_length" status=none) || exit $? + if [[ "${#COREKEY}" == "$corekey_length" && "$COREKEY" =~ ^[0-9A-Fa-f]+$ ]]; then : else echo "unexpected value for coreKey \"${COREKEY}\"." >&2 From f79b20374517370201d2e213128346e4639afb38 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Sun, 19 Jul 2026 13:41:47 -0500 Subject: [PATCH 16/18] wolfcrypt/src/sha3.c, wolfssl/wolfcrypt/sha3.h, wolfssl/wolfcrypt/error-crypt.h, wolfcrypt/src/error.c: * Fix vector register restore on error paths in Sha3Update(). * Add SP 800-185 check against KMAC_FIPS_MIN_KEY in KmacInit() and KMAC_FIPS_MIN_OUTPUT in KmacFinal(), returning KMAC_MIN_KEYLEN_E and BAD_LENGTH_E respectively on failure. * Use word32 rather than byte for wc_Sha3.i, wc_Cshake.count, wc_Kmac.count, and related, and add explicit range checking where needed, to fix a -Wconversion, fix possible overruns, obviate 14 casts, and eliminate (negligible) runtime overhead from masking and promotions. --- wolfcrypt/src/error.c | 3 + wolfcrypt/src/sha3.c | 116 ++++++++++++++++++++++---------- wolfssl/wolfcrypt/error-crypt.h | 5 +- wolfssl/wolfcrypt/sha3.h | 15 +++-- 4 files changed, 96 insertions(+), 43 deletions(-) diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index 62a67470bb6..2a076978ccc 100644 --- a/wolfcrypt/src/error.c +++ b/wolfcrypt/src/error.c @@ -738,6 +738,9 @@ const char* wc_GetErrorString(int error) case FIPS_WRONG_API_E: return "Requested API is not allowed in FIPS mode"; + case KMAC_MIN_KEYLEN_E: + return "FIPS Mode KMAC Minimum Key Length error"; + case MAX_CODE_E: case WC_SPAN1_MIN_CODE_E: case MIN_CODE_E: diff --git a/wolfcrypt/src/sha3.c b/wolfcrypt/src/sha3.c index a375b552b3b..1ead204fb5f 100644 --- a/wolfcrypt/src/sha3.c +++ b/wolfcrypt/src/sha3.c @@ -821,10 +821,11 @@ void BlockSha3(word64* s) * p Number of 64-bit numbers in a block of data to process. * returns 0 on success. */ -static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) +static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, word32 p) { word32 i; word32 blocks; + int ret = 0; #ifdef WC_SHA3_FAULT_HARDEN word32 check = 0; word32 total_check = 0; @@ -835,13 +836,19 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) void (*sha3_block_n)(word64 *s, const byte* data, word32 n, word64 c) = SHA3_BLOCK_N; #endif +#endif /* USE_INTEL_SPEEDUP */ + + if ((p < WC_SHA3_512_COUNT) || (p > WC_SHA3_128_COUNT)) + return BAD_STATE_E; +#ifdef USE_INTEL_SPEEDUP if (SHA3_BLOCK_VREGS(sha3_block)) { - int ret = SAVE_VECTOR_REGISTERS2(); + ret = SAVE_VECTOR_REGISTERS2(); if (ret != 0) { #ifdef WC_C_DYNAMIC_FALLBACK sha3_block = BlockSha3; sha3_block_n = NULL; + ret = 0; #else return ret; #endif @@ -851,9 +858,14 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) if (sha3->i > 0) { byte *t; - byte l = (byte)(p * 8 - sha3->i); + word32 l; + if (p * 8 < sha3->i) { + ret = BAD_STATE_E; + goto out; + } + l = (p * 8 - sha3->i); if (l > len) { - l = (byte)len; + l = len; } t = &sha3->t[sha3->i]; @@ -865,13 +877,14 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) } #ifdef WC_SHA3_FAULT_HARDEN if (check != l) { - return BAD_COND_E; + ret = BAD_COND_E; + goto out; } total_check += l; #endif data += i; len -= i; - sha3->i = (byte)(sha3->i + i); + sha3->i += i; if (sha3->i == p * 8) { #if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_FAULT_HARDEN) @@ -885,7 +898,8 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) } #ifdef WC_SHA3_FAULT_HARDEN if (check != p + l) { - return BAD_COND_E; + ret = BAD_COND_E; + goto out; } total_check += p; #endif @@ -922,7 +936,8 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) } #ifdef WC_SHA3_FAULT_HARDEN if (check != total_check - ((blocks - 1) * p)) { - return BAD_COND_E; + ret = BAD_COND_E; + goto out; } #endif #endif @@ -936,20 +951,27 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) } #ifdef WC_SHA3_FAULT_HARDEN if (check != total_check) { - return BAD_COND_E; + ret = BAD_COND_E; + goto out; } #endif + +out: + #ifdef USE_INTEL_SPEEDUP if (SHA3_BLOCK_VREGS(sha3_block)) { RESTORE_VECTOR_REGISTERS(); } #endif - if (len > 0) { - XMEMCPY(sha3->t, data, len); + + if (ret == 0) { + if (len > 0) { + XMEMCPY(sha3->t, data, len); + } + sha3->i += len; } - sha3->i = (byte)(sha3->i + len); - return 0; + return ret; } /* Calculate the SHA-3 hash based on all the message data seen. @@ -960,7 +982,7 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) * len Number of bytes in output. * returns 0 on success. */ -static int Sha3Final(wc_Sha3* sha3, byte padChar, byte* hash, byte p, word32 l) +static int Sha3Final(wc_Sha3* sha3, byte padChar, byte* hash, word32 p, word32 l) { word32 rate = p * 8U; word32 j; @@ -968,12 +990,17 @@ static int Sha3Final(wc_Sha3* sha3, byte padChar, byte* hash, byte p, word32 l) word32 i; #endif #ifdef WC_SHA3_FAULT_HARDEN - int check = 0; + word32 check = 0; #endif #if defined(WC_C_DYNAMIC_FALLBACK) && defined(USE_INTEL_SPEEDUP) void (*sha3_block)(word64 *s) = SHA3_BLOCK; #endif + if ((p < WC_SHA3_512_COUNT) || (p > WC_SHA3_128_COUNT)) + return BAD_STATE_E; + if (sha3->i >= rate) + return BAD_STATE_E; + #if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_FAULT_HARDEN) xorbuf(sha3->s, sha3->t, sha3->i); #ifdef WOLFSSL_HASH_FLAGS @@ -992,7 +1019,7 @@ static int Sha3Final(wc_Sha3* sha3, byte padChar, byte* hash, byte p, word32 l) #endif sha3->t[sha3->i ] = padChar; sha3->t[rate - 1] |= 0x80; - if (rate - 1 > (word32)sha3->i + 1) { + if (rate - 1 > sha3->i + 1) { XMEMSET(sha3->t + sha3->i + 1, 0, rate - 1U - (sha3->i + 1U)); } for (i = 0; i < p; i++) { @@ -1070,7 +1097,7 @@ static int wc_InitSha3(wc_Sha3* sha3, void* heap, int devId) return 0; } -static int Stm32GetAlgo(byte p) +static int Stm32GetAlgo(word32 p) { switch(p) { case WC_SHA3_224_COUNT: @@ -1086,7 +1113,7 @@ static int Stm32GetAlgo(byte p) return WC_SHA3_224_COUNT; } -static int wc_Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) +static int wc_Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, word32 p) { int ret = 0; @@ -1110,7 +1137,7 @@ static int wc_Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) return ret; } -static int wc_Sha3Final(wc_Sha3* sha3, byte* hash, byte p, byte len) +static int wc_Sha3Final(wc_Sha3* sha3, byte* hash, word32 p, word32 len) { int ret = 0; @@ -1151,7 +1178,7 @@ static int wc_InitSha3(wc_Sha3* sha3, void* heap, int devId) return ret; } -static int wc_Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) +static int wc_Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, word32 p) { int ret; @@ -1176,7 +1203,7 @@ static int wc_Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) return ret; } -static int wc_Sha3Final(wc_Sha3* sha3, byte* hash, byte p, byte len) +static int wc_Sha3Final(wc_Sha3* sha3, byte* hash, word32 p, word32 len) { int ret; @@ -1247,7 +1274,7 @@ static int wc_InitSha3(wc_Sha3* sha3, void* heap, int devId) * p Number of 64-bit numbers in a block of data to process. * returns 0 on success. */ -static int wc_Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) +static int wc_Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, word32 p) { int ret; @@ -1317,7 +1344,7 @@ static int wc_Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) * len Number of bytes in output. * returns 0 on success. */ -static int wc_Sha3Final(wc_Sha3* sha3, byte* hash, byte p, byte len) +static int wc_Sha3Final(wc_Sha3* sha3, byte* hash, word32 p, word32 len) { int ret; @@ -1485,7 +1512,7 @@ static int wc_Sha3Copy(wc_Sha3* src, wc_Sha3* dst) * len Number of bytes in output. * returns 0 on success. */ -static int wc_Sha3GetHash(wc_Sha3* sha3, byte* hash, byte p, byte len) +static int wc_Sha3GetHash(wc_Sha3* sha3, byte* hash, word32 p, word32 len) { int ret; WC_DECLARE_VAR(tmpSha3, wc_Sha3, 1, sha3 ? sha3->heap : NULL); @@ -2508,7 +2535,7 @@ static word32 KmacRightEncode(byte* out, word64 value) * @return 0 on success. * @return Negative error code from the sponge update on failure. */ -static int CshakeBytePad(wc_Sha3* shake, byte count, word32 rate) +static int CshakeBytePad(wc_Sha3* shake, word32 count, word32 rate) { int ret = 0; word32 pad = (rate - shake->i) % rate; @@ -2517,7 +2544,7 @@ static int CshakeBytePad(wc_Sha3* shake, byte count, word32 rate) /* Zero the rest of the block in place and flush it - a zero-length * update with i == rate triggers the XOR-in and permutation. */ XMEMSET(shake->t + shake->i, 0, pad); - shake->i = (byte)rate; + shake->i = rate; ret = Sha3Update(shake, shake->t, 0, count); } return ret; @@ -2543,10 +2570,10 @@ static int CshakeBytePad(wc_Sha3* shake, byte count, word32 rate) * @return 0 on success. * @return Negative error code from the sponge update on failure. */ -static int CshakeAbsorbBlock(wc_Sha3* shake, byte count, const byte* name, +static int CshakeAbsorbBlock(wc_Sha3* shake, word32 count, const byte* name, word32 nameLen, const byte* custom, word32 customLen) { - word32 rate = (word32)count * 8U; + word32 rate = count * 8U; byte enc[9]; word32 e; word32 h; @@ -2576,11 +2603,11 @@ static int CshakeAbsorbBlock(wc_Sha3* shake, byte count, const byte* name, XMEMCPY(shake->t + h, custom, customLen); h += customLen; } - shake->i = (byte)h; + shake->i = h; } else { /* name and/or custom cross a block boundary - absorb them. */ - shake->i = (byte)h; + shake->i = h; if (nameLen > 0) { ret = Sha3Update(shake, name, nameLen, count); } @@ -2621,7 +2648,7 @@ static int CshakeAbsorbBlock(wc_Sha3* shake, byte count, const byte* name, * @return BAD_FUNC_ARG when a NULL pointer has a non-zero length. * @return Negative error code from the sponge update on failure. */ -static int KmacInit(wc_Kmac* kmac, byte count, const byte* key, word32 keyLen, +static int KmacInit(wc_Kmac* kmac, word32 count, const byte* key, word32 keyLen, const byte* custom, word32 customLen, void* heap, int devId) { /* The KMAC function name string "KMAC". */ @@ -2633,9 +2660,14 @@ static int KmacInit(wc_Kmac* kmac, byte count, const byte* key, word32 keyLen, ((custom == NULL) && (customLen != 0))) { ret = BAD_FUNC_ARG; } +#ifdef HAVE_FIPS + else if (keyLen < KMAC_FIPS_MIN_KEY) { + ret = KMAC_MIN_KEYLEN_E; + } +#endif else { kmac->count = count; - rate = (word32)count * 8U; + rate = count * 8U; ret = wc_InitSha3(&kmac->shake, heap, devId); /* bytepad(encode_string("KMAC") || encode_string(custom), rate) */ @@ -2652,7 +2684,7 @@ static int KmacInit(wc_Kmac* kmac, byte count, const byte* key, word32 keyLen, h = KmacLeftEncode(kmac->shake.t, (word64)rate); h += KmacLeftEncode(kmac->shake.t + h, (word64)keyLen * 8); - kmac->shake.i = (byte)h; + kmac->shake.i = h; if (keyLen > 0) { /* Copy a key that fits into the block straight in and flush @@ -2722,17 +2754,27 @@ static int KmacFinal(wc_Kmac* kmac, byte* out, word32 outLen, int xof) if ((kmac == NULL) || (out == NULL)) { ret = BAD_FUNC_ARG; } +#ifdef HAVE_FIPS + else if ((xof == 0) && (outLen < KMAC_FIPS_MIN_OUTPUT)) { + ret = BAD_LENGTH_E; + } +#endif + else if ((kmac->count < WC_SHA3_512_COUNT) || + (kmac->count > WC_SHA3_128_COUNT) || + (kmac->shake.i >= kmac->count * 8U)) { + ret = BAD_STATE_E; + } else { /* right_encode(outLen * 8), or right_encode(0) for the XOF. */ word64 v = xof ? (word64)0 : (word64)outLen * 8; - rate = (word32)kmac->count * 8U; + rate = kmac->count * 8U; /* The encoding is at most 9 bytes; when that many fit in the current * block, write it straight into the block buffer, otherwise use a * temporary and Sha3Update (which handles crossing the boundary). */ - if ((word32)kmac->shake.i + 9 < rate) { + if (kmac->shake.i + 9 < rate) { word32 l = KmacRightEncode(kmac->shake.t + kmac->shake.i, v); - kmac->shake.i = (byte)(kmac->shake.i + l); + kmac->shake.i += l; } else { byte enc[9]; @@ -2798,7 +2840,7 @@ static int KmacCopy(wc_Kmac* src, wc_Kmac* dst) * @return BAD_FUNC_ARG when a NULL pointer has a non-zero length. * @return Negative error code from the sponge update on failure. */ -static int CshakeInit(wc_Cshake* cshake, byte count, const byte* name, +static int CshakeInit(wc_Cshake* cshake, word32 count, const byte* name, word32 nameLen, const byte* custom, word32 customLen, void* heap, int devId) { int ret; diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index 922102a6697..e3f091ff736 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -344,9 +344,10 @@ enum wolfCrypt_ErrorCodes { * than unknown. */ AES_KW_KAT_FIPS_E = -1024, /* AES Key Wrap KAT failure */ FIPS_WRONG_API_E = -1025, /* Requested API is not allowed in FIPS mode */ + KMAC_MIN_KEYLEN_E = -1026, /* FIPS Mode KMAC Minimum Key Length error */ - WC_SPAN2_LAST_E = -1025, /* Update to indicate last used error code */ - WC_LAST_E = -1025, /* the last code used either here or in + WC_SPAN2_LAST_E = -1026, /* Update to indicate last used error code */ + WC_LAST_E = -1026, /* the last code used either here or in * error-ssl.h */ WC_SPAN2_MIN_CODE_E = -1999, /* Last usable code in span 2 */ diff --git a/wolfssl/wolfcrypt/sha3.h b/wolfssl/wolfcrypt/sha3.h index 7116ea52e62..238e239e354 100644 --- a/wolfssl/wolfcrypt/sha3.h +++ b/wolfssl/wolfcrypt/sha3.h @@ -96,7 +96,14 @@ enum { WC_SHAKE256 = WC_HASH_TYPE_SHAKE256, #endif - WOLF_ENUM_DUMMY_LAST_ELEMENT(WC_SHA3) + KMAC_FIPS_MIN_KEY = 14, /* 112 bit key length minimum, per SP 800-185 + * section 8.4.1. */ + + KMAC_FIPS_MIN_OUTPUT = 4 /* 32 bit output length minimum, per SP 800-185 + * section 8.4.2, which further establishes that + * 4-7 byte output requires "careful risk + * analysis", and is permitted here to delegate + * that analysis to the caller. */ }; #ifndef NO_OLD_WC_NAMES @@ -146,7 +153,7 @@ struct wc_Sha3 { /* Unprocessed message data. */ byte t[200]; /* Index into unprocessed data to place next message byte. */ - byte i; + word32 i; void* heap; @@ -288,7 +295,7 @@ WOLFSSL_API int wc_Shake256_Copy(wc_Shake* src, wc_Sha3* dst); * (0x04 when customized, 0x1f when it reduces to plain SHAKE). */ struct wc_Cshake { wc_Shake shake; - byte count; + word32 count; byte pad; }; @@ -303,7 +310,7 @@ struct wc_Kmac { wc_Shake shake; /* Number of 64-bit words in a KECCAK block (rate / 8) - selects the * KMAC128 (SHAKE128) or KMAC256 (SHAKE256) variant. */ - byte count; + word32 count; }; #ifndef WC_KMAC_TYPE_DEFINED From 6fcfadfee2ea8c6147609631588d905598e96ae2 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Sun, 19 Jul 2026 14:45:23 -0500 Subject: [PATCH 17/18] configure.ac: more FIPS v7/ready/dev DH purging: omit HAVE_FFDHE_* too. --- configure.ac | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index 547a6e04373..4c5c326174f 100644 --- a/configure.ac +++ b/configure.ac @@ -1668,6 +1668,8 @@ then if test "$ENABLED_FIPS" = "no" || test "$HAVE_FIPS_VERSION" -lt 7 then + # Enable DH const table speedups (eliminates `-lm` math lib dependency) + AM_CFLAGS="$AM_CFLAGS -DHAVE_FFDHE_2048 -DHAVE_FFDHE_3072" # "Anonymous suite requires DH." test "$enable_anon" = "" && enable_anon=yes fi @@ -1697,8 +1699,6 @@ then AM_CFLAGS="$AM_CFLAGS -DHAVE_AES_DECRYPT -DHAVE_AES_ECB -DWOLFSSL_ALT_NAMES" - # Enable DH const table speedups (eliminates `-lm` math lib dependency) - AM_CFLAGS="$AM_CFLAGS -DHAVE_FFDHE_2048 -DHAVE_FFDHE_3072" DEFAULT_MAX_CLASSIC_ASYM_KEY_BITS=4096 # Enable all parsing features for ASN */ @@ -1766,8 +1766,11 @@ then test "$enable_shake256" = "" && test "$enable_sha3" = "yes" && enable_shake256=yes test "$enable_compkey" = "" && enable_compkey=yes fi - # Enable DH const table speedups (eliminates `-lm` math lib dependency) - AM_CFLAGS="$AM_CFLAGS -DHAVE_FFDHE_2048 -DHAVE_FFDHE_3072" + if test "$ENABLED_FIPS" = "no" || test "$HAVE_FIPS_VERSION" -lt 7 + then + # Enable DH const table speedups (eliminates `-lm` math lib dependency) + AM_CFLAGS="$AM_CFLAGS -DHAVE_FFDHE_2048 -DHAVE_FFDHE_3072" + fi DEFAULT_MAX_CLASSIC_ASYM_KEY_BITS=4096 AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DH_EXTRA" AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ECDSA_DETERMINISTIC_K_VARIANT" @@ -6777,12 +6780,7 @@ AS_CASE([$FIPS_VERSION], -DECC_USER_CURVES \ -DHAVE_ECC384 \ -DHAVE_ECC521 \ - -DWOLFSSL_VALIDATE_FFC_IMPORT \ - -DHAVE_FFDHE_Q \ - -DHAVE_FFDHE_3072 \ - -DHAVE_FFDHE_4096 \ - -DHAVE_FFDHE_6144 \ - -DHAVE_FFDHE_8192" + -DWOLFSSL_VALIDATE_FFC_IMPORT" # KCAPI API does not support custom k for sign, don't force enable ECC key sizes and don't use seed callback AS_IF([test "x$ENABLED_KCAPI_ECC" = "xno"], From 3f9bc8c77558f0ce4fb43fcc7b55a0a4535b91bf Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Mon, 20 Jul 2026 11:09:27 -0500 Subject: [PATCH 18/18] linuxkm/Makefile: fix module-update-fips-hash recipe to allow SHA512 verifyCore. --- linuxkm/Makefile | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/linuxkm/Makefile b/linuxkm/Makefile index 5fdbd4f2629..00fc70df6a0 100644 --- a/linuxkm/Makefile +++ b/linuxkm/Makefile @@ -361,17 +361,18 @@ module-update-fips-hash: $(LIBWOLFSSL_NAME).ko @if test -z '$(FIPS_HASH)'; then echo ' $$FIPS_HASH is unset' >&2; exit 1; fi @if [[ ! '$(FIPS_HASH)' =~ [0-9a-fA-F]{64} ]]; then echo ' $$FIPS_HASH is malformed' >&2; exit 1; fi @readarray -t rodata_segment < <($(READELF) --wide --sections "$<" | \ - sed -E -n 's/^[[:space:]]*\[[[:space:]]*([0-9]+)\][[:space:]]+\.rodata_wolfcrypt[[:space:]]+PROGBITS[[:space:]]+[0-9a-fA-F]+[[:space:]]+([0-9a-fA-F]+)[[:space:]].*$$/\1\n\2/p'); \ - if [[ $${#rodata_segment[@]} != 2 ]]; then echo ' unexpected rodata_segment.' >&2; exit 1; fi; \ + sed -E -n 's/^[[:space:]]*\[[[:space:]]*([0-9]+)\][[:space:]]+\.rodata_wolfcrypt[[:space:]]+PROGBITS[[:space:]]+[0-9a-fA-F]+[[:space:]]+([0-9a-fA-F]+)[[:space:]].*$$/\1\n\2/p') + if [[ $${#rodata_segment[@]} != 2 ]]; then echo ' unexpected rodata_segment.' >&2; exit 1; fi readarray -t verifyCore_attrs < <($(READELF) --wide --symbols "$<" | \ sed -E -n 's/^[[:space:]]*[0-9]+: ([0-9a-fA-F]+)[[:space:]]+([0-9]+)[[:space:]]+OBJECT[[:space:]]+[A-Z]+[[:space:]]+[A-Z]+[[:space:]]+'"$${rodata_segment[0]}"'[[:space:]]+verifyCore$$/\1\n\2/p'); \ - if [[ $${#verifyCore_attrs[@]} != 2 ]]; then echo ' unexpected verifyCore_attrs.' >&2; exit 1; fi; \ - if [[ "$${verifyCore_attrs[1]}" != "65" ]]; then echo " verifyCore has unexpected length $${verifyCore_attrs[1]}." >&2; exit 1; fi; \ - verifyCore_offset=$$((0x$${rodata_segment[1]} + 0x$${verifyCore_attrs[0]})); \ - current_verifyCore=$$(dd bs=1 if="$<" skip=$$verifyCore_offset count=64 status=none); \ - if [[ ! "$$current_verifyCore" =~ [0-9a-fA-F]{64} ]]; then echo " verifyCore at offset $$verifyCore_offset has unexpected value." >&2; exit 1; fi; \ - if [[ '$(FIPS_HASH)' == "$$current_verifyCore" ]]; then echo ' Supplied FIPS_HASH matches existing verifyCore -- no update needed.'; exit 0; fi; \ - echo -n '$(FIPS_HASH)' | dd bs=1 conv=notrunc of="$<" seek=$$verifyCore_offset count=64 status=none && \ + if [[ $${#verifyCore_attrs[@]} != 2 ]]; then echo ' unexpected verifyCore_attrs.' >&2; exit 1; fi + verifyCore_size=$$(("$${verifyCore_attrs[1]}" - 1)) + if [[ "$$verifyCore_size" != "64" && "$$verifyCore_size" != "128" ]]; then echo " verifyCore has unexpected length $${verifyCore_size}." >&2; exit 1; fi + verifyCore_offset=$$((0x$${rodata_segment[1]} + 0x$${verifyCore_attrs[0]})) + current_verifyCore=$$(dd bs=1 if="$<" skip=$$verifyCore_offset count=$$verifyCore_size status=none) + if [[ ! "$$current_verifyCore" =~ [0-9a-fA-F]{64} ]]; then echo " verifyCore at offset $$verifyCore_offset has unexpected value." >&2; exit 1; fi + if [[ '$(FIPS_HASH)' == "$$current_verifyCore" ]]; then echo ' Supplied FIPS_HASH matches existing verifyCore -- no update needed.'; exit 0; fi + echo -n '$(FIPS_HASH)' | dd bs=1 conv=notrunc of="$<" seek=$$verifyCore_offset count=$$verifyCore_size status=none && \ echo " FIPS verifyCore updated successfully." && \ if [[ -f '$(LIBWOLFSSL_NAME).ko.signed' ]]; then $(MAKE) $(QFLAG) --no-print-directory $(NO_SILENT) -C . '$(LIBWOLFSSL_NAME).ko.signed'; fi