diff --git a/.github/workflows/cryptocb-only.yml b/.github/workflows/cryptocb-only.yml index 4dc323fec2..4753d018db 100644 --- a/.github/workflows/cryptocb-only.yml +++ b/.github/workflows/cryptocb-only.yml @@ -28,6 +28,13 @@ jobs: # software path via cryptocb. - name: RSA cppflags: -DWOLF_CRYPTO_CB_ONLY_RSA + # WOLF_CRYPTO_CB_ONLY_SHA256: strips software SHA-256; swdev provides + # the software path via cryptocb. SHA-224 piggybacks on the SHA-256 + # software core so it is incompatible with this strip and must be + # explicitly disabled (it is default-on on x86_64/aarch64). + - name: SHA256 + extra_config: --disable-sha224 + cppflags: -DWOLF_CRYPTO_CB_ONLY_SHA256 name: make check (${{ matrix.name }}) if: github.repository_owner == 'wolfssl' runs-on: ubuntu-24.04 diff --git a/tests/api.c b/tests/api.c index 79f1bed2d5..f5d046f3fc 100644 --- a/tests/api.c +++ b/tests/api.c @@ -30609,6 +30609,7 @@ static int test_SSL_CIPHER_get_xxx(void) } #if defined(WOLF_CRYPTO_CB) && defined(HAVE_IO_TESTS_DEPENDENCIES) && \ + !defined(WOLF_CRYPTO_CB_ONLY_SHA256) && \ !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA) static int load_pem_key_file_as_der(const char* privKeyFile, DerBuffer** pDer, @@ -31612,6 +31613,7 @@ static int test_wc_CryptoCb(void) { EXPECT_DECLS; #if defined(WOLF_CRYPTO_CB) && \ + !defined(WOLF_CRYPTO_CB_ONLY_SHA256) && \ !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA) /* TODO: Add crypto callback API tests */ diff --git a/tests/swdev/swdev.c b/tests/swdev/swdev.c index 2b328d3969..4067a26dbe 100644 --- a/tests/swdev/swdev.c +++ b/tests/swdev/swdev.c @@ -13,6 +13,9 @@ #ifdef HAVE_ECC #include #endif +#ifndef NO_SHA256 +#include +#endif static int swdev_initialized = 0; @@ -120,6 +123,62 @@ static int swdev_ecc_get_sig_size(wc_CryptoInfo* info) } #endif /* HAVE_ECC */ +#ifndef NO_SHA256 +/* Copy hash state between caller's wc_Sha256 and swdev's shadow, leaving + * admin fields (heap, devId, devCtx, W, async, HW ctx) per-side. */ +static void swdev_sha256_copy_state(wc_Sha256* dst, const wc_Sha256* src) +{ + XMEMCPY(dst->digest, src->digest, sizeof(dst->digest)); + XMEMCPY(dst->buffer, src->buffer, sizeof(dst->buffer)); + dst->buffLen = src->buffLen; + dst->loLen = src->loLen; + dst->hiLen = src->hiLen; +#ifdef WC_C_DYNAMIC_FALLBACK + dst->sha_method = src->sha_method; +#endif +#ifdef WOLFSSL_HASH_FLAGS + dst->flags = src->flags; +#endif +} + +/* Run the op on a per-call shadow wc_Sha256 owned by swdev, copying state + * in and out around it. The caller's struct, allocated by libwolfssl with + * the software init stripped, can't be used directly. */ +static int swdev_sha256(wc_CryptoInfo* info) +{ + wc_Sha256* sha256 = info->hash.sha256; + wc_Sha256 shadow; + int ret; + + if (sha256 == NULL) + return BAD_FUNC_ARG; + + ret = wc_InitSha256(&shadow); + if (ret != 0) + return ret; + + swdev_sha256_copy_state(&shadow, sha256); + + if (info->hash.in != NULL) { + ret = wc_Sha256Update(&shadow, info->hash.in, info->hash.inSz); + if (ret != 0) + goto out; + } + + if (info->hash.digest != NULL) { + ret = wc_Sha256Final(&shadow, info->hash.digest); + if (ret != 0) + goto out; + } + + swdev_sha256_copy_state(sha256, &shadow); + +out: + wc_Sha256Free(&shadow); + return ret; +} +#endif /* !NO_SHA256 */ + WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, void* ctx) { @@ -164,6 +223,15 @@ WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, default: return CRYPTOCB_UNAVAILABLE; } +#endif +#ifndef NO_SHA256 + case WC_ALGO_TYPE_HASH: + switch (info->hash.type) { + case WC_HASH_TYPE_SHA256: + return swdev_sha256(info); + default: + return CRYPTOCB_UNAVAILABLE; + } #endif default: return CRYPTOCB_UNAVAILABLE; diff --git a/tests/swdev/user_settings.h b/tests/swdev/user_settings.h index bf364459a8..aaf16c0e25 100644 --- a/tests/swdev/user_settings.h +++ b/tests/swdev/user_settings.h @@ -15,6 +15,7 @@ #undef WOLF_CRYPTO_CB_ONLY_RSA #undef WOLF_CRYPTO_CB_ONLY_ECC +#undef WOLF_CRYPTO_CB_ONLY_SHA256 #ifndef WOLF_CRYPTO_CB #error "wc_swdev requires the main build to define WOLF_CRYPTO_CB" diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index 0036556ba9..bbefe6b3e1 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -52,6 +52,7 @@ Crypto Callback Build Options: * and SHA-512 operations. * WOLF_CRYPTO_CB_ONLY_ECC: Use only callbacks for ECC default: off * WOLF_CRYPTO_CB_ONLY_RSA: Use only callbacks for RSA default: off + * WOLF_CRYPTO_CB_ONLY_SHA256: Use only callbacks for SHA-256 default: off */ #include diff --git a/wolfcrypt/src/sha256.c b/wolfcrypt/src/sha256.c index 93a079a507..5e7b8d01ac 100644 --- a/wolfcrypt/src/sha256.c +++ b/wolfcrypt/src/sha256.c @@ -60,6 +60,10 @@ on the specific device platform. #if !defined(NO_SHA256) && !defined(WOLFSSL_RISCV_ASM) +#if defined(WOLF_CRYPTO_CB_ONLY_SHA256) && defined(WOLFSSL_SHA224) + #error "WOLF_CRYPTO_CB_ONLY_SHA256 is incompatible with WOLFSSL_SHA224" +#endif + #if defined(HAVE_FIPS) && defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2) /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ #define FIPS_NO_WRAPPERS @@ -291,7 +295,8 @@ static int InitSha256(wc_Sha256* sha256) /* Hardware Acceleration */ #if defined(WOLFSSL_X86_64_BUILD) && defined(USE_INTEL_SPEEDUP) && \ - (defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)) + (defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)) && \ + !defined(WOLF_CRYPTO_CB_ONLY_SHA256) /* in case intel instructions aren't available, plus we need the K[] global */ #define NEED_SOFT_SHA256 @@ -1084,7 +1089,7 @@ static int InitSha256(wc_Sha256* sha256) #elif defined(WOLFSSL_RENESAS_RX64_HASH) /* implemented in wolfcrypt/src/port/Renesas/renesas_rx64_hw_sha.c */ -#elif defined(WOLFSSL_PPC32_ASM) +#elif defined(WOLFSSL_PPC32_ASM) && !defined(WOLF_CRYPTO_CB_ONLY_SHA256) extern void Transform_Sha256_Len(wc_Sha256* sha256, const byte* data, word32 len); @@ -1114,7 +1119,7 @@ static int Transform_Sha256(wc_Sha256* sha256, const byte* data) #define XTRANSFORM Transform_Sha256 #define XTRANSFORM_LEN Transform_Sha256_Len -#elif defined(WOLFSSL_ARMASM) +#elif defined(WOLFSSL_ARMASM) && !defined(WOLF_CRYPTO_CB_ONLY_SHA256) int wc_InitSha256_ex(wc_Sha256* sha256, void* heap, int devId) { @@ -1169,6 +1174,21 @@ static WC_INLINE int Transform_Sha256_Len(wc_Sha256* sha256, const byte* data, #define XTRANSFORM Transform_Sha256 #define XTRANSFORM_LEN Transform_Sha256_Len +#elif defined(WOLF_CRYPTO_CB_ONLY_SHA256) + /* Software SHA-256 stripped; every op dispatches via cryptocb. */ + int wc_InitSha256_ex(wc_Sha256* sha256, void* heap, int devId) + { + int ret; + if (sha256 == NULL) + return BAD_FUNC_ARG; + ret = InitSha256(sha256); + if (ret != 0) + return ret; + sha256->heap = heap; + sha256->devId = devId; + sha256->devCtx = NULL; + return ret; + } #else #define NEED_SOFT_SHA256 @@ -1401,7 +1421,6 @@ static WC_INLINE int Transform_Sha256_Len(wc_Sha256* sha256, const byte* data, #endif /* End wc_ software implementation */ - #ifdef XTRANSFORM static WC_INLINE void AddLength(wc_Sha256* sha256, word32 len) @@ -1778,6 +1797,7 @@ static WC_INLINE int Transform_Sha256_Len(wc_Sha256* sha256, const byte* data, #if !defined(WOLFSSL_KCAPI_HASH) +#ifndef WOLFSSL_NO_HASH_RAW int wc_Sha256FinalRaw(wc_Sha256* sha256, byte* hash) { #ifdef LITTLE_ENDIAN_ORDER @@ -1801,6 +1821,7 @@ static WC_INLINE int Transform_Sha256_Len(wc_Sha256* sha256, const byte* data, return 0; } +#endif /* !WOLFSSL_NO_HASH_RAW */ int wc_Sha256Final(wc_Sha256* sha256, byte* hash) { @@ -1964,6 +1985,55 @@ static WC_INLINE int Transform_Sha256_Len(wc_Sha256* sha256, const byte* data, #endif /* XTRANSFORM */ +#ifdef WOLF_CRYPTO_CB_ONLY_SHA256 + + int wc_Sha256Update(wc_Sha256* sha256, const byte* data, word32 len) + { + if (sha256 == NULL) { + return BAD_FUNC_ARG; + } + if (data == NULL && len == 0) { + /* valid, but do nothing */ + return 0; + } + if (data == NULL) { + return BAD_FUNC_ARG; + } + + #ifndef WOLF_CRYPTO_CB_FIND + if (sha256->devId != INVALID_DEVID) + #endif + { + int ret = wc_CryptoCb_Sha256Hash(sha256, data, len, NULL); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + } + + return NO_VALID_DEVID; + } + + int wc_Sha256Final(wc_Sha256* sha256, byte* hash) + { + int ret; + + if (sha256 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + + #ifndef WOLF_CRYPTO_CB_FIND + if (sha256->devId != INVALID_DEVID) + #endif + { + ret = wc_CryptoCb_Sha256Hash(sha256, NULL, 0, hash); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + } + + return NO_VALID_DEVID; + } + +#endif /* WOLF_CRYPTO_CB_ONLY_SHA256 */ + #ifdef WOLFSSL_SHA224 diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index a46eec36ac..43c26e718a 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -5968,7 +5968,8 @@ exit: #undef LARGE_HASH_TEST_INPUT_SZ #endif /* NO_LARGE_HASH_TEST */ -#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_FULL_HASH) +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_FULL_HASH) && \ + !defined(WOLF_CRYPTO_CB_ONLY_SHA256) static wc_test_ret_t sha256_lms_test(wc_Sha256* sha) { byte hash[WC_SHA256_DIGEST_SIZE]; @@ -6061,7 +6062,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sha256_test(void) if ((ret = sha256_large_hash_test(&sha)) != 0) return ret; #endif -#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_FULL_HASH) +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_FULL_HASH) && \ + !defined(WOLF_CRYPTO_CB_ONLY_SHA256) if ((ret = sha256_lms_test(&sha)) != 0) return ret; #endif @@ -71320,6 +71322,52 @@ exit_onlycb: } #endif +#ifdef WOLF_CRYPTO_CB_ONLY_SHA256 +/* Exercise SHA-256 dispatch under CB_ONLY_SHA256: cb-handled then cb-delegated. */ +static wc_test_ret_t sha256_onlycb_test(myCryptoDevCtx *ctx) +{ + wc_test_ret_t ret = 0; +#if !defined(NO_SHA256) + wc_Sha256 sha; + byte hash[WC_SHA256_DIGEST_SIZE]; + const byte in[] = "abc"; + + ret = wc_InitSha256_ex(&sha, HEAP_HINT, devId); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* cb handles the op, expects 0(success) */ + ctx->exampleVar = 99; + ret = wc_Sha256Update(&sha, in, (word32)sizeof(in) - 1); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + ret = wc_Sha256Final(&sha, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + + /* cb delegates to software, expects NO_VALID_DEVID(failure) */ + ctx->exampleVar = 1; + ret = wc_Sha256Update(&sha, in, (word32)sizeof(in) - 1); + if (ret != WC_NO_ERR_TRACE(NO_VALID_DEVID)) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + } else { + ret = 0; + } + ret = wc_Sha256Final(&sha, hash); + if (ret != WC_NO_ERR_TRACE(NO_VALID_DEVID)) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + } else { + ret = 0; + } + +exit_onlycb: + wc_Sha256Free(&sha); +#endif /* !NO_SHA256 */ + (void)ctx; + return ret; +} +#endif /* WOLF_CRYPTO_CB_ONLY_SHA256 */ + /* Example crypto dev callback function that calls software version */ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) { @@ -72034,6 +72082,15 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) /* set devId to invalid, so software is used */ info->hash.sha256->devId = INVALID_DEVID; + #if defined(WOLF_CRYPTO_CB_ONLY_SHA256) + #ifdef DEBUG_WOLFSSL + printf("CryptoDevCb: exampleVar %d\n", myCtx->exampleVar); + #endif + if (myCtx->exampleVar == 99) { + info->hash.sha256->devId = devIdArg; + return 0; + } + #endif if (info->hash.in != NULL) { ret = wc_Sha256Update( @@ -73162,6 +73219,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) ret = ecc_onlycb_test(&myCtx); PRIVATE_KEY_LOCK(); #endif +#if defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLFSSL_SWDEV) + PRIVATE_KEY_UNLOCK(); + if (ret == 0) + ret = sha256_onlycb_test(&myCtx); + PRIVATE_KEY_LOCK(); +#endif #ifdef WOLFSSL_HAVE_MLKEM if (ret == 0) ret = mlkem_test(); diff --git a/wolfssl/wolfcrypt/sha256.h b/wolfssl/wolfcrypt/sha256.h index dd69f57603..ea354695f9 100644 --- a/wolfssl/wolfcrypt/sha256.h +++ b/wolfssl/wolfcrypt/sha256.h @@ -102,6 +102,12 @@ #define WOLFSSL_NO_HASH_RAW #endif +/* no raw hash access when software transform is stripped */ +#if defined(WOLF_CRYPTO_CB_ONLY_SHA256) +#undef WOLFSSL_NO_HASH_RAW +#define WOLFSSL_NO_HASH_RAW +#endif + #define SHA256_NOINLINE WC_NO_INLINE #if !defined(NO_OLD_SHA_NAMES)