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

Merge pull request #11668 from kaleb-himes/PQ-FS-2026-Part3-SecurityReview-nofallback-U

3x compliance items (CBC, ECDH, DSA)
This commit is contained in:
philljj
2026-10-09 18:15:53 -05:00
committed by GitHub
11 changed files with 392 additions and 33 deletions

View File

@@ -54,7 +54,7 @@ if (wc_UnpackOctets(sig, (word32)sizeof(sig), sigPacked,
(word32)sizeof(sigPacked), WC_MLDSA_65_SIG_SIZE) == 0) {
ret = wc_MlDsaKey_VerifyCtxHash(key, sig, WC_MLDSA_65_SIG_SIZE,
ctx, ctxLen, hash, hashLen,
WC_HASH_TYPE_SHA256, &res);
WC_HASH_TYPE_SHA512, &res);
}
```

View File

@@ -359,6 +359,9 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out,
\ingroup ECC
\brief Create an ECC shared secret between private key and public point.
The point is first given full public key validation on the private key's
curve with wc_ecc_check_key() (SP 800-56Ar3 5.6.2.3.3). A build without
the order check (NO_ECC_CHECK_PUBKEY_ORDER) still checks range and curve.
\return MP_OKAY Indicates success.
\return BAD_FUNC_ARG Error returned when any arguments are null.
@@ -368,6 +371,8 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out,
\return MEMORY_E Error to create a new point.
\return MP_VAL possible when an initialization failure occurs.
\return MP_MEM possible when an initialization failure occurs.
\return IS_POINT_E, ECC_OUT_OF_RANGE_E, ECC_INF_E or MP_VAL when the point
fails validation (not on the curve, out of range, or the identity).
\param private_key The private ECC key.
\param point The point to use (public key).

View File

@@ -303,8 +303,8 @@ int wc_MlDsaKey_SignCtx(wc_MlDsaKey* key, const byte* ctx, byte ctxLen,
\return 0 on success.
\return BAD_FUNC_ARG if any required pointer is NULL, ctxLen is
invalid, hashAlg is not supported or the key has no private key
set.
invalid, hashAlg is not supported or is weaker than the parameter set
(FIPS 204 sec 5.4), or the key has no private key set.
\return BUFFER_E if the sig buffer is too small.
\param [in,out] key Pointer to a wc_MlDsaKey with the private key.
@@ -482,7 +482,8 @@ int wc_MlDsaKey_VerifyCtx(wc_MlDsaKey* key, const byte* sig, word32 sigLen,
\return 0 if verification completed (check res for the result).
\return BAD_FUNC_ARG if any required pointer is NULL, ctxLen is
invalid, or hashAlg is unsupported.
invalid, or hashAlg is unsupported or weaker than the parameter set
(FIPS 204 sec 5.4).
\param [in,out] key Pointer to a wc_MlDsaKey with the public key.
\param [in] sig Signature bytes to verify.

View File

@@ -834,6 +834,112 @@ static int ecc_shared_secret_size_bound(WC_RNG* rng, int curveId, int fieldSz)
}
#endif
/* wc_ecc_shared_secret_ex fully validates a raw peer point, SP 800-56Ar3
* 5.6.2.3.3. Rejections run first: a pending async call leaves key state set. */
int test_wc_ecc_shared_secret_ex_peer_point(void)
{
EXPECT_DECLS;
#if defined(HAVE_ECC) && defined(HAVE_ECC_DHE) && \
defined(HAVE_ECC_KEY_IMPORT) && !defined(WC_NO_RNG) && \
!defined(NO_ECC256) && !defined(WOLFSSL_ATECC508A) && \
!defined(WOLFSSL_ATECC608A) && !defined(WOLFSSL_MICROCHIP_TA100) && \
!defined(PLUTON_CRYPTO_ECC) && !defined(WOLFSSL_CRYPTOCELL) && \
!defined(WOLFSSL_KCAPI_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_ECC)
/* P-256 base point G, uncompressed X9.63 encoding. Not const: older
* wc_ecc_import_point_der() takes byte*. */
byte g[] = {
0x04,
0x6B,0x17,0xD1,0xF2,0xE1,0x2C,0x42,0x47,0xF8,0xBC,0xE6,0xE5,
0x63,0xA4,0x40,0xF2,0x77,0x03,0x7D,0x81,0x2D,0xEB,0x33,0xA0,
0xF4,0xA1,0x39,0x45,0xD8,0x98,0xC2,0x96,
0x4F,0xE3,0x42,0xE2,0xFE,0x1A,0x7F,0x9B,0x8E,0xE7,0xEB,0x4A,
0x7C,0x0F,0x9E,0x16,0x2B,0xCE,0x33,0x57,0x6B,0x31,0x5E,0xCE,
0xCB,0xB6,0x40,0x68,0x37,0xBF,0x51,0xF5
};
byte bad[sizeof(g)];
ecc_key key;
ecc_point* peer = NULL;
WC_RNG rng;
byte out[MAX_ECC_BYTES];
word32 outLen;
int idx = wc_ecc_get_curve_idx(ECC_SECP256R1);
int ret;
XMEMSET(&key, 0, sizeof(key));
XMEMSET(&rng, 0, sizeof(rng));
PRIVATE_KEY_UNLOCK();
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ecc_init(&key), 0);
ret = wc_ecc_make_key_ex(&rng, 32, &key, ECC_SECP256R1);
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &key.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
ExpectIntEQ(ret, 0);
#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
!defined(HAVE_SELFTEST)
ExpectIntEQ(wc_ecc_set_rng(&key, &rng), 0);
#endif
ExpectNotNull(peer = wc_ecc_new_point());
/* Older FIPS and selftest modules keep an ecc.c without this check, and
* SE050, STM32 PKA and SILABS hardware are not covered here. */
#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \
!defined(HAVE_SELFTEST) && !defined(WOLFSSL_SE050) && \
!defined(WOLFSSL_STM32_PKA) && !defined(WOLFSSL_SILABS_SE_ACCEL)
/* G with one bit of y flipped is off the curve. */
XMEMCPY(bad, g, sizeof(g));
bad[sizeof(bad) - 1] ^= 0x01;
ExpectIntEQ(wc_ecc_import_point_der(bad, (word32)sizeof(bad), idx, peer),
0);
outLen = sizeof(out);
ExpectIntNE(wc_ecc_shared_secret_ex(&key, peer, out, &outLen), 0);
#if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
{
/* A P-384 point is not on P-256. */
ecc_key key2;
XMEMSET(&key2, 0, sizeof(key2));
ExpectIntEQ(wc_ecc_init(&key2), 0);
ret = wc_ecc_make_key_ex(&rng, 48, &key2, ECC_SECP384R1);
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &key2.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
ExpectIntEQ(ret, 0);
outLen = sizeof(out);
ExpectIntNE(wc_ecc_shared_secret_ex(&key, &key2.pubkey, out, &outLen),
0);
wc_ecc_free(&key2);
}
#endif
#ifdef WOLFSSL_PUBLIC_MP
/* G with Z = 2: ECDH would use the Jacobian point (x/4, y/8), not the
* affine (x, y) that the checks read. */
ExpectIntEQ(wc_ecc_import_point_der(g, (word32)sizeof(g), idx, peer), 0);
ExpectIntEQ(mp_set(peer->z, 2), MP_OKAY);
outLen = sizeof(out);
ExpectIntNE(wc_ecc_shared_secret_ex(&key, peer, out, &outLen), 0);
#endif
#else
(void)bad;
#endif
ExpectIntEQ(wc_ecc_import_point_der(g, (word32)sizeof(g), idx, peer), 0);
outLen = sizeof(out);
ret = wc_ecc_shared_secret_ex(&key, peer, out, &outLen);
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &key.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
ExpectIntEQ(ret, 0);
wc_ecc_del_point(peer);
wc_ecc_free(&key);
DoExpectIntEQ(wc_FreeRng(&rng), 0);
PRIVATE_KEY_LOCK();
#endif
return EXPECT_RESULT();
}
/*
* Testing wc_ecc_shared_secret() output buffer bounds at the field-size edge.
*/
@@ -3169,11 +3275,8 @@ int test_wc_ecc_shared_secret_ssh(void)
WC_RNG rng;
int ret;
int keySz = KEY32;
#if FIPS_VERSION3_GE(6,0,0)
int key2Sz = KEY28;
#else
int key2Sz = KEY24;
#endif
/* ECDH needs both keys on one curve, SP 800-56A Rev 3 sec 5.7.1.2. */
int key2Sz = KEY32;
byte secret[KEY32];
word32 secretLen = (word32)keySz;

View File

@@ -38,6 +38,7 @@ int test_wc_ecc_params(void);
int test_wc_ecc_signVerify_hash(void);
int test_wc_ecc_shared_secret(void);
int test_wc_ecc_shared_secret_at_infinity(void);
int test_wc_ecc_shared_secret_ex_peer_point(void);
int test_wc_ecc_shared_secret_size_bounds(void);
int test_wc_ecc_export_x963(void);
int test_wc_ecc_export_x963_ex(void);
@@ -94,6 +95,7 @@ int test_wc_EccPublicKeyDecode_explicit_curve_size(void);
TEST_DECL_GROUP("ecc", test_wc_ecc_signVerify_hash), \
TEST_DECL_GROUP("ecc", test_wc_ecc_shared_secret), \
TEST_DECL_GROUP("ecc", test_wc_ecc_shared_secret_at_infinity), \
TEST_DECL_GROUP("ecc", test_wc_ecc_shared_secret_ex_peer_point), \
TEST_DECL_GROUP("ecc", test_wc_ecc_shared_secret_size_bounds), \
TEST_DECL_GROUP("ecc", test_wc_ecc_export_x963), \
TEST_DECL_GROUP("ecc", test_wc_ecc_export_x963_ex), \

View File

@@ -1351,6 +1351,123 @@ int test_mldsa_sign_vfy(void)
return EXPECT_RESULT();
}
#if defined(WOLFSSL_HAVE_MLDSA) && defined(WC_MLDSA_HAVE_NATIVE) && \
!defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \
!defined(WOLFSSL_MLDSA_NO_SIGN) && !defined(WOLFSSL_MLDSA_NO_VERIFY)
/* Collision strength in bits of each pre-hash, FIPS 202 Table 4. */
static const struct {
int hash;
int strength;
} mldsa_prehash_strengths[] = {
{ WC_HASH_TYPE_SHA224, 112 },
{ WC_HASH_TYPE_SHA256, 128 },
{ WC_HASH_TYPE_SHA384, 192 },
{ WC_HASH_TYPE_SHA512, 256 },
{ WC_HASH_TYPE_SHA512_224, 112 },
{ WC_HASH_TYPE_SHA512_256, 128 },
{ WC_HASH_TYPE_SHA3_224, 112 },
{ WC_HASH_TYPE_SHA3_256, 128 },
{ WC_HASH_TYPE_SHA3_384, 192 },
{ WC_HASH_TYPE_SHA3_512, 256 },
{ WC_HASH_TYPE_SHAKE128, 128 },
{ WC_HASH_TYPE_SHAKE256, 256 },
};
static int mldsa_prehash_strength_level(byte level, int lambda, WC_RNG* rng)
{
EXPECT_DECLS;
wc_MlDsaKey* key;
byte* sig;
byte* goodSig;
word32 sigLen;
word32 goodSigLen = MLDSA_MAX_SIG_SIZE;
byte digest[WC_MAX_DIGEST_SIZE];
int digestSz;
int hash;
int res = 0;
int i;
key = (wc_MlDsaKey*)XMALLOC(sizeof(*key), NULL, DYNAMIC_TYPE_TMP_BUFFER);
sig = (byte*)XMALLOC(MLDSA_MAX_SIG_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
goodSig = (byte*)XMALLOC(MLDSA_MAX_SIG_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
ExpectNotNull(key);
ExpectNotNull(sig);
ExpectNotNull(goodSig);
if (key != NULL) {
XMEMSET(key, 0, sizeof(*key));
}
XMEMSET(digest, 0x5A, sizeof(digest));
ExpectIntEQ(wc_MlDsaKey_Init(key, NULL, INVALID_DEVID), 0);
ExpectIntEQ(wc_MlDsaKey_SetParams(key, level), 0);
ExpectIntEQ(wc_MlDsaKey_MakeKey(key, rng), 0);
/* SHAKE256 is in every ML-DSA build and allowed at every level: a
* well-formed signature to verify. */
ExpectIntEQ(wc_MlDsaKey_SignCtxHash(key, NULL, 0, goodSig, &goodSigLen,
digest, (word32)wc_HashGetDigestSize(WC_HASH_TYPE_SHAKE256),
WC_HASH_TYPE_SHAKE256, rng), 0);
for (i = 0; i < (int)(sizeof(mldsa_prehash_strengths) /
sizeof(mldsa_prehash_strengths[0])); i++) {
hash = mldsa_prehash_strengths[i].hash;
digestSz = wc_HashGetDigestSize((enum wc_HashType)hash);
if (digestSz <= 0) {
continue; /* hash not compiled in */
}
sigLen = MLDSA_MAX_SIG_SIZE;
if (mldsa_prehash_strengths[i].strength >= lambda) {
ExpectIntEQ(wc_MlDsaKey_SignCtxHash(key, NULL, 0, sig, &sigLen,
digest, (word32)digestSz, hash, rng), 0);
ExpectIntEQ(wc_MlDsaKey_VerifyCtxHash(key, sig, sigLen, NULL, 0,
digest, (word32)digestSz, hash, &res), 0);
ExpectIntEQ(res, 1);
}
else {
ExpectIntEQ(wc_MlDsaKey_SignCtxHash(key, NULL, 0, sig, &sigLen,
digest, (word32)digestSz, hash, rng),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_MlDsaKey_VerifyCtxHash(key, goodSig, goodSigLen,
NULL, 0, digest, (word32)digestSz, hash, &res),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
}
}
wc_MlDsaKey_Free(key);
XFREE(goodSig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return EXPECT_RESULT();
}
#endif
/* HashML-DSA rejects a pre-hash weaker than lambda, FIPS 204 sec 5.4. */
int test_mldsa_prehash_strength(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_MLDSA) && defined(WC_MLDSA_HAVE_NATIVE) && \
!defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \
!defined(WOLFSSL_MLDSA_NO_SIGN) && !defined(WOLFSSL_MLDSA_NO_VERIFY)
WC_RNG rng;
XMEMSET(&rng, 0, sizeof(WC_RNG));
ExpectIntEQ(wc_InitRng(&rng), 0);
#ifndef WOLFSSL_NO_ML_DSA_44
ExpectIntEQ(mldsa_prehash_strength_level(WC_ML_DSA_44, 128, &rng),
TEST_SUCCESS);
#endif
#ifndef WOLFSSL_NO_ML_DSA_65
ExpectIntEQ(mldsa_prehash_strength_level(WC_ML_DSA_65, 192, &rng),
TEST_SUCCESS);
#endif
#ifndef WOLFSSL_NO_ML_DSA_87
ExpectIntEQ(mldsa_prehash_strength_level(WC_ML_DSA_87, 256, &rng),
TEST_SUCCESS);
#endif
DoExpectIntEQ(wc_FreeRng(&rng), 0);
#endif
return EXPECT_RESULT();
}
int test_mldsa_check_key(void)
{
EXPECT_DECLS;

View File

@@ -33,6 +33,7 @@ int test_mldsa_make_key(void);
int test_mldsa_sign(void);
int test_mldsa_verify(void);
int test_mldsa_sign_vfy(void);
int test_mldsa_prehash_strength(void);
int test_mldsa_check_key(void);
int test_mldsa_public_der_decode(void);
int test_mldsa_der(void);
@@ -79,6 +80,7 @@ int test_wc_MlDsaKey_SetPrecompA(void);
TEST_DECL_GROUP("mldsa", test_mldsa_sign), \
TEST_DECL_GROUP("mldsa", test_mldsa_verify), \
TEST_DECL_GROUP("mldsa", test_mldsa_sign_vfy), \
TEST_DECL_GROUP("mldsa", test_mldsa_prehash_strength), \
TEST_DECL_GROUP("mldsa", test_mldsa_check_key), \
TEST_DECL_GROUP("mldsa", test_mldsa_public_der_decode), \
TEST_DECL_GROUP("mldsa", test_mldsa_der), \

View File

@@ -1551,6 +1551,13 @@ static int _ecc_validate_public_key(ecc_key* key, int partial, int priv);
!defined(WOLFSSL_KCAPI_ECC)
static int _ecc_pairwise_consistency_test(ecc_key* key, WC_RNG* rng);
#endif
#if defined(HAVE_ECC_DHE) && !defined(WOLFSSL_ATECC508A) && \
!defined(WOLFSSL_ATECC608A) && !defined(WOLFSSL_MICROCHIP_TA100) && \
!defined(WOLFSSL_CRYPTOCELL) && !defined(WOLFSSL_KCAPI_ECC) && \
!defined(WOLF_CRYPTO_CB_ONLY_ECC)
static int ecc_shared_secret_point(ecc_key* private_key, ecc_point* point,
byte* out, word32* outlen, int checkPoint);
#endif
#ifdef HAVE_COMP_KEY
@@ -4883,10 +4890,13 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out,
if (private_key->keyIdSet)
err = se050_ecc_shared_secret(private_key, public_key, out, outlen);
else
err = wc_ecc_shared_secret_ex(private_key, &public_key->pubkey, out,
outlen);
err = ecc_shared_secret_point(private_key, &public_key->pubkey, out,
outlen, 0);
#else
err = wc_ecc_shared_secret_ex(private_key, &public_key->pubkey, out, outlen);
/* No point check: the key got whatever its import ran, in full under
* WOLFSSL_VALIDATE_ECC_IMPORT. */
err = ecc_shared_secret_point(private_key, &public_key->pubkey, out, outlen,
0);
#endif /* WOLFSSL_ATECC508A */
#endif /* !WOLF_CRYPTO_CB_ONLY_ECC */
@@ -5263,17 +5273,61 @@ static int wc_ecc_shared_secret_gen_async(ecc_key* private_key,
#endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_ECC */
#ifndef WOLF_CRYPTO_CB_ONLY_ECC
/**
Create an ECC shared secret between private key and public point
private_key The private ECC key (heap hint based on private key)
point The point to use (public key)
out [out] Destination of the shared secret
Conforms to EC-DH from ANSI X9.63
outlen [in/out] The max size and resulting size of the shared secret
return MP_OKAY if successful
*/
int wc_ecc_shared_secret_ex(ecc_key* private_key, ecc_point* point,
byte* out, word32 *outlen)
#ifdef HAVE_ECC_CHECK_PUBKEY_ORDER
/* Full public key validation of a peer point through wc_ecc_check_key,
* SP 800-56Ar3 5.6.2.3.3. */
static int ecc_check_peer_point(ecc_key* key, ecc_point* point)
{
int err;
WC_DECLARE_VAR(peer, ecc_key, 1, key->heap);
WC_ALLOC_VAR_EX(peer, ecc_key, 1, key->heap, DYNAMIC_TYPE_ECC,
return MEMORY_E);
err = wc_ecc_init_ex(peer, key->heap, INVALID_DEVID);
if (err == MP_OKAY) {
#ifdef WOLFSSL_CUSTOM_CURVES
if (key->idx == ECC_CUSTOM_IDX)
err = wc_ecc_set_custom_curve(peer, key->dp);
else
#endif
err = wc_ecc_set_curve(peer, key->dp->size, key->dp->id);
if (err == MP_OKAY)
err = wc_ecc_copy_point(point, &peer->pubkey);
if (err == MP_OKAY) {
peer->type = ECC_PUBLICKEY;
err = wc_ecc_check_key(peer);
}
wc_ecc_free(peer);
}
WC_FREE_VAR_EX(peer, key->heap, DYNAMIC_TYPE_ECC);
return err;
}
#else
/* wc_ecc_check_key checks nothing in this build: still reject the identity,
* out of range and off-curve points, SP 800-56Ar3 5.6.2.3.4. */
static int ecc_check_peer_point(ecc_key* key, ecc_point* point)
{
int err;
DECLARE_CURVE_SPECS(3);
if (wc_ecc_point_is_at_infinity(point))
return ECC_INF_E;
ALLOC_CURVE_SPECS(3, err);
if (err == MP_OKAY) {
err = wc_ecc_curve_load(key->dp, &curve, (ECC_CURVE_FIELD_PRIME |
ECC_CURVE_FIELD_AF | ECC_CURVE_FIELD_BF));
}
if (err == MP_OKAY)
err = wc_ecc_is_point(point, curve->Af, curve->Bf, curve->prime);
wc_ecc_curve_free(curve);
FREE_CURVE_SPECS();
return err;
}
#endif /* HAVE_ECC_CHECK_PUBKEY_ORDER */
/* checkPoint is 0 only for a public key that went through key import. */
static int ecc_shared_secret_point(ecc_key* private_key, ecc_point* point,
byte* out, word32* outlen, int checkPoint)
{
int err;
@@ -5295,6 +5349,12 @@ int wc_ecc_shared_secret_ex(ecc_key* private_key, ecc_point* point,
return ECC_BAD_ARG_E;
}
if (checkPoint && private_key->state == ECC_STATE_NONE) {
err = ecc_check_peer_point(private_key, point);
if (err != MP_OKAY)
return err;
}
switch (private_key->state) {
case ECC_STATE_NONE:
case ECC_STATE_SHARED_SEC_GEN:
@@ -5337,8 +5397,13 @@ int wc_ecc_shared_secret_ex(ecc_key* private_key, ecc_point* point,
err = BAD_STATE_E;
} /* switch */
/* if async pending then return and skip done cleanup below */
if (err == WC_NO_ERR_TRACE(WC_PENDING_E)) {
/* if async pending or non-blocking then return and skip done cleanup below
* so the peer point is checked once per operation, not once per call */
if (err == WC_NO_ERR_TRACE(WC_PENDING_E)
#ifdef WC_ECC_NONBLOCK
|| err == WC_NO_ERR_TRACE(MP_WOULDBLOCK)
#endif
) {
return err;
}
@@ -5350,6 +5415,21 @@ int wc_ecc_shared_secret_ex(ecc_key* private_key, ecc_point* point,
return err;
}
/**
Create an ECC shared secret between private key and public point
private_key The private ECC key (heap hint based on private key)
point The point to use (public key), fully validated here
out [out] Destination of the shared secret
Conforms to EC-DH from ANSI X9.63
outlen [in/out] The max size and resulting size of the shared secret
return MP_OKAY if successful
*/
int wc_ecc_shared_secret_ex(ecc_key* private_key, ecc_point* point,
byte* out, word32 *outlen)
{
return ecc_shared_secret_point(private_key, point, out, outlen, 1);
}
#endif /* WOLF_CRYPTO_CB_ONLY_ECC */
#elif defined(WOLFSSL_KCAPI_ECC)
int wc_ecc_shared_secret_ex(ecc_key* private_key, ecc_point* point,
@@ -11455,6 +11535,13 @@ static int _ecc_validate_public_key(ecc_key* key, int partial, int priv)
#else
/* ECDH uses the point's Z but the SP checks read only x and y, so accept
* only an affine point (Z = 1); all zero x and y still reports ECC_INF_E. */
if (!wc_ecc_point_is_at_infinity(&key->pubkey) &&
!mp_isone(key->pubkey.z)) {
return ECC_BAD_ARG_E;
}
#ifdef WOLFSSL_HAVE_SP_ECC
#ifndef WOLFSSL_SP_NO_256
if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP256R1) {

View File

@@ -862,6 +862,35 @@ static int mldsa_hash256_ctx_msg(wc_Shake* shake256, const byte* tr,
return ret;
}
/* Pre-hash must give at least lambda bits of collision strength.
* FIPS 204 sec 5.4; strengths from FIPS 202 Table 4. */
static int mldsa_check_hash_strength(int hashAlg, word16 lambda)
{
word16 strength;
switch (hashAlg) {
case WC_HASH_TYPE_SHA256:
case WC_HASH_TYPE_SHA512_256:
case WC_HASH_TYPE_SHA3_256:
case WC_HASH_TYPE_SHAKE128:
strength = 128;
break;
case WC_HASH_TYPE_SHA384:
case WC_HASH_TYPE_SHA3_384:
strength = 192;
break;
case WC_HASH_TYPE_SHA512:
case WC_HASH_TYPE_SHA3_512:
case WC_HASH_TYPE_SHAKE256:
strength = 256;
break;
default:
return BAD_FUNC_ARG;
}
return (strength >= lambda) ? 0 : BAD_FUNC_ARG;
}
/* Get the OID for the digest hash.
*
* @param [in] hash Hash algorithm.
@@ -11723,6 +11752,9 @@ static int mldsa_sign_ctx_hash_with_seed(wc_MlDsaKey* key,
if ((int)hashLen != wc_HashGetDigestSize((enum wc_HashType)hashAlg)) {
ret = BAD_LENGTH_E;
}
if (ret == 0) {
ret = mldsa_check_hash_strength(hashAlg, key->params->lambda);
}
if (ret == 0) {
XMEMCPY(seedMu, seed, MLDSA_RND_SZ);
@@ -12584,6 +12616,9 @@ static int mldsa_verify_ctx_hash(wc_MlDsaKey* key, const byte* ctx,
{
ret = BAD_LENGTH_E;
}
if (ret == 0) {
ret = mldsa_check_hash_strength(hashAlg, key->params->lambda);
}
if (ret == 0) {
/* Step 6: Hash public key. */

View File

@@ -69007,25 +69007,27 @@ static wc_test_ret_t mldsa_param_test(int param, WC_RNG* rng)
if (res != 1)
ERROR_OUT(WC_TEST_RET_ENC_I(res), out);
#ifndef NO_SHA256
#ifdef WOLFSSL_SHAKE256
/* HashML-DSA: the pre-hash APIs take a digest plus its hash type, and
* reach a crypto callback with a preHashType other than NONE. */
* reach a crypto callback with a preHashType other than NONE. SHAKE256
* is strong enough for every parameter set, FIPS 204 sec 5.4. */
{
byte digest[WC_SHA256_DIGEST_SIZE];
byte digest[WC_SHA3_512_DIGEST_SIZE];
ret = wc_Sha256Hash(msg, (word32)sizeof(msg), digest);
ret = wc_Shake256Hash(msg, (word32)sizeof(msg), digest,
(word32)sizeof(digest));
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
sigLen = wc_MlDsaKey_SigSize(key);
ret = wc_MlDsaKey_SignCtxHash(key, NULL, 0, sig, &sigLen, digest,
(word32)sizeof(digest), WC_HASH_TYPE_SHA256, rng);
(word32)sizeof(digest), WC_HASH_TYPE_SHAKE256, rng);
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
res = 0;
ret = wc_MlDsaKey_VerifyCtxHash(key, sig, sigLen, NULL, 0, digest,
(word32)sizeof(digest), WC_HASH_TYPE_SHA256, &res);
(word32)sizeof(digest), WC_HASH_TYPE_SHAKE256, &res);
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
if (res != 1)
@@ -96481,11 +96483,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void)
ret = WC_TEST_RET_ENC_NC;
#endif
/* The pre-hash arms are reached only by the HashML-DSA round trip in
* mldsa_param_test(), so they need !NO_MAKE_KEY and SHA-256 too. */
* mldsa_param_test(), so they need !NO_MAKE_KEY and SHAKE256 too. */
#if !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \
!defined(WOLFSSL_MLDSA_NO_SIGN) && \
!defined(WOLFSSL_MLDSA_NO_VERIFY) && \
!defined(WOLFSSL_MLDSA_NO_CTX) && !defined(NO_SHA256) && \
!defined(WOLFSSL_MLDSA_NO_CTX) && defined(WOLFSSL_SHAKE256) && \
!defined(HAVE_FIPS)
if ((ret == 0) && (myCtx.mldsaSignHashCount == 0))
ret = WC_TEST_RET_ENC_NC;

View File

@@ -6258,6 +6258,11 @@ blinding by defining WC_BLINDING_NO_RNG_ACKNOWLEDGE_WEAKNESS."
#error WC_C_DYNAMIC_FALLBACK needs --enable-fips=dev or dev-no-post
#endif
/* SP 800-38A sec 5.2: CBC input must be a whole number of blocks. */
#if FIPS_VERSION3_GE(7,0,0) && !defined(WOLFSSL_AES_CBC_LENGTH_CHECKS)
#define WOLFSSL_AES_CBC_LENGTH_CHECKS
#endif
/* setup for opt-in DH in FIPS v7+ */
#if FIPS_VERSION3_GE(7,0,0) && !defined(HAVE_DH) && !defined(NO_DH)
#define NO_DH