Skip to content

Commit 8923ea5

Browse files
committed
SecurityReview FND 40.2 + FND 36.1: integrity HMAC SHA-512 + SLH-DSA PCT
Two findings from the v7.0.0 security review, squashed into one commit per the Part3 branch invariant. FND 40.2 (in-core integrity HMAC upgraded to SHA-512) FIPS 140-3 v7.0.0 security review: the in-core integrity test must use HMAC-SHA-512 with a 512-bit key for NSA 2.0 compliance (customers requiring no SHA-256 usage anywhere in the validated module). - wolfssl/wolfcrypt/fips_test.h: add v7+ branch that selects SHA-512 / 64-byte digest / 512-bit key / 64-byte verify-size. Older versions (v5.3, v6.x) keep HMAC-SHA-256. - fips-hash.sh: drop the hardcoded cut -c1-64 so the script works for SHA-512 (128 hex chars) as well as SHA-256. Length is guarded at compile time by the static_assert on sizeof(verifyCore). Companion change in kh-fork-fips updates fips_test.c verifyCore placeholder, coreKey (fresh 512-bit random), and the static_assert to use FIPS_IN_CORE_DIGEST_SIZE. Paperwork (PQ-FS-dev-area/Final_Submission_Paperwork/): - PL-R36 compliance summary already reflects HMAC-SHA-512 (no change). - PL-R34 Security Policy section 5.1 updated via tracked changes to say HMAC-SHA2-512 with a 512-bit key. FND 36.1 (SLH-DSA KeyGen now runs a Pairwise Consistency Test) wc_SlhDsaKey_MakeKey previously generated random seeds and delegated to MakeKeyWithRandom without any PCT. ML-KEM and ML-DSA both have inline PCTs citing FIPS 140-3 IG 10.3.A TE10.35.02; SLH-DSA had none. SLH-DSA is a stateless hash-based signature scheme (FIPS 205), so the relaxed PCT rule for stateful HBS (LMS/XMSS) does not apply -- PCT is mandatory on every KeyGen. Changes: - wolfssl/wolfcrypt/error-crypt.h: add SLH_DSA_PCT_E = -1013, shift WC_SPAN2_LAST_E / WC_LAST_E to -1013. - wolfcrypt/src/error.c: add a description string for SLH_DSA_PCT_E. - wolfcrypt/src/wc_slhdsa.c wc_SlhDsaKey_MakeKey: after MakeKeyWithRandom succeeds, sign a fixed PCT message with the new sk using wc_SlhDsaKey_SignDeterministic (no extra RNG state; reproducible) and verify with the matching pk. Signature buffer is heap-allocated (SLH-DSA sigs can be ~50 KB) and ForceZero'd before XFREE. On PCT failure the key is wc_SlhDsaKey_Free'd so a caller that ignores the return value cannot use the broken key pair. Companion fips change: fips.c DEGRADE_STATE handler for SLH_DSA_PCT_E and optest-140-3/optest.h case_1013 entry. Verified: make + fips-hash.sh + make; make check all pass.
1 parent 13d5cd9 commit 8923ea5

5 files changed

Lines changed: 68 additions & 6 deletions

File tree

fips-hash.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ then
1313
fi
1414

1515
OUT=$(./wolfcrypt/test/testwolfcrypt | sed -n 's/hash = \(.*\)/\1/p')
16-
NEWHASH=$(echo "$OUT" | cut -c1-64)
16+
# FIPS v7.0.0+ uses HMAC-SHA-512 (128 hex chars); older FIPS versions
17+
# use HMAC-SHA-256 (64 hex chars). Take the whole captured hash; the
18+
# static_assert on sizeof(verifyCore) guards against wrong length at
19+
# compile time after this script runs.
20+
NEWHASH=$(echo "$OUT" | head -n1 | tr -d '[:space:]')
1721
if test -n "$NEWHASH"
1822
then
1923
cp wolfcrypt/src/fips_test.c wolfcrypt/src/fips_test.c.bak

wolfcrypt/src/error.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,9 @@ const char* wc_GetErrorString(int error)
692692
case SLH_DSA_KAT_FIPS_E:
693693
return "SLH-DSA Known Answer Test check FIPS error";
694694

695+
case SLH_DSA_PCT_E:
696+
return "wolfcrypt SLH-DSA Pairwise Consistency Test Failure";
697+
695698
case SEQ_OVERFLOW_E:
696699
return "Sequence counter would overflow";
697700

wolfcrypt/src/wc_slhdsa.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6570,6 +6570,45 @@ int wc_SlhDsaKey_MakeKey(SlhDsaKey* key, WC_RNG* rng)
65706570
key->sk + 2 * n, n);
65716571
}
65726572

6573+
#ifdef HAVE_FIPS
6574+
/* Pairwise Consistency Test (PCT) per FIPS 140-3 IG 10.3.A (TE10.35.02):
6575+
* sign with the new sk, verify with the matching pk. SLH-DSA is a
6576+
* stateless hash-based signature scheme (FIPS 205), so the relaxed PCT
6577+
* rule for stateful HBS (LMS/XMSS) does not apply -- PCT runs on every
6578+
* KeyGen. SignDeterministic avoids consuming RNG state; heap allocation
6579+
* is used because SLH-DSA signatures can reach ~50 KB. */
6580+
if (ret == 0) {
6581+
static const byte pct_msg[] = "wolfSSL SLH-DSA PCT";
6582+
byte* pct_sig = (byte*)XMALLOC(WC_SLHDSA_MAX_SIG_LEN, NULL,
6583+
DYNAMIC_TYPE_TMP_BUFFER);
6584+
word32 pct_sigSz = WC_SLHDSA_MAX_SIG_LEN;
6585+
6586+
if (pct_sig == NULL) {
6587+
ret = MEMORY_E;
6588+
}
6589+
if (ret == 0) {
6590+
ret = wc_SlhDsaKey_SignDeterministic(key, NULL, 0,
6591+
pct_msg, sizeof(pct_msg), pct_sig, &pct_sigSz);
6592+
}
6593+
if (ret == 0) {
6594+
ret = wc_SlhDsaKey_Verify(key, NULL, 0,
6595+
pct_msg, sizeof(pct_msg), pct_sig, pct_sigSz);
6596+
if (ret != 0) {
6597+
ret = SLH_DSA_PCT_E;
6598+
}
6599+
}
6600+
if (pct_sig != NULL) {
6601+
ForceZero(pct_sig, WC_SLHDSA_MAX_SIG_LEN);
6602+
XFREE(pct_sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
6603+
}
6604+
/* IG 10.3.A (TE10.35.02): a key pair that fails the PCT must be
6605+
* rendered unusable. */
6606+
if (ret != 0) {
6607+
wc_SlhDsaKey_Free(key);
6608+
}
6609+
}
6610+
#endif /* HAVE_FIPS */
6611+
65736612
return ret;
65746613
}
65756614

wolfssl/wolfcrypt/error-crypt.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -319,9 +319,10 @@ enum wolfCrypt_ErrorCodes {
319319
DRBG_SHA512_KAT_FIPS_E = -1010, /* SHA-512 DRBG KAT failure */
320320

321321
SEQ_OVERFLOW_E = -1011, /* Sequence counter would overflow */
322-
SLH_DSA_KAT_FIPS_E = -1012, /* SLH-DSA CAST KAT failure */
323-
WC_SPAN2_LAST_E = -1012, /* Update to indicate last used error code */
324-
WC_LAST_E = -1012, /* the last code used either here or in
322+
SLH_DSA_KAT_FIPS_E = -1012, /* SLH-DSA CAST KAT failure */
323+
SLH_DSA_PCT_E = -1013, /* SLH-DSA Pairwise Consistency Test failure */
324+
WC_SPAN2_LAST_E = -1013, /* Update to indicate last used error code */
325+
WC_LAST_E = -1013, /* the last code used either here or in
325326
* error-ssl.h */
326327

327328
WC_SPAN2_MIN_CODE_E = -1999, /* Last usable code in span 2 */

wolfssl/wolfcrypt/fips_test.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,23 @@
3131
extern "C" {
3232
#endif
3333

34-
/* Added for FIPS v5.3 or later */
35-
#if defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)
34+
/* Added for FIPS v5.3 or later.
35+
*
36+
* v7.0.0 and later upgrade the in-core integrity HMAC to SHA-512 (with a
37+
* 512-bit key) for NSA 2.0 compliance. Customers that must avoid SHA-256
38+
* anywhere in the validated module can therefore use the v7 module without
39+
* residual SHA-256 integrity material. v5.3 and v6.x retain HMAC-SHA-256.
40+
*/
41+
#if defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(7,0)
42+
#ifdef WOLFSSL_SHA512
43+
#define FIPS_IN_CORE_DIGEST_SIZE 64
44+
#define FIPS_IN_CORE_HASH_TYPE WC_SHA512
45+
#define FIPS_IN_CORE_KEY_SZ 64
46+
#define FIPS_IN_CORE_VERIFY_SZ FIPS_IN_CORE_KEY_SZ
47+
#else
48+
#error FIPS v7+ integrity test requires WOLFSSL_SHA512
49+
#endif
50+
#elif defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)
3651
/* Determine FIPS in core hash type and size */
3752
#ifndef NO_SHA256
3853
#define FIPS_IN_CORE_DIGEST_SIZE 32

0 commit comments

Comments
 (0)