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:
@@ -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);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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), \
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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), \
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user