Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion fips-hash.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ then
fi

OUT=$(./wolfcrypt/test/testwolfcrypt | sed -n 's/hash = \(.*\)/\1/p')
NEWHASH=$(echo "$OUT" | cut -c1-64)
# FIPS v7.0.0+ uses HMAC-SHA-512 (128 hex chars); older FIPS versions
# use HMAC-SHA-256 (64 hex chars). Take the whole captured hash; the
# static_assert on sizeof(verifyCore) guards against wrong length at
# compile time after this script runs.
NEWHASH=$(echo "$OUT" | head -n1 | tr -d '[:space:]')
if test -n "$NEWHASH"
then
cp wolfcrypt/src/fips_test.c wolfcrypt/src/fips_test.c.bak
Expand Down
14 changes: 14 additions & 0 deletions wolfcrypt/src/aes.c
Original file line number Diff line number Diff line change
Expand Up @@ -10962,6 +10962,16 @@ int wc_AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz,

VECTOR_REGISTERS_POP;

/* FIPS 140-3 / SP 800-38D: on authentication failure, the decrypted-but-
* unauthenticated plaintext in `out` must not be released to the caller.
* Wipe it here so a caller that ignores the return value cannot observe
* plaintext derived from forged ciphertext. All software paths (AES-NI,
* AVX1/2, ARM HW/NEON, C fallback) funnel through `ret` here, so this
* single guard covers every sub-implementation. */
if (ret == WC_NO_ERR_TRACE(AES_GCM_AUTH_E) && out != NULL && sz > 0) {
ForceZero(out, sz);
}

return ret;
}
#endif
Expand Down Expand Up @@ -12665,6 +12675,10 @@ int wc_AesGcmDecryptFinal(Aes* aes, const byte* authTag, word32 authTagSz)
}
}

/* Streaming decrypt cannot zeroize prior Update output buffers from here
* (Final does not see them). On AES_GCM_AUTH_E, the caller is responsible
* for treating all Update-produced plaintext as invalid and wiping it.
* See PL-R34 Security Policy section 8 (Operational Rules). */
return ret;
}
#endif /* HAVE_AES_DECRYPT || HAVE_AESGCM_DECRYPT */
Expand Down
32 changes: 28 additions & 4 deletions wolfcrypt/src/dh.c
Original file line number Diff line number Diff line change
Expand Up @@ -1400,8 +1400,20 @@ int wc_DhGeneratePublic(DhKey* key, byte* priv, word32 privSz,
#if FIPS_VERSION_GE(5,0) || defined(WOLFSSL_VALIDATE_DH_KEYGEN)
if (ret == 0)
ret = _ffc_validate_public_key(key, pub, *pubSz, NULL, 0, 0);
if (ret == 0)
ret = _ffc_pairwise_consistency_test(key, pub, *pubSz, priv, privSz);
if (ret == 0) {
/* Pairwise Consistency Test per SP 800-56A r3 sec 5.6.2.1.4
* (FFC key pair). FIPS 140-3 IG 10.3.B requires a PCT after
* KeyGen for key-establishment algorithms; on failure under a
* FIPS build the error is remapped to DH_PCT_E so the FIPS
* module's DEGRADE_STATE handler transitions FIPS_CAST_DH_
* PRIMITIVE_Z to the error state. */
ret = _ffc_pairwise_consistency_test(key, pub, *pubSz, priv,
privSz);
#ifdef HAVE_FIPS
if (ret != 0)
ret = DH_PCT_E;
#endif
}
#endif /* FIPS V5 or later || WOLFSSL_VALIDATE_DH_KEYGEN */

RESTORE_VECTOR_REGISTERS();
Expand All @@ -1428,8 +1440,20 @@ static int wc_DhGenerateKeyPair_Sync(DhKey* key, WC_RNG* rng,
#if FIPS_VERSION_GE(5,0) || defined(WOLFSSL_VALIDATE_DH_KEYGEN)
if (ret == 0)
ret = _ffc_validate_public_key(key, pub, *pubSz, NULL, 0, 0);
if (ret == 0)
ret = _ffc_pairwise_consistency_test(key, pub, *pubSz, priv, *privSz);
if (ret == 0) {
/* Pairwise Consistency Test per SP 800-56A r3 sec 5.6.2.1.4
* (FFC key pair). FIPS 140-3 IG 10.3.B requires a PCT after
* KeyGen for key-establishment algorithms; on failure under a
* FIPS build the error is remapped to DH_PCT_E so the FIPS
* module's DEGRADE_STATE handler transitions FIPS_CAST_DH_
* PRIMITIVE_Z to the error state. */
ret = _ffc_pairwise_consistency_test(key, pub, *pubSz, priv,
*privSz);
#ifdef HAVE_FIPS
if (ret != 0)
ret = DH_PCT_E;
#endif
}
#endif /* FIPS V5 or later || WOLFSSL_VALIDATE_DH_KEYGEN */


Expand Down
15 changes: 15 additions & 0 deletions wolfcrypt/src/error.c
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,21 @@ const char* wc_GetErrorString(int error)
case SLH_DSA_KAT_FIPS_E:
return "SLH-DSA Known Answer Test check FIPS error";

case SLH_DSA_PCT_E:
return "wolfcrypt SLH-DSA Pairwise Consistency Test Failure";

case CMAC_KAT_FIPS_E:
return "AES-CMAC Known Answer Test FIPS error";

case SHAKE_KAT_FIPS_E:
return "SHAKE Known Answer Test FIPS error";

case DH_PCT_E:
return "wolfcrypt DH (FFC) Pairwise Consistency Test Failure";

case AES_KW_KAT_FIPS_E:
return "AES-KW Known Answer Test FIPS error";

case SEQ_OVERFLOW_E:
return "Sequence counter would overflow";

Expand Down
39 changes: 39 additions & 0 deletions wolfcrypt/src/wc_slhdsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -6681,6 +6681,45 @@ int wc_SlhDsaKey_MakeKey(SlhDsaKey* key, WC_RNG* rng)
key->sk + 2 * n, n);
}

#ifdef HAVE_FIPS
/* Pairwise Consistency Test (PCT) per FIPS 140-3 IG 10.3.A (TE10.35.02):
* sign with the new sk, verify with the matching pk. 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 runs on every
* KeyGen. SignDeterministic avoids consuming RNG state; heap allocation
* is used because SLH-DSA signatures can reach ~50 KB. */
if (ret == 0) {
static const byte pct_msg[] = "wolfSSL SLH-DSA PCT";
byte* pct_sig = (byte*)XMALLOC(WC_SLHDSA_MAX_SIG_LEN, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
word32 pct_sigSz = WC_SLHDSA_MAX_SIG_LEN;

if (pct_sig == NULL) {
ret = MEMORY_E;
}
if (ret == 0) {
ret = wc_SlhDsaKey_SignDeterministic(key, NULL, 0,
pct_msg, sizeof(pct_msg), pct_sig, &pct_sigSz);
}
if (ret == 0) {
ret = wc_SlhDsaKey_Verify(key, NULL, 0,
pct_msg, sizeof(pct_msg), pct_sig, pct_sigSz);
if (ret != 0) {
ret = SLH_DSA_PCT_E;
}
}
if (pct_sig != NULL) {
ForceZero(pct_sig, WC_SLHDSA_MAX_SIG_LEN);
XFREE(pct_sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
/* IG 10.3.A (TE10.35.02): a key pair that fails the PCT must be
* rendered unusable. */
if (ret != 0) {
wc_SlhDsaKey_Free(key);
}
}
#endif /* HAVE_FIPS */

return ret;
}

Expand Down
14 changes: 11 additions & 3 deletions wolfssl/wolfcrypt/error-crypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,9 +327,17 @@ enum wolfCrypt_ErrorCodes {
ML_DSA_PCT_E = -1016, /* ML-DSA Pairwise Consistency Test failure */
DRBG_SHA512_KAT_FIPS_E = -1017, /* SHA-512 DRBG KAT failure */
SLH_DSA_KAT_FIPS_E = -1018, /* SLH-DSA CAST KAT failure */

WC_SPAN2_LAST_E = -1018, /* Update to indicate last used error code */
WC_LAST_E = -1018, /* the last code used either here or in
SLH_DSA_PCT_E = -1019, /* SLH-DSA Pairwise Consistency Test failure */
CMAC_KAT_FIPS_E = -1020, /* AES-CMAC KAT failure (vendor-elected) */
SHAKE_KAT_FIPS_E = -1021, /* SHAKE KAT failure (vendor-elected) */
DH_PCT_E = -1022, /* DH (FFC) Pairwise Consistency Test
* failure (SP 800-56A r3 sec 5.6.2.1.4,
* FIPS 140-3 IG 10.3.B) */
AES_KW_KAT_FIPS_E = -1023, /* AES-KW KAT failure (vendor-elected,
* SP 800-38F sec 6.2 / RFC 3394) */

WC_SPAN2_LAST_E = -1023, /* Update to indicate last used error code */
WC_LAST_E = -1023, /* the last code used either here or in
* error-ssl.h */

WC_SPAN2_MIN_CODE_E = -1999, /* Last usable code in span 2 */
Expand Down
24 changes: 21 additions & 3 deletions wolfssl/wolfcrypt/fips_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,23 @@
extern "C" {
#endif

/* Added for FIPS v5.3 or later */
#if defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)
/* Added for FIPS v5.3 or later.
*
* v7.0.0 and later upgrade the in-core integrity HMAC to SHA-512 (with a
* 512-bit key) for NSA 2.0 compliance. Customers that must avoid SHA-256
* anywhere in the validated module can therefore use the v7 module without
* residual SHA-256 integrity material. v5.3 and v6.x retain HMAC-SHA-256.
*/
#if defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(7,0)
#ifdef WOLFSSL_SHA512
#define FIPS_IN_CORE_DIGEST_SIZE 64
#define FIPS_IN_CORE_HASH_TYPE WC_SHA512
#define FIPS_IN_CORE_KEY_SZ 64
#define FIPS_IN_CORE_VERIFY_SZ FIPS_IN_CORE_KEY_SZ
#else
#error FIPS v7+ integrity test requires WOLFSSL_SHA512
#endif
#elif defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)
/* Determine FIPS in core hash type and size */
#ifndef NO_SHA256
#define FIPS_IN_CORE_DIGEST_SIZE 32
Expand Down Expand Up @@ -80,7 +95,10 @@ enum FipsCastId {
FIPS_CAST_XMSS = 23,
FIPS_CAST_DRBG_SHA512 = 24,
FIPS_CAST_SLH_DSA = 25,
FIPS_CAST_COUNT = 26
FIPS_CAST_AES_CMAC = 26,
FIPS_CAST_SHAKE = 27,
FIPS_CAST_AES_KW = 28,
FIPS_CAST_COUNT = 29
};

enum FipsCastStateId {
Expand Down
6 changes: 5 additions & 1 deletion wolfssl/wolfcrypt/random.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,12 @@
#define DRBG_SEED_LEN (440/8)
#endif

/* Size of the DRBG seed (SHA-512) */
#ifdef WOLFSSL_DRBG_SHA512
#define DRBG_SHA512_SEED_LEN (888/8) /* 111 bytes per SP 800-90A Table 2 */
#ifndef DRBG_SHA512_SEED_LEN
#define DRBG_SHA512_SEED_LEN (888/8) /* 111 bytes per SP 800-90A
* Table 2 */
#endif
#endif


Expand Down
Loading