Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions tests/api/test_aes.c
Original file line number Diff line number Diff line change
Expand Up @@ -3381,8 +3381,8 @@ int test_wc_AesGcmEncryptDecrypt(void)
sizeof(iv)/sizeof(byte), resultT, sizeof(resultT) + 1, a, sizeof(a)),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_AesGcmEncrypt(&aes, enc, vector, sizeof(vector), iv,
sizeof(iv)/sizeof(byte), resultT, sizeof(resultT) - 5, a, sizeof(a)),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
sizeof(iv)/sizeof(byte), resultT, WOLFSSL_MIN_AUTH_TAG_SZ - 1, a,
sizeof(a)), WC_NO_ERR_TRACE(BAD_FUNC_ARG));

#if (defined(HAVE_FIPS) && defined(HAVE_FIPS_VERSION) && \
(HAVE_FIPS_VERSION == 2)) || defined(HAVE_SELFTEST) || \
Expand Down Expand Up @@ -4928,7 +4928,7 @@ int test_wc_GmacUpdate(void)
ExpectIntEQ(wc_GmacUpdate(NULL, iv3, sizeof(iv3), authIn3, sizeof(authIn3),
tagOut3, sizeof(tag3)), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_GmacUpdate(&gmac, iv3, sizeof(iv3), authIn3, sizeof(authIn3),
tagOut3, sizeof(tag3) - 5), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
tagOut3, WOLFSSL_MIN_AUTH_TAG_SZ - 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_GmacUpdate(&gmac, iv3, sizeof(iv3), authIn3, sizeof(authIn3),
tagOut3, sizeof(tag3) + 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
wc_AesFree(&gmac.aes);
Expand Down
5 changes: 4 additions & 1 deletion wolfcrypt/src/dh.c
Original file line number Diff line number Diff line change
Expand Up @@ -1138,7 +1138,7 @@ static int GeneratePrivateDh186(DhKey* key, WC_RNG* rng, byte* priv,
* WOLFSSL_SMALL_STACK path to avoid unbounded heap allocation. */
if (*privSz > DH_MAX_SIZE) {
WOLFSSL_MSG("DH private key size exceeds DH_MAX_SIZE");
return BAD_FUNC_ARG;
return WC_KEY_SIZE_E;
}

qSz = (word32)mp_unsigned_bin_size(&key->q);
Expand Down Expand Up @@ -1732,6 +1732,9 @@ int wc_DhCheckPubValue(const byte* prime, word32 primeSz, const byte* pub,
int ret = 0;
word32 i;

if (prime == NULL || pub == NULL)
return BAD_FUNC_ARG;

for (i = 0; i < pubSz && pub[i] == 0; i++) {
}
pubSz -= i;
Expand Down
22 changes: 15 additions & 7 deletions wolfcrypt/src/ecc.c
Original file line number Diff line number Diff line change
Expand Up @@ -11414,16 +11414,24 @@ static int _ecc_import_x963_ex2(const byte* in, word32 inLen, ecc_key* key,
if (err == MP_OKAY) {
#ifdef HAVE_COMP_KEY
/* adjust inLen if compressed */
if (compressed)
inLen = inLen*2 + 1; /* used uncompressed len */
if (compressed) {
/* a compressed coordinate cannot exceed MAX_ECC_BYTES; bound it
* before doubling so inLen*2 + 1 cannot overflow word32. */
if (inLen > MAX_ECC_BYTES)
err = ECC_BAD_ARG_E;
else
inLen = inLen*2 + 1; /* used uncompressed len */
}
#endif

/* determine key size */
keysize = (int)(inLen>>1);
/* NOTE: FIPS v6.0.0 or greater, no restriction on imported keys, only
* on created keys or signatures */
err = wc_ecc_set_curve(key, keysize, curve_id);
key->type = ECC_PUBLICKEY;
if (err == MP_OKAY) {
keysize = (int)(inLen>>1);
/* NOTE: FIPS v6.0.0 or greater, no restriction on imported keys,
* only on created keys or signatures */
err = wc_ecc_set_curve(key, keysize, curve_id);
key->type = ECC_PUBLICKEY;
}
}

/* read data */
Expand Down
39 changes: 33 additions & 6 deletions wolfcrypt/src/kdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ int wc_PRF(byte* result, word32 resLen, const byte* secret,
Hmac hmac[1];
#endif

if ((result == NULL && resLen != 0) || (secret == NULL && secLen != 0) ||
Comment thread
lealem47 marked this conversation as resolved.
(seed == NULL && seedLen != 0))
return BAD_FUNC_ARG;

switch (hash_type) {
#ifndef NO_MD5
case md5_mac:
Expand Down Expand Up @@ -234,8 +238,18 @@ int wc_PRF_TLSv1(byte* digest, word32 digLen, const byte* secret,
WC_DECLARE_VAR(sha_result, byte, MAX_PRF_DIG, heap); /* digLen is real size */
WC_DECLARE_VAR(labelSeed, byte, MAX_PRF_LABSEED, heap);

if ((digest == NULL && digLen != 0) ||
(secret == NULL && secLen != 0) ||
(label == NULL && labLen != 0) ||
(seed == NULL && seedLen != 0)) {
return BAD_FUNC_ARG;
}

/* labLen + seedLen is checked with subtraction to avoid word32 wraparound
* (the labLen bound first ensures MAX_PRF_LABSEED - labLen cannot
* underflow). */
if (half > MAX_PRF_HALF ||
labLen + seedLen > MAX_PRF_LABSEED ||
labLen > MAX_PRF_LABSEED || seedLen > (MAX_PRF_LABSEED - labLen) ||
digLen > MAX_PRF_DIG)
{
return BUFFER_E;
Comment thread
lealem47 marked this conversation as resolved.
Expand All @@ -251,8 +265,10 @@ int wc_PRF_TLSv1(byte* digest, word32 digLen, const byte* secret,
sha_half = secret + half - secLen % 2;
md5_result = digest;

XMEMCPY(labelSeed, label, labLen);
XMEMCPY(labelSeed + labLen, seed, seedLen);
if (labLen != 0)
XMEMCPY(labelSeed, label, labLen);
if (seedLen != 0)
XMEMCPY(labelSeed + labLen, seed, seedLen);

if ((ret = wc_PRF(md5_result, digLen, md5_half, half, labelSeed,
labLen + seedLen, md5_mac, heap, devId)) == 0) {
Expand Down Expand Up @@ -286,6 +302,13 @@ int wc_PRF_TLS(byte* digest, word32 digLen, const byte* secret, word32 secLen,
{
int ret = 0;

if ((digest == NULL && digLen != 0) ||
(secret == NULL && secLen != 0) ||
(label == NULL && labLen != 0) ||
(seed == NULL && seedLen != 0)) {
return BAD_FUNC_ARG;
}

#ifdef WOLFSSL_DEBUG_TLS
WOLFSSL_MSG(" secret");
WOLFSSL_BUFFER(secret, secLen);
Expand All @@ -298,15 +321,19 @@ int wc_PRF_TLS(byte* digest, word32 digLen, const byte* secret, word32 secLen,
if (useAtLeastSha256) {
WC_DECLARE_VAR(labelSeed, byte, MAX_PRF_LABSEED, 0);

if (labLen + seedLen > MAX_PRF_LABSEED) {
/* Checked with subtraction to avoid word32 wraparound of
* labLen + seedLen. */
if (labLen > MAX_PRF_LABSEED || seedLen > (MAX_PRF_LABSEED - labLen)) {
return BUFFER_E;
Comment thread
lealem47 marked this conversation as resolved.
}

WC_ALLOC_VAR_EX(labelSeed, byte, MAX_PRF_LABSEED, heap,
DYNAMIC_TYPE_DIGEST, return MEMORY_E);

XMEMCPY(labelSeed, label, labLen);
XMEMCPY(labelSeed + labLen, seed, seedLen);
if (labLen != 0)
XMEMCPY(labelSeed, label, labLen);
if (seedLen != 0)
XMEMCPY(labelSeed + labLen, seed, seedLen);

/* If a cipher suite wants an algorithm better than sha256, it
* should use better. */
Expand Down
6 changes: 5 additions & 1 deletion wolfcrypt/src/rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -1825,7 +1825,7 @@ static int RsaUnPad_OAEP(byte *pkcsBlock, unsigned int pkcsBlockLen,
if (ret != 0) {
ForceZero(tmp, hLen);
#ifdef WOLFSSL_SMALL_STACK
XFREE(tmp, NULL, DYNAMIC_TYPE_RSA_BUFFER);
XFREE(tmp, heap, DYNAMIC_TYPE_RSA_BUFFER);
#elif defined(WOLFSSL_CHECK_MEM_ZERO)
wc_MemZero_Check(tmp, hLen);
#endif
Expand Down Expand Up @@ -5445,7 +5445,11 @@ int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng)
goto out;
}

#if defined(HAVE_FIPS)
Comment thread
Frauschi marked this conversation as resolved.
if (e < WC_RSA_EXPONENT || (e & 1) == 0) {
#else
if (e < 3 || (e & 1) == 0) {
#endif
err = BAD_FUNC_ARG;
goto out;
}
Expand Down
2 changes: 1 addition & 1 deletion wolfcrypt/test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -31197,7 +31197,7 @@ static wc_test_ret_t dh_fips_generate_test(WC_RNG *rng)
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &key->asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
if (ret != WC_NO_ERR_TRACE(WC_KEY_SIZE_E))
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_gen_test);
}
#endif /* !WOLFSSL_NO_DH186 && !HAVE_SELFTEST && !HAVE_FIPS */
Expand Down
21 changes: 14 additions & 7 deletions wolfssl/wolfcrypt/cmac.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,21 @@ struct Cmac {




#ifndef NO_AES
#define WC_CMAC_TAG_MAX_SZ WC_AES_BLOCK_SIZE
#define WC_CMAC_TAG_MIN_SZ (WC_AES_BLOCK_SIZE/4)
#else
/* Reasonable defaults */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [Medium] WC_CMAC_TAG_MAX_SZ made user-overridable without bounding it to the 16-byte digest buffer
💡 SUGGEST api

The macro was previously hard-tied to the AES block size (#define WC_CMAC_TAG_MAX_SZ WC_AES_BLOCK_SIZE) and could not be overridden. Wrapping it in #ifndef makes it a user-tunable knob, but the only consumer is the upper bound in wc_CmacFinalNoFree() (wolfcrypt/src/cmac.c:396), which is immediately followed by XMEMCPY(out, cmac->digest, *outSz) (wolfcrypt/src/cmac.c:452, :456) where cmac->digest is a fixed byte digest[WC_AES_BLOCK_SIZE] (cmac.h:63). Any build defining WC_CMAC_TAG_MAX_SZ above 16 therefore turns a legal API call into an out-of-bounds read of the Cmac struct and leaks adjacent struct bytes (including k1/k2 subkey material) into the caller's output buffer. The header change alone creates the footgun; nothing in the tree enforces the upper bound.

Suggestion:

Suggested change
/* Reasonable defaults */
/* Reasonable defaults */
#ifndef WC_CMAC_TAG_MAX_SZ
#define WC_CMAC_TAG_MAX_SZ 16
#endif
#if !defined(NO_AES) && (WC_CMAC_TAG_MAX_SZ > WC_AES_BLOCK_SIZE)
#error WC_CMAC_TAG_MAX_SZ cannot exceed WC_AES_BLOCK_SIZE
#endif

#define WC_CMAC_TAG_MAX_SZ 16
#define WC_CMAC_TAG_MIN_SZ 4
#ifndef WC_CMAC_TAG_MAX_SZ
#define WC_CMAC_TAG_MAX_SZ 16
#endif

#if !defined(NO_AES) && (WC_CMAC_TAG_MAX_SZ > 16)
#error WC_CMAC_TAG_MAX_SZ cannot exceed WC_AES_BLOCK_SIZE
#endif

/* SP800-38b recommends a minimum tag length of 64-bits */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 [Low] WC_CMAC_TAG_MIN_SZ redefined without #undef in the FIPS >= 7 branch
💡 SUGGEST convention

The #elif !defined(WC_CMAC_TAG_MIN_SZ) arm newly advertises WC_CMAC_TAG_MIN_SZ as a user-overridable macro, but the FIPS >= 7.0.0 arm above it does a bare #define with no #undef. A FIPS v7 build that also passes -DWC_CMAC_TAG_MIN_SZ=4 (or sets it in user_settings.h) gets a macro redefinition with a different value - a diagnostic that becomes a hard error under the -Werror used in several CI configs. The settings.h changes in this same PR consistently use #undef before #define for exactly this reason.

Suggestion:

Suggested change
/* SP800-38b recommends a minimum tag length of 64-bits */
/* SP800-38b recommends a minimum tag length of 64-bits */
#if FIPS_VERSION3_GE(7,0,0)
#undef WC_CMAC_TAG_MIN_SZ
#define WC_CMAC_TAG_MIN_SZ 8
#elif !defined(WC_CMAC_TAG_MIN_SZ)
#define WC_CMAC_TAG_MIN_SZ 4
#endif

#if FIPS_VERSION3_GE(7,0,0)
#undef WC_CMAC_TAG_MIN_SZ
#define WC_CMAC_TAG_MIN_SZ 8
#elif !defined(WC_CMAC_TAG_MIN_SZ)
#define WC_CMAC_TAG_MIN_SZ 4
#endif

#if FIPS_VERSION3_GE(6,0,0)
Expand Down
56 changes: 26 additions & 30 deletions wolfssl/wolfcrypt/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -3892,10 +3892,32 @@
#error WOLFSSL_MIN_AUTH_TAG_SZ must be at least 1
#endif

#if defined(HAVE_FIPS) && FIPS_VERSION3_GE(7, 0, 0)
/* No short (<96 bit) tags per SP 800-38D 2026 revision in process. */
#if WOLFSSL_MIN_AUTH_TAG_SZ < 12
#error WOLFSSL_MIN_AUTH_TAG_SZ must be >= 12 per SP 800-38D Rev 1
#if defined(HAVE_FIPS)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [High] FIPS gate narrowed from <7.0.0 to ==5.2.4 raises min GCM tag to 12 for kernel FIPS 6.x, breaking RFC 4106 8-byte ICV
🚫 BLOCK bug

The block moved out of the WOLFSSL_LINUXKM section did not move verbatim: the FIPS condition changed from FIPS_VERSION3_LT(7, 0, 0) to FIPS_VERSION3_EQ(5, 2, 4). For a LINUXKM build with wolfCrypt FIPS v6.x (a supported kernel configuration - see linuxkm/module_hooks.c:115,639,1216 and linuxkm/linuxkm_wc_port.h:874 which all branch on FIPS_VERSION3_GE(6,0,0)), WOLFSSL_MIN_AUTH_TAG_SZ goes from 8 to 12. The kernel glue still advertises and accepts an 8-byte ICV for RFC 4106: km_AesGcmSetAuthsize_Rfc4106() (linuxkm/lkcapi_aes_glue.c:1092-1100) returns 0 for authsize == 8, and rfc4106(gcm(aes)) registration is not FIPS-gated (linuxkm/lkcapi_aes_glue.c:162-168). The tfm therefore accepts setauthsize(8), but every subsequent wc_AesGcmEncrypt/wc_AesGcmDecrypt/*Final call fails with BAD_FUNC_ARG at wolfcrypt/src/aes.c:20086 and :20389. IPsec ESP with a 64-bit ICV silently stops working on FIPS v6 kernel modules. The module self-test (linuxkm_test_aesgcm_rfc4106) uses a 16-byte tag, so nothing catches this at load time. The commit message says only "Remove MIN_AUTH_TAG_SZ logic from kernel section to synchronize with user-space build" - the version-predicate change is not mentioned and looks unintended.

Suggestion:

Suggested change
#if defined(HAVE_FIPS)
#if defined(HAVE_FIPS)
#if FIPS_VERSION3_LT(7, 0, 0)
/* support RFC 4106 IPsec ESP 64 bit tags */
#if WOLFSSL_MIN_AUTH_TAG_SZ > 8
#undef WOLFSSL_MIN_AUTH_TAG_SZ
#define WOLFSSL_MIN_AUTH_TAG_SZ 8
#endif
#else
/* No short (<96 bit) tags per SP 800-38D 2026 revision in process. */
#if WOLFSSL_MIN_AUTH_TAG_SZ < 12
#undef WOLFSSL_MIN_AUTH_TAG_SZ
#define WOLFSSL_MIN_AUTH_TAG_SZ 12
#endif
#endif

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [Medium] FIPS 5.2.4 branch force-lowers WOLFSSL_MIN_AUTH_TAG_SZ to 8 for user-space builds and overrides an explicit user setting
💡 SUGGEST api

Before this PR the whole adjustment block lived inside the #ifdef WOLFSSL_LINUXKM section, so a user-space FIPS build used the default (or user-supplied) WOLFSSL_MIN_AUTH_TAG_SZ from line 3889 - normally 12. Now every FIPS 5.2.4 build, kernel or user-space, gets 8. Two consequences: (1) user-space FIPS 5.2.4 applications silently start accepting 64-bit GCM tags where they previously required 96-bit; (2) unlike the two sibling branches at 3914-3925, this one is an unconditional #undef/#define rather than a clamp, so a deliberate -DWOLFSSL_MIN_AUTH_TAG_SZ=16 is silently downgraded to 8 - a "minimum" macro behaving as a hard ceiling. Relaxing an authentication-tag minimum for every consumer of one FIPS version is a security-relevant default change that deserves to be explicit in the PR description.

Suggestion:

Suggested change
#if defined(HAVE_FIPS)
#if FIPS_VERSION3_EQ(5, 2, 4)
/* support RFC 4106 IPsec ESP 64 bit tags */
#if WOLFSSL_MIN_AUTH_TAG_SZ > 8
#undef WOLFSSL_MIN_AUTH_TAG_SZ
#define WOLFSSL_MIN_AUTH_TAG_SZ 8
#endif
#else

#if FIPS_VERSION3_EQ(5, 2, 4) || (FIPS_VERSION3_LT(7, 0, 0) && \
defined(WOLFSSL_LINUXKM))
/* support RFC 4106 IPsec ESP 64 bit tags */
#undef WOLFSSL_MIN_AUTH_TAG_SZ
#define WOLFSSL_MIN_AUTH_TAG_SZ 8
#else
/* No short (<96 bit) tags per SP 800-38D 2026 revision in process. */
#if WOLFSSL_MIN_AUTH_TAG_SZ < 12
#undef WOLFSSL_MIN_AUTH_TAG_SZ
#define WOLFSSL_MIN_AUTH_TAG_SZ 12
#endif
#endif
#elif defined(WOLFSSL_LINUXKM) && (defined(CONFIG_CRYPTO_MANAGER_EXTRA_TESTS) \
|| defined(CONFIG_CRYPTO_SELFTESTS_FULL))
/* The Linux kernel native crypto fuzzer expects small AES-GCM tag
* sizes to succeed. */
#if WOLFSSL_MIN_AUTH_TAG_SZ > 4
#undef WOLFSSL_MIN_AUTH_TAG_SZ
#define WOLFSSL_MIN_AUTH_TAG_SZ 4
#endif
#elif defined(WOLFSSL_LINUXKM)
/* support RFC 4106 IPsec ESP */
#if WOLFSSL_MIN_AUTH_TAG_SZ > 8
#undef WOLFSSL_MIN_AUTH_TAG_SZ
#define WOLFSSL_MIN_AUTH_TAG_SZ 8
#endif
#endif

Expand Down Expand Up @@ -4371,32 +4393,6 @@
#undef HAVE_PUBLIC_FFDHE
#endif

#if defined(HAVE_FIPS)
#if FIPS_VERSION3_LT(7, 0, 0)
/* support RFC 4106 IPsec ESP 64 bit tags */
#undef WOLFSSL_MIN_AUTH_TAG_SZ
#define WOLFSSL_MIN_AUTH_TAG_SZ 8
#else
/* No short (<96 bit) tags per SP 800-38D 2026 revision in process. */
#if WOLFSSL_MIN_AUTH_TAG_SZ < 12
#undef WOLFSSL_MIN_AUTH_TAG_SZ
#define WOLFSSL_MIN_AUTH_TAG_SZ 12
#endif
#endif
#elif defined(CONFIG_CRYPTO_MANAGER_EXTRA_TESTS) || defined(CONFIG_CRYPTO_SELFTESTS_FULL)
/* The Linux kernel native crypto fuzzer expects small AES-GCM tag sizes to succeed. */
#if WOLFSSL_MIN_AUTH_TAG_SZ > 4
#undef WOLFSSL_MIN_AUTH_TAG_SZ
#define WOLFSSL_MIN_AUTH_TAG_SZ 4
#endif
#else
/* support RFC 4106 IPsec ESP */
#if WOLFSSL_MIN_AUTH_TAG_SZ > 8
#undef WOLFSSL_MIN_AUTH_TAG_SZ
#define WOLFSSL_MIN_AUTH_TAG_SZ 8
#endif
#endif

#if defined(LINUXKM_LKCAPI_REGISTER) && !defined(WOLFSSL_ASN_INT_LEAD_0_ANY)
/* kernel 5.10 crypto manager tests key(s) that fail unless leading
* zero bytes are tolerated in GetASN_Integer().
Expand Down
Loading