wolfssl/wolfcrypt/dh.h, wolfcrypt/src/dh.c: add wc_dh_enable/disable/

is_enabled, WC_DH_INITIAL_RUNTIME_ENABLEMENT, WC_DH_HAVE_RUNTIME_ENABLEMENT.
Place the enablement check AFTER key->heap/trustedGroup init in the five entry
points (wc_InitDhKey_ex, wc_DhGenerateKeyPair, wc_DhAgree, wc_DhAgree_ct,
_DhSetKey) so a disabled-DH early return never leaves a half-initialized key for
wc_FreeDhKey to mp_clear on garbage.

configure.ac: add --enable-dh=conditional; when DH is enabled (directly or via
all-crypto) set it initially usable under FIPS v7 with
-DWC_DH_INITIAL_RUNTIME_ENABLEMENT=1; remove the FIPS-v7 DH force-off (in FIPS
v7+, disable build by default, unless building in kernel mode with DH
registration enabled).

linuxkm/lkcapi_glue.c: bracket LKCAPI registration with
`need_dh_disable = (wc_dh_enable() == 0)` ... `if (need_dh_disable)
wc_dh_disable();`, so DH is disabled on every exit path, and only by the caller
that actually enabled it (wc_dh_enable returns ALREADY_E if DH was already on,
so this never disables a DH some other context legitimately enabled).

tests/unit.c, wolfcrypt/test/test.c: bracket the DH tests with enable/disable so
they succeed regardless of runtime initial default enablement.
This commit is contained in:
Daniel Pouzzner
2026-08-05 13:53:45 -05:00
parent df972c5266
commit eedceef23d
6 changed files with 140 additions and 11 deletions
+44 -10
View File
@@ -1698,6 +1698,7 @@ then
test "$enable_md5" = "" && enable_md5=yes
test "$enable_ssh" = "" && test "$enable_hmac" != "no" && enable_ssh=yes
test "$enable_rng_bank" = "" && enable_rng_bank=yes
test "$enable_dh" = "" && enable_dh=yes
if test "$KERNEL_MODE_DEFAULTS" != "yes"
then
@@ -1742,7 +1743,7 @@ then
test "$enable_pkcallbacks" = "" && enable_pkcallbacks=yes
fi
if test "$ENABLED_FIPS" = "no" || test "$HAVE_FIPS_VERSION" -lt 7
if test "$enable_dh" = "yes"
then
# Enable DH const table speedups (eliminates `-lm` math lib dependency)
AM_CFLAGS="$AM_CFLAGS -DHAVE_FFDHE_2048 -DHAVE_FFDHE_3072"
@@ -1775,6 +1776,8 @@ then
AM_CFLAGS="$AM_CFLAGS -DHAVE_AES_DECRYPT -DHAVE_AES_ECB -DWOLFSSL_ALT_NAMES"
# Caution, asym key bits above 4096 can disrupt TLS fragment size dynamics
# (see tests/test-maxfrag.conf).
DEFAULT_MAX_CLASSIC_ASYM_KEY_BITS=4096
# Enable all parsing features for ASN */
@@ -1842,13 +1845,31 @@ then
test "$enable_shake256" = "" && test "$enable_sha3" = "yes" && enable_shake256=yes
test "$enable_compkey" = "" && enable_compkey=yes
fi
if test "$ENABLED_FIPS" = "no" || test "$HAVE_FIPS_VERSION" -lt 7
# Enable DH even for FIPS v7, to allow non-FIPS pro forma DH in kernel
# modules (effectively disabling it kernel-wide at runtime). The
# "conditional" value leaves it disabled (unusable) after registration.
if test "$HAVE_FIPS_VERSION" -ge 7 && test "$enable_dh" = "" && test "$enable_linuxkm_lkcapi_register" != ""
then
# Enable DH const table speedups (eliminates `-lm` math lib dependency)
AM_CFLAGS="$AM_CFLAGS -DHAVE_FFDHE_2048 -DHAVE_FFDHE_3072"
for lkcapi_alg in $(echo "$enable_linuxkm_lkcapi_register" | tr ',' ' ')
do
case "$lkcapi_alg" in
all | all-kconfig | dh) enable_dh=conditional ;;
esac
done
for lkcapi_alg in $(echo "$enable_linuxkm_lkcapi_register" | tr ',' ' ')
do
case "$lkcapi_alg" in
-dh) enable_dh="" ;;
esac
done
fi
# Enable WOLFSSL_DH_EXTRA and DH const table speedups (eliminates `-lm` math lib dependency)
# No effect if DH is disabled.
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DH_EXTRA -DHAVE_FFDHE_2048 -DHAVE_FFDHE_3072"
DEFAULT_MAX_CLASSIC_ASYM_KEY_BITS=4096
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DH_EXTRA"
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ECDSA_DETERMINISTIC_K_VARIANT"
fi
@@ -6345,16 +6366,28 @@ then
ENABLED_DH_DEFAULT=yes
else
ENABLED_DH_DEFAULT=no
# DH is outside the boundary in FIPS v7+, but if it's enabled directly or
# via --enable-all-crypto, then callers and the test suite will expect it to
# work.
if test "$enable_dh" = "yes"
then
AM_CFLAGS="$AM_CFLAGS -DWC_DH_INITIAL_RUNTIME_ENABLEMENT=1"
fi
fi
if test "$enable_dh" = "conditional"
then
AM_CFLAGS="$AM_CFLAGS -DWC_DH_INITIAL_RUNTIME_ENABLEMENT=0"
enable_dh=yes
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])],
[AS_HELP_STRING([--enable-dh],[Enable DH (default: ${ENABLED_DH_DEFAULT}). Set to "nonblock" to enable non-blocking DH key agreement via SP small mod_exp_nb])],
[ ENABLED_DH=$enableval ],
[ 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"
@@ -6987,9 +7020,10 @@ AS_CASE([$FIPS_VERSION],
(test "$ENABLED_FIPS_DEV" != "yes" || 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"])
# DH is outside the FIPS v7 boundary and off by default in v7, but freely
# configurable for non-FIPS use, provided the user first calls wc_dh_enable(),
# defines WC_DH_INITIAL_RUNTIME_ENABLEMENT to 1, or enables it explicitly with
# --enable-dh or indirectly with --enable-all-crypto.
AS_IF([test "$ENABLED_ECC" != "yes" &&
(test "$ENABLED_FIPS_DEV" != "yes" || test "$enable_ecc" != "no")],
+11
View File
@@ -708,6 +708,11 @@ static int linuxkm_lkcapi_register(void)
#endif
#ifdef LINUXKM_LKCAPI_REGISTER_DH
{
#ifdef WC_DH_HAVE_RUNTIME_ENABLEMENT
int need_dh_disable = (wc_dh_enable() == 0);
#endif
#ifdef HAVE_FFDHE_2048
REGISTER_ALG(ffdhe2048, kpp, linuxkm_test_ffdhe2048);
#endif /* HAVE_FFDHE_2048 */
@@ -731,6 +736,12 @@ static int linuxkm_lkcapi_register(void)
#ifdef LINUXKM_DH
REGISTER_ALG(dh, kpp, linuxkm_test_dh);
#endif /* LINUXKM_DH */
#ifdef WC_DH_HAVE_RUNTIME_ENABLEMENT
if (need_dh_disable)
(void)wc_dh_disable();
#endif
}
#endif /* LINUXKM_LKCAPI_REGISTER_DH */
#undef REGISTER_ALG
+10
View File
@@ -79,8 +79,13 @@ int unit_test(int argc, char** argv)
{
int ret = 0;
#ifdef WC_DH_HAVE_RUNTIME_ENABLEMENT
int need_dh_disable = (wc_dh_enable() == 0);
#endif
(void)argc;
(void)argv;
#ifdef WOLFSSL_FORCE_MALLOC_FAIL_TEST
if (argc > 1) {
int memFailCount = atoi(argv[1]);
@@ -408,5 +413,10 @@ exit:
fflush(stdout);
}
#ifdef WC_DH_HAVE_RUNTIME_ENABLEMENT
if (need_dh_disable)
(void)wc_dh_disable();
#endif
return ret;
}
+48
View File
@@ -57,6 +57,29 @@
}
#endif
#ifdef WC_DH_INITIAL_RUNTIME_ENABLEMENT
static volatile int wc_dh_enabled = WC_DH_INITIAL_RUNTIME_ENABLEMENT;
int wc_dh_enable(void) {
if (wc_dh_enabled)
return ALREADY_E;
else {
wc_dh_enabled = 1;
return 0;
}
}
int wc_dh_disable(void) {
if (wc_dh_enabled) {
wc_dh_enabled = 0;
return 0;
}
else
return ALREADY_E;
}
int wc_dh_is_enabled(void) {
return wc_dh_enabled;
}
#endif
/*
Possible DH enable options:
* NO_RSA: Overall control of DH default: on (not defined)
@@ -943,6 +966,11 @@ int wc_InitDhKey_ex(DhKey* key, void* heap, int devId)
key->heap = heap; /* for XMALLOC/XFREE in future */
key->trustedGroup = 0;
#ifdef WC_DH_INITIAL_RUNTIME_ENABLEMENT
if (! wc_dh_enabled)
return FIPS_NOT_ALLOWED_E;
#endif
#ifdef WOLFSSL_DH_EXTRA
if (mp_init_multi(&key->p, &key->g, &key->q, &key->pub, &key->priv, NULL) != MP_OKAY)
#else
@@ -2012,6 +2040,11 @@ int wc_DhGenerateKeyPair(DhKey* key, WC_RNG* rng,
return BAD_FUNC_ARG;
}
#ifdef WC_DH_INITIAL_RUNTIME_ENABLEMENT
if (! wc_dh_enabled)
return FIPS_NOT_ALLOWED_E;
#endif
#ifdef WOLFSSL_KCAPI_DH
(void)priv;
(void)privSz;
@@ -2381,6 +2414,11 @@ int wc_DhAgree(DhKey* key, byte* agree, word32* agreeSz, const byte* priv,
return BAD_FUNC_ARG;
}
#ifdef WC_DH_INITIAL_RUNTIME_ENABLEMENT
if (! wc_dh_enabled)
return FIPS_NOT_ALLOWED_E;
#endif
#ifdef WOLFSSL_KCAPI_DH
(void)priv;
(void)privSz;
@@ -2424,6 +2462,11 @@ int wc_DhAgree_ct(DhKey* key, byte* agree, word32 *agreeSz, const byte* priv,
return BAD_FUNC_ARG;
}
#ifdef WC_DH_INITIAL_RUNTIME_ENABLEMENT
if (! wc_dh_enabled)
return FIPS_NOT_ALLOWED_E;
#endif
requested_agreeSz = (word32)mp_unsigned_bin_size(&key->p);
if (requested_agreeSz > *agreeSz) {
return BUFFER_E;
@@ -2594,6 +2637,11 @@ static int _DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
ret = BAD_FUNC_ARG;
}
#ifdef WC_DH_INITIAL_RUNTIME_ENABLEMENT
if ((ret == 0) && (! wc_dh_enabled))
ret = FIPS_NOT_ALLOWED_E;
#endif
if (ret == 0) {
/* may have leading 0 */
if (p[0] == 0) {
+15 -1
View File
@@ -32315,7 +32315,9 @@ static wc_test_ret_t dh_key_import_export_test(DhKey* key, DhKey* key2,
/* for HAVE_WOLF_BIGINT prevent leak */
wc_FreeDhKey(key);
(void)wc_InitDhKey_ex(key, HEAP_HINT, devId);
ret = wc_InitDhKey_ex(key, HEAP_HINT, devId);
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_dh_import_export);
idx = 0;
XMEMSET(tmp2, 0, DH_TEST_TMP_SIZE);
@@ -32381,6 +32383,9 @@ exit_dh_set_check:
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t dh_test(void)
{
#ifdef WC_DH_HAVE_RUNTIME_ENABLEMENT
int need_dh_disable = 0;
#endif
wc_test_ret_t ret;
word32 bytes;
word32 idx = 0;
@@ -32426,6 +32431,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t dh_test(void)
#endif
#endif /* !WC_NO_RNG */
#ifdef WC_DH_HAVE_RUNTIME_ENABLEMENT
need_dh_disable = (wc_dh_enable() == 0);
#endif
WOLFSSL_ENTER("dh_test");
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
@@ -32664,6 +32673,11 @@ done:
(void)pubSz2;
(void)privSz2;
#ifdef WC_DH_HAVE_RUNTIME_ENABLEMENT
if (need_dh_disable)
(void)wc_dh_disable();
#endif
return ret;
}
+12
View File
@@ -161,6 +161,18 @@ enum {
WOLFSSL_LOCAL int wolfCrypt_FIPS_DH_sanity(void);
#endif
#if FIPS_VERSION3_GE(7,0,0) || defined(WC_DH_INITIAL_RUNTIME_ENABLEMENT)
#ifndef WC_DH_INITIAL_RUNTIME_ENABLEMENT
#define WC_DH_INITIAL_RUNTIME_ENABLEMENT 0
#endif
#define WC_DH_HAVE_RUNTIME_ENABLEMENT
WOLFSSL_API int wc_dh_enable(void);
WOLFSSL_API int wc_dh_disable(void);
WOLFSSL_API int wc_dh_is_enabled(void);
#else
#undef WC_DH_HAVE_RUNTIME_ENABLEMENT
#endif
#ifdef HAVE_PUBLIC_FFDHE
#ifdef HAVE_FFDHE_2048
WOLFSSL_API const DhParams* wc_Dh_ffdhe2048_Get(void);