diff --git a/.github/workflows/cryptocb-only.yml b/.github/workflows/cryptocb-only.yml index d8883f81ac..d4c4f954b7 100644 --- a/.github/workflows/cryptocb-only.yml +++ b/.github/workflows/cryptocb-only.yml @@ -117,9 +117,18 @@ jobs: {"name": "curve25519", "comment": "WOLF_CRYPTO_CB_ONLY_CURVE25519: strips software X25519 (keygen/shared-secret); swdev provides the software path via cryptocb. Nonblock and async X25519 have no callback path and are left disabled.", "configure": ["CPPFLAGS=-DWOLF_CRYPTO_CB_ONLY_CURVE25519"]}, + {"name": "mldsa", + "comment": "WOLF_CRYPTO_CB_ONLY_MLDSA: strips the software ML-DSA core (NTT, matrix expansion, rejection sampling, the sign/verify workers and the x86 assembly); key import/export, the size queries and the DER paths stay, and the cached matrix/vector fields stay in the key struct so its layout is unchanged. The in-tree cryptocb test registers a callback-only ML-DSA device and drives key generation, signing, verifying and the private-key check through it, so the successful dispatch path is covered and not just the no-device refusal.", + "configure": ["CPPFLAGS=-DWOLF_CRYPTO_CB_ONLY_MLDSA"]}, + {"name": "mldsa-verify-only", + "comment": "WOLF_CRYPTO_CB_ONLY_MLDSA against a verify-only ML-DSA build. That combination drops WOLFSSL_MLDSA_CHECK_KEY and the signing entry points, so it catches a callback-only path that assumes an API which this configuration does not compile.", + "configure": ["--enable-mldsa=verify-only", "CPPFLAGS=-DWOLF_CRYPTO_CB_ONLY_MLDSA"]}, + {"name": "mldsa-no-verify", + "comment": "WOLF_CRYPTO_CB_ONLY_MLDSA against a sign-only ML-DSA build (WOLFSSL_MLDSA_NO_VERIFY), the mirror of the verify-only entry.", + "configure": ["--enable-mldsa=sign", "CPPFLAGS=-DWOLF_CRYPTO_CB_ONLY_MLDSA"]}, {"name": "all", - "comment": "All seven ONLY_* macros at once: every supported software primitive is stripped and dispatched through cryptocb. Catches any cross-algorithm call that a single-strip entry would still resolve via the remaining software paths.", - "configure": ["CPPFLAGS=-DWOLF_CRYPTO_CB_ONLY_ECC -DWOLF_CRYPTO_CB_ONLY_RSA -DWOLF_CRYPTO_CB_ONLY_SHA256 -DWOLF_CRYPTO_CB_ONLY_SHA512 -DWOLF_CRYPTO_CB_ONLY_AES -DWOLF_CRYPTO_CB_ONLY_ED25519 -DWOLF_CRYPTO_CB_ONLY_CURVE25519"]} + "comment": "All eight ONLY_* macros at once: every supported software primitive is stripped and dispatched through cryptocb. Catches any cross-algorithm call that a single-strip entry would still resolve via the remaining software paths.", + "configure": ["CPPFLAGS=-DWOLF_CRYPTO_CB_ONLY_ECC -DWOLF_CRYPTO_CB_ONLY_RSA -DWOLF_CRYPTO_CB_ONLY_SHA256 -DWOLF_CRYPTO_CB_ONLY_SHA512 -DWOLF_CRYPTO_CB_ONLY_AES -DWOLF_CRYPTO_CB_ONLY_ED25519 -DWOLF_CRYPTO_CB_ONLY_CURVE25519 -DWOLF_CRYPTO_CB_ONLY_MLDSA"]} ]} EOF .github/scripts/parallel-make-check.py \ diff --git a/tests/api.c b/tests/api.c index dcffdf9edd..7908c51036 100644 --- a/tests/api.c +++ b/tests/api.c @@ -27983,6 +27983,7 @@ static int test_wc_SignCRL_mldsa(void) EXPECT_DECLS; #if defined(WOLFSSL_CERT_GEN) && defined(HAVE_CRL) && !defined(NO_FILESYSTEM) && \ !defined(NO_ASN) && defined(WOLFSSL_HAVE_MLDSA) && \ + defined(WC_MLDSA_HAVE_NATIVE) && \ defined(WOLFSSL_PEM_TO_DER) && !defined(WOLFSSL_MLDSA_NO_SIGN) && \ !defined(WOLFSSL_MLDSA_NO_ASN1) static const struct { diff --git a/tests/api/test_mldsa.c b/tests/api/test_mldsa.c index c7abe5f6dc..9797a7d555 100644 --- a/tests/api/test_mldsa.c +++ b/tests/api/test_mldsa.c @@ -710,7 +710,8 @@ int test_mldsa(void) int test_mldsa_sign_pubonly_fails(void) { EXPECT_DECLS; -#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) +#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + defined(WC_MLDSA_HAVE_NATIVE) #if defined(WOLFSSL_HAVE_MLDSA) && \ !defined(WOLFSSL_MLDSA_NO_SIGN) && \ !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \ @@ -803,6 +804,7 @@ int test_mldsa_make_key(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_MLDSA) && \ + defined(WC_MLDSA_HAVE_NATIVE) && \ !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) wc_MlDsaKey* key; WC_RNG rng; @@ -1263,6 +1265,7 @@ int test_mldsa_sign_vfy(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_MlDsaKey* key; @@ -1351,6 +1354,7 @@ int test_mldsa_check_key(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_MLDSA) && \ + defined(WC_MLDSA_HAVE_NATIVE) && \ defined(WOLFSSL_MLDSA_CHECK_KEY) && \ !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) wc_MlDsaKey* checkKey; @@ -3020,6 +3024,7 @@ int test_mldsa_der(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_MLDSA) && \ + defined(WC_MLDSA_HAVE_NATIVE) && \ !defined(WOLFSSL_MLDSA_NO_ASN1) && \ !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) wc_MlDsaKey* key; @@ -3292,6 +3297,7 @@ int test_mldsa_oneasymkey_version(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLFSSL_MLDSA_NO_ASN1) && \ + defined(WC_MLDSA_HAVE_NATIVE) && \ !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) #ifndef WOLFSSL_NO_ML_DSA_44 ExpectIntEQ(mldsa_oneasymkey_version_check(WC_ML_DSA_44), @@ -3313,6 +3319,7 @@ int test_mldsa_make_key_from_seed(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_MLDSA) && \ + defined(WC_MLDSA_HAVE_NATIVE) && \ !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) wc_MlDsaKey* key; #ifndef WOLFSSL_NO_ML_DSA_44 @@ -12597,6 +12604,7 @@ int test_mldsa_sign_ctx_kats(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_MLDSA) && \ + defined(WC_MLDSA_HAVE_NATIVE) && \ !defined(WOLFSSL_MLDSA_NO_SIGN) wc_MlDsaKey* key; word32 sigLen; @@ -16829,6 +16837,7 @@ int test_mldsa_verify_ctx_kats(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_MLDSA) && \ + defined(WC_MLDSA_HAVE_NATIVE) && \ !defined(WOLFSSL_MLDSA_NO_VERIFY) wc_MlDsaKey* key; int res; @@ -24622,6 +24631,7 @@ int test_mldsa_sign_mu_kats(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLFSSL_MLDSA_NO_SIGN) && \ + defined(WC_MLDSA_HAVE_NATIVE) && \ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) wc_MlDsaKey* key = NULL; word32 sigLen; @@ -27483,6 +27493,7 @@ int test_mldsa_verify_mu_kats(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLFSSL_MLDSA_NO_VERIFY) && \ + defined(WC_MLDSA_HAVE_NATIVE) && \ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) wc_MlDsaKey* key = NULL; byte* sigBuf = NULL; @@ -29747,6 +29758,7 @@ int test_mldsa_PrivateKeyDecode_OpenSSL_form(void) EXPECT_DECLS; #if !defined(NO_ASN) && defined(HAVE_PKCS8) && \ + defined(WC_MLDSA_HAVE_NATIVE) && \ defined(WOLFSSL_HAVE_MLDSA) && \ !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \ !defined(WOLFSSL_MLDSA_NO_ASN1) && defined(WOLFSSL_ASN_TEMPLATE) @@ -29840,6 +29852,7 @@ int test_mldsa_pkcs8_import_OpenSSL_form(void) { EXPECT_DECLS; #if !defined(NO_ASN) && defined(HAVE_PKCS8) && \ + defined(WC_MLDSA_HAVE_NATIVE) && \ defined(WOLFSSL_HAVE_MLDSA) && \ !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \ !defined(WOLFSSL_MLDSA_NO_SIGN) && \ @@ -29914,6 +29927,7 @@ int test_mldsa_pkcs8_export_import_wolfSSL_form(void) { EXPECT_DECLS; #if !defined(NO_ASN) && defined(HAVE_PKCS8) && \ + defined(WC_MLDSA_HAVE_NATIVE) && \ defined(WOLFSSL_HAVE_MLDSA) && !defined(NO_TLS) && \ (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)) && \ !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \ @@ -30028,7 +30042,7 @@ int test_mldsa_pkcs8_export_import_wolfSSL_form(void) int test_mldsa_encode_w1_large_values(void) { EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_MLDSA) && \ +#if defined(WOLFSSL_HAVE_MLDSA) && defined(WC_MLDSA_HAVE_NATIVE) && \ (!defined(WOLFSSL_MLDSA_NO_SIGN) || \ !defined(WOLFSSL_MLDSA_NO_VERIFY)) @@ -30546,6 +30560,7 @@ int test_mldsa_verify_hash(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_MLDSA) && \ + defined(WC_MLDSA_HAVE_NATIVE) && \ !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \ !defined(WOLFSSL_MLDSA_NO_VERIFY) wc_MlDsaKey key; @@ -30586,6 +30601,7 @@ int test_dilithium_hash(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_MLDSA) && \ + defined(WC_MLDSA_HAVE_NATIVE) && \ !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \ !defined(WOLFSSL_MLDSA_NO_VERIFY) wc_MlDsaKey key; @@ -30799,6 +30815,7 @@ int test_wc_MldsaFeatureCoverage(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_MLDSA) && \ + defined(WC_MLDSA_HAVE_NATIVE) && \ !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \ !defined(WOLFSSL_MLDSA_VERIFY_ONLY) && \ !defined(WOLFSSL_MLDSA_NO_SIGN) && \ @@ -30888,7 +30905,8 @@ int test_wc_MldsaFeatureCoverage(void) int test_wc_MldsaDecisionCoverage2(void) { EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_MLDSA) +#if defined(WOLFSSL_HAVE_MLDSA) && \ + defined(WC_MLDSA_HAVE_NATIVE) wc_MlDsaKey key; int inited = 0; diff --git a/tests/api/test_mldsa_legacy.c b/tests/api/test_mldsa_legacy.c index a8f1c131f4..6de7cd0db5 100644 --- a/tests/api/test_mldsa_legacy.c +++ b/tests/api/test_mldsa_legacy.c @@ -373,7 +373,8 @@ int test_mldsa_legacy_shim(void) #if !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && !defined(WOLFSSL_MLDSA_NO_SIGN) && \ !defined(WOLFSSL_MLDSA_NO_VERIFY) && !defined(WOLFSSL_NO_ML_DSA_44) && \ defined(WOLFSSL_MLDSA_PUBLIC_KEY) && defined(WOLFSSL_MLDSA_PRIVATE_KEY) && \ - !defined(WC_NO_RNG) + !defined(WC_NO_RNG) && \ + defined(WC_MLDSA_HAVE_NATIVE) { dilithium_key key; /* legacy typedef */ WC_RNG rng; diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index 569a68e01a..73b24616bf 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -66,6 +66,7 @@ Crypto Callback Build Options: * WOLF_CRYPTO_CB_ONLY_AES: Use only callbacks for AES default: off * WOLF_CRYPTO_CB_ONLY_ED25519: Use only callbacks for Ed25519 default: off * WOLF_CRYPTO_CB_ONLY_CURVE25519: Use only callbacks for X25519 default: off + * WOLF_CRYPTO_CB_ONLY_MLDSA: Use only callbacks for ML-DSA default: off */ #include diff --git a/wolfcrypt/src/wc_mldsa.c b/wolfcrypt/src/wc_mldsa.c index 353ef26288..b102dda8c6 100644 --- a/wolfcrypt/src/wc_mldsa.c +++ b/wolfcrypt/src/wc_mldsa.c @@ -477,6 +477,7 @@ static int mldsa_alloc_pub_buf(wc_MlDsaKey* key) } #endif +#ifndef WOLF_CRYPTO_CB_ONLY_MLDSA /****************************************************************************** * Hash operations ******************************************************************************/ @@ -11190,6 +11191,7 @@ static int mldsa_verify_ctx_hash(wc_MlDsaKey* key, const byte* ctx, return ret; } #endif /* WOLFSSL_MLDSA_NO_VERIFY */ +#endif /* !WOLF_CRYPTO_CB_ONLY_MLDSA */ #ifndef WOLFSSL_MLDSA_NO_MAKE_KEY int wc_MlDsaKey_MakeKey(wc_MlDsaKey* key, WC_RNG* rng) @@ -11217,6 +11219,13 @@ int wc_MlDsaKey_MakeKey(wc_MlDsaKey* key, WC_RNG* rng) } #endif +#ifdef WOLF_CRYPTO_CB_ONLY_MLDSA + if (ret == 0) { + /* No software fallback: only a crypto callback can service + * the request. */ + ret = NO_VALID_DEVID; + } +#else if (ret == 0) { /* Check the level or parameters have been set. */ if (key->params == NULL) { @@ -11227,6 +11236,7 @@ int wc_MlDsaKey_MakeKey(wc_MlDsaKey* key, WC_RNG* rng) ret = mldsa_make_key(key, rng); } } +#endif /* WOLF_CRYPTO_CB_ONLY_MLDSA */ #ifdef HAVE_FIPS /* Pairwise Consistency Test (PCT) per FIPS 140-3 / ISO 19790:2012 @@ -11277,6 +11287,13 @@ int wc_MlDsaKey_MakeKeyFromSeed(wc_MlDsaKey* key, const byte* seed) ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB_ONLY_MLDSA + if (ret == 0) { + /* No software fallback: only a crypto callback can service + * the request. */ + ret = NO_VALID_DEVID; + } +#else if (ret == 0) { /* Check the level or parameters have been set. */ if (key->params == NULL) { @@ -11287,6 +11304,7 @@ int wc_MlDsaKey_MakeKeyFromSeed(wc_MlDsaKey* key, const byte* seed) ret = mldsa_make_key_from_seed(key, seed); } } +#endif /* WOLF_CRYPTO_CB_ONLY_MLDSA */ /* Note: PCT is performed in wc_MlDsaKey_MakeKey() which calls this * function and has the RNG parameter needed for signing. */ @@ -11346,11 +11364,19 @@ int wc_MlDsaKey_SignCtx(wc_MlDsaKey* key, const byte* ctx, byte ctxLen, ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB_ONLY_MLDSA + if (ret == 0) { + /* No software fallback: only a crypto callback can service + * the request. */ + ret = NO_VALID_DEVID; + } +#else if (ret == 0) { /* Sign message. */ ret = mldsa_sign_ctx_msg(key, rng, ctx, ctxLen, msg, msgLen, sig, sigLen); } +#endif /* WOLF_CRYPTO_CB_ONLY_MLDSA */ return ret; } @@ -11400,10 +11426,18 @@ int wc_MlDsaKey_Sign(wc_MlDsaKey* key, byte* sig, word32 *sigLen, ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB_ONLY_MLDSA + if (ret == 0) { + /* No software fallback: only a crypto callback can service + * the request. */ + ret = NO_VALID_DEVID; + } +#else if (ret == 0) { /* Sign message. */ ret = mldsa_sign_msg(key, rng, msg, msgLen, sig, sigLen); } +#endif /* WOLF_CRYPTO_CB_ONLY_MLDSA */ return ret; } @@ -11459,11 +11493,19 @@ int wc_MlDsaKey_SignCtxHash(wc_MlDsaKey* key, const byte* ctx, byte ctxLen, ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB_ONLY_MLDSA + if (ret == 0) { + /* No software fallback: only a crypto callback can service + * the request. */ + ret = NO_VALID_DEVID; + } +#else if (ret == 0) { /* Sign message. */ ret = mldsa_sign_ctx_hash(key, rng, ctx, ctxLen, hashAlg, hash, hashLen, sig, sigLen); } +#endif /* WOLF_CRYPTO_CB_ONLY_MLDSA */ return ret; } @@ -11501,11 +11543,20 @@ int wc_MlDsaKey_SignCtxWithSeed(wc_MlDsaKey* key, const byte* ctx, byte ctxLen, ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB_ONLY_MLDSA + if (ret == 0) { + /* No software fallback: only a crypto callback can service + * the request. */ + ret = NO_VALID_DEVID; + } + (void)msgLen; +#else if (ret == 0) { /* Sign message. */ ret = mldsa_sign_ctx_msg_with_seed(key, seed, ctx, ctxLen, msg, msgLen, sig, sigLen); } +#endif /* WOLF_CRYPTO_CB_ONLY_MLDSA */ return ret; } @@ -11539,10 +11590,19 @@ int wc_MlDsaKey_SignWithSeed(wc_MlDsaKey* key, byte* sig, word32 *sigLen, ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB_ONLY_MLDSA + (void)msgLen; + if (ret == 0) { + /* No software fallback: only a crypto callback can service + * the request. */ + ret = NO_VALID_DEVID; + } +#else if (ret == 0) { /* Sign message. */ ret = mldsa_sign_msg_with_seed(key, seed, msg, msgLen, sig, sigLen); } +#endif /* WOLF_CRYPTO_CB_ONLY_MLDSA */ return ret; } @@ -11582,11 +11642,21 @@ int wc_MlDsaKey_SignCtxHashWithSeed(wc_MlDsaKey* key, const byte* ctx, ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB_ONLY_MLDSA + if (ret == 0) { + /* No software fallback: only a crypto callback can service + * the request. */ + ret = NO_VALID_DEVID; + } + (void)hashLen; + (void)hashAlg; +#else if (ret == 0) { /* Sign message. */ ret = mldsa_sign_ctx_hash_with_seed(key, seed, ctx, ctxLen, hashAlg, hash, hashLen, sig, sigLen); } +#endif /* WOLF_CRYPTO_CB_ONLY_MLDSA */ return ret; } @@ -11626,6 +11696,13 @@ int wc_MlDsaKey_SignMuWithSeed(wc_MlDsaKey* key, byte* sig, word32 *sigLen, ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB_ONLY_MLDSA + if (ret == 0) { + /* No software fallback: only a crypto callback can service + * the request. */ + ret = NO_VALID_DEVID; + } +#else if (ret == 0) { /* Build [seed||mu] buffer and call internal sign function. */ byte seedMu[MLDSA_RND_SZ + MLDSA_MU_SZ]; @@ -11641,6 +11718,7 @@ int wc_MlDsaKey_SignMuWithSeed(wc_MlDsaKey* key, byte* sig, word32 *sigLen, wc_MemZero_Check(seedMu, sizeof(seedMu)); #endif } +#endif /* WOLF_CRYPTO_CB_ONLY_MLDSA */ return ret; } @@ -11695,11 +11773,19 @@ int wc_MlDsaKey_VerifyCtx(wc_MlDsaKey* key, const byte* sig, word32 sigLen, } #endif +#ifdef WOLF_CRYPTO_CB_ONLY_MLDSA + if (ret == 0) { + /* No software fallback: only a crypto callback can service + * the request. */ + ret = NO_VALID_DEVID; + } +#else if (ret == 0) { /* Verify message with signature. */ ret = mldsa_verify_ctx_msg(key, ctx, ctxLen, msg, msgLen, sig, sigLen, res); } +#endif /* WOLF_CRYPTO_CB_ONLY_MLDSA */ return ret; } @@ -11745,10 +11831,18 @@ int wc_MlDsaKey_Verify(wc_MlDsaKey* key, const byte* sig, word32 sigLen, } #endif +#ifdef WOLF_CRYPTO_CB_ONLY_MLDSA + if (ret == 0) { + /* No software fallback: only a crypto callback can service + * the request. */ + ret = NO_VALID_DEVID; + } +#else if (ret == 0) { /* Verify message with signature. */ ret = mldsa_verify_msg(key, msg, msgLen, sig, sigLen, res); } +#endif /* WOLF_CRYPTO_CB_ONLY_MLDSA */ return ret; } @@ -11800,11 +11894,19 @@ int wc_MlDsaKey_VerifyCtxHash(wc_MlDsaKey* key, const byte* sig, word32 sigLen, } #endif +#ifdef WOLF_CRYPTO_CB_ONLY_MLDSA + if (ret == 0) { + /* No software fallback: only a crypto callback can service + * the request. */ + ret = NO_VALID_DEVID; + } +#else if (ret == 0) { /* Verify message with signature. */ ret = mldsa_verify_ctx_hash(key, ctx, ctxLen, hashAlg, hash, hashLen, sig, sigLen, res); } +#endif /* WOLF_CRYPTO_CB_ONLY_MLDSA */ return ret; } @@ -11838,9 +11940,18 @@ int wc_MlDsaKey_VerifyMu(wc_MlDsaKey* key, const byte* sig, word32 sigLen, ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB_ONLY_MLDSA + if (ret == 0) { + /* No software fallback: only a crypto callback can service + * the request. */ + ret = NO_VALID_DEVID; + } + (void)sigLen; +#else if (ret == 0) { ret = mldsa_verify_with_mu(key, mu, sig, sigLen, res); } +#endif /* WOLF_CRYPTO_CB_ONLY_MLDSA */ return ret; } @@ -12424,6 +12535,7 @@ int wc_MlDsaKey_GetSigLen(wc_MlDsaKey* key, int* len) int wc_MlDsaKey_CheckKey(wc_MlDsaKey* key) { int ret = 0; +#ifndef WOLF_CRYPTO_CB_ONLY_MLDSA const wc_MlDsaParams* params = NULL; sword32* a = NULL; sword32* s1 = NULL; @@ -12431,11 +12543,48 @@ int wc_MlDsaKey_CheckKey(wc_MlDsaKey* key) sword32* t = NULL; sword32* t0 = NULL; sword32* t1 = NULL; +#endif /* Validate parameter. */ if (key == NULL) { ret = BAD_FUNC_ARG; } + +#ifdef WOLF_CRYPTO_CB + /* A device-backed key holds no local private material, so dispatch before + * the prvKeySet check the software path makes. */ + if (ret == 0) { + #ifndef WOLF_CRYPTO_CB_FIND + if (key->devId != INVALID_DEVID) + #endif + { + const byte* pub = NULL; + word32 pubSz = 0; + + if (key->pubKeySet) { + int sz = wc_MlDsaKey_PubSize(key); + if (sz > 0) { + pub = key->p; + pubSz = (word32)sz; + } + } + ret = wc_CryptoCb_PqcSignatureCheckPrivKey(key, + WC_PQC_SIG_TYPE_MLDSA, pub, pubSz); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + /* fall-through when unavailable */ + ret = 0; + } + } +#endif /* WOLF_CRYPTO_CB */ + +#ifdef WOLF_CRYPTO_CB_ONLY_MLDSA + /* No software fallback: the check recomputes the public key from the + * private key, which only the device holding it can do. */ + if (ret == 0) { + ret = NO_VALID_DEVID; + } +#else if ((ret == 0) && (!key->prvKeySet)) { ret = BAD_FUNC_ARG; } @@ -12572,6 +12721,8 @@ int wc_MlDsaKey_CheckKey(wc_MlDsaKey* key) /* Dispose of allocated memory. */ XFREE(s1, key->heap, DYNAMIC_TYPE_MLDSA); } +#endif /* WOLF_CRYPTO_CB_ONLY_MLDSA */ + return ret; } #endif /* WOLFSSL_MLDSA_CHECK_KEY */ @@ -12755,7 +12906,8 @@ int wc_MlDsaKey_ImportPubRaw(wc_MlDsaKey* key, const byte* in, word32 inLen) XMEMCPY(key->p, in, inLen); #endif -#ifdef WC_MLDSA_CACHE_PUB_VECTORS +#if defined(WC_MLDSA_CACHE_PUB_VECTORS) && !defined(WOLF_CRYPTO_CB_ONLY_MLDSA) + /* The caches only feed the native signer and verifier. */ #ifndef WC_MLDSA_FIXED_ARRAY /* Allocate t1 if required. */ if (key->t1 == NULL) { @@ -12774,7 +12926,7 @@ int wc_MlDsaKey_ImportPubRaw(wc_MlDsaKey* key, const byte* in, word32 inLen) /* Compute t1 from public key data. */ mldsa_make_pub_vec(key, key->t1); #endif -#ifdef WC_MLDSA_CACHE_MATRIX_A +#if defined(WC_MLDSA_CACHE_MATRIX_A) && !defined(WOLF_CRYPTO_CB_ONLY_MLDSA) #ifndef WC_MLDSA_FIXED_ARRAY /* Allocate matrix a if required. */ if (key->a == NULL) { @@ -12875,7 +13027,9 @@ static int mldsa_set_priv_key(const byte* priv, word32 privSz, { int ret = 0; int expPrivSz; -#ifdef WC_MLDSA_CACHE_MATRIX_A +#if (defined(WC_MLDSA_CACHE_MATRIX_A) || \ + defined(WC_MLDSA_CACHE_PRIV_VECTORS)) && \ + !defined(WOLF_CRYPTO_CB_ONLY_MLDSA) const wc_MlDsaParams* params = key->params; #endif @@ -12915,8 +13069,9 @@ static int mldsa_set_priv_key(const byte* priv, word32 privSz, #endif } - /* Allocate and create cached values. */ -#ifdef WC_MLDSA_CACHE_MATRIX_A + /* Allocate and create cached values. The caches only feed the + * native signer and verifier. */ +#if defined(WC_MLDSA_CACHE_MATRIX_A) && !defined(WOLF_CRYPTO_CB_ONLY_MLDSA) #ifndef WC_MLDSA_FIXED_ARRAY if (ret == 0) { /* Allocate matrix a if required. */ @@ -12941,7 +13096,7 @@ static int mldsa_set_priv_key(const byte* priv, word32 privSz, } } #endif -#ifdef WC_MLDSA_CACHE_PRIV_VECTORS +#if defined(WC_MLDSA_CACHE_PRIV_VECTORS) && !defined(WOLF_CRYPTO_CB_ONLY_MLDSA) #ifndef WC_MLDSA_FIXED_ARRAY if ((ret == 0) && (key->s1 == NULL)) { /* Allocate L vector s1, K vector s2 and K vector t0 if required. */ diff --git a/wolfcrypt/src/wc_mldsa_asm.S b/wolfcrypt/src/wc_mldsa_asm.S index 1fc0d8646e..3ed8e7c64b 100644 --- a/wolfcrypt/src/wc_mldsa_asm.S +++ b/wolfcrypt/src/wc_mldsa_asm.S @@ -43,7 +43,7 @@ #endif /* HAVE_INTEL_AVX512 */ #endif /* NO_AVX512_SUPPORT */ -#ifdef WOLFSSL_HAVE_MLDSA +#if defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLF_CRYPTO_CB_ONLY_MLDSA) #ifdef HAVE_INTEL_AVX2 #ifndef __APPLE__ .data @@ -39757,8 +39757,8 @@ _wc_mldsa_poly_make_pos_avx2: .size wc_mldsa_poly_make_pos_avx2,.-wc_mldsa_poly_make_pos_avx2 #endif /* __APPLE__ */ #endif /* HAVE_INTEL_AVX2 */ -#endif /* WOLFSSL_HAVE_MLDSA */ -#ifdef WOLFSSL_HAVE_MLDSA +#endif /* WOLFSSL_HAVE_MLDSA && !WOLF_CRYPTO_CB_ONLY_MLDSA */ +#if defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLF_CRYPTO_CB_ONLY_MLDSA) #ifndef NO_AVX512_SUPPORT #ifndef HAVE_INTEL_AVX512 #define HAVE_INTEL_AVX512 @@ -63877,8 +63877,8 @@ _wc_mldsa_poly_make_pos_avx512: .size wc_mldsa_poly_make_pos_avx512,.-wc_mldsa_poly_make_pos_avx512 #endif /* __APPLE__ */ #endif /* HAVE_INTEL_AVX512 */ -#endif /* WOLFSSL_HAVE_MLDSA */ -#ifdef WOLFSSL_HAVE_MLDSA +#endif /* WOLFSSL_HAVE_MLDSA && !WOLF_CRYPTO_CB_ONLY_MLDSA */ +#if defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLF_CRYPTO_CB_ONLY_MLDSA) #ifndef NO_AVX512_SUPPORT #ifndef NO_AVX512_VBMI_SUPPORT #ifndef HAVE_INTEL_AVX512_VBMI @@ -64484,7 +64484,7 @@ _wc_mldsa_encode_t0_t1_avx512_vbmi: .size wc_mldsa_encode_t0_t1_avx512_vbmi,.-wc_mldsa_encode_t0_t1_avx512_vbmi #endif /* __APPLE__ */ #endif /* HAVE_INTEL_AVX512_VBMI */ -#endif /* WOLFSSL_HAVE_MLDSA */ +#endif /* WOLFSSL_HAVE_MLDSA && !WOLF_CRYPTO_CB_ONLY_MLDSA */ #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 0556fd5351..586d203d44 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -57020,6 +57020,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t frodokem_test(void) #endif /* WOLFSSL_HAVE_FRODOKEM */ #ifdef WOLFSSL_HAVE_MLDSA +#ifdef WC_MLDSA_HAVE_NATIVE #ifndef WOLFSSL_MLDSA_NO_VERIFY static wc_test_ret_t mldsa_param_vfy_test(int param, const byte* pubKey, word32 pubKeyLen, const byte* sig, word32 sigLen) @@ -60655,6 +60656,7 @@ static wc_test_ret_t mldsa_decode_test(void) } #endif /* (WOLFSSL_MLDSA_PUBLIC_KEY && !WOLFSSL_MLDSA_NO_VERIFY) || * (WOLFSSL_MLDSA_PRIVATE_KEY && !WOLFSSL_MLDSA_NO_SIGN) */ +#endif /* WC_MLDSA_HAVE_NATIVE */ #endif /* WOLFSSL_HAVE_MLDSA - Falcon test below is independent of ML-DSA */ @@ -61295,6 +61297,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t falcon_test(void) WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mldsa_test(void) { wc_test_ret_t ret; +#ifdef WC_MLDSA_HAVE_NATIVE WC_RNG rng; #ifndef HAVE_FIPS @@ -61384,6 +61387,65 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mldsa_test(void) #endif wc_FreeRng(&rng); return ret; +#else /* !WC_MLDSA_HAVE_NATIVE */ + /* Software ML-DSA is compiled out. Confirm the public API refuses an + * operation with NO_VALID_DEVID when the key uses INVALID_DEVID and no + * crypto-callback device is registered, rather than silently doing + * nothing. */ + { + wc_MlDsaKey key; + int key_inited = 0; + int r; + + ret = 0; + r = wc_MlDsaKey_Init(&key, HEAP_HINT, INVALID_DEVID); + if (r != 0) + ret = WC_TEST_RET_ENC_EC(r); + else + key_inited = 1; + if (ret == 0) { + r = wc_MlDsaKey_SetParams(&key, WC_ML_DSA_44); + if (r != 0) + ret = WC_TEST_RET_ENC_EC(r); + } +#ifndef WOLFSSL_MLDSA_NO_SIGN + if (ret == 0) { + byte sig[4]; + word32 sigLen = (word32)sizeof(sig); + + /* Argument checks still run ahead of the dispatch report: no + * private key is set, so this is refused before the question of + * a device even arises. */ + r = wc_MlDsaKey_SignCtx(&key, NULL, 0, sig, &sigLen, + (const byte*)"m", 1, NULL); + if (r != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_NC; + } +#endif +#ifndef WOLFSSL_MLDSA_NO_VERIFY + if (ret == 0) { + byte sig[4]; + word32 sigLen = (word32)sizeof(sig); + int res = 0; + + r = wc_MlDsaKey_VerifyCtx(&key, sig, sigLen, NULL, 0, + (const byte*)"m", 1, &res); + if (r != WC_NO_ERR_TRACE(NO_VALID_DEVID)) + ret = WC_TEST_RET_ENC_NC; + } +#endif +#ifdef WOLFSSL_MLDSA_CHECK_KEY + if (ret == 0) { + r = wc_MlDsaKey_CheckKey(&key); + if (r != WC_NO_ERR_TRACE(NO_VALID_DEVID)) + ret = WC_TEST_RET_ENC_NC; + } +#endif + if (key_inited) + wc_MlDsaKey_Free(&key); + } + return ret; +#endif /* WC_MLDSA_HAVE_NATIVE */ } #endif /* WOLFSSL_HAVE_MLDSA */ @@ -73512,7 +73574,8 @@ static wc_test_ret_t pkcs7_signed_no_content_test(byte* cert, word32 certSz, #endif /* !NO_RSA && !NO_SHA256 */ -#if defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLFSSL_MLDSA_NO_ASN1) && \ +#if defined(WOLFSSL_HAVE_MLDSA) && defined(WC_MLDSA_HAVE_NATIVE) && \ + !defined(WOLFSSL_MLDSA_NO_ASN1) && \ !defined(WOLFSSL_MLDSA_NO_SIGN) && !defined(WOLFSSL_MLDSA_NO_VERIFY) && \ !defined(NO_FILESYSTEM) && !defined(NO_ASN) @@ -74084,7 +74147,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pkcs7signed_test(void) rsaCaCertBuf, (word32)rsaCaCertBufSz); #endif -#if defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLFSSL_MLDSA_NO_ASN1) && \ +#if defined(WOLFSSL_HAVE_MLDSA) && defined(WC_MLDSA_HAVE_NATIVE) && \ + !defined(WOLFSSL_MLDSA_NO_ASN1) && \ !defined(WOLFSSL_MLDSA_NO_SIGN) && !defined(WOLFSSL_MLDSA_NO_VERIFY) && \ !defined(NO_FILESYSTEM) && !defined(NO_ASN) if (ret >= 0) @@ -79235,6 +79299,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t blob_test(void) /* Example custom context for crypto callback */ typedef struct { int exampleVar; /* flag for testing if only crypt is enabled. */ +#if defined(WOLFSSL_HAVE_MLDSA) && !defined(WC_MLDSA_HAVE_NATIVE) + int mldsaCount; /* ML-DSA callback invocations */ + int mldsaFail; /* when set, the ML-DSA handler returns this error */ +#endif #ifdef HAVE_ECC int eccMakePubCount; /* EC make-pub callback invocations */ int eccCheckPubCount; /* EC check-pubkey callback invocations */ @@ -80164,6 +80232,28 @@ static int myCryptoCbExportPointX963(const ecc_set_type* dp, ecc_point* pub, #endif /* HAVE_ECC && !WOLFSSL_NO_MALLOC && HAVE_ECC_KEY_EXPORT */ /* Example crypto dev callback function that calls software version */ +#if defined(WOLFSSL_HAVE_MLDSA) && !defined(WC_MLDSA_HAVE_NATIVE) +#define MLDSA_CB_SIG_LEN 32 +/* Deterministic stand-in signature for the callback-only ML-DSA device: it + * covers the message, the context and the pre-hash selector, so a dispatch + * that loses any of them fails the matching verify. */ +static void mldsa_cb_sign(const byte* msg, word32 msgLen, const byte* ctx, + byte ctxLen, word32 preHashType, byte* out) +{ + word32 i; + + for (i = 0; i < MLDSA_CB_SIG_LEN; i++) { + byte b = (byte)(0x5a ^ (byte)i ^ (byte)ctxLen ^ (byte)preHashType); + + if (msgLen > 0) + b ^= msg[i % msgLen]; + if ((ctx != NULL) && (ctxLen > 0)) + b ^= ctx[i % ctxLen]; + out[i] = b; + } +} +#endif + static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) { int ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN); /* return this to bypass HW and @@ -81028,6 +81118,76 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) myCtx->exampleVar++; } #endif /* HAVE_FALCON && !WOLF_CRYPTO_CB_ONLY_FALCON */ + #if defined(WOLFSSL_HAVE_MLDSA) && !defined(WC_MLDSA_HAVE_NATIVE) + /* The software core is stripped, so this device cannot delegate to the + * public API the way the other handlers do; it would dispatch straight + * back here. It answers with its own deterministic signature instead, + * which is enough to prove the dispatch reaches a device for all four + * ML-DSA operations, that the signature and the verify result travel + * back to the caller, and that a device error is reported as-is. The + * signature covers the message and the context, so a call site that + * drops either is caught by the verify step. */ + if ((info->pk.type == WC_PK_TYPE_PQC_SIG_KEYGEN) && + (info->pk.pqc_sig_kg.type == WC_PQC_SIG_TYPE_MLDSA)) { + wc_MlDsaKey* dk = (wc_MlDsaKey*)info->pk.pqc_sig_kg.key; + + myCtx->mldsaCount++; + if (myCtx->mldsaFail != 0) { + ret = myCtx->mldsaFail; + } + else { + /* The device holds the key material; the caller's object only + * records that it now has one. */ + dk->pubKeySet = 1; + dk->prvKeySet = 1; + ret = 0; + } + } + else if ((info->pk.type == WC_PK_TYPE_PQC_SIG_SIGN) && + (info->pk.pqc_sign.type == WC_PQC_SIG_TYPE_MLDSA)) { + myCtx->mldsaCount++; + if (myCtx->mldsaFail != 0) { + ret = myCtx->mldsaFail; + } + else if (*info->pk.pqc_sign.outlen < MLDSA_CB_SIG_LEN) { + ret = BUFFER_E; + } + else { + mldsa_cb_sign(info->pk.pqc_sign.in, info->pk.pqc_sign.inlen, + info->pk.pqc_sign.context, info->pk.pqc_sign.contextLen, + info->pk.pqc_sign.preHashType, info->pk.pqc_sign.out); + *info->pk.pqc_sign.outlen = MLDSA_CB_SIG_LEN; + ret = 0; + } + } + else if ((info->pk.type == WC_PK_TYPE_PQC_SIG_VERIFY) && + (info->pk.pqc_verify.type == WC_PQC_SIG_TYPE_MLDSA)) { + myCtx->mldsaCount++; + if (myCtx->mldsaFail != 0) { + ret = myCtx->mldsaFail; + } + else { + byte expected[MLDSA_CB_SIG_LEN]; + + mldsa_cb_sign(info->pk.pqc_verify.msg, + info->pk.pqc_verify.msglen, info->pk.pqc_verify.context, + info->pk.pqc_verify.contextLen, + info->pk.pqc_verify.preHashType, expected); + if (info->pk.pqc_verify.res != NULL) { + *info->pk.pqc_verify.res = + ((info->pk.pqc_verify.siglen == MLDSA_CB_SIG_LEN) && + (XMEMCMP(info->pk.pqc_verify.sig, expected, + MLDSA_CB_SIG_LEN) == 0)) ? 1 : 0; + } + ret = 0; + } + } + else if ((info->pk.type == WC_PK_TYPE_PQC_SIG_CHECK_PRIV_KEY) && + (info->pk.pqc_sig_check.type == WC_PQC_SIG_TYPE_MLDSA)) { + myCtx->mldsaCount++; + ret = (myCtx->mldsaFail != 0) ? myCtx->mldsaFail : 0; + } + #endif /* WOLFSSL_HAVE_MLDSA && !WC_MLDSA_HAVE_NATIVE */ #ifdef WOLFSSL_HAVE_MLKEM if (info->pk.type == WC_PK_TYPE_PQC_KEM_KEYGEN) { if ((info->pk.pqc_kem_kg.type == WC_PQC_KEM_TYPE_MLKEM) && @@ -82747,6 +82907,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) /* example data for callback */ myCtx.exampleVar = 1; +#if defined(WOLFSSL_HAVE_MLDSA) && !defined(WC_MLDSA_HAVE_NATIVE) + myCtx.mldsaCount = 0; + myCtx.mldsaFail = 0; +#endif #ifdef HAVE_ECC myCtx.eccMakePubCount = 0; myCtx.eccCheckPubCount = 0; @@ -83042,6 +83206,114 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) #ifdef WOLFSSL_HAVE_MLDSA if (ret == 0) ret = mldsa_test(); +#if !defined(WC_MLDSA_HAVE_NATIVE) && !defined(WOLFSSL_MLDSA_NO_SIGN) && \ + !defined(WOLFSSL_MLDSA_NO_VERIFY) && !defined(WC_NO_RNG) + /* With the software core stripped, an ML-DSA operation can only succeed + * through a registered device. Drive key generation, signing, verifying + * and the private-key check that way and confirm the results came back, + * so a dispatch regression cannot hide behind the NO_VALID_DEVID checks + * in mldsa_test(). */ + if (ret == 0) { + WC_DECLARE_VAR(key, wc_MlDsaKey, 1, HEAP_HINT); + WC_DECLARE_VAR(mldsaRng, WC_RNG, 1, HEAP_HINT); + byte sig[MLDSA_CB_SIG_LEN]; + word32 sigLen = (word32)sizeof(sig); + static const byte msg[] = "wolfSSL ML-DSA callback-only dispatch"; + static const byte sigCtx[] = { 0x01, 0x02, 0x03 }; + int key_inited = 0; + int rng_inited = 0; + int baseline = myCtx.mldsaCount; + int res = 0; + int r; + + WC_ALLOC_VAR(key, wc_MlDsaKey, 1, HEAP_HINT); + WC_ALLOC_VAR(mldsaRng, WC_RNG, 1, HEAP_HINT); + if ((!WC_VAR_OK(key)) || (!WC_VAR_OK(mldsaRng))) + ret = WC_TEST_RET_ENC_EC(MEMORY_E); + if (ret == 0) { + /* The device ignores the RNG; keep it off the callback path. */ + r = wc_InitRng_ex(mldsaRng, HEAP_HINT, INVALID_DEVID); + if (r != 0) + ret = WC_TEST_RET_ENC_EC(r); + else + rng_inited = 1; + } + if (ret == 0) { + r = wc_MlDsaKey_Init(key, HEAP_HINT, devId); + if (r != 0) + ret = WC_TEST_RET_ENC_EC(r); + else + key_inited = 1; + } + if (ret == 0) { + r = wc_MlDsaKey_SetParams(key, WC_ML_DSA_44); + if (r != 0) + ret = WC_TEST_RET_ENC_EC(r); + } + if (ret == 0) { + r = wc_MlDsaKey_MakeKey(key, mldsaRng); + if (r != 0) + ret = WC_TEST_RET_ENC_EC(r); + } + if (ret == 0) { + r = wc_MlDsaKey_SignCtx(key, sigCtx, (byte)sizeof(sigCtx), sig, + &sigLen, msg, (word32)sizeof(msg), mldsaRng); + if (r != 0) + ret = WC_TEST_RET_ENC_EC(r); + else if (sigLen != MLDSA_CB_SIG_LEN) + ret = WC_TEST_RET_ENC_NC; + } + if (ret == 0) { + r = wc_MlDsaKey_VerifyCtx(key, sig, sigLen, sigCtx, + (byte)sizeof(sigCtx), msg, (word32)sizeof(msg), &res); + if (r != 0) + ret = WC_TEST_RET_ENC_EC(r); + else if (res != 1) + ret = WC_TEST_RET_ENC_NC; + } + /* A different context must not verify: proves the context reached the + * device rather than being dropped on the way. */ + if (ret == 0) { + static const byte otherCtx[] = { 0x09, 0x09, 0x09 }; + + res = 1; + r = wc_MlDsaKey_VerifyCtx(key, sig, sigLen, otherCtx, + (byte)sizeof(otherCtx), msg, (word32)sizeof(msg), &res); + if (r != 0) + ret = WC_TEST_RET_ENC_EC(r); + else if (res != 0) + ret = WC_TEST_RET_ENC_NC; + } +#ifdef WOLFSSL_MLDSA_CHECK_KEY + /* This is the operation a no-device test cannot cover: before the key + * check dispatched, it could only ever fail. */ + if (ret == 0) { + r = wc_MlDsaKey_CheckKey(key); + if (r != 0) + ret = WC_TEST_RET_ENC_EC(r); + } +#endif + /* Every operation above went through the callback. */ + if ((ret == 0) && (myCtx.mldsaCount <= baseline)) + ret = WC_TEST_RET_ENC_NC; + /* A device error must reach the caller unchanged. */ + if (ret == 0) { + myCtx.mldsaFail = WC_NO_ERR_TRACE(WC_HW_E); + sigLen = (word32)sizeof(sig); + r = wc_MlDsaKey_SignCtx(key, sigCtx, (byte)sizeof(sigCtx), sig, + &sigLen, msg, (word32)sizeof(msg), mldsaRng); + myCtx.mldsaFail = 0; + if (r != WC_NO_ERR_TRACE(WC_HW_E)) + ret = WC_TEST_RET_ENC_NC; + } + if (key_inited) + wc_MlDsaKey_Free(key); + if (rng_inited) + wc_FreeRng(mldsaRng); + WC_FREE_VAR(mldsaRng, HEAP_HINT); + WC_FREE_VAR(key, HEAP_HINT); + } +#endif /* !WC_MLDSA_HAVE_NATIVE && sign && verify && !WC_NO_RNG */ #endif #ifdef WOLFSSL_HAVE_SLHDSA if (ret == 0) { diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 2bfbb4ddef..978ef0fb6f 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -5880,6 +5880,17 @@ blinding by defining WC_BLINDING_NO_RNG_ACKNOWLEDGE_WEAKNESS." #error "WOLF_CRYPTO_CB_ONLY_ED25519 with " \ "WOLFSSL_ED25519_STREAMING_VERIFY is not supported" #endif +#if defined(WOLF_CRYPTO_CB_ONLY_MLDSA) && !defined(WOLF_CRYPTO_CB) + #error "WOLF_CRYPTO_CB_ONLY_MLDSA requires WOLF_CRYPTO_CB" +#endif +#if defined(WOLF_CRYPTO_CB_ONLY_MLDSA) && !defined(WOLFSSL_HAVE_MLDSA) + #error "WOLF_CRYPTO_CB_ONLY_MLDSA requires WOLFSSL_HAVE_MLDSA" +#endif +#if defined(WOLF_CRYPTO_CB_ONLY_MLDSA) && defined(HAVE_FIPS) + /* Key generation runs a pairwise consistency test that the callback would + * have to service; not validated. */ + #error "WOLF_CRYPTO_CB_ONLY_MLDSA is incompatible with FIPS builds" +#endif #if defined(WOLF_CRYPTO_CB_ONLY_CURVE25519) && !defined(WOLF_CRYPTO_CB) #error "WOLF_CRYPTO_CB_ONLY_CURVE25519 requires WOLF_CRYPTO_CB" #endif diff --git a/wolfssl/wolfcrypt/wc_mldsa.h b/wolfssl/wolfcrypt/wc_mldsa.h index 64e0472ebc..b42e34c5f0 100644 --- a/wolfssl/wolfcrypt/wc_mldsa.h +++ b/wolfssl/wolfcrypt/wc_mldsa.h @@ -1081,5 +1081,16 @@ WOLFSSL_TEST_VIS void wc_mldsa_encode_w1_32(const sword32* w1, byte* w1e); } /* extern "C" */ #endif +/* Native implementation core (internal). The public wc_MlDsaKey_* functions + * in wc_mldsa.c wrap it with cryptocb dispatch and argument checking. With + * WOLF_CRYPTO_CB_ONLY_MLDSA the native core is not compiled: all operations go + * through the crypto callback. */ +#ifndef WOLF_CRYPTO_CB_ONLY_MLDSA +/* Signals that native key generation, signing and verifying are available. + * Tests gate on this rather than on the build switch, so a test says what it + * needs rather than which configuration removed it. */ +#define WC_MLDSA_HAVE_NATIVE +#endif + #endif /* WOLFSSL_HAVE_MLDSA */ #endif /* WOLF_CRYPT_WC_MLDSA_H */