1
0
mirror of https://github.com/wolfSSL/wolfssl.git synced 2026-10-24 04:09:07 +03:00

Fix key-free condition, lock balance and bench portability nits

This commit is contained in:
kaleb-himes
2026-08-28 15:56:42 -06:00
parent 0a940443ed
commit 8fd39b8af3
6 changed files with 100 additions and 52 deletions

View File

@@ -95,13 +95,12 @@ static const char* cast_name(int id)
case FIPS_CAST_KDF_TLS12: return "KDF-TLS12";
case FIPS_CAST_KDF_TLS13: return "KDF-TLS13";
case FIPS_CAST_KDF_SSH: return "KDF-SSH";
#if defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(6,0)
/* No inner version guards: this file only compiles for v7.0.0+
* (see the #if at the top), where every id below exists. */
case FIPS_CAST_KDF_SRTP: return "KDF-SRTP";
case FIPS_CAST_ED25519: return "Ed25519";
case FIPS_CAST_ED448: return "Ed448";
case FIPS_CAST_PBKDF2: return "PBKDF2";
#endif
#if defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(7,0)
case FIPS_CAST_AES_ECB: return "AES-ECB";
case FIPS_CAST_ML_KEM: return "ML-KEM";
case FIPS_CAST_ML_DSA: return "ML-DSA";
@@ -112,7 +111,6 @@ static const char* cast_name(int id)
case FIPS_CAST_AES_CMAC: return "AES-CMAC";
case FIPS_CAST_SHAKE: return "SHAKE";
case FIPS_CAST_AES_KW: return "AES-KW";
#endif
default: return "(unknown)";
}
}
@@ -141,6 +139,15 @@ static double bench_now(void)
}
/* Elapsed seconds, never negative. bench_now() returns -1.0 if the clock
* fails, and a negative interval would corrupt the statistics. */
static double bench_delta(double t0, double t1)
{
double dt = t1 - t0;
return (dt > 0.0) ? dt : 0.0;
}
/* Run a single CAST iters times, populate stats (in milliseconds).
* Returns 0 on success, non-zero on first CAST failure. */
static int run_one_cast(int id, int iters,
@@ -166,9 +173,7 @@ static int run_one_cast(int id, int iters,
t1 = bench_now();
if (rc != 0)
return rc;
dt = t1 - t0;
if (dt < 0.0)
dt = 0.0;
dt = bench_delta(t0, t1);
if ((i == 0) || (dt < mn))
mn = dt;
if (dt > mx)
@@ -323,7 +328,7 @@ static int bench_pct_mlkem(int iters)
t1 = bench_now();
if (rc != 0)
break;
kg_s += t1 - t0;
kg_s += bench_delta(t0, t1);
t0 = bench_now();
rc = wc_MlKemKey_CipherTextSize(&key, &ctSz);
@@ -338,7 +343,7 @@ static int bench_pct_mlkem(int iters)
t1 = bench_now();
if (rc != 0)
break;
pct_s += t1 - t0;
pct_s += bench_delta(t0, t1);
}
if (rc != 0) {
@@ -416,7 +421,7 @@ static int bench_pct_mldsa(int iters)
t1 = bench_now();
if (rc != 0)
break;
kg_s += t1 - t0;
kg_s += bench_delta(t0, t1);
t0 = bench_now();
rc = wc_MlDsaKey_SignCtxWithSeed(&key, NULL, 0, sig, &sigSz,
@@ -430,7 +435,7 @@ static int bench_pct_mldsa(int iters)
t1 = bench_now();
if (rc != 0)
break;
pct_s += t1 - t0;
pct_s += bench_delta(t0, t1);
}
if (rc != 0) {
@@ -491,6 +496,7 @@ static int bench_pct_slhdsa(int iters)
byte sk_seed[BENCH_SLHDSA_MAX_N];
byte sk_prf[BENCH_SLHDSA_MAX_N];
byte pk_seed[BENCH_SLHDSA_MAX_N];
byte priv[BENCH_SLHDSA_MAX_N * 4];
byte pub[BENCH_SLHDSA_MAX_N * 2];
int failures = 0;
size_t t;
@@ -541,6 +547,7 @@ static int bench_pct_slhdsa(int iters)
for (i = 0; i < iters; i++) {
double t0, t1;
word32 sigSz = (word32)sigLen;
word32 pl = (word32)privLen;
word32 ul = (word32)(n * 2);
XMEMSET(sk_seed, (byte)(0x11 + i), (size_t)n);
@@ -553,7 +560,7 @@ static int bench_pct_slhdsa(int iters)
t1 = bench_now();
if (rc != 0)
break;
kg_s += t1 - t0;
kg_s += bench_delta(t0, t1);
/* The alternative not taken, timed for comparison. */
t0 = bench_now();
@@ -566,19 +573,21 @@ static int bench_pct_slhdsa(int iters)
t1 = bench_now();
if (rc != 0)
break;
a_s += t1 - t0;
a_s += bench_delta(t0, t1);
/* The IG shortcut. See bench_pct_slhdsa_notes(). */
t0 = bench_now();
rc = wc_SlhDsaKey_ExportPublic(&key, pub, &ul);
if ((rc == 0) && (XMEMCMP(pub, key.sk + (size_t)(n * 2),
rc = wc_SlhDsaKey_ExportPrivate(&key, priv, &pl);
if (rc == 0)
rc = wc_SlhDsaKey_ExportPublic(&key, pub, &ul);
if ((rc == 0) && (XMEMCMP(priv + (size_t)(n * 2), pub,
(size_t)n) != 0)) {
rc = SLH_DSA_PCT_E;
}
t1 = bench_now();
if (rc != 0)
break;
c_s += t1 - t0;
c_s += bench_delta(t0, t1);
}
if (rc != 0) {
@@ -624,6 +633,7 @@ static int bench_pct(int iters, const char* only)
int ran = 0;
#ifdef BENCH_HAVE_PCT
int rc;
int err = 0;
#endif
#ifndef BENCH_HAVE_PCT
@@ -647,30 +657,36 @@ static int bench_pct(int iters, const char* only)
* error if it could not run. Keep those apart: summing them lets a
* -125 cancel real failures and report success. */
#ifdef WOLFSSL_HAVE_MLKEM
if ((only == NULL) || (XSTRCMP(only, "mlkem") == 0)) {
if ((err == 0) && ((only == NULL) || (XSTRCMP(only, "mlkem") == 0))) {
rc = bench_pct_mlkem(iters);
if (rc < 0)
return rc;
failures += rc;
ran++;
err = rc;
else {
failures += rc;
ran++;
}
}
#endif
#ifdef WOLFSSL_HAVE_MLDSA
if ((only == NULL) || (XSTRCMP(only, "mldsa") == 0)) {
if ((err == 0) && ((only == NULL) || (XSTRCMP(only, "mldsa") == 0))) {
rc = bench_pct_mldsa(iters);
if (rc < 0)
return rc;
failures += rc;
ran++;
err = rc;
else {
failures += rc;
ran++;
}
}
#endif
#ifdef WOLFSSL_HAVE_SLHDSA
if ((only == NULL) || (XSTRCMP(only, "slhdsa") == 0)) {
if ((err == 0) && ((only == NULL) || (XSTRCMP(only, "slhdsa") == 0))) {
rc = bench_pct_slhdsa(iters);
if (rc < 0)
return rc;
failures += rc;
ran++;
err = rc;
else {
failures += rc;
ran++;
}
}
#endif
@@ -678,6 +694,10 @@ static int bench_pct(int iters, const char* only)
* which reads as "measured, costs nothing". */
#ifdef BENCH_HAVE_PCT
PRIVATE_KEY_LOCK();
/* Returned only after the lock is restored: an early return above would
* leave private-key operations unlocked for the whole process. */
if (err != 0)
return err;
#endif
if (ran == 0) {
@@ -772,6 +792,11 @@ int main(int argc, char** argv)
|| XSTRCMP(argv[i], "--help") == 0) {
usage(argv[0]);
return 0;
} else if ((XSTRCMP(argv[i], "-i") == 0) ||
(XSTRCMP(argv[i], "-c") == 0) ||
(XSTRCMP(argv[i], "-a") == 0)) {
fprintf(stderr, "%s requires a value\n", argv[i]);
return 2;
} else {
fprintf(stderr, "unknown argument: %s\n", argv[i]);
usage(argv[0]);
@@ -792,6 +817,13 @@ int main(int argc, char** argv)
if (pct_only && !iters_set)
iters = BENCH_PCT_DEFAULT_ITERS;
/* Before -l, so an out-of-range -c is rejected whichever mode runs. */
if (single >= FIPS_CAST_COUNT) { /* -1 when -c was not given */
fprintf(stderr, "CAST id %d out of range (0..%d)\n",
single, FIPS_CAST_COUNT - 1);
return 2;
}
if (list_only) {
printf("FIPS CAST IDs (FIPS_CAST_COUNT = %d):\n", FIPS_CAST_COUNT);
for (i = 0; i < FIPS_CAST_COUNT; i++)
@@ -799,12 +831,6 @@ int main(int argc, char** argv)
return 0;
}
if (single >= 0 && single >= FIPS_CAST_COUNT) {
fprintf(stderr, "CAST id %d out of range (0..%d)\n",
single, FIPS_CAST_COUNT - 1);
return 2;
}
printf("wolfCrypt FIPS %s benchmark\n", pct_only ? "PCT" : "CAST");
printf("Library version: %s\n", LIBWOLFSSL_VERSION_STRING);
printf("FIPS_CAST_COUNT: %d\n", FIPS_CAST_COUNT);

View File

@@ -15,7 +15,10 @@ noinst_HEADERS += wolfcrypt/benchmark/benchmark.h
if BUILD_FIPS
noinst_PROGRAMS += wolfcrypt/benchmark/fips_cast_bench
wolfcrypt_benchmark_fips_cast_bench_SOURCES = wolfcrypt/benchmark/fips_cast_bench.c
wolfcrypt_benchmark_fips_cast_bench_LDADD = src/libwolfssl@LIBSUFFIX@.la $(LIB_STATIC_ADD) $(LIBM)
# -lm, not $(LIBM): configure.ac AC_SUBSTs LIBM but never assigns it, so
# $(LIBM) expands to nothing and the sqrt() in fips_cast_bench.c would be left
# to resolve transitively.
wolfcrypt_benchmark_fips_cast_bench_LDADD = src/libwolfssl@LIBSUFFIX@.la $(LIB_STATIC_ADD) -lm
wolfcrypt_benchmark_fips_cast_bench_DEPENDENCIES = src/libwolfssl@LIBSUFFIX@.la
endif

View File

@@ -933,10 +933,13 @@ int wc_CheckRsaKey(RsaKey* key)
ret = WC_KEY_SIZE_E;
}
/* Public exponent: odd, and 65537 <= e < 2^256 (item B). e is an
* mp_int here, so the upper bound needs an explicit bit count. */
/* Public exponent: odd, and 65537 <= e < 2^256 (item B). Bounds are
* bit counts, not mp_cmp_d: a digit can be 8 or 16 bits wide
* (sp_int.h), and 65537 would truncate there. An odd e of at least
* 17 bits is >= 65537, because 65536 is the only 17-bit value below
* it and that one is even. */
if ((ret == 0) && (mp_iseven(&key->e) ||
(mp_cmp_d(&key->e, 65537) == MP_LT) ||
(mp_count_bits(&key->e) < 17) ||
(mp_count_bits(&key->e) > 256))) {
ret = MP_EXPTMOD_E;
}
@@ -983,7 +986,10 @@ int wc_CheckRsaKey(RsaKey* key)
/* Check dP, dQ and u if they exist */
if (ret == 0 && !mp_iszero(&key->dP)) {
#if FIPS_VERSION3_GE(7,0,0)
/* Each CRT component must be greater than 1.
/* Guarded on the version alone, unlike the block above: this needs
* no WOLFSSL_KEY_GEN because it calls no key-generation helper.
*
* Each CRT component must be greater than 1.
* SP 800-56B Rev2 sec 6.4.1.4.3 item F, steps 7a/7b/7c.
* Their upper bounds are checked just below. */
if ((mp_cmp_d(&key->dP, 1) != MP_GT) ||

View File

@@ -9158,11 +9158,11 @@ static int mldsa_pct(wc_MlDsaKey* key)
ForceZero(pct_sig, MLDSA_MAX_SIG_SIZE);
WC_FREE_VAR_EX(pct_sig, key->heap, DYNAMIC_TYPE_MLDSA);
/* Free a key that failed the test, so a caller ignoring the return value
* cannot sign with it. ISO/IEC 19790:2012 sec 7.10.1 forbids using
* anything that failed a self-test. Only on ML_DSA_PCT_E: a MEMORY_E
* here means the test could not run. */
if (ret == ML_DSA_PCT_E) {
/* Free a key that failed the test, so a caller ignoring the return
* value cannot sign with it. ISO/IEC 19790:2012 sec 7.10.1 forbids using
* anything that failed a self-test. MEMORY_E is excluded: it
* means the test never ran, so the key is not implicated. */
if ((ret != 0) && (ret != MEMORY_E)) {
wc_MlDsaKey_Free(key);
}
@@ -11295,6 +11295,16 @@ int wc_MlDsaKey_MakeKey(wc_MlDsaKey* key, WC_RNG* rng)
return ret;
}
/* Expand a seed into an ML-DSA key pair and test it.
*
* @param [in, out] key ML-DSA key to fill in.
* @param [in] seed Seed of MLDSA_SEED_SZ bytes.
* @return 0 on success.
* @return BAD_FUNC_ARG when key or seed is NULL.
* @return BAD_STATE_E when the parameters have not been set.
* @return ML_DSA_PCT_E when the key pair fails its consistency test. The
* key is freed in that case and must be re-initialised before reuse.
*/
int wc_MlDsaKey_MakeKeyFromSeed(wc_MlDsaKey* key, const byte* seed)
{
int ret = 0;

View File

@@ -755,6 +755,8 @@ int wc_MlKemKey_MakeKey(MlKemKey* key, WC_RNG* rng)
* @return NOT_COMPILED_IN when key type is not supported.
* @return MEMORY_E when dynamic memory allocation failed.
* @return BAD_COND_E when fault attack detected.
* @return ML_KEM_PCT_E when the key pair fails its consistency test. The
* key is freed in that case and must be re-initialised before reuse.
*/
int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, const unsigned char* rand,
int len)
@@ -1064,10 +1066,9 @@ for the key-pair test required by ISO/IEC 19790:2012 sec 7.10.3.3"
/* Free a key that failed the test, so a caller ignoring the return
* value cannot use it. ISO/IEC 19790:2012 sec 7.10.1 forbids using
* anything that failed a self-test. Only on ML_KEM_PCT_E: a
* MEMORY_E here means the test could not run, and destroying a
* good key over a transient allocation failure helps no one. */
if (ret == ML_KEM_PCT_E) {
* anything that failed a self-test. MEMORY_E is excluded: it
* means the test never ran, so the key is not implicated. */
if ((ret != 0) && (ret != MEMORY_E)) {
wc_MlKemKey_Free(key);
}
}

View File

@@ -7080,6 +7080,8 @@ int wc_SlhDsaKey_MakeKey(SlhDsaKey* key, WC_RNG* rng)
* @return BAD_FUNC_ARG when pk_seed is NULL or length is not n.
* @return MEMORY_E on dynamic memory allocation failure.
* @return SHAKE-256 error return code on digest failure.
* @return SLH_DSA_PCT_E when the key pair fails its consistency test. The
* key is freed in that case and must be re-initialised before reuse.
*/
int wc_SlhDsaKey_MakeKeyWithRandom(SlhDsaKey* key, const byte* sk_seed,
word32 sk_seed_len, const byte* sk_prf, word32 sk_prf_len,
@@ -7172,10 +7174,10 @@ int wc_SlhDsaKey_MakeKeyWithRandom(SlhDsaKey* key, const byte* sk_seed,
}
/* Free a key that failed the test, so a caller ignoring the return
* value cannot sign with it. ISO/IEC 19790:2012 sec 7.10.1 forbids
* using anything that failed a self-test. Only on SLH_DSA_PCT_E:
* any other error means the test could not run. */
if (ret == SLH_DSA_PCT_E) {
* value cannot sign with it. ISO/IEC 19790:2012 sec 7.10.1 forbids using
* anything that failed a self-test. MEMORY_E is excluded: it
* means the test never ran, so the key is not implicated. */
if ((ret != 0) && (ret != MEMORY_E)) {
wc_SlhDsaKey_Free(key);
}
}