Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
f95bbdf
Reject HMAC keys longer than 1024 bits in the FIPS v7 approved mode, …
jackctj117 Sep 2, 2026
f4c807a
Refuse ECDSA key pair generation and signature generation on curves b…
jackctj117 Sep 2, 2026
e8c2bf4
Expect the FIPS v7 1024-bit HMAC key maximum from the long RFC 4231 s…
jackctj117 Sep 2, 2026
b5de09c
Expect the FIPS v7 generic HKDF wrappers to refuse SHA-1 per SP 800-5…
jackctj117 Sep 2, 2026
184d188
Gate FIPS v7 wrapper expectations on !FIPS_NO_WRAPPERS
jackctj117 Oct 20, 2026
51f6a14
Return BAD_FUNC_ARG for a too-small FIPS v7 ECC keygen keysize
jackctj117 Oct 20, 2026
06c40ea
Exempt the TLS PRF from the FIPS v7 HMAC key maximum
jackctj117 Oct 20, 2026
60df2ce
Keep the HMAC minimum key length for the FIPS v7 TLS PRF
jackctj117 Oct 21, 2026
6c19eae
Let linuxkm HMAC keys above the FIPS v7 cap through
jackctj117 Oct 21, 2026
8b9e8c5
Apply the FIPS v7 ECDSA signing curve minimum ahead of crypto-callbac…
jackctj117 Nov 11, 2026
1d28d81
Enforce the FIPS v7 HMAC key maximum in the KCAPI wc_HmacSetKey()
jackctj117 Nov 11, 2026
0ee2cce
Exempt linuxkm HMAC from the FIPS v7 key maximum only when the kernel…
jackctj117 Nov 11, 2026
1d5b629
Test the FIPS v7 ECC keygen and signing curve gates and the wc_PRF se…
jackctj117 Nov 11, 2026
3363684
Expect the FIPS v7 HKDF SHA-1 refusal only when fips.h defines WC_HAV…
jackctj117 Nov 12, 2026
01fdb6a
Provide a KCAPI wc_HmacSetKey_ex so the key is set on the backend tha…
jackctj117 Nov 12, 2026
3381929
Recheck the FIPS v7 signing curve minimum after a crypto callback res…
jackctj117 Nov 12, 2026
81ea11b
Drop the FIPS v7 HMAC key maximum: the CAVP harness HMAC vectors use …
jackctj117 Nov 12, 2026
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
26 changes: 26 additions & 0 deletions tests/api/test_ecc.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,15 @@ int test_wc_ecc_make_key(void)
ExpectIntEQ(wc_ecc_make_key(&rng, KEY14, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));

#if FIPS_VERSION3_GE(7,0,0)
/* v7 refuses key generation on a named curve below 224 bits even when
* the requested key size is large enough. */
wc_ecc_free(&key);
ExpectIntEQ(wc_ecc_init(&key), 0);
ExpectIntEQ(wc_ecc_make_key_ex(&rng, 32, &key, ECC_SECP192R1),
WC_NO_ERR_TRACE(ECC_CURVE_OID_E));
#endif

DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ecc_free(&key);

Expand Down Expand Up @@ -600,6 +609,23 @@ int test_wc_ecc_signVerify_hash(void)
#endif
#endif /* HAVE_ECC_VERIFY */

#if FIPS_VERSION3_GE(7,0,0) && \
(defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)) && \
(ECC_MIN_KEY_SZ <= 192)
/* v7 refuses to sign on a curve below 224 bits. Key generation there is
* refused too, so import a P-192 key (d = 1, Q = G). */
wc_ecc_free(&key);
ExpectIntEQ(wc_ecc_init(&key), 0);
ExpectIntEQ(wc_ecc_import_raw_ex(&key,
"188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",
"07192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
"000000000000000000000000000000000000000000000001",
ECC_SECP192R1), 0);
siglen = ECC_BUFSIZE;
ExpectIntEQ(wc_ecc_sign_hash(digest, digestlen, sig, &siglen, &rng, &key),
WC_NO_ERR_TRACE(SIG_TYPE_E));
#endif

DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ecc_free(&key);

Expand Down
75 changes: 74 additions & 1 deletion wolfcrypt/src/ecc.c
Original file line number Diff line number Diff line change
Expand Up @@ -6532,6 +6532,27 @@ int wc_ecc_make_key_ex2(WC_RNG* rng, int keysize, ecc_key* key, int curve_id,
{
int err;

#if FIPS_VERSION3_GE(7,0,0)
/* SP 800-131A Rev. 2 Table 2 disallows ECDSA key pair generation
* providing fewer than 112 bits of security strength (len(n) < 224), and
* SP 800-186 Section 3.2.1.1 retains P-192 for legacy use only, so
* refuse to generate on any curve smaller than 224 bits. The bound
* mirrors wc_ecc_set_curve(): an explicit curve_id selects the curve
* directly, otherwise keysize selects the smallest compiled curve that
* fits, so keysize 0 would land on the smallest compiled curve and is
* rejected too. Signature verification with the small curves stays
* available (legacy use per SP 800-131A Rev. 2 Table 2). */
if (curve_id > ECC_CURVE_DEF) {
if (wc_ecc_get_curve_size_from_id(curve_id) < WC_ECC_FIPS_GEN_MIN) {
return ECC_CURVE_OID_E;
}
}
else if (keysize < WC_ECC_FIPS_GEN_MIN) {
/* Same code the fips.c keygen wrappers return for this case. */
return BAD_FUNC_ARG;
}
#endif

err = _ecc_make_key_ex(rng, keysize, key, curve_id, flags);

#if (FIPS_VERSION_GE(5,0) || defined(WOLFSSL_VALIDATE_ECC_KEYGEN)) && \
Expand Down Expand Up @@ -7229,6 +7250,25 @@ static int wc_ecc_sign_hash_async(const byte* in, word32 inlen, byte* out,
}
#endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_ECC */

#if FIPS_VERSION3_GE(7,0,0)
/* SP 800-131A Rev. 2 Table 2: ECDSA digital signature generation with
* len(n) < 224 is disallowed, while signature verification with those
* curves remains legacy use, so only the signing paths are gated. Every
* signing entry point calls this ahead of any crypto-callback or hardware
* dispatch, so no backend signs on a too-small curve. The curve is resolved
* from key->dp, never from ecc_sets[key->idx], so a custom-curve key
* (idx == ECC_CUSTOM_IDX) cannot index out of range. A key with no curve
* set is left to the caller's own argument checks; wc_ecc_sign_hash()
* checks again after a crypto callback has had the chance to resolve it. */
static int ecc_fips_sign_curve_allowed(const ecc_key* key)
{
if ((key->dp != NULL) && (key->dp->size < WC_ECC_FIPS_GEN_MIN)) {
Comment thread
jackctj117 marked this conversation as resolved.
Resolved
return SIG_TYPE_E;
}
return 0;
}
#endif /* FIPS_VERSION3_GE(7,0,0) */

/**
Sign a message digest
in The message digest to sign
Expand Down Expand Up @@ -7264,14 +7304,33 @@ int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen,
return BAD_LENGTH_E;
}

#if FIPS_VERSION3_GE(7,0,0)
err = ecc_fips_sign_curve_allowed(key);
if (err != 0) {
return err;
}
#endif

#ifdef WOLF_CRYPTO_CB
#ifndef WOLF_CRYPTO_CB_FIND
if (key->devId != INVALID_DEVID)
#endif
{
err = wc_CryptoCb_EccSign(in, inlen, out, outlen, rng, key);
if (err != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
if (err != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
#if FIPS_VERSION3_GE(7,0,0)
/* A key referenced by id or label has no curve until the
* callback resolves it, so it passed the check above. Check
* again and do not release a signature made on a too-small
* curve. */
if ((err == 0) && (ecc_fips_sign_curve_allowed(key) != 0)) {
ForceZero(out, *outlen);
*outlen = 0;
err = SIG_TYPE_E;
}
#endif
return err;
}
/* fall-through when unavailable */
}
#endif
Expand Down Expand Up @@ -7495,6 +7554,12 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng,
return ECC_BAD_ARG_E;
#endif

#if FIPS_VERSION3_GE(7,0,0)
if (ecc_fips_sign_curve_allowed(key) != 0) {
return SIG_TYPE_E;
}
#endif

return stm32_ecc_sign_hash_ex(in, inlen, rng, key, r, s);
}

Expand Down Expand Up @@ -7893,6 +7958,14 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng,
return ECC_BAD_ARG_E;
}

#if FIPS_VERSION3_GE(7,0,0)
/* wc_ecc_sign_hash_ex() is public, so it is gated as well as
* wc_ecc_sign_hash(). */
if (ecc_fips_sign_curve_allowed(key) != 0) {
return SIG_TYPE_E;
}
#endif

#if defined(WOLFSSL_SP_MATH)
if (key->idx == ECC_CUSTOM_IDX || (1
#ifndef WOLFSSL_SP_NO_256
Expand Down
2 changes: 2 additions & 0 deletions wolfcrypt/src/hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@

/* map the _Software calls used by kcapi_hmac.c */
#define wc_HmacSetKey wc_HmacSetKey_Software
#define wc_HmacSetKey_ex wc_HmacSetKey_ex_Software
#define wc_HmacUpdate wc_HmacUpdate_Software
#define wc_HmacFinal wc_HmacFinal_Software
#endif
Expand Down Expand Up @@ -1727,6 +1728,7 @@ int wc_HmacFinal(Hmac* hmac, byte* hash)

/* unmap the _Software calls used by kcapi_hmac.c */
#undef wc_HmacSetKey
#undef wc_HmacSetKey_ex
#undef wc_HmacUpdate
#undef wc_HmacFinal

Expand Down
41 changes: 31 additions & 10 deletions wolfcrypt/src/port/kcapi/kcapi_hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,12 @@ void wc_HmacFree(Hmac* hmac)
}
}

int wc_HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length)
/* KCAPI counterpart of the software wc_HmacSetKey_ex(): callers that pass
* allowFlag (the TLS PRF, HKDF, PBKDF2) then use wc_HmacUpdate() and
* wc_HmacFinal() from this file, so the key has to be set on the same
* backend. */
int wc_HmacSetKey_ex(Hmac* hmac, int type, const byte* key, word32 length,
int allowFlag)
{
int ret = 0;
const char* ciphername = NULL;
Expand All @@ -107,23 +112,29 @@ int wc_HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length)
#endif

#ifdef HAVE_FIPS
if (length < HMAC_FIPS_MIN_KEY)
return HMAC_MIN_KEYLEN_E;
if (!allowFlag) {
if (length < HMAC_FIPS_MIN_KEY)
return HMAC_MIN_KEYLEN_E;
}
#else
(void)allowFlag;
#endif

if (ret == 0) {
switch (type) {
#ifndef NO_MD5
case WC_MD5:
return wc_HmacSetKey_Software(hmac, type, key, length);
return wc_HmacSetKey_ex_Software(hmac, type, key, length,
allowFlag);
#endif
#ifndef NO_SHA
case WC_SHA:
#if !defined(WOLFSSL_NO_KCAPI_HMAC_SHA1)
ciphername = WC_NAME_HMAC_SHA1;
break;
#else
return wc_HmacSetKey_Software(hmac, type, key, length);
return wc_HmacSetKey_ex_Software(hmac, type, key, length,
allowFlag);
#endif
#endif
#ifdef WOLFSSL_SHA224
Expand All @@ -132,7 +143,8 @@ int wc_HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length)
ciphername = WC_NAME_HMAC_SHA224;
break;
#else
return wc_HmacSetKey_Software(hmac, type, key, length);
return wc_HmacSetKey_ex_Software(hmac, type, key, length,
allowFlag);
#endif
#endif
#ifndef NO_SHA256
Expand All @@ -141,7 +153,8 @@ int wc_HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length)
ciphername = WC_NAME_HMAC_SHA256;
break;
#else
return wc_HmacSetKey_Software(hmac, type, key, length);
return wc_HmacSetKey_ex_Software(hmac, type, key, length,
allowFlag);
#endif
#endif
#ifdef WOLFSSL_SHA384
Expand All @@ -150,7 +163,8 @@ int wc_HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length)
ciphername = WC_NAME_HMAC_SHA384;
break;
#else
return wc_HmacSetKey_Software(hmac, type, key, length);
return wc_HmacSetKey_ex_Software(hmac, type, key, length,
allowFlag);
#endif
#endif
#ifdef WOLFSSL_SHA512
Expand All @@ -159,7 +173,8 @@ int wc_HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length)
ciphername = WC_NAME_HMAC_SHA512;
break;
#else
return wc_HmacSetKey_Software(hmac, type, key, length);
return wc_HmacSetKey_ex_Software(hmac, type, key, length,
allowFlag);
#endif
#endif
#ifdef WOLFSSL_SHA3
Expand All @@ -175,7 +190,8 @@ int wc_HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length)
#ifndef WOLFSSL_NOSHA3_512
case WC_SHA3_512:
#endif
return wc_HmacSetKey_Software(hmac, type, key, length);
return wc_HmacSetKey_ex_Software(hmac, type, key, length,
allowFlag);
#endif
default:
ret = BAD_FUNC_ARG;
Expand Down Expand Up @@ -204,6 +220,11 @@ int wc_HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length)
return ret;
}

int wc_HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length)
{
return wc_HmacSetKey_ex(hmac, type, key, length, 0);
}

int wc_HmacUpdate(Hmac* hmac, const byte* msg, word32 length)
{
int ret = 0;
Expand Down
24 changes: 24 additions & 0 deletions wolfcrypt/test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -12274,6 +12274,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hmac_sha_test(void)
#endif
}


out:

wc_HmacFree(&hmac);
Expand Down Expand Up @@ -50521,6 +50522,26 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hkdf_test(void)
#endif /* !NO_SHA256 */

#ifndef NO_SHA
#if FIPS_VERSION3_GE(7,0,0) && defined(WC_HAVE_FIPS_INDICATOR) && \
!defined(FIPS_NO_WRAPPERS)
/* SP 800-56C Rev. 2 Section 4 approves the HKDF auxiliary function only
* with an approved hash and the module's key-derivation coverage is
* SHA-256/384/512, so the generic wrappers refuse SHA-1 (see
* HkdfDigestAllowed in fips.c). */
PRIVATE_KEY_UNLOCK();
ret = wc_HKDF_Extract_ex(WC_SHA, NULL, 0, ikm1, (word32)sizeof(ikm1),
prk, HEAP_HINT, devId);
PRIVATE_KEY_LOCK();
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_EC(ret);
PRIVATE_KEY_UNLOCK();
ret = wc_HKDF_Expand_ex(WC_SHA, prk, WC_SHA_DIGEST_SIZE, NULL, 0,
okm1, (word32)L, HEAP_HINT, devId);
PRIVATE_KEY_LOCK();
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_EC(ret);
ret = 0;
#else
PRIVATE_KEY_UNLOCK();
#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0))
ret = wc_HKDF_Extract_ex(WC_SHA, NULL, 0, ikm1, (word32)sizeof(ikm1),
Expand All @@ -50546,6 +50567,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hkdf_test(void)

if (XMEMCMP(okm1, res1, (unsigned long)L) != 0)
return WC_TEST_RET_ENC_NC;
#endif /* FIPS_VERSION3_GE(7,0,0) && WC_HAVE_FIPS_INDICATOR &&
* !FIPS_NO_WRAPPERS */

#ifndef HAVE_FIPS
/* fips can't have key size under 14 bytes, salt is key too */
Expand Down Expand Up @@ -50886,6 +50909,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t prf_test(void)
return WC_TEST_RET_ENC_NC;
}


return 0;
}
#endif /* WOLFSSL_HAVE_PRF && !NO_HMAC && WOLFSSL_SHA384 && !WOLFSSL_NO_TLS12 */
Expand Down
3 changes: 3 additions & 0 deletions wolfssl/wolfcrypt/hmac.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ WOLFSSL_API int wc_HmacFinal(Hmac* hmac, byte* hash);
#ifdef WOLFSSL_KCAPI_HMAC
WOLFSSL_API int wc_HmacSetKey_Software(Hmac* hmac, int type, const byte* key,
word32 keySz);
WOLFSSL_API int wc_HmacSetKey_ex_Software(Hmac* hmac, int type,
const byte* key, word32 keySz,
int allowFlag);
WOLFSSL_API int wc_HmacUpdate_Software(Hmac* hmac, const byte* in, word32 sz);
WOLFSSL_API int wc_HmacFinal_Software(Hmac* hmac, byte* out);
#endif
Expand Down
Loading