mirror of https://github.com/wolfSSL/wolfssl.git
SLH-DSA pre-hash enforcement per FIPS 205 and FIPS v7 test fixes
parent
b273b7d11b
commit
e8e0630c76
|
|
@ -763,6 +763,7 @@ WC_DISABLE_RADIX_ZERO_PAD
|
|||
WC_DRBG_BANKREF
|
||||
WC_FIPS_AESGCM_NO_SHORT_NONCES
|
||||
WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED
|
||||
WC_FIPS_ED25519CTX_NOT_APPROVED
|
||||
WC_FLAG_DONT_USE_AESNI
|
||||
WC_FORCE_LINUXKM_FORTIFY_SOURCE
|
||||
WC_HASH_CUSTOM_MAX_BLOCK_SIZE
|
||||
|
|
|
|||
|
|
@ -542,6 +542,9 @@ int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime,
|
|||
|
||||
\return 0 on success.
|
||||
\return BAD_FUNC_ARG if key, hash, sig, or sigSz is NULL.
|
||||
\return BAD_FUNC_ARG if hashType is WC_HASH_TYPE_NONE, or if the
|
||||
pre-hash gives less collision strength than the parameter set's
|
||||
security category (FIPS 205 sec. 10.2).
|
||||
\return BAD_LENGTH_E if hashSz does not equal the digest size for hashType
|
||||
(32 for SHAKE128, 64 for SHAKE256 per FIPS 205 Section 10.2.2).
|
||||
\return NOT_COMPILED_IN if hashType is not supported in this build.
|
||||
|
|
@ -595,6 +598,9 @@ int wc_SlhDsaKey_SignHashDeterministic(SlhDsaKey* key,
|
|||
|
||||
\return 0 on success.
|
||||
\return BAD_FUNC_ARG if key, hash, sig, sigSz, or addRnd is NULL.
|
||||
\return BAD_FUNC_ARG if hashType is WC_HASH_TYPE_NONE, or if the
|
||||
pre-hash gives less collision strength than the parameter set's
|
||||
security category (FIPS 205 sec. 10.2).
|
||||
\return BAD_LENGTH_E if hashSz does not equal the digest size for hashType
|
||||
(32 for SHAKE128, 64 for SHAKE256 per FIPS 205 Section 10.2.2).
|
||||
\return NOT_COMPILED_IN if hashType is not supported in this build.
|
||||
|
|
@ -629,6 +635,9 @@ int wc_SlhDsaKey_SignHashWithRandom(SlhDsaKey* key,
|
|||
|
||||
\return 0 on success.
|
||||
\return BAD_FUNC_ARG if key, hash, sig, sigSz, or rng is NULL.
|
||||
\return BAD_FUNC_ARG if hashType is WC_HASH_TYPE_NONE, or if the
|
||||
pre-hash gives less collision strength than the parameter set's
|
||||
security category (FIPS 205 sec. 10.2).
|
||||
\return BAD_LENGTH_E if hashSz does not equal the digest size for hashType
|
||||
(32 for SHAKE128, 64 for SHAKE256 per FIPS 205 Section 10.2.2).
|
||||
\return NOT_COMPILED_IN if hashType is not supported in this build.
|
||||
|
|
@ -663,6 +672,9 @@ int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx,
|
|||
|
||||
\return 0 on success (signature valid).
|
||||
\return BAD_FUNC_ARG if key, hash, or sig is NULL.
|
||||
\return BAD_FUNC_ARG if hashType is WC_HASH_TYPE_NONE, or if the
|
||||
pre-hash gives less collision strength than the parameter set's
|
||||
security category (FIPS 205 sec. 10.2).
|
||||
\return BAD_LENGTH_E if sigSz does not match the parameter set, or if
|
||||
hashSz does not equal the digest size for hashType (32 for SHAKE128, 64
|
||||
for SHAKE256 per FIPS 205 Section 10.2.2).
|
||||
|
|
|
|||
|
|
@ -3849,24 +3849,38 @@ int test_wc_PKCS7_DecodeAuthEnvelopedData_truncated(void)
|
|||
|
||||
static long pkcs7_leak_live; /* outstanding allocations */
|
||||
|
||||
static void* pkcs7_leak_malloc_cb(size_t size)
|
||||
/* These callback types take (func, line) too under WOLFSSL_DEBUG_MEMORY. */
|
||||
#ifdef WOLFSSL_DEBUG_MEMORY
|
||||
#define PKCS7_LEAK_CB_TAIL , const char* func, unsigned int line
|
||||
#define PKCS7_LEAK_CB_UNUSED (void)func; (void)line;
|
||||
#else
|
||||
#define PKCS7_LEAK_CB_TAIL
|
||||
#define PKCS7_LEAK_CB_UNUSED
|
||||
#endif
|
||||
|
||||
static void* pkcs7_leak_malloc_cb(size_t size PKCS7_LEAK_CB_TAIL)
|
||||
{
|
||||
void* p = malloc(size);
|
||||
void* p;
|
||||
PKCS7_LEAK_CB_UNUSED
|
||||
p = malloc(size);
|
||||
if (p != NULL)
|
||||
pkcs7_leak_live++;
|
||||
return p;
|
||||
}
|
||||
|
||||
static void pkcs7_leak_free_cb(void* ptr)
|
||||
static void pkcs7_leak_free_cb(void* ptr PKCS7_LEAK_CB_TAIL)
|
||||
{
|
||||
PKCS7_LEAK_CB_UNUSED
|
||||
if (ptr != NULL)
|
||||
pkcs7_leak_live--;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
static void* pkcs7_leak_realloc_cb(void* ptr, size_t size)
|
||||
static void* pkcs7_leak_realloc_cb(void* ptr, size_t size PKCS7_LEAK_CB_TAIL)
|
||||
{
|
||||
void* p = realloc(ptr, size);
|
||||
void* p;
|
||||
PKCS7_LEAK_CB_UNUSED
|
||||
p = realloc(ptr, size);
|
||||
/* realloc(NULL, n) is an allocation; realloc(p, n) replaces one. */
|
||||
if (ptr == NULL && p != NULL)
|
||||
pkcs7_leak_live++;
|
||||
|
|
|
|||
|
|
@ -49,12 +49,14 @@
|
|||
* variants in the same order. */
|
||||
#if defined(WOLFSSL_SLHDSA_PARAM_128S)
|
||||
#define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHAKE128S
|
||||
#define TEST_SLHDSA_DEFAULT_CAT1
|
||||
#define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHAKE128S_SIG_LEN
|
||||
#define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHAKE128S_PRIV_LEN
|
||||
#define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHAKE128S_PUB_LEN
|
||||
#define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHAKE128S_SEED_LEN
|
||||
#elif defined(WOLFSSL_SLHDSA_PARAM_128F)
|
||||
#define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHAKE128F
|
||||
#define TEST_SLHDSA_DEFAULT_CAT1
|
||||
#define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHAKE128F_SIG_LEN
|
||||
#define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHAKE128F_PRIV_LEN
|
||||
#define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHAKE128F_PUB_LEN
|
||||
|
|
@ -85,12 +87,14 @@
|
|||
#define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHAKE256F_SEED_LEN
|
||||
#elif defined(WOLFSSL_SLHDSA_PARAM_SHA2_128S)
|
||||
#define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHA2_128S
|
||||
#define TEST_SLHDSA_DEFAULT_CAT1
|
||||
#define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHA2_128S_SIG_LEN
|
||||
#define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHA2_128S_PRIV_LEN
|
||||
#define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHA2_128S_PUB_LEN
|
||||
#define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHA2_128S_SEED_LEN
|
||||
#elif defined(WOLFSSL_SLHDSA_PARAM_SHA2_128F)
|
||||
#define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHA2_128F
|
||||
#define TEST_SLHDSA_DEFAULT_CAT1
|
||||
#define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHA2_128F_SIG_LEN
|
||||
#define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHA2_128F_PRIV_LEN
|
||||
#define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHA2_128F_PUB_LEN
|
||||
|
|
@ -120,6 +124,31 @@
|
|||
#define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHA2_256F_PUB_LEN
|
||||
#define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHA2_256F_SEED_LEN
|
||||
#endif
|
||||
|
||||
/* FIPS 205 sec. 10.2.2 allows SHA-256 and SHAKE128 only at category 1, so a
|
||||
* build whose default parameter set is larger needs a stronger pre-hash. */
|
||||
/* The hash, its digest size, the last byte of its FIPS 205 Algorithm 23 OID
|
||||
* and the call that produces the digest are chosen together here, so they
|
||||
* cannot disagree. */
|
||||
#ifdef TEST_SLHDSA_DEFAULT_CAT1
|
||||
#define TEST_SLHDSA_PH WC_HASH_TYPE_SHA256
|
||||
#define TEST_SLHDSA_PH_SZ 32
|
||||
#define TEST_SLHDSA_PH_OID 0x01
|
||||
#define TEST_SLHDSA_PH_HASH(in, inSz, out) \
|
||||
wc_Sha256Hash((in), (inSz), (out))
|
||||
#elif defined(WOLFSSL_SHA512)
|
||||
#define TEST_SLHDSA_PH WC_HASH_TYPE_SHA512
|
||||
#define TEST_SLHDSA_PH_SZ 64
|
||||
#define TEST_SLHDSA_PH_OID 0x03
|
||||
#define TEST_SLHDSA_PH_HASH(in, inSz, out) \
|
||||
wc_Sha512Hash((in), (inSz), (out))
|
||||
#else
|
||||
#define TEST_SLHDSA_PH WC_HASH_TYPE_SHAKE256
|
||||
#define TEST_SLHDSA_PH_SZ 64
|
||||
#define TEST_SLHDSA_PH_OID 0x0C
|
||||
#define TEST_SLHDSA_PH_HASH(in, inSz, out) \
|
||||
wc_Shake256Hash((in), (inSz), (out), TEST_SLHDSA_PH_SZ)
|
||||
#endif
|
||||
#endif /* WOLFSSL_HAVE_SLHDSA */
|
||||
|
||||
|
||||
|
|
@ -1026,7 +1055,9 @@ int test_wc_slhdsa_sign_hash(void)
|
|||
#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY)
|
||||
SlhDsaKey key;
|
||||
WC_RNG rng;
|
||||
byte hash[64];
|
||||
/* 64 for the SHA-512 and SHAKE256 cases, plus one for the deliberate
|
||||
* too-long case. */
|
||||
byte hash[65];
|
||||
byte* sig = NULL;
|
||||
word32 sigLen;
|
||||
word32 expSigLen;
|
||||
|
|
@ -1046,83 +1077,89 @@ int test_wc_slhdsa_sign_hash(void)
|
|||
expSigLen = TEST_SLHDSA_DEFAULT_SIG_LEN;
|
||||
ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0);
|
||||
|
||||
/* Test SignHash NULL parameter handling. Use 32-byte hash length so the
|
||||
* NULL check trips before the digest-length check (HashSLH-DSA expects
|
||||
* SHA-256 digest = 32 bytes). */
|
||||
/* Test SignHash NULL parameter handling. Use the right digest length so
|
||||
* the NULL check trips before the length check. */
|
||||
sigLen = WC_SLHDSA_MAX_SIG_LEN;
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHash(NULL, ctx, sizeof(ctx), hash,
|
||||
32, WC_HASH_TYPE_SHA256, sig, &sigLen, &rng),
|
||||
TEST_SLHDSA_PH_SZ, TEST_SLHDSA_PH, sig, &sigLen, &rng),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), NULL,
|
||||
32, WC_HASH_TYPE_SHA256, sig, &sigLen, &rng),
|
||||
TEST_SLHDSA_PH_SZ, TEST_SLHDSA_PH, sig, &sigLen, &rng),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash,
|
||||
32, WC_HASH_TYPE_SHA256, NULL, &sigLen, &rng),
|
||||
TEST_SLHDSA_PH_SZ, TEST_SLHDSA_PH, NULL, &sigLen, &rng),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash,
|
||||
32, WC_HASH_TYPE_SHA256, sig, NULL, &rng),
|
||||
TEST_SLHDSA_PH_SZ, TEST_SLHDSA_PH, sig, NULL, &rng),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash,
|
||||
32, WC_HASH_TYPE_SHA256, sig, &sigLen, NULL),
|
||||
TEST_SLHDSA_PH_SZ, TEST_SLHDSA_PH, sig, &sigLen, NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* HashSLH-DSA must reject digest lengths that don't match hashType. */
|
||||
sigLen = WC_SLHDSA_MAX_SIG_LEN;
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 31,
|
||||
WC_HASH_TYPE_SHA256, sig, &sigLen, &rng),
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash,
|
||||
TEST_SLHDSA_PH_SZ - 1, TEST_SLHDSA_PH, sig, &sigLen, &rng),
|
||||
WC_NO_ERR_TRACE(BAD_LENGTH_E));
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 33,
|
||||
WC_HASH_TYPE_SHA256, sig, &sigLen, &rng),
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash,
|
||||
TEST_SLHDSA_PH_SZ + 1, TEST_SLHDSA_PH, sig, &sigLen, &rng),
|
||||
WC_NO_ERR_TRACE(BAD_LENGTH_E));
|
||||
/* Generate a real signature first so VerifyHash gets to its length check
|
||||
* rather than failing on signature size. */
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32,
|
||||
WC_HASH_TYPE_SHA256, sig, &sigLen, &rng), 0);
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 31,
|
||||
WC_HASH_TYPE_SHA256, sig, sigLen),
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash,
|
||||
TEST_SLHDSA_PH_SZ, TEST_SLHDSA_PH, sig, &sigLen, &rng), 0);
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash,
|
||||
TEST_SLHDSA_PH_SZ - 1, TEST_SLHDSA_PH, sig, sigLen),
|
||||
WC_NO_ERR_TRACE(BAD_LENGTH_E));
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 33,
|
||||
WC_HASH_TYPE_SHA256, sig, sigLen),
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash,
|
||||
TEST_SLHDSA_PH_SZ + 1, TEST_SLHDSA_PH, sig, sigLen),
|
||||
WC_NO_ERR_TRACE(BAD_LENGTH_E));
|
||||
/* Verify rejects the no-pre-hash sentinel too. Done while sigLen is
|
||||
* still a real length, or the length check fires first and hides it. */
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash,
|
||||
TEST_SLHDSA_PH_SZ, WC_HASH_TYPE_NONE, sig, sigLen),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* Unsupported hashType (FIPS 205 doesn't list WC_HASH_TYPE_NONE) hits
|
||||
* the default branch of slhdsakey_validate_prehash. */
|
||||
/* WC_HASH_TYPE_NONE means "no pre-hash", so it is never valid here. */
|
||||
sigLen = WC_SLHDSA_MAX_SIG_LEN;
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32,
|
||||
WC_HASH_TYPE_NONE, sig, &sigLen, &rng),
|
||||
WC_NO_ERR_TRACE(NOT_COMPILED_IN));
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash,
|
||||
TEST_SLHDSA_PH_SZ, WC_HASH_TYPE_NONE, sig, &sigLen, &rng),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* Test SignHash with SHA-256. */
|
||||
/* Round trip with the parameter set's own pre-hash. */
|
||||
sigLen = WC_SLHDSA_MAX_SIG_LEN;
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32,
|
||||
WC_HASH_TYPE_SHA256, sig, &sigLen, &rng), 0);
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash,
|
||||
TEST_SLHDSA_PH_SZ, TEST_SLHDSA_PH, sig, &sigLen, &rng), 0);
|
||||
ExpectIntEQ(sigLen, expSigLen);
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 32,
|
||||
WC_HASH_TYPE_SHA256, sig, sigLen), 0);
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash,
|
||||
TEST_SLHDSA_PH_SZ, TEST_SLHDSA_PH, sig, sigLen), 0);
|
||||
|
||||
/* Test VerifyHash NULL parameter handling. */
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(NULL, ctx, sizeof(ctx), hash, 32,
|
||||
WC_HASH_TYPE_SHA256, sig, sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), NULL, 32,
|
||||
WC_HASH_TYPE_SHA256, sig, sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 32,
|
||||
WC_HASH_TYPE_SHA256, NULL, sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(NULL, ctx, sizeof(ctx), hash,
|
||||
TEST_SLHDSA_PH_SZ,
|
||||
TEST_SLHDSA_PH, sig, sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), NULL,
|
||||
TEST_SLHDSA_PH_SZ,
|
||||
TEST_SLHDSA_PH, sig, sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash,
|
||||
TEST_SLHDSA_PH_SZ,
|
||||
TEST_SLHDSA_PH, NULL, sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* Test VerifyHash with wrong hash. */
|
||||
hash[0] ^= 0xFF;
|
||||
ExpectIntNE(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 32,
|
||||
WC_HASH_TYPE_SHA256, sig, sigLen), 0);
|
||||
ExpectIntNE(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash,
|
||||
TEST_SLHDSA_PH_SZ, TEST_SLHDSA_PH, sig, sigLen), 0);
|
||||
hash[0] ^= 0xFF;
|
||||
|
||||
/* Test SignHashDeterministic. */
|
||||
sigLen = WC_SLHDSA_MAX_SIG_LEN;
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHashDeterministic(NULL, ctx, sizeof(ctx),
|
||||
hash, 32, WC_HASH_TYPE_SHA256, sig, &sigLen),
|
||||
hash, TEST_SLHDSA_PH_SZ, TEST_SLHDSA_PH, sig, &sigLen),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHashDeterministic(&key, ctx, sizeof(ctx),
|
||||
hash, 32, WC_HASH_TYPE_SHA256, sig, &sigLen), 0);
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 32,
|
||||
WC_HASH_TYPE_SHA256, sig, sigLen), 0);
|
||||
hash, TEST_SLHDSA_PH_SZ, TEST_SLHDSA_PH, sig, &sigLen), 0);
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash,
|
||||
TEST_SLHDSA_PH_SZ, TEST_SLHDSA_PH, sig, sigLen), 0);
|
||||
|
||||
/* Test SignHashWithRandom. */
|
||||
{
|
||||
|
|
@ -1131,15 +1168,15 @@ int test_wc_slhdsa_sign_hash(void)
|
|||
|
||||
sigLen = WC_SLHDSA_MAX_SIG_LEN;
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHashWithRandom(NULL, ctx, sizeof(ctx),
|
||||
hash, 32, WC_HASH_TYPE_SHA256, sig, &sigLen, addRnd),
|
||||
hash, TEST_SLHDSA_PH_SZ, TEST_SLHDSA_PH, sig, &sigLen, addRnd),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHashWithRandom(&key, ctx, sizeof(ctx),
|
||||
hash, 32, WC_HASH_TYPE_SHA256, sig, &sigLen, NULL),
|
||||
hash, TEST_SLHDSA_PH_SZ, TEST_SLHDSA_PH, sig, &sigLen, NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHashWithRandom(&key, ctx, sizeof(ctx),
|
||||
hash, 32, WC_HASH_TYPE_SHA256, sig, &sigLen, addRnd), 0);
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 32,
|
||||
WC_HASH_TYPE_SHA256, sig, sigLen), 0);
|
||||
hash, TEST_SLHDSA_PH_SZ, TEST_SLHDSA_PH, sig, &sigLen, addRnd), 0);
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash,
|
||||
TEST_SLHDSA_PH_SZ, TEST_SLHDSA_PH, sig, sigLen), 0);
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_SHA512
|
||||
|
|
@ -1155,8 +1192,8 @@ int test_wc_slhdsa_sign_hash(void)
|
|||
WC_NO_ERR_TRACE(BAD_LENGTH_E));
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_SHAKE128
|
||||
/* SHAKE128 PHM is fixed at 256 bits per FIPS 205 Section 10.2.2. */
|
||||
#if defined(WOLFSSL_SHAKE128) && defined(TEST_SLHDSA_DEFAULT_CAT1)
|
||||
/* SHAKE128 digest is fixed at 256 bits, and is category 1 only. */
|
||||
sigLen = WC_SLHDSA_MAX_SIG_LEN;
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32,
|
||||
WC_HASH_TYPE_SHAKE128, sig, &sigLen, &rng), 0);
|
||||
|
|
@ -1277,26 +1314,29 @@ int test_wc_slhdsa_sign_msg(void)
|
|||
ExpectIntEQ(wc_SlhDsaKey_VerifyMsg(&key, mprime, sizeof(mprime), NULL,
|
||||
sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* Equivalence cross-check: build M' = 0x01 || ctxSz || OID(SHA-256) ||
|
||||
* SHA256(orig) externally, sign it via SignMsgDeterministic, and verify
|
||||
* via VerifyHash with the same SHA-256 digest. Both paths must agree. */
|
||||
/* Equivalence cross-check: build M' = 0x01 || ctxSz || OID || digest
|
||||
* externally, sign it via SignMsgDeterministic, and verify via VerifyHash
|
||||
* with the same digest. Both paths must agree. The OID must match the
|
||||
* pre-hash the parameter set allows. */
|
||||
{
|
||||
static const byte sha256_oid[] = {
|
||||
/* FIPS 205 Algorithm 23 OID for TEST_SLHDSA_PH. */
|
||||
static const byte ph_oid[] = {
|
||||
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
|
||||
0x04, 0x02, 0x01
|
||||
0x04, 0x02, TEST_SLHDSA_PH_OID
|
||||
};
|
||||
static const byte orig[] = "Hello World!";
|
||||
byte digest[WC_SHA256_DIGEST_SIZE];
|
||||
byte built_mprime[2 + sizeof(sha256_oid) + WC_SHA256_DIGEST_SIZE];
|
||||
byte digest[TEST_SLHDSA_PH_SZ];
|
||||
byte built_mprime[2 + sizeof(ph_oid) + TEST_SLHDSA_PH_SZ];
|
||||
word32 idx = 0;
|
||||
word32 sigLen2;
|
||||
|
||||
ExpectIntEQ(wc_Sha256Hash(orig, (word32)sizeof(orig) - 1, digest), 0);
|
||||
ExpectIntEQ(TEST_SLHDSA_PH_HASH(orig, (word32)sizeof(orig) - 1,
|
||||
digest), 0);
|
||||
|
||||
built_mprime[idx++] = 0x01; /* HashSLH-DSA domain separator */
|
||||
built_mprime[idx++] = 0; /* ctxSz = 0 */
|
||||
XMEMCPY(built_mprime + idx, sha256_oid, sizeof(sha256_oid));
|
||||
idx += (word32)sizeof(sha256_oid);
|
||||
XMEMCPY(built_mprime + idx, ph_oid, sizeof(ph_oid));
|
||||
idx += (word32)sizeof(ph_oid);
|
||||
XMEMCPY(built_mprime + idx, digest, sizeof(digest));
|
||||
idx += (word32)sizeof(digest);
|
||||
|
||||
|
|
@ -1306,7 +1346,7 @@ int test_wc_slhdsa_sign_msg(void)
|
|||
|
||||
/* The same signature must verify via the HashSLH-DSA external API. */
|
||||
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, NULL, 0, digest,
|
||||
sizeof(digest), WC_HASH_TYPE_SHA256, sig, sigLen), 0);
|
||||
sizeof(digest), TEST_SLHDSA_PH, sig, sigLen), 0);
|
||||
|
||||
/* And the deterministic HashSLH-DSA path must produce the SAME
|
||||
* signature bytes (this is the strongest interop check). */
|
||||
|
|
@ -1316,7 +1356,7 @@ int test_wc_slhdsa_sign_msg(void)
|
|||
DYNAMIC_TYPE_TMP_BUFFER);
|
||||
ExpectNotNull(sig2);
|
||||
ExpectIntEQ(wc_SlhDsaKey_SignHashDeterministic(&key, NULL, 0,
|
||||
digest, sizeof(digest), WC_HASH_TYPE_SHA256, sig2,
|
||||
digest, sizeof(digest), TEST_SLHDSA_PH, sig2,
|
||||
&sigLen2), 0);
|
||||
ExpectIntEQ(sigLen2, sigLen);
|
||||
ExpectIntEQ(XMEMCMP(sig2, sig, sigLen), 0);
|
||||
|
|
|
|||
|
|
@ -14214,16 +14214,27 @@ void bench_slhdsa(int param)
|
|||
);
|
||||
bench_stats_asym_finish(name, len, "vrfy-msg", 0, count, start, ret);
|
||||
|
||||
#ifndef NO_SHA256
|
||||
#if !defined(NO_SHA256) && defined(WOLFSSL_SHA512)
|
||||
/* Pre-hash interface: hash message ONCE outside the timed loop (the
|
||||
* bench measures sign/verify, not the application-side hash), then sign
|
||||
* and verify the digest. SHA-256 path: only built when SHA-256 is
|
||||
* available; HashSLH-DSA still works at runtime with any hashType the
|
||||
* build supports, but the bench needs a compile-time choice. */
|
||||
* and verify the digest. SHA-256 is only strong enough for category 1,
|
||||
* so larger parameter sets pre-hash with SHA-512, which is why both are
|
||||
* required here. */
|
||||
{
|
||||
byte digest[WC_SHA256_DIGEST_SIZE];
|
||||
byte digest[WC_SHA512_DIGEST_SIZE];
|
||||
word32 digestSz;
|
||||
enum wc_HashType phType;
|
||||
|
||||
ret = wc_Sha256Hash(msg, (word32)sizeof(msg), digest);
|
||||
if (key->params->n == WC_SLHDSA_N_128) {
|
||||
phType = WC_HASH_TYPE_SHA256;
|
||||
digestSz = WC_SHA256_DIGEST_SIZE;
|
||||
ret = wc_Sha256Hash(msg, (word32)sizeof(msg), digest);
|
||||
}
|
||||
else {
|
||||
phType = WC_HASH_TYPE_SHA512;
|
||||
digestSz = WC_SHA512_DIGEST_SIZE;
|
||||
ret = wc_Sha512Hash(msg, (word32)sizeof(msg), digest);
|
||||
}
|
||||
if (ret != 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
|
@ -14233,7 +14244,7 @@ void bench_slhdsa(int param)
|
|||
do {
|
||||
sigLen = WC_SLHDSA_MAX_SIG_LEN;
|
||||
ret = wc_SlhDsaKey_SignHashDeterministic(key, ctx, 0, digest,
|
||||
(word32)sizeof(digest), WC_HASH_TYPE_SHA256, sig, &sigLen);
|
||||
digestSz, phType, sig, &sigLen);
|
||||
if (ret != 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
|
@ -14250,7 +14261,7 @@ void bench_slhdsa(int param)
|
|||
bench_stats_start(&count, &start);
|
||||
do {
|
||||
ret = wc_SlhDsaKey_VerifyHash(key_vfy, ctx, 0, digest,
|
||||
(word32)sizeof(digest), WC_HASH_TYPE_SHA256, sig, sigLen);
|
||||
digestSz, phType, sig, sigLen);
|
||||
if (ret != 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
|
@ -14264,7 +14275,8 @@ void bench_slhdsa(int param)
|
|||
bench_stats_asym_finish(name, len, "vrfy-pre", 0, count, start, ret);
|
||||
}
|
||||
#elif defined(WOLFSSL_SHAKE256)
|
||||
/* SHAKE-only build (NO_SHA256): use SHAKE256 prehash bench instead. */
|
||||
/* Reached without SHA-256, or without the SHA-512 the larger parameter
|
||||
* sets need. SHAKE256 is strong enough for every parameter set. */
|
||||
{
|
||||
byte digest[WC_SHA3_512_DIGEST_SIZE];
|
||||
|
||||
|
|
|
|||
|
|
@ -7997,7 +7997,46 @@ static const byte slhdsakey_oid_sha3_512[] = {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
/* Validate the caller-supplied pre-hashed digest length and look up the
|
||||
/* The CMVP PQC validation worksheet requires the pre-hash to provide classical
|
||||
* security strength at least equal to the parameter set that uses it (item 2.5,
|
||||
* citing FIPS 205 sec. 10.2). A hash gives half its digest size in collision
|
||||
* strength, and sec. 11 ties the category to n, so both are compared in bytes:
|
||||
* the pre-hash strength must be >= n. This also gives the sec. 10.2.2 rule
|
||||
* that SHA-256 and SHAKE128 are category 1 only.
|
||||
* Returns 0 if allowed, else BAD_FUNC_ARG. */
|
||||
static int slhdsa_check_hash_for_n(enum wc_HashType hashType, byte n)
|
||||
{
|
||||
byte strength;
|
||||
|
||||
switch ((int)hashType) {
|
||||
case WC_HASH_TYPE_SHA256:
|
||||
case WC_HASH_TYPE_SHA512_256:
|
||||
case WC_HASH_TYPE_SHA3_256:
|
||||
case WC_HASH_TYPE_SHAKE128:
|
||||
strength = WC_SLHDSA_N_128;
|
||||
break;
|
||||
case WC_HASH_TYPE_SHA384:
|
||||
case WC_HASH_TYPE_SHA3_384:
|
||||
strength = WC_SLHDSA_N_192;
|
||||
break;
|
||||
case WC_HASH_TYPE_SHA512:
|
||||
case WC_HASH_TYPE_SHA3_512:
|
||||
case WC_HASH_TYPE_SHAKE256:
|
||||
strength = WC_SLHDSA_N_256;
|
||||
break;
|
||||
default:
|
||||
/* Includes SHA-224 and friends, which are below every category. */
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
return (strength >= n) ? 0 : BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
/* Both callers run slhdsa_check_hash_for_n() first, so the entries below that
|
||||
* are too weak for any parameter set are already rejected by the time this
|
||||
* runs. The table stays complete so the two concerns remain separate.
|
||||
*
|
||||
* Validate the caller-supplied pre-hashed digest length and look up the
|
||||
* corresponding OID for the chosen hash algorithm.
|
||||
*
|
||||
* The HashSLH-DSA family takes the digest as input rather than the full
|
||||
|
|
@ -8223,6 +8262,11 @@ static int slhdsakey_signhash_external(SlhDsaKey* key, const byte* ctx,
|
|||
/* Alg 23, Step 6: Return error. */
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
/* Covers SignHashDeterministic and SignHashWithRandom, which reach here
|
||||
* without passing the check in wc_SlhDsaKey_SignHash. */
|
||||
if (ret == 0) {
|
||||
ret = slhdsa_check_hash_for_n(hashType, key->params->n);
|
||||
}
|
||||
if (ret == 0) {
|
||||
/* Alg 23, Steps 8-23: Validate caller-supplied pre-hashed digest length
|
||||
* and select OID for the chosen hash algorithm. */
|
||||
|
|
@ -8438,11 +8482,9 @@ int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx, byte ctxSz,
|
|||
int ret = 0;
|
||||
byte addRnd[SLHDSA_MAX_N];
|
||||
|
||||
/* Validate parameters before generating random.
|
||||
* hashSz / hashType validation lives in the internal worker and therefore
|
||||
* runs after wc_RNG_GenerateBlock. A call with a bad hashSz/hashType will
|
||||
* waste n bytes of DRBG output before the error is reported (similar to
|
||||
* ML-DSA pre-hash handling). */
|
||||
/* Validate parameters before generating random. hashType is checked
|
||||
* here; only hashSz is left to the internal worker, so a bad hashSz still
|
||||
* costs n bytes of DRBG output before the error comes back. */
|
||||
if ((key == NULL) || (key->params == NULL) ||
|
||||
((ctx == NULL) && (ctxSz > 0)) || (hash == NULL) || (sig == NULL) ||
|
||||
(sigSz == NULL) || (rng == NULL)) {
|
||||
|
|
@ -8456,10 +8498,11 @@ int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx, byte ctxSz,
|
|||
else if ((key->flags & WC_SLHDSA_FLAG_PRIVATE) == 0) {
|
||||
ret = MISSING_KEY;
|
||||
}
|
||||
/* First sanity check on hashType; the downstream prehash validator does
|
||||
* the detailed check for the actual type. */
|
||||
else if ((word32)hashType > (word32)WC_HASH_TYPE_MAX) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
/* Before the callback dispatch, so a device cannot sign a combination
|
||||
* this build rejects on verify. Also rejects WC_HASH_TYPE_NONE and any
|
||||
* out-of-range value, which the gate does not list. */
|
||||
else {
|
||||
ret = slhdsa_check_hash_for_n(hashType, key->params->n);
|
||||
}
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
|
|
@ -8588,10 +8631,8 @@ int wc_SlhDsaKey_VerifyHash(SlhDsaKey* key, const byte* ctx, byte ctxSz,
|
|||
else if ((key->flags & WC_SLHDSA_FLAG_PUBLIC) == 0) {
|
||||
ret = MISSING_KEY;
|
||||
}
|
||||
/* First sanity check on hashType; the downstream prehash validator does
|
||||
* the detailed check for the actual type. */
|
||||
else if ((word32)hashType > (word32)WC_HASH_TYPE_MAX) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
else {
|
||||
ret = slhdsa_check_hash_for_n(hashType, key->params->n);
|
||||
}
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
|
|
|
|||
|
|
@ -30142,7 +30142,9 @@ static wc_test_ret_t rsa_pss_test(WC_RNG* rng, RsaKey* key)
|
|||
enum wc_HashType hash[] = { WC_HASH_TYPE_SHA256 };
|
||||
#else
|
||||
int mgf[] = {
|
||||
#ifndef NO_SHA
|
||||
/* FIPS 186-5 sec 5.4 disallows SHA-1 for RSA signature generation; the module
|
||||
* rejects it at the RSA-PSS signing service. */
|
||||
#if !defined(NO_SHA) && FIPS_VERSION3_LT(7,0,0)
|
||||
WC_MGF1SHA1,
|
||||
#endif
|
||||
#ifdef WOLFSSL_SHA224
|
||||
|
|
@ -30159,7 +30161,7 @@ static wc_test_ret_t rsa_pss_test(WC_RNG* rng, RsaKey* key)
|
|||
#endif
|
||||
};
|
||||
enum wc_HashType hash[] = {
|
||||
#ifndef NO_SHA
|
||||
#if !defined(NO_SHA) && FIPS_VERSION3_LT(7,0,0)
|
||||
WC_HASH_TYPE_SHA,
|
||||
#endif
|
||||
#ifdef WOLFSSL_SHA224
|
||||
|
|
@ -49601,6 +49603,24 @@ static wc_test_ret_t ed25519ctx_test(void)
|
|||
|
||||
ret = wc_ed25519_import_private_key(sKeyCtx, ED25519_KEY_SIZE, pKeyCtx,
|
||||
sizeof(pKeyCtx), &key);
|
||||
#ifdef WC_FIPS_ED25519CTX_NOT_APPROVED
|
||||
/* The FIPS module does not approve Ed25519ctx, so it must refuse to
|
||||
* sign. Keyed off the module's own macro because some v7.0.0 builds
|
||||
* report the same version but still sign. */
|
||||
if (ret == 0) {
|
||||
ret = wc_ed25519ctx_sign_msg(msgCtx, sizeof(msgCtx), out, &outlen, &key,
|
||||
contextCtx, sizeof(contextCtx));
|
||||
if (ret == WC_NO_ERR_TRACE(SIG_TYPE_E))
|
||||
ret = 0;
|
||||
else if (ret == 0)
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
}
|
||||
(void)sigCtx1;
|
||||
(void)sigCtx2;
|
||||
#ifdef HAVE_ED25519_VERIFY
|
||||
(void)verify;
|
||||
#endif
|
||||
#else
|
||||
if (ret == 0)
|
||||
ret = wc_ed25519ctx_sign_msg(msgCtx, sizeof(msgCtx), out, &outlen, &key,
|
||||
contextCtx, sizeof(contextCtx));
|
||||
|
|
@ -49631,6 +49651,7 @@ static wc_test_ret_t ed25519ctx_test(void)
|
|||
if (ret == 0 && verify != 1)
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
#endif
|
||||
#endif /* WC_FIPS_ED25519CTX_NOT_APPROVED */
|
||||
|
||||
wc_ed25519_free(&key);
|
||||
|
||||
|
|
@ -52520,8 +52541,15 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ed448_test(void)
|
|||
}
|
||||
#endif /* HAVE_ED448 */
|
||||
|
||||
/* KATs that feed in fixed NIST seeds. A FIPS build must make its own
|
||||
* randomness, so those calls are rejected there. Non-FIPS only. */
|
||||
#if !defined(HAVE_FIPS)
|
||||
#define WOLFSSL_TEST_PQC_SEED_KAT
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_HAVE_MLKEM
|
||||
#if !defined(WOLFSSL_NO_KYBER512) && !defined(WOLFSSL_NO_ML_KEM_512)
|
||||
#if !defined(WOLFSSL_NO_KYBER512) && !defined(WOLFSSL_NO_ML_KEM_512) && \
|
||||
defined(WOLFSSL_TEST_PQC_SEED_KAT)
|
||||
static wc_test_ret_t mlkem512_kat(void)
|
||||
{
|
||||
wc_test_ret_t ret;
|
||||
|
|
@ -53615,7 +53643,8 @@ out:
|
|||
}
|
||||
#endif /* !WOLFSSL_NO_KYBER512 && !WOLFSSL_NO_ML_KEM_512 */
|
||||
|
||||
#if !defined(WOLFSSL_NO_KYBER768) && !defined(WOLFSSL_NO_ML_KEM_768)
|
||||
#if !defined(WOLFSSL_NO_KYBER768) && !defined(WOLFSSL_NO_ML_KEM_768) && \
|
||||
defined(WOLFSSL_TEST_PQC_SEED_KAT)
|
||||
static wc_test_ret_t mlkem768_kat(void)
|
||||
{
|
||||
wc_test_ret_t ret;
|
||||
|
|
@ -55055,7 +55084,8 @@ out:
|
|||
}
|
||||
#endif /* !WOLFSSL_NO_KYBER768 && !WOLFSSL_NO_ML_KEM_768 */
|
||||
|
||||
#if !defined(WOLFSSL_NO_KYBER1024) && !defined(WOLFSSL_NO_ML_KEM_1024)
|
||||
#if !defined(WOLFSSL_NO_KYBER1024) && !defined(WOLFSSL_NO_ML_KEM_1024) && \
|
||||
defined(WOLFSSL_TEST_PQC_SEED_KAT)
|
||||
static wc_test_ret_t mlkem1024_kat(void)
|
||||
{
|
||||
wc_test_ret_t ret;
|
||||
|
|
@ -57155,17 +57185,20 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mlkem_test(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
#if !defined(WOLFSSL_NO_KYBER512) && !defined(WOLFSSL_NO_ML_KEM_512)
|
||||
#if !defined(WOLFSSL_NO_KYBER512) && !defined(WOLFSSL_NO_ML_KEM_512) && \
|
||||
defined(WOLFSSL_TEST_PQC_SEED_KAT)
|
||||
ret = mlkem512_kat();
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
#endif
|
||||
#if !defined(WOLFSSL_NO_KYBER768) && !defined(WOLFSSL_NO_ML_KEM_768)
|
||||
#if !defined(WOLFSSL_NO_KYBER768) && !defined(WOLFSSL_NO_ML_KEM_768) && \
|
||||
defined(WOLFSSL_TEST_PQC_SEED_KAT)
|
||||
ret = mlkem768_kat();
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
#endif
|
||||
#if !defined(WOLFSSL_NO_KYBER1024) && !defined(WOLFSSL_NO_ML_KEM_1024)
|
||||
#if !defined(WOLFSSL_NO_KYBER1024) && !defined(WOLFSSL_NO_ML_KEM_1024) && \
|
||||
defined(WOLFSSL_TEST_PQC_SEED_KAT)
|
||||
ret = mlkem1024_kat();
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
|
|
@ -63105,7 +63138,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test_verify_only(void)
|
|||
#define WOLFSSL_SLHDSA_VERIFY_ONLY
|
||||
#endif
|
||||
|
||||
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
|
||||
#if !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && defined(WOLFSSL_TEST_PQC_SEED_KAT)
|
||||
/* KeyGen KAT: deterministic key generation cross-validated against NIST CAVP
|
||||
* vectors. Verifies that MakeKeyWithRandom produces the expected sk and pk
|
||||
* for a given parameter set. */
|
||||
|
|
@ -63173,7 +63206,7 @@ out:
|
|||
WC_FREE_VAR_EX(key, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
return ret;
|
||||
}
|
||||
#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */
|
||||
#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY && WOLFSSL_TEST_PQC_SEED_KAT */
|
||||
|
||||
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
|
||||
static wc_test_ret_t slhdsa_test_param(enum SlhDsaParam param)
|
||||
|
|
@ -63251,9 +63284,16 @@ static wc_test_ret_t slhdsa_test_param(enum SlhDsaParam param)
|
|||
|
||||
/* HashSLH-DSA takes the caller's pre-hashed digest as input. */
|
||||
{
|
||||
/* FIPS 205 sec. 10.2.2 approves SHA-256 only for category 1, so the
|
||||
* larger SHA-2 parameter sets pre-hash with SHA-512. */
|
||||
#ifdef WOLFSSL_SLHDSA_SHA2
|
||||
enum wc_HashType phType = SLHDSA_IS_SHA2(param) ?
|
||||
WC_HASH_TYPE_SHA256 : WC_HASH_TYPE_SHAKE256;
|
||||
enum wc_HashType phType = !SLHDSA_IS_SHA2(param) ? WC_HASH_TYPE_SHAKE256
|
||||
: (key->params->n == WC_SLHDSA_N_128) ? WC_HASH_TYPE_SHA256
|
||||
#ifdef WOLFSSL_SHA512
|
||||
: WC_HASH_TYPE_SHA512;
|
||||
#else
|
||||
: WC_HASH_TYPE_SHAKE256;
|
||||
#endif
|
||||
#else
|
||||
enum wc_HashType phType = WC_HASH_TYPE_SHAKE256;
|
||||
#endif
|
||||
|
|
@ -63265,6 +63305,12 @@ static wc_test_ret_t slhdsa_test_param(enum SlhDsaParam param)
|
|||
ret = wc_Sha256Hash(msg, (word32)sizeof(msg), digest);
|
||||
digestLen = WC_SHA256_DIGEST_SIZE;
|
||||
}
|
||||
#ifdef WOLFSSL_SHA512
|
||||
else if (phType == WC_HASH_TYPE_SHA512) {
|
||||
ret = wc_Sha512Hash(msg, (word32)sizeof(msg), digest);
|
||||
digestLen = WC_SHA512_DIGEST_SIZE;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
#endif
|
||||
{
|
||||
|
|
@ -63290,9 +63336,10 @@ static wc_test_ret_t slhdsa_test_param(enum SlhDsaParam param)
|
|||
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
|
||||
}
|
||||
|
||||
/* Additional pre-hash test: SHA-384 exercises a different OID path */
|
||||
/* SHA-384 exercises a different OID path. Its 192-bit strength covers
|
||||
* categories 1 and 3 only. */
|
||||
#ifdef WOLFSSL_SHA384
|
||||
{
|
||||
if (key->params->n <= WC_SLHDSA_N_192) {
|
||||
byte digest384[WC_SHA384_DIGEST_SIZE];
|
||||
|
||||
ret = wc_Sha384Hash(msg, (word32)sizeof(msg), digest384);
|
||||
|
|
@ -63352,6 +63399,145 @@ out:
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Must list exactly the parameter sets the call sites below use, or the
|
||||
* build either fails to compile or warns about an unused function. */
|
||||
#if defined(WOLFSSL_SLHDSA_PARAM_192S) || \
|
||||
defined(WOLFSSL_SLHDSA_PARAM_192F) || \
|
||||
defined(WOLFSSL_SLHDSA_PARAM_256S) || \
|
||||
defined(WOLFSSL_SLHDSA_PARAM_256F) || \
|
||||
defined(WOLFSSL_SLHDSA_PARAM_SHA2_192S) || \
|
||||
defined(WOLFSSL_SLHDSA_PARAM_SHA2_192F) || \
|
||||
defined(WOLFSSL_SLHDSA_PARAM_SHA2_256S) || \
|
||||
defined(WOLFSSL_SLHDSA_PARAM_SHA2_256F)
|
||||
/* Negative test: HashSLH-DSA must reject a pre-hash whose collision resistance
|
||||
* is below the parameter set's claimed security strength (FIPS 205 sec.
|
||||
* 10.2.2 with sec. 11). Asserts sigGen and sigVer both
|
||||
* reject. */
|
||||
static wc_test_ret_t slhdsa_hash_paramset_rejection_test(enum SlhDsaParam param)
|
||||
{
|
||||
int ret = 0;
|
||||
wc_test_ret_t testRet = 0;
|
||||
WC_RNG rng;
|
||||
WC_DECLARE_VAR(key, SlhDsaKey, 1, HEAP_HINT);
|
||||
/* Signature is about 49KB, too big for a small stack. */
|
||||
WC_DECLARE_VAR(sig, byte, WC_SLHDSA_MAX_SIG_LEN, HEAP_HINT);
|
||||
word32 sigLen;
|
||||
/* Content does not matter, only that the length matches the hash. */
|
||||
byte msg[48];
|
||||
byte addRnd[WC_SLHDSA_MAX_SEED];
|
||||
/* Rejected by every parameter set above category 1. */
|
||||
enum wc_HashType badHash = WC_HASH_TYPE_SHA256;
|
||||
int rngInited = 0;
|
||||
int keyInited = 0;
|
||||
|
||||
WC_ALLOC_VAR_EX(key, SlhDsaKey, 1, HEAP_HINT,
|
||||
DYNAMIC_TYPE_TMP_BUFFER, return WC_TEST_RET_ENC_EC(MEMORY_E));
|
||||
/* Goes to out, not return, so a failure here still frees key. */
|
||||
WC_ALLOC_VAR_EX(sig, byte, WC_SLHDSA_MAX_SIG_LEN, HEAP_HINT,
|
||||
DYNAMIC_TYPE_TMP_BUFFER,
|
||||
testRet = WC_TEST_RET_ENC_EC(MEMORY_E); goto out);
|
||||
XMEMSET(key, 0, sizeof(*key));
|
||||
XMEMSET(msg, 0xAB, sizeof(msg));
|
||||
XMEMSET(addRnd, 0x55, sizeof(addRnd));
|
||||
|
||||
#ifndef HAVE_FIPS
|
||||
ret = wc_InitRng_ex(&rng, HEAP_HINT, devId);
|
||||
#else
|
||||
ret = wc_InitRng(&rng);
|
||||
#endif
|
||||
if (ret != 0) {
|
||||
testRet = WC_TEST_RET_ENC_EC(ret);
|
||||
goto out;
|
||||
}
|
||||
rngInited = 1;
|
||||
|
||||
ret = wc_SlhDsaKey_Init(key, param, NULL, devId);
|
||||
if (ret != 0) {
|
||||
testRet = WC_TEST_RET_ENC_EC(ret);
|
||||
goto out;
|
||||
}
|
||||
keyInited = 1;
|
||||
|
||||
ret = wc_SlhDsaKey_MakeKey(key, &rng);
|
||||
if (ret != 0) {
|
||||
testRet = WC_TEST_RET_ENC_EC(ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* SHA-256 is allowed at category 1, so nothing to reject. */
|
||||
if (key->params->n == WC_SLHDSA_N_128) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* sigGen with too-weak PH must be REJECTED. */
|
||||
sigLen = WC_SLHDSA_MAX_SIG_LEN;
|
||||
PRIVATE_KEY_UNLOCK();
|
||||
ret = wc_SlhDsaKey_SignHash(key, NULL, 0, msg, 32,
|
||||
badHash, sig, &sigLen, &rng);
|
||||
PRIVATE_KEY_LOCK();
|
||||
/* Must be this rejection, not some earlier error. */
|
||||
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) {
|
||||
testRet = WC_TEST_RET_ENC_NC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* These two reach the check by a different route, through
|
||||
* slhdsakey_signhash_external, so assert them separately. */
|
||||
sigLen = WC_SLHDSA_MAX_SIG_LEN;
|
||||
PRIVATE_KEY_UNLOCK();
|
||||
ret = wc_SlhDsaKey_SignHashDeterministic(key, NULL, 0, msg, 32,
|
||||
badHash, sig, &sigLen);
|
||||
PRIVATE_KEY_LOCK();
|
||||
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) {
|
||||
testRet = WC_TEST_RET_ENC_NC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sigLen = WC_SLHDSA_MAX_SIG_LEN;
|
||||
PRIVATE_KEY_UNLOCK();
|
||||
ret = wc_SlhDsaKey_SignHashWithRandom(key, NULL, 0, msg, 32,
|
||||
badHash, sig, &sigLen, addRnd);
|
||||
PRIVATE_KEY_LOCK();
|
||||
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) {
|
||||
testRet = WC_TEST_RET_ENC_NC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Verify must reject it too. Use the real signature length, or the
|
||||
* length check fires first and hides the result. */
|
||||
sigLen = key->params->sigLen;
|
||||
ret = wc_SlhDsaKey_VerifyHash(key, NULL, 0, msg, 32,
|
||||
badHash, sig, sigLen);
|
||||
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) {
|
||||
testRet = WC_TEST_RET_ENC_NC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_SHA384
|
||||
/* SHA-384 is 192-bit, so category 5 must reject it as well. */
|
||||
if (key->params->n == WC_SLHDSA_N_256) {
|
||||
ret = wc_SlhDsaKey_VerifyHash(key, NULL, 0, msg, 48,
|
||||
WC_HASH_TYPE_SHA384, sig, sigLen);
|
||||
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) {
|
||||
testRet = WC_TEST_RET_ENC_NC;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
out:
|
||||
if (keyInited) {
|
||||
wc_SlhDsaKey_Free(key);
|
||||
}
|
||||
if (rngInited) {
|
||||
wc_FreeRng(&rng);
|
||||
}
|
||||
WC_FREE_VAR_EX(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
WC_FREE_VAR_EX(key, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
return testRet;
|
||||
}
|
||||
#endif /* any category 3/5 param set */
|
||||
#endif
|
||||
|
||||
/* True iff slhdsa_test() actually emits at least one `goto out;` /
|
||||
|
|
@ -63538,7 +63724,7 @@ wc_test_ret_t slhdsa_test(void)
|
|||
int ret = 0;
|
||||
#ifdef WOLFSSL_SLHDSA_PARAM_128S
|
||||
WC_DECLARE_VAR(key_vfy, SlhDsaKey, 1, HEAP_HINT);
|
||||
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
|
||||
#if !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && defined(WOLFSSL_TEST_PQC_SEED_KAT)
|
||||
WC_DECLARE_VAR(key, SlhDsaKey, 1, HEAP_HINT);
|
||||
static const byte sk_seed_shake128s[] = {
|
||||
0x17, 0x3D, 0x04, 0xC9, 0x38, 0xC1, 0xC3, 0x6B,
|
||||
|
|
@ -63569,7 +63755,7 @@ wc_test_ret_t slhdsa_test(void)
|
|||
0x82, 0x6e, 0x97, 0xbc, 0xb0, 0x1b, 0x78, 0x7b,
|
||||
0xc6, 0xb5, 0xa7, 0xbb, 0xe3, 0x7e, 0xb4, 0xa8
|
||||
};
|
||||
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
|
||||
#if !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && defined(WOLFSSL_TEST_PQC_SEED_KAT)
|
||||
WC_DECLARE_VAR(sk, byte, WC_SLHDSA_MAX_PRIV_LEN, HEAP_HINT);
|
||||
WC_DECLARE_VAR(pk, byte, WC_SLHDSA_MAX_PUB_LEN, HEAP_HINT);
|
||||
word32 outLen;
|
||||
|
|
@ -64563,14 +64749,14 @@ wc_test_ret_t slhdsa_test(void)
|
|||
0xc0, 0x48, 0xd0, 0x63, 0x82, 0x20, 0x2b, 0x06,
|
||||
0xe8, 0x21, 0xf8, 0xcd, 0x56, 0xc5, 0xc7, 0x31,
|
||||
};
|
||||
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
|
||||
#if !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && defined(WOLFSSL_TEST_PQC_SEED_KAT)
|
||||
WC_DECLARE_VAR(sig, byte, sizeof(sig_shake128s), HEAP_HINT);
|
||||
#endif
|
||||
|
||||
WC_ALLOC_VAR_EX(key_vfy, SlhDsaKey, 1, HEAP_HINT,
|
||||
DYNAMIC_TYPE_TMP_BUFFER, ERROR_OUT(WC_TEST_RET_ENC_EC(MEMORY_E), out));
|
||||
XMEMSET(key_vfy, 0, sizeof(*key_vfy));
|
||||
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
|
||||
#if !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && defined(WOLFSSL_TEST_PQC_SEED_KAT)
|
||||
WC_ALLOC_VAR_EX(key, SlhDsaKey, 1, HEAP_HINT,
|
||||
DYNAMIC_TYPE_TMP_BUFFER, ERROR_OUT(WC_TEST_RET_ENC_EC(MEMORY_E), out));
|
||||
XMEMSET(key, 0, sizeof(*key));
|
||||
|
|
@ -64584,7 +64770,7 @@ wc_test_ret_t slhdsa_test(void)
|
|||
/* // NOLINTEND(bugprone-sizeof-expression) */
|
||||
#endif
|
||||
|
||||
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
|
||||
#if !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && defined(WOLFSSL_TEST_PQC_SEED_KAT)
|
||||
ret = wc_SlhDsaKey_Init(key, SLHDSA_SHAKE128S, NULL, devId);
|
||||
if (ret != 0) {
|
||||
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
|
||||
|
|
@ -64644,7 +64830,7 @@ wc_test_ret_t slhdsa_test(void)
|
|||
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
|
||||
}
|
||||
|
||||
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
|
||||
#if !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && defined(WOLFSSL_TEST_PQC_SEED_KAT)
|
||||
outLen = (word32)sizeof(sig_shake128s);
|
||||
PRIVATE_KEY_UNLOCK();
|
||||
ret = wc_SlhDsaKey_SignWithRandom(key, ctx, 0, msg, (word32)sizeof(msg),
|
||||
|
|
@ -64670,7 +64856,7 @@ wc_test_ret_t slhdsa_test(void)
|
|||
* These verify that deterministic key generation produces the exact pk/sk
|
||||
* that NIST expects. Covers both SHA-256 (cat 1, n=16) and SHA-512
|
||||
* (cat 3 n=24, cat 5 n=32) code paths. */
|
||||
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
|
||||
#if !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && defined(WOLFSSL_TEST_PQC_SEED_KAT)
|
||||
#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S
|
||||
{
|
||||
/* NIST CAVP SLH-DSA-SHA2-128s keyGen vector (tgId=1, tcId=1).
|
||||
|
|
@ -65260,6 +65446,12 @@ wc_test_ret_t slhdsa_test(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Below here nothing feeds in a seed, so it must stay outside the gate
|
||||
* above. Putting it inside dropped these tests from every FIPS build. */
|
||||
#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY && WOLFSSL_TEST_PQC_SEED_KAT */
|
||||
|
||||
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
|
||||
|
||||
#ifdef WOLFSSL_SLHDSA_PARAM_128S
|
||||
ret = slhdsa_test_param(SLHDSA_SHAKE128S);
|
||||
if (ret != 0) {
|
||||
|
|
@ -65345,6 +65537,45 @@ wc_test_ret_t slhdsa_test(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* FIPS 205 sec. 10.2.2 allows SHA-256 only at category 1, so every larger
|
||||
* parameter set must reject it. Each is tested on its own; an #elif chain
|
||||
* would stop at the first one the build enables. */
|
||||
#define SLHDSA_REJECT_CASE(param) \
|
||||
if (ret == 0) { \
|
||||
ret = slhdsa_hash_paramset_rejection_test(param); \
|
||||
if (ret != 0) { \
|
||||
wc_test_render_error_message(#param " (hash-paramset reject)", \
|
||||
0); \
|
||||
goto out; \
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_SLHDSA_PARAM_192S
|
||||
SLHDSA_REJECT_CASE(SLHDSA_SHAKE192S)
|
||||
#endif
|
||||
#ifdef WOLFSSL_SLHDSA_PARAM_192F
|
||||
SLHDSA_REJECT_CASE(SLHDSA_SHAKE192F)
|
||||
#endif
|
||||
#ifdef WOLFSSL_SLHDSA_PARAM_256S
|
||||
SLHDSA_REJECT_CASE(SLHDSA_SHAKE256S)
|
||||
#endif
|
||||
#ifdef WOLFSSL_SLHDSA_PARAM_256F
|
||||
SLHDSA_REJECT_CASE(SLHDSA_SHAKE256F)
|
||||
#endif
|
||||
#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S
|
||||
SLHDSA_REJECT_CASE(SLHDSA_SHA2_192S)
|
||||
#endif
|
||||
#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F
|
||||
SLHDSA_REJECT_CASE(SLHDSA_SHA2_192F)
|
||||
#endif
|
||||
#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S
|
||||
SLHDSA_REJECT_CASE(SLHDSA_SHA2_256S)
|
||||
#endif
|
||||
#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F
|
||||
SLHDSA_REJECT_CASE(SLHDSA_SHA2_256F)
|
||||
#endif
|
||||
#undef SLHDSA_REJECT_CASE
|
||||
|
||||
#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */
|
||||
|
||||
#if defined(WOLF_PRIVATE_KEY_ID) && \
|
||||
|
|
@ -65378,7 +65609,7 @@ out:
|
|||
/* key, sig, sk, pk are declared inside #ifdef WOLFSSL_SLHDSA_PARAM_128S
|
||||
* (alongside the SHAKE-128s test data) so they only exist when 128S is
|
||||
* built. Their cleanup must match. */
|
||||
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
|
||||
#if !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && defined(WOLFSSL_TEST_PQC_SEED_KAT)
|
||||
#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
|
||||
if (key)
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue