diff --git a/tests/api/test_aes.c b/tests/api/test_aes.c index c463cea61d..f5986f2068 100644 --- a/tests/api/test_aes.c +++ b/tests/api/test_aes.c @@ -3381,7 +3381,7 @@ 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)), + sizeof(iv)/sizeof(byte), resultT, sizeof(resultT) - 10, a, sizeof(a)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); #if (defined(HAVE_FIPS) && defined(HAVE_FIPS_VERSION) && \ @@ -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, sizeof(tag3) - 10), 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); diff --git a/wolfcrypt/src/dh.c b/wolfcrypt/src/dh.c index 5a6daa9853..42a8dfe8a7 100644 --- a/wolfcrypt/src/dh.c +++ b/wolfcrypt/src/dh.c @@ -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); @@ -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; diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 117adfd5ae..edc85bdcb4 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -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 */ diff --git a/wolfcrypt/src/kdf.c b/wolfcrypt/src/kdf.c index 6f6825b740..295f8011d7 100644 --- a/wolfcrypt/src/kdf.c +++ b/wolfcrypt/src/kdf.c @@ -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) || + (seed == NULL && seedLen != 0)) + return BAD_FUNC_ARG; + switch (hash_type) { #ifndef NO_MD5 case md5_mac: @@ -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; @@ -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) { @@ -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); @@ -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; } 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. */ diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index 096c0e50e2..f35ccc079b 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -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 @@ -5445,7 +5445,11 @@ int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng) goto out; } +#if defined(HAVE_FIPS) + if (e < WC_RSA_EXPONENT || (e & 1) == 0) { +#else if (e < 3 || (e & 1) == 0) { +#endif err = BAD_FUNC_ARG; goto out; } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index def621bde6..47e07b3bfd 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -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 */ diff --git a/wolfssl/wolfcrypt/cmac.h b/wolfssl/wolfcrypt/cmac.h index 40a6e1a64e..01b78b6f10 100644 --- a/wolfssl/wolfcrypt/cmac.h +++ b/wolfssl/wolfcrypt/cmac.h @@ -98,14 +98,13 @@ 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 */ -#define WC_CMAC_TAG_MAX_SZ 16 -#define WC_CMAC_TAG_MIN_SZ 4 +/* SP800-38b recommends a minimum tag length of 64-bits */ +#ifndef WC_CMAC_TAG_MAX_SZ + #define WC_CMAC_TAG_MAX_SZ 16 +#endif +#ifndef WC_CMAC_TAG_MIN_SZ + #define WC_CMAC_TAG_MIN_SZ 8 #endif #if FIPS_VERSION3_GE(6,0,0) diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index c12265b023..241c1fafae 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -3899,6 +3899,32 @@ #endif #endif +#if defined(HAVE_FIPS) + #if FIPS_VERSION3_EQ(5, 2, 4) + /* 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 +#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 + #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) @@ -4371,32 +4397,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().