diff --git a/wolfcrypt/src/dh.c b/wolfcrypt/src/dh.c index 849ff81025..26166c7310 100644 --- a/wolfcrypt/src/dh.c +++ b/wolfcrypt/src/dh.c @@ -1122,13 +1122,24 @@ static int GeneratePrivateDh186(DhKey* key, WC_RNG* rng, byte* priv, byte cBuf[DH_MAX_SIZE + 64 / WOLFSSL_BIT_SIZE]; #endif - /* Parameters validated in calling functions. */ + /* Pointer parameters validated by the public entry wc_DhGenerateKeyPair. */ if (mp_iszero(&key->q) == MP_YES) { WOLFSSL_MSG("DH q parameter needed for FIPS 186-4 key generation"); return BAD_FUNC_ARG; } + /* Bound *privSz so cSz (= *privSz + 8) cannot exceed the cBuf capacity. + * Note: DH_MAX_SIZE is documented as a bit count, but the cBuf declaration + * above uses it directly as a byte count (cBuf is DH_MAX_SIZE + 8 bytes). + * This check matches that convention so *privSz (in bytes) is bounded by + * the actual byte capacity of cBuf. The same bound is applied to the + * 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; + } + qSz = (word32)mp_unsigned_bin_size(&key->q); pSz = (word32)mp_unsigned_bin_size(&key->p); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 6725de6aca..e225347f56 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -29605,6 +29605,27 @@ static wc_test_ret_t dh_fips_generate_test(WC_RNG *rng) if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_gen_test); +#if !defined(WOLFSSL_NO_DH186) && !defined(HAVE_SELFTEST) && \ + !defined(HAVE_FIPS) + /* Regression: an oversized *privSz must be rejected before + * GeneratePrivateDh186 writes (*privSz + 8) bytes of RNG output into the + * stack-allocated cBuf (sized DH_MAX_SIZE + 8 in non-WOLFSSL_SMALL_STACK + * builds). The key still has q set here, so the call dispatches through + * GeneratePrivateDh186. Only exercised when the local src/dh.c bound + * check is in play (not HAVE_SELFTEST / HAVE_FIPS builds, which use + * separate validated modules). */ + { + word32 hugePrivSz = (word32)DH_MAX_SIZE + 1; + word32 outPubSz = sizeof(pub); + ret = wc_DhGenerateKeyPair(key, rng, priv, &hugePrivSz, pub, &outPubSz); + #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)) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_gen_test); + } +#endif /* !WOLFSSL_NO_DH186 && !HAVE_SELFTEST && !HAVE_FIPS */ + wc_FreeDhKey(key); ret = wc_InitDhKey_ex(key, HEAP_HINT, devId); if (ret != 0)