From 0f82b9e5fb44bf94c78221784c841939352ced86 Mon Sep 17 00:00:00 2001 From: rizlik Date: Wed, 22 Apr 2026 13:12:47 +0000 Subject: [PATCH 01/21] tests/swdev: add scaffolding for WOLF_CRYPTO_CB_ONLY_* testing Add a software crypto-callback device (wc_swdev) that lets the wolfcrypt test suite run under WOLF_CRYPTO_CB_ONLY_* flags without per-test devId plumbing. The bundle is a separately-compiled second copy of wolfcrypt (software implementations enabled, WOLF_CRYPTO_CB_ONLY_* stripped) linked into testwolfcrypt as a single relocatable object; every symbol is demoted to local via objcopy --keep-global-symbol except wc_SwDev_Callback, so there is no collision with the main libwolfssl. A find callback routes unbound operations (devId == INVALID_DEVID) to the swdev while letting real device IDs pass through. wc_SwDev_Init / wc_SwDev_Cleanup hooks are wired into wolfcrypt/test/test.c. cryptocb_test's WOLF_CRYPTO_CB_FIND and WOLF_CRYPTO_CB_ONLY_RSA blocks are gated off under WOLFSSL_SWDEV. Enable via --enable-swdev (requires --enable-cryptocb). --- .github/workflows/cryptocb-only.yml | 75 ++++++++++++++++++++ configure.ac | 20 ++++++ tests/api.c | 6 +- tests/api/test_pkcs7.c | 28 ++++---- tests/swdev/.gitignore | 4 ++ tests/swdev/Makefile | 104 ++++++++++++++++++++++++++++ tests/swdev/swdev.c | 40 +++++++++++ tests/swdev/swdev.h | 27 ++++++++ tests/swdev/swdev_loader.c | 57 +++++++++++++++ tests/swdev/swdev_loader.h | 29 ++++++++ tests/swdev/user_settings.h | 23 ++++++ wolfcrypt/test/include.am | 47 +++++++++++++ wolfcrypt/test/test.c | 23 +++++- 13 files changed, 464 insertions(+), 19 deletions(-) create mode 100644 .github/workflows/cryptocb-only.yml create mode 100644 tests/swdev/.gitignore create mode 100644 tests/swdev/Makefile create mode 100644 tests/swdev/swdev.c create mode 100644 tests/swdev/swdev.h create mode 100644 tests/swdev/swdev_loader.c create mode 100644 tests/swdev/swdev_loader.h create mode 100644 tests/swdev/user_settings.h diff --git a/.github/workflows/cryptocb-only.yml b/.github/workflows/cryptocb-only.yml new file mode 100644 index 00000000000..4dc323fec27 --- /dev/null +++ b/.github/workflows/cryptocb-only.yml @@ -0,0 +1,75 @@ +name: cryptocb-only Tests + +# START OF COMMON SECTION +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +# END OF COMMON SECTION + +jobs: + make_check: + strategy: + fail-fast: false + matrix: + include: + # WOLF_CRYPTO_CB_ONLY_ECC: strips software ECC; swdev provides the + # software path via cryptocb. FP_ECC / ECCSI / SAKKE / deterministic-k + # test / OPENSSL_EXTRA compat layer all reference stripped primitives + # directly, so they stay off. + - name: ECC + cppflags: -DWOLF_CRYPTO_CB_ONLY_ECC + # WOLF_CRYPTO_CB_ONLY_RSA: strips software RSA; swdev provides the + # software path via cryptocb. + - name: RSA + cppflags: -DWOLF_CRYPTO_CB_ONLY_RSA + name: make check (${{ matrix.name }}) + if: github.repository_owner == 'wolfssl' + runs-on: ubuntu-24.04 + timeout-minutes: 10 + env: + # Common feature set for every entry. SHA-224 is left at the platform + # default (on for x86_64/aarch64); entries that need it off pass + # --disable-sha224 in extra_config. + BASE_CONFIG: >- + --enable-swdev --enable-cryptocb --enable-ecc --enable-rsa --enable-dh + --enable-aesgcm --enable-aesccm --enable-aesctr --enable-aescfb + --enable-aeskeywrap --enable-aessiv --enable-aesofb --enable-aesxts + --enable-camellia --enable-chacha --enable-poly1305 + --enable-sha --enable-sha3 --enable-shake128 --enable-shake256 + --enable-blake2 --enable-blake2s + --enable-hkdf --enable-hashdrbg --enable-hashflags + --enable-curve25519 --enable-ed25519 --enable-curve448 --enable-ed448 + --enable-mlkem --enable-dilithium + --enable-scrypt --enable-pwdbased --enable-pkcs7 --enable-pkcs12 + --enable-certgen --enable-certreq --enable-certext + --enable-keygen --enable-asn=all + --enable-cmac --enable-xchacha + --enable-crl --enable-ocsp --enable-ocspstapling --enable-ocspstapling2 + --enable-dtls --enable-dtls13 --enable-tls13 + steps: + - uses: actions/checkout@v4 + name: Checkout wolfSSL + + - name: Test wolfSSL + run: | + ./autogen.sh + ./configure $BASE_CONFIG ${{ matrix.extra_config }} CPPFLAGS="${{ matrix.cppflags }}" + make -j 4 + make check + + - name: Print errors + if: ${{ failure() }} + run: | + for file in scripts/*.log + do + if [ -f "$file" ]; then + echo "${file}:" + cat "$file" + fi + done diff --git a/configure.ac b/configure.ac index 88208ce605a..5807a198c3e 100644 --- a/configure.ac +++ b/configure.ac @@ -10648,6 +10648,25 @@ if test "$ENABLED_CRYPTOCB_UTILS" != "no"; then fi +# wc_swdev: software crypto-callback device for testing +AC_ARG_ENABLE([swdev], + [AS_HELP_STRING([--enable-swdev],[Build wc_swdev software crypto-callback for tests (default: disabled). Requires --enable-cryptocb, forces WOLF_CRYPTO_CB_FIND, and currently supports in-tree builds only.])], + [ ENABLED_SWDEV=$enableval ], + [ ENABLED_SWDEV=no ] +) + +if test "$ENABLED_SWDEV" = "yes" +then + if test "$ENABLED_CRYPTOCB" != "yes"; then + AC_MSG_ERROR([--enable-swdev requires --enable-cryptocb]) + fi + if test "x$srcdir" != "x."; then + AC_MSG_ERROR([--enable-swdev currently supports in-tree builds only]) + fi + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SWDEV -DWOLF_CRYPTO_CB_FIND" +fi + + # Asynchronous Crypto AC_ARG_ENABLE([asynccrypt], [AS_HELP_STRING([--enable-asynccrypt],[Enable Asynchronous Crypto (default: disabled)])], @@ -12268,6 +12287,7 @@ AM_CONDITIONAL([BUILD_MCAPI],[test "x$ENABLED_MCAPI" = "xyes"]) AM_CONDITIONAL([BUILD_ASYNCCRYPT],[test "x$ENABLED_ASYNCCRYPT" = "xyes"]) AM_CONDITIONAL([BUILD_WOLFEVENT],[test "x$ENABLED_ASYNCCRYPT" = "xyes"]) AM_CONDITIONAL([BUILD_CRYPTOCB],[test "x$ENABLED_CRYPTOCB" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) +AM_CONDITIONAL([BUILD_SWDEV],[test "x$ENABLED_SWDEV" = "xyes"]) AM_CONDITIONAL([BUILD_PSK],[test "x$ENABLED_PSK" = "xyes"]) AM_CONDITIONAL([BUILD_TRUST_PEER_CERT],[test "x$ENABLED_TRUSTED_PEER_CERT" = "xyes"]) AM_CONDITIONAL([BUILD_PKI],[test "x$ENABLED_PKI" = "xyes"]) diff --git a/tests/api.c b/tests/api.c index 4b0a657f6d9..983d02ecd61 100644 --- a/tests/api.c +++ b/tests/api.c @@ -30604,7 +30604,8 @@ static int test_SSL_CIPHER_get_xxx(void) return EXPECT_RESULT(); } -#if defined(WOLF_CRYPTO_CB) && defined(HAVE_IO_TESTS_DEPENDENCIES) +#if defined(WOLF_CRYPTO_CB) && defined(HAVE_IO_TESTS_DEPENDENCIES) && \ + !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, int* keyFormat) @@ -31606,7 +31607,8 @@ static int test_wc_CryptoCb_TLS(int tlsVer, static int test_wc_CryptoCb(void) { EXPECT_DECLS; -#ifdef WOLF_CRYPTO_CB +#if defined(WOLF_CRYPTO_CB) && \ + !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA) /* TODO: Add crypto callback API tests */ #ifdef HAVE_IO_TESTS_DEPENDENCIES diff --git a/tests/api/test_pkcs7.c b/tests/api/test_pkcs7.c index c779faacf41..4aae3382ce9 100644 --- a/tests/api/test_pkcs7.c +++ b/tests/api/test_pkcs7.c @@ -2203,7 +2203,7 @@ int test_wc_PKCS7_VerifySignedData_RSA(void) /* verify using pre-computed content digest only (no content) */ { ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); - ExpectIntEQ(wc_PKCS7_Init(pkcs7, NULL, 0), 0); + ExpectIntEQ(wc_PKCS7_Init(pkcs7, NULL, testDevId), 0); ExpectIntEQ(wc_PKCS7_VerifySignedData_ex(pkcs7, hashBuf, hashSz, output, outputSz, NULL, 0), 0); wc_PKCS7_Free(pkcs7); @@ -2521,7 +2521,7 @@ int test_wc_PKCS7_VerifySignedData_ECC(void) ExpectIntEQ(wc_HashFree(&hash, hashType), 0); ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); - ExpectIntEQ(wc_PKCS7_Init(pkcs7, NULL, 0), 0); + ExpectIntEQ(wc_PKCS7_Init(pkcs7, NULL, testDevId), 0); ExpectIntEQ(wc_PKCS7_VerifySignedData_ex(pkcs7, hashBuf, hashSz, output, outputSz, NULL, 0), 0); wc_PKCS7_Free(pkcs7); @@ -4741,7 +4741,7 @@ int test_wc_PKCS7_signed_enveloped(void) ExpectIntGT(keySz = wolfSSL_KeyPemToDer(key, keySz, key, keySz, NULL), 0); /* sign cert for envelope */ - ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, 0)); + ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, testDevId)); ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, cert, (word32)certSz), 0); if (pkcs7 != NULL) { @@ -4761,7 +4761,7 @@ int test_wc_PKCS7_signed_enveloped(void) #if defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256) /* create envelope */ - ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, 0)); + ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, testDevId)); ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, cert, (word32)certSz), 0); if (pkcs7 != NULL) { pkcs7->content = sig; @@ -4779,7 +4779,7 @@ int test_wc_PKCS7_signed_enveloped(void) /* create bad signed enveloped data */ sigSz = FOURK_BUF * 2; - ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, 0)); + ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, testDevId)); ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, cert, (word32)certSz), 0); if (pkcs7 != NULL) { @@ -4804,7 +4804,7 @@ int test_wc_PKCS7_signed_enveloped(void) pkcs7 = NULL; /* check verify fails */ - ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, 0)); + ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, testDevId)); ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, NULL, 0), 0); ExpectIntEQ(wc_PKCS7_VerifySignedData(pkcs7, sig, (word32)sigSz), WC_NO_ERR_TRACE(PKCS7_SIGNEEDS_CHECK)); @@ -4831,7 +4831,7 @@ int test_wc_PKCS7_signed_enveloped(void) pkcs7 = NULL; /* initializing the PKCS7 struct with the signing certificate should pass */ - ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, 0)); + ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, testDevId)); ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, cert, (word32)certSz), 0); ExpectIntEQ(wc_PKCS7_VerifySignedData(pkcs7, sig, (word32)sigSz), 0); @@ -4857,7 +4857,7 @@ int test_wc_PKCS7_signed_enveloped(void) /* create valid degenerate bundle */ sigSz = FOURK_BUF * 2; - ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, 0)); + ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, testDevId)); if (pkcs7 != NULL) { pkcs7->content = env; pkcs7->contentSz = (word32)envSz; @@ -4875,7 +4875,7 @@ int test_wc_PKCS7_signed_enveloped(void) wc_FreeRng(&rng); /* check verify */ - ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, 0)); + ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, testDevId)); ExpectIntEQ(wc_PKCS7_Init(pkcs7, HEAP_HINT, testDevId), 0); ExpectIntEQ(wc_PKCS7_VerifySignedData(pkcs7, sig, (word32)sigSz), 0); ExpectNotNull(pkcs7->content); @@ -4886,7 +4886,7 @@ int test_wc_PKCS7_signed_enveloped(void) /* create valid degenerate bundle */ sigSz = FOURK_BUF * 2; - ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, 0)); + ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, testDevId)); if (pkcs7 != NULL) { pkcs7->content = env; pkcs7->contentSz = (word32)envSz; @@ -4904,7 +4904,7 @@ int test_wc_PKCS7_signed_enveloped(void) wc_FreeRng(&rng); /* check verify */ - ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, 0)); + ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, testDevId)); ExpectIntEQ(wc_PKCS7_Init(pkcs7, HEAP_HINT, testDevId), 0); /* test for streaming */ ret = -1; @@ -4919,7 +4919,7 @@ int test_wc_PKCS7_signed_enveloped(void) #ifdef HAVE_AES_CBC /* check decode */ - ExpectNotNull(inner = wc_PKCS7_New(NULL, 0)); + ExpectNotNull(inner = wc_PKCS7_New(NULL, testDevId)); ExpectIntEQ(wc_PKCS7_InitWithCert(inner, cert, (word32)certSz), 0); if (inner != NULL) { inner->privateKey = key; @@ -4935,7 +4935,7 @@ int test_wc_PKCS7_signed_enveloped(void) #ifdef HAVE_AES_CBC /* check cert set */ - ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, 0)); + ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, testDevId)); ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, NULL, 0), 0); ExpectIntEQ(wc_PKCS7_VerifySignedData(pkcs7, decoded, (word32)decodedSz), 0); ExpectNotNull(pkcs7->singleCert); @@ -4944,7 +4944,7 @@ int test_wc_PKCS7_signed_enveloped(void) pkcs7 = NULL; #ifndef NO_PKCS7_STREAM - ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, 0)); + ExpectNotNull(pkcs7 = wc_PKCS7_New(NULL, testDevId)); ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, NULL, 0), 0); /* test for streaming */ ret = -1; diff --git a/tests/swdev/.gitignore b/tests/swdev/.gitignore new file mode 100644 index 00000000000..b021c8ed3ee --- /dev/null +++ b/tests/swdev/.gitignore @@ -0,0 +1,4 @@ +build/ +*.o +.deps/ +.dirstamp diff --git a/tests/swdev/Makefile b/tests/swdev/Makefile new file mode 100644 index 00000000000..1c0ce6a5738 --- /dev/null +++ b/tests/swdev/Makefile @@ -0,0 +1,104 @@ +# tests/swdev/Makefile -- builds swdev.o. +# +# Standalone: cd tests/swdev && make +# Invoked from wolfcrypt/test/include.am in the main build. + +SRCDIR ?= $(CURDIR) +WOLFROOT ?= $(abspath $(SRCDIR)/../..) +BUILDDIR ?= $(SRCDIR)/build + +CC ?= cc +CCAS ?= $(CC) +LD ?= ld +OBJCOPY ?= objcopy +NM ?= nm + +SWDEV_LOCAL_SRCS = swdev.c + +# PARENT_SRCS / PARENT_ASM_SRCS mirror the exact source set that the +# parent build compiled into libwolfssl (passed down by wolfcrypt/test/include.am). +# The configure.ac gate already requires in-tree builds, so PARENT_SRCS +# is always populated when swdev is built in-tree; fail loudly otherwise. +ifeq ($(strip $(PARENT_SRCS)),) +$(error PARENT_SRCS is empty -- swdev must be built from the top-level \ + Makefile so its source set matches the main library) +endif + +SWDEV_CRYPT_SRCS = $(filter wolfcrypt/src/%,$(PARENT_SRCS)) +SWDEV_SSL_SRCS = $(filter src/%,$(PARENT_SRCS)) +SWDEV_ASM_SRCS = $(PARENT_ASM_SRCS) + +# -I$(SRCDIR) routes settings.h to the swdev's user_settings.h. +# No BUILDING_WOLFSSL so WOLFSSL_API/LOCAL stay empty; then -fvisibility=hidden +# hides every emitted symbol. +CPPFLAGS_SWDEV = \ + $(PARENT_CPPFLAGS) \ + -DWOLFSSL_USER_SETTINGS \ + -I$(SRCDIR) \ + -I$(WOLFROOT) \ + -I$(WOLFROOT)/wolfssl + +# -fvisibility=hidden + -fno-common mark every symbol hidden at the ELF +# level (ABI-safe: attribute only, no struct layout impact). Optimization +# level and other flags are inherited from the parent build (PARENT_*_CFLAGS) +# so codegen stays in lockstep with libwolfssl. Use EXTRA_SWDEV_CFLAGS to +# append debug flags (e.g. -O0 -ggdb) on demand. +CFLAGS_SWDEV = \ + $(PARENT_BUILD_CFLAGS) \ + $(PARENT_CFLAGS) \ + -fvisibility=hidden \ + -fno-common \ + -Wno-pragmas \ + $(EXTRA_SWDEV_CFLAGS) + +CCASFLAGS_SWDEV = \ + $(PARENT_BUILD_CCASFLAGS) \ + $(PARENT_CCASFLAGS) + +CRYPT_OBJS = $(patsubst wolfcrypt/src/%.c,$(BUILDDIR)/wc/%.o,$(SWDEV_CRYPT_SRCS)) +SSL_OBJS = $(patsubst src/%.c,$(BUILDDIR)/ssl/%.o,$(SWDEV_SSL_SRCS)) +ASM_OBJS = $(patsubst wolfcrypt/src/%.S,$(BUILDDIR)/wc/%.o,$(SWDEV_ASM_SRCS)) +LOCAL_OBJS = $(patsubst %.c,$(BUILDDIR)/local/%.o,$(SWDEV_LOCAL_SRCS)) +ALL_OBJS = $(CRYPT_OBJS) $(SSL_OBJS) $(ASM_OBJS) $(LOCAL_OBJS) + +.PHONY: all clean +all: $(BUILDDIR)/swdev.o + +$(BUILDDIR)/wc/%.o: $(WOLFROOT)/wolfcrypt/src/%.c $(SRCDIR)/user_settings.h $(WOLFROOT)/wolfssl/options.h | $(BUILDDIR)/wc + $(CC) $(CPPFLAGS_SWDEV) $(CFLAGS_SWDEV) -c $< -o $@ + +$(BUILDDIR)/wc/%.o: $(WOLFROOT)/wolfcrypt/src/%.S $(SRCDIR)/user_settings.h $(WOLFROOT)/wolfssl/options.h | $(BUILDDIR)/wc + $(CCAS) $(CPPFLAGS_SWDEV) $(CCASFLAGS_SWDEV) -c $< -o $@ + +$(BUILDDIR)/ssl/%.o: $(WOLFROOT)/src/%.c $(SRCDIR)/user_settings.h $(WOLFROOT)/wolfssl/options.h | $(BUILDDIR)/ssl + $(CC) $(CPPFLAGS_SWDEV) $(CFLAGS_SWDEV) -c $< -o $@ + +$(BUILDDIR)/local/%.o: $(SRCDIR)/%.c $(SRCDIR)/swdev.h $(SRCDIR)/user_settings.h $(WOLFROOT)/wolfssl/options.h | $(BUILDDIR)/local + $(CC) $(CPPFLAGS_SWDEV) $(CFLAGS_SWDEV) -c $< -o $@ + +$(BUILDDIR)/swdev.partial.o: $(ALL_OBJS) + $(LD) -r -o $@ $(ALL_OBJS) + +$(BUILDDIR)/swdev.o: $(BUILDDIR)/swdev.partial.o + @# --keep-global-symbol localizes every global symbol *except* the + @# named one. We can't rely on --localize-hidden here because + @# wolfssl/wolfcrypt/libwolfssl_sources.h auto-defines BUILDING_WOLFSSL + @# at the top of every compiled source, which expands WOLFSSL_API to + @# visibility("default") and overrides the command-line + @# -fvisibility=hidden. --keep-global-symbol sidesteps that by matching + @# on symbol name directly. + $(OBJCOPY) --keep-global-symbol=wc_SwDev_Callback $< $@ + @# Sanity-check: only wc_SwDev_Callback may be externally visible. + @visible=$$( $(NM) --extern-only --defined-only $@ | awk '{print $$3}' \ + | grep -v '^wc_SwDev_Callback$$' || true); \ + if [ -n "$$visible" ]; then \ + echo "error: unexpected externally-visible symbols in $@:"; \ + echo "$$visible"; \ + exit 1; \ + fi + +$(BUILDDIR) $(BUILDDIR)/wc $(BUILDDIR)/ssl $(BUILDDIR)/local: + mkdir -p $@ + +clean: + rm -rf $(BUILDDIR) diff --git a/tests/swdev/swdev.c b/tests/swdev/swdev.c new file mode 100644 index 00000000000..476bbfb243c --- /dev/null +++ b/tests/swdev/swdev.c @@ -0,0 +1,40 @@ +/* tests/swdev/swdev.c -- wc_swdev callback. */ + +#include "swdev.h" + +#include +#include +#include +#include + +static int swdev_initialized = 0; + +static int swdev_ensure_init(void) +{ + if (!swdev_initialized) { + int ret = wolfCrypt_Init(); + if (ret != 0) + return ret; + swdev_initialized = 1; + } + return 0; +} + +WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, + void* ctx) +{ + int ret; + + (void)devId; + (void)ctx; + + if (info == NULL) + return BAD_FUNC_ARG; + + ret = swdev_ensure_init(); + if (ret != 0) + return ret; + + (void)ret; + return CRYPTOCB_UNAVAILABLE; +} diff --git a/tests/swdev/swdev.h b/tests/swdev/swdev.h new file mode 100644 index 00000000000..7003fcacaf2 --- /dev/null +++ b/tests/swdev/swdev.h @@ -0,0 +1,27 @@ +/* tests/swdev/swdev.h -- sole exported interface. */ + +#ifndef WC_SWDEV_H +#define WC_SWDEV_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define WC_SWDEV_ID 0x77736465 /* 'w' 's' 'd' 'e' */ + +#if defined(__GNUC__) || defined(__clang__) +#define WC_SWDEV_EXPORT __attribute__((visibility("default"))) +#else +#define WC_SWDEV_EXPORT +#endif + +WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, + void* ctx); + +#ifdef __cplusplus +} +#endif + +#endif /* WC_SWDEV_H */ diff --git a/tests/swdev/swdev_loader.c b/tests/swdev/swdev_loader.c new file mode 100644 index 00000000000..a1af81db068 --- /dev/null +++ b/tests/swdev/swdev_loader.c @@ -0,0 +1,57 @@ +/* tests/swdev/swdev_loader.c -- main-side loader for wc_swdev. */ + +#include "swdev_loader.h" + +#include + +#ifndef WOLF_CRYPTO_CB +#error "wc_swdev loader requires WOLF_CRYPTO_CB" +#endif + +/* resolved at link time from swdev.o */ +extern int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, void* ctx); + +static int swdev_registered = 0; + +int wc_SwDev_Init(void) +{ + int ret; + + /* always re-register: cryptocb table is wiped by wolfCrypt_Cleanup */ + ret = wc_CryptoCb_RegisterDevice(WC_SWDEV_ID, wc_SwDev_Callback, NULL); + if (ret != 0) + return ret; + +#ifdef WOLF_CRYPTO_CB_FIND + wc_CryptoCb_SetDeviceFindCb(wc_SwDev_FindCb); +#endif + + swdev_registered = 1; + return 0; +} + +void wc_SwDev_Cleanup(void) +{ + if (!swdev_registered) + return; + +#ifdef WOLF_CRYPTO_CB_FIND + wc_CryptoCb_SetDeviceFindCb(NULL); +#endif + + wc_CryptoCb_UnRegisterDevice(WC_SWDEV_ID); + swdev_registered = 0; +} + +#ifdef WOLF_CRYPTO_CB_FIND +int wc_SwDev_FindCb(int currentId, int algoType) +{ + (void)algoType; + + /* only redirect ops with no bound device; let others pass through */ + if (currentId == INVALID_DEVID) + return WC_SWDEV_ID; + + return currentId; +} +#endif diff --git a/tests/swdev/swdev_loader.h b/tests/swdev/swdev_loader.h new file mode 100644 index 00000000000..49c9c49e2fd --- /dev/null +++ b/tests/swdev/swdev_loader.h @@ -0,0 +1,29 @@ +/* tests/swdev/swdev_loader.h -- test harness interface to register wc_swdev. */ + +#ifndef WC_SWDEV_LOADER_H +#define WC_SWDEV_LOADER_H + +#if !defined(WOLFSSL_USER_SETTINGS) && !defined(WOLFSSL_NO_OPTIONS_H) + #include +#endif +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define WC_SWDEV_ID 0x77736465 /* 'w' 's' 'd' 'e' */ + +int wc_SwDev_Init(void); +void wc_SwDev_Cleanup(void); + +#ifdef WOLF_CRYPTO_CB_FIND +int wc_SwDev_FindCb(int currentId, int algoType); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* WC_SWDEV_LOADER_H */ diff --git a/tests/swdev/user_settings.h b/tests/swdev/user_settings.h new file mode 100644 index 00000000000..bf364459a8f --- /dev/null +++ b/tests/swdev/user_settings.h @@ -0,0 +1,23 @@ +/* tests/swdev/user_settings.h -- settings for wc_swdev. + * + * The swdev software backend must stay ABI-identical to the main library: + * every wolfCrypt struct that crosses the cryptocb boundary (wc_Sha256, + * Aes, RsaKey, ecc_key, ...) is allocated by one compilation and used by + * the other. The only macros that may differ between the two compilations + * are the WOLF_CRYPTO_CB_ONLY_* gates below -- those strip the software + * implementations from the main library so every operation routes through + * the crypto callback; swdev needs the software paths intact. Every other + * setting is inherited from wolfssl/options.h so layouts stay in sync. */ +#ifndef WC_SWDEV_USER_SETTINGS_H +#define WC_SWDEV_USER_SETTINGS_H + +#include + +#undef WOLF_CRYPTO_CB_ONLY_RSA +#undef WOLF_CRYPTO_CB_ONLY_ECC + +#ifndef WOLF_CRYPTO_CB + #error "wc_swdev requires the main build to define WOLF_CRYPTO_CB" +#endif + +#endif /* WC_SWDEV_USER_SETTINGS_H */ diff --git a/wolfcrypt/test/include.am b/wolfcrypt/test/include.am index 8f13876a215..e647b979742 100644 --- a/wolfcrypt/test/include.am +++ b/wolfcrypt/test/include.am @@ -12,10 +12,57 @@ noinst_PROGRAMS+= wolfcrypt/test/testwolfcrypt wolfcrypt_test_testwolfcrypt_SOURCES = wolfcrypt/test/test.c wolfcrypt_test_testwolfcrypt_LDADD = src/libwolfssl@LIBSUFFIX@.la $(LIB_STATIC_ADD) wolfcrypt_test_testwolfcrypt_DEPENDENCIES = src/libwolfssl@LIBSUFFIX@.la +if BUILD_SWDEV +wolfcrypt_test_testwolfcrypt_SOURCES += tests/swdev/swdev_loader.c +wolfcrypt_test_testwolfcrypt_LDADD += $(top_builddir)/tests/swdev/build/swdev.o $(LIBM) +wolfcrypt_test_testwolfcrypt_DEPENDENCIES += $(top_builddir)/tests/swdev/build/swdev.o +endif noinst_HEADERS += wolfcrypt/test/test.h wolfcrypt/test/test_paths.h.in endif endif +if BUILD_SWDEV +# delegates to tests/swdev/Makefile +$(top_builddir)/tests/swdev/build/swdev.o: $(top_builddir)/wolfssl/options.h FORCE + @test "$(abs_top_srcdir)" = "$(abs_top_builddir)" || { \ + echo "error: --enable-swdev currently supports in-tree builds only"; \ + exit 1; \ + } + $(MAKE) -C $(top_srcdir)/tests/swdev \ + SRCDIR=$(abs_top_srcdir)/tests/swdev \ + WOLFROOT=$(abs_top_srcdir) \ + $(if $(CC),CC='$(CC)') \ + $(if $(CCAS),CCAS='$(CCAS)') \ + $(if $(LD),LD='$(LD)') \ + $(if $(OBJCOPY),OBJCOPY='$(OBJCOPY)') \ + PARENT_SRCS='$(filter wolfcrypt/src/%.c src/%.c,$(src_libwolfssl_la_SOURCES))' \ + PARENT_ASM_SRCS='$(filter %.S,$(src_libwolfssl_la_SOURCES))' \ + PARENT_CPPFLAGS='$(CPPFLAGS) $(filter-out -DBUILDING_WOLFSSL,$(DEFS))' \ + PARENT_BUILD_CFLAGS='$(filter-out -include ./.build_params -DBUILDING_WOLFSSL,$(AM_CFLAGS))' \ + PARENT_CFLAGS='$(CFLAGS)' \ + PARENT_BUILD_CCASFLAGS='$(filter-out -DBUILDING_WOLFSSL,$(AM_CCASFLAGS))' \ + PARENT_CCASFLAGS='$(CCASFLAGS)' \ + BUILDDIR=$(abs_top_builddir)/tests/swdev/build + +FORCE: + +EXTRA_DIST += tests/swdev/swdev.c \ + tests/swdev/swdev.h \ + tests/swdev/swdev_loader.c \ + tests/swdev/swdev_loader.h \ + tests/swdev/user_settings.h \ + tests/swdev/Makefile + +CLEANFILES += $(top_builddir)/tests/swdev/build/swdev.o \ + $(top_builddir)/tests/swdev/build/swdev.partial.o + +# Use mostlyclean-local rather than clean-local to avoid colliding with +# doc/include.am's clean-local (automake allows only one definition per +# Makefile). make clean triggers mostlyclean, so coverage is equivalent. +mostlyclean-local: + rm -rf $(top_builddir)/tests/swdev/build +endif + if BUILD_WOLFCRYPT_TESTS_LIBS lib_LTLIBRARIES += wolfcrypt/test/libwolfcrypttest.la wolfcrypt_test_libwolfcrypttest_la_SOURCES = wolfcrypt/test/test.c diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 1f00a5c51dc..a6c8bcb1242 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -64,6 +64,10 @@ #undef err_sys #endif +#ifdef WOLFSSL_SWDEV + #include "../../tests/swdev/swdev_loader.h" +#endif + #if defined(WC_ECC_NONBLOCK) && defined(WOLFSSL_PUBLIC_MP) && \ defined(HAVE_ECC_SIGN) && defined(HAVE_ECC_VERIFY) && \ !defined(NO_STDINT_H) @@ -3483,6 +3487,14 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ err_sys("Error with wolfCrypt_Init!\n", args.return_code); } +#ifdef WOLFSSL_SWDEV + if ((ret = wc_SwDev_Init()) != 0) { + printf("wc_SwDev_Init failed %d\n", (int)ret); + args.return_code = WC_TEST_RET_ENC_EC(ret); + err_sys("Error with wc_SwDev_Init!\n", args.return_code); + } +#endif + #ifdef HAVE_WC_INTROSPECTION printf("Math: %s\n", wc_GetMathInfo()); #endif @@ -3495,6 +3507,10 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ #endif } +#ifdef WOLFSSL_SWDEV + wc_SwDev_Cleanup(); +#endif + if ((ret = wolfCrypt_Cleanup()) != 0) { printf("wolfCrypt_Cleanup failed %d\n", (int)ret); args.return_code = WC_TEST_RET_ENC_EC(ret); @@ -73103,9 +73119,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) ret = wc_CryptoCb_RegisterDevice(devId, myCryptoDevCb, &myCtx); if (ret != 0) ret = WC_TEST_RET_ENC_EC(ret); -#ifdef WOLF_CRYPTO_CB_FIND + /* don't overwrite find cb when using WOLFSSL_SWDEV */ +#if defined(WOLF_CRYPTO_CB_FIND) && !defined(WOLFSSL_SWDEV) wc_CryptoCb_SetDeviceFindCb(myCryptoCbFind); -#endif /* WOLF_CRYPTO_CB_FIND */ +#endif #ifndef WC_NO_RNG if (ret == 0) ret = random_test(); @@ -73116,7 +73133,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) ret = rsa_test(); PRIVATE_KEY_LOCK(); #endif -#if defined(WOLF_CRYPTO_CB_ONLY_RSA) +#if defined(WOLF_CRYPTO_CB_ONLY_RSA) && !defined(WOLFSSL_SWDEV) PRIVATE_KEY_UNLOCK(); if (ret == 0) ret = rsa_onlycb_test(&myCtx); From 6fb617aba96d6eab02860f3c11dddef6710bc3cd Mon Sep 17 00:00:00 2001 From: rizlik Date: Wed, 22 Apr 2026 13:14:00 +0000 Subject: [PATCH 02/21] tests/swdev: add ECC support to wc_swdev Extend the swdev callback to handle ECC operations: keygen, ECDH, sign, verify, get-size, get-sig-size. Relax WOLF_CRYPTO_CB_ONLY_ECC guards in the test suite so that tests run under swdev, and wire wc_SwDev_Init/Cleanup into testsuite, client, and server. Two tests are intentionally kept excluded even with swdev because they call raw ECC math primitives (wc_ecc_mulmod, on-curve validation in wc_ecc_import_x963) that are stripped below the cryptocb dispatch layer: - ecc_mulmod_test (wolfcrypt/test/test.c) - test_wc_ecc_import_x963_off_curve (tests/api/test_ecc.c) --- examples/client/client.c | 13 +++++ examples/client/include.am | 5 ++ examples/server/include.am | 5 ++ examples/server/server.c | 13 +++++ tests/api.c | 54 ++++++++++++--------- tests/api/test_ecc.c | 5 +- tests/include.am | 5 ++ tests/suites.c | 3 +- tests/swdev/swdev.c | 97 +++++++++++++++++++++++++++++++++++++- tests/unit.c | 31 ++++++++++++ testsuite/include.am | 5 ++ testsuite/testsuite.c | 30 +++++++++++- wolfcrypt/test/test.c | 62 ++++++++++++++---------- wolfcrypt/test/test.h | 2 +- 14 files changed, 276 insertions(+), 54 deletions(-) diff --git a/examples/client/client.c b/examples/client/client.c index 4a60f3b6a18..a35639ef84c 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -51,6 +51,10 @@ static const char *wolfsentry_config_path = NULL; #include #include +#ifdef WOLFSSL_SWDEV + #include "tests/swdev/swdev_loader.h" +#endif + #ifdef USE_FLAT_TEST_H #include "client.h" #else @@ -5056,6 +5060,12 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) wolfSSL_Debugging_ON(); #endif wolfSSL_Init(); +#ifdef WOLFSSL_SWDEV + if (wc_SwDev_Init() != 0) { + fprintf(stderr, "wc_SwDev_Init failed\n"); + return EXIT_FAILURE; + } +#endif ChangeToWolfRoot(); #if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) @@ -5066,6 +5076,9 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif #else fprintf(stderr, "Client not compiled in!\n"); +#endif +#ifdef WOLFSSL_SWDEV + wc_SwDev_Cleanup(); #endif wolfSSL_Cleanup(); diff --git a/examples/client/include.am b/examples/client/include.am index 36e65f218c0..30d70e8c81c 100644 --- a/examples/client/include.am +++ b/examples/client/include.am @@ -7,6 +7,11 @@ noinst_HEADERS += examples/client/client.h examples_client_client_SOURCES = examples/client/client.c examples_client_client_LDADD = src/libwolfssl@LIBSUFFIX@.la $(LIB_STATIC_ADD) $(WOLFSENTRY_LIB) examples_client_client_DEPENDENCIES = src/libwolfssl@LIBSUFFIX@.la +if BUILD_SWDEV +examples_client_client_SOURCES += tests/swdev/swdev_loader.c +examples_client_client_LDADD += $(top_builddir)/tests/swdev/build/swdev.o $(LIBM) +examples_client_client_DEPENDENCIES += $(top_builddir)/tests/swdev/build/swdev.o +endif examples_client_client_CFLAGS = $(WOLFSENTRY_INCLUDE) $(AM_CFLAGS) endif EXTRA_DIST += examples/client/client.sln diff --git a/examples/server/include.am b/examples/server/include.am index cb591d9e34b..990bff650db 100644 --- a/examples/server/include.am +++ b/examples/server/include.am @@ -9,6 +9,11 @@ noinst_HEADERS += examples/server/server.h examples_server_server_SOURCES = examples/server/server.c examples_server_server_LDADD = src/libwolfssl@LIBSUFFIX@.la $(LIB_STATIC_ADD) $(WOLFSENTRY_LIB) examples_server_server_DEPENDENCIES = src/libwolfssl@LIBSUFFIX@.la +if BUILD_SWDEV +examples_server_server_SOURCES += tests/swdev/swdev_loader.c +examples_server_server_LDADD += $(top_builddir)/tests/swdev/build/swdev.o $(LIBM) +examples_server_server_DEPENDENCIES += $(top_builddir)/tests/swdev/build/swdev.o +endif examples_server_server_CFLAGS = $(WOLFSENTRY_INCLUDE) $(AM_CFLAGS) endif EXTRA_DIST += examples/server/server.sln diff --git a/examples/server/server.c b/examples/server/server.c index e0e0d85da17..a3fba6591e7 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -67,6 +67,10 @@ static const char *wolfsentry_config_path = NULL; #include #include +#ifdef WOLFSSL_SWDEV + #include "tests/swdev/swdev_loader.h" +#endif + #ifdef USE_FLAT_TEST_H #include "server.h" #else @@ -4255,6 +4259,12 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) wolfSSL_Init(); #ifdef WC_RNG_SEED_CB wc_SetSeed_Cb(WC_GENERATE_SEED_DEFAULT); +#endif +#ifdef WOLFSSL_SWDEV + if (wc_SwDev_Init() != 0) { + fprintf(stderr, "wc_SwDev_Init failed\n"); + return EXIT_FAILURE; + } #endif ChangeToWolfRoot(); @@ -4268,6 +4278,9 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) fprintf(stderr, "Server not compiled in!\n"); #endif +#ifdef WOLFSSL_SWDEV + wc_SwDev_Cleanup(); +#endif wolfSSL_Cleanup(); FreeTcpReady(&ready); diff --git a/tests/api.c b/tests/api.c index 983d02ecd61..79f1bed2d56 100644 --- a/tests/api.c +++ b/tests/api.c @@ -65,6 +65,10 @@ #include #include +#ifdef WOLFSSL_SWDEV +#include "swdev/swdev_loader.h" +#endif + /* for testing compatibility layer callbacks */ #include "examples/server/server.h" @@ -40790,7 +40794,9 @@ TEST_CASE testCases[] = { static void TestSetup(void) { -/* Stub, for now. Add common test setup code here. */ +#ifdef WOLFSSL_SWDEV + (void)wc_SwDev_Init(); +#endif } static void TestCleanup(void) @@ -41012,20 +41018,24 @@ int ApiTest(void) printf(" Begin API Tests\n"); fflush(stdout); - /* we must perform init and cleanup if not all tests are running */ - if (!testAll) { - #ifdef WOLFCRYPT_ONLY - if (wolfCrypt_Init() != 0) { - printf("wolfCrypt Initialization failed\n"); - res = 1; - } - #else - if (wolfSSL_Init() != WOLFSSL_SUCCESS) { - printf("wolfSSL Initialization failed\n"); - res = 1; - } - #endif +#ifdef WOLFCRYPT_ONLY + if (wolfCrypt_Init() != 0) { + printf("wolfCrypt Initialization failed\n"); + res = 1; + } +#else + if (wolfSSL_Init() != WOLFSSL_SUCCESS) { + printf("wolfSSL Initialization failed\n"); + res = 1; } +#endif + +#ifdef WOLFSSL_SWDEV + if (res == 0 && wc_SwDev_Init() != 0) { + printf("wc_SwDev_Init failed\n"); + res = 1; + } +#endif #ifdef WOLFSSL_DUMP_MEMIO_STREAM if (res == 0) { @@ -41117,13 +41127,15 @@ int ApiTest(void) wc_ecc_fp_free(); /* free per thread cache */ #endif - if (!testAll) { - #ifdef WOLFCRYPT_ONLY - wolfCrypt_Cleanup(); - #else - wolfSSL_Cleanup(); - #endif - } +#ifdef WOLFSSL_SWDEV + wc_SwDev_Cleanup(); +#endif + +#ifdef WOLFCRYPT_ONLY + wolfCrypt_Cleanup(); +#else + wolfSSL_Cleanup(); +#endif (void)testDevId; diff --git a/tests/api/test_ecc.c b/tests/api/test_ecc.c index 88d1ece7fca..90d5ced8822 100644 --- a/tests/api/test_ecc.c +++ b/tests/api/test_ecc.c @@ -785,9 +785,12 @@ int test_wc_ecc_import_x963(void) int test_wc_ecc_import_x963_off_curve(void) { EXPECT_DECLS; +/* point-on-curve validation inside wc_ecc_import_x963 is raw math stripped + * by WOLF_CRYPTO_CB_ONLY_ECC; swdev cannot reach below the dispatch layer. */ #if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_IMPORT) && \ !defined(NO_ECC256) && !defined(NO_ECC_SECP) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && !defined(HAVE_SELFTEST) + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && !defined(HAVE_SELFTEST) && \ + !defined(WOLF_CRYPTO_CB_ONLY_ECC) ecc_key pubKey; /* Uncompressed X9.63 P-256 point: 0x04 || Gx || Gy with the last byte * of Gy flipped by 1. Gx/Gy are the NIST P-256 generator coordinates; diff --git a/tests/include.am b/tests/include.am index b512f724498..fae3242a885 100644 --- a/tests/include.am +++ b/tests/include.am @@ -24,6 +24,11 @@ endif tests_unit_test_CFLAGS = -DNO_MAIN_DRIVER $(AM_CFLAGS) $(WOLFSENTRY_INCLUDE) tests_unit_test_LDADD = src/libwolfssl@LIBSUFFIX@.la $(LIB_STATIC_ADD) $(WOLFSENTRY_LIB) tests_unit_test_DEPENDENCIES = src/libwolfssl@LIBSUFFIX@.la +if BUILD_SWDEV +tests_unit_test_SOURCES += tests/swdev/swdev_loader.c +tests_unit_test_LDADD += $(top_builddir)/tests/swdev/build/swdev.o $(LIBM) +tests_unit_test_DEPENDENCIES += $(top_builddir)/tests/swdev/build/swdev.o +endif include tests/api/include.am endif EXTRA_DIST += tests/unit.h \ diff --git a/tests/suites.c b/tests/suites.c index 3192e5070ca..4e830fd75ae 100644 --- a/tests/suites.c +++ b/tests/suites.c @@ -1008,7 +1008,8 @@ int SuiteTest(int argc, char** argv) { #if !defined(NO_WOLFSSL_SERVER) && !defined(NO_WOLFSSL_CLIENT) && \ !defined(NO_TLS) && !defined(SINGLE_THREADED) && \ - !defined(WOLF_CRYPTO_CB_ONLY_RSA) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) + (defined(WOLFSSL_SWDEV) || \ + (!defined(WOLF_CRYPTO_CB_ONLY_RSA) && !defined(WOLF_CRYPTO_CB_ONLY_ECC))) func_args args; char argv0[3][80]; char* myArgv[3]; diff --git a/tests/swdev/swdev.c b/tests/swdev/swdev.c index 476bbfb243c..6c85e54973a 100644 --- a/tests/swdev/swdev.c +++ b/tests/swdev/swdev.c @@ -7,6 +7,10 @@ #include #include +#ifdef HAVE_ECC +#include +#endif + static int swdev_initialized = 0; static int swdev_ensure_init(void) @@ -20,6 +24,74 @@ static int swdev_ensure_init(void) return 0; } +#ifdef HAVE_ECC +static int swdev_ecc_keygen(wc_CryptoInfo* info) +{ +#ifdef HAVE_ECC_DHE + return wc_ecc_make_key_ex(info->pk.eckg.rng, info->pk.eckg.size, + info->pk.eckg.key, info->pk.eckg.curveId); +#else + (void)info; + return CRYPTOCB_UNAVAILABLE; +#endif +} + +static int swdev_ecdh(wc_CryptoInfo* info) +{ +#ifdef HAVE_ECC_DHE + return wc_ecc_shared_secret(info->pk.ecdh.private_key, + info->pk.ecdh.public_key, info->pk.ecdh.out, + info->pk.ecdh.outlen); +#else + (void)info; + return CRYPTOCB_UNAVAILABLE; +#endif +} + +static int swdev_ecc_sign(wc_CryptoInfo* info) +{ +#ifdef HAVE_ECC_SIGN + return wc_ecc_sign_hash(info->pk.eccsign.in, info->pk.eccsign.inlen, + info->pk.eccsign.out, info->pk.eccsign.outlen, + info->pk.eccsign.rng, info->pk.eccsign.key); +#else + (void)info; + return CRYPTOCB_UNAVAILABLE; +#endif +} + +static int swdev_ecc_verify(wc_CryptoInfo* info) +{ +#ifdef HAVE_ECC_VERIFY + return wc_ecc_verify_hash(info->pk.eccverify.sig, + info->pk.eccverify.siglen, info->pk.eccverify.hash, + info->pk.eccverify.hashlen, info->pk.eccverify.res, + info->pk.eccverify.key); +#else + (void)info; + return CRYPTOCB_UNAVAILABLE; +#endif +} + +static int swdev_ecc_get_size(wc_CryptoInfo* info) +{ + int sz = wc_ecc_size((ecc_key*)info->pk.ecc_get_size.key); + if (sz <= 0) + return sz; /* propagate negative error */ + *info->pk.ecc_get_size.keySize = sz; + return 0; +} + +static int swdev_ecc_get_sig_size(wc_CryptoInfo* info) +{ + int sz = wc_ecc_sig_size(info->pk.ecc_get_sig_size.key); + if (sz <= 0) + return sz; + *info->pk.ecc_get_sig_size.sigSize = sz; + return 0; +} +#endif /* HAVE_ECC */ + WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, void* ctx) { @@ -35,6 +107,27 @@ WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, if (ret != 0) return ret; - (void)ret; - return CRYPTOCB_UNAVAILABLE; + switch (info->algo_type) { +#ifdef HAVE_ECC + case WC_ALGO_TYPE_PK: + switch (info->pk.type) { + case WC_PK_TYPE_EC_KEYGEN: + return swdev_ecc_keygen(info); + case WC_PK_TYPE_ECDH: + return swdev_ecdh(info); + case WC_PK_TYPE_ECDSA_SIGN: + return swdev_ecc_sign(info); + case WC_PK_TYPE_ECDSA_VERIFY: + return swdev_ecc_verify(info); + case WC_PK_TYPE_EC_GET_SIZE: + return swdev_ecc_get_size(info); + case WC_PK_TYPE_EC_GET_SIG_SIZE: + return swdev_ecc_get_sig_size(info); + default: + return CRYPTOCB_UNAVAILABLE; + } +#endif /* HAVE_ECC */ + default: + return CRYPTOCB_UNAVAILABLE; + } } diff --git a/tests/unit.c b/tests/unit.c index 9a26183e83a..1734f7abbef 100644 --- a/tests/unit.c +++ b/tests/unit.c @@ -37,6 +37,10 @@ #include "wolfcrypt/test/test.h" #endif +#ifdef WOLFSSL_SWDEV +#include "swdev/swdev_loader.h" +#endif + int allTesting = 1; int apiTesting = 1; int myoptind = 0; @@ -263,6 +267,13 @@ int unit_test(int argc, char** argv) goto exit; } + #ifdef WOLFSSL_SWDEV + if ((ret = wc_SwDev_Init()) != 0) { + fprintf(stderr, "wc_SwDev_Init failed: %d\n", (int)ret); + goto exit; + } + #endif + XMEMSET(&wc_args, 0, sizeof(wc_args)); wolfcrypt_test(&wc_args); if (wc_args.return_code != 0) { @@ -270,6 +281,10 @@ int unit_test(int argc, char** argv) goto exit; } + #ifdef WOLFSSL_SWDEV + wc_SwDev_Cleanup(); + #endif + if ((ret = wolfCrypt_Cleanup()) != 0) { fprintf(stderr, "wolfCrypt_Cleanup failed: %d\n", (int)ret); goto exit; @@ -322,10 +337,26 @@ int unit_test(int argc, char** argv) !defined(NO_TLS) && \ !defined(SINGLE_THREADED) && \ defined(WOLFSSL_PEM_TO_DER) + #ifdef WOLFSSL_SWDEV + if (wolfCrypt_Init() != 0) { + fprintf(stderr, "wolfCrypt_Init before SuiteTest failed\n"); + ret = 1; + goto exit; + } + if (wc_SwDev_Init() != 0) { + fprintf(stderr, "wc_SwDev_Init before SuiteTest failed\n"); + ret = 1; + goto exit; + } + #endif if ((ret = SuiteTest(argc, argv)) != 0) { fprintf(stderr, "suite test failed with %d\n", ret); goto exit; } + #ifdef WOLFSSL_SWDEV + wc_SwDev_Cleanup(); + wolfCrypt_Cleanup(); + #endif #endif exit: diff --git a/testsuite/include.am b/testsuite/include.am index 5c750e6a3fa..97fe77ccdae 100644 --- a/testsuite/include.am +++ b/testsuite/include.am @@ -17,6 +17,11 @@ testsuite_testsuite_test_SOURCES = \ testsuite_testsuite_test_CFLAGS = -DNO_MAIN_DRIVER $(AM_CFLAGS) $(WOLFSENTRY_INCLUDE) testsuite_testsuite_test_LDADD = src/libwolfssl@LIBSUFFIX@.la $(LIB_STATIC_ADD) $(WOLFSENTRY_LIB) testsuite_testsuite_test_DEPENDENCIES = src/libwolfssl@LIBSUFFIX@.la +if BUILD_SWDEV +testsuite_testsuite_test_SOURCES += tests/swdev/swdev_loader.c +testsuite_testsuite_test_LDADD += $(top_builddir)/tests/swdev/build/swdev.o $(LIBM) +testsuite_testsuite_test_DEPENDENCIES += $(top_builddir)/tests/swdev/build/swdev.o +endif endif EXTRA_DIST += testsuite/testsuite.sln EXTRA_DIST += testsuite/testsuite.vcproj diff --git a/testsuite/testsuite.c b/testsuite/testsuite.c index 0b48adbd177..9dda0e51d4d 100644 --- a/testsuite/testsuite.c +++ b/testsuite/testsuite.c @@ -47,6 +47,10 @@ #include #include +#ifdef WOLFSSL_SWDEV + #include "../tests/swdev/swdev_loader.h" +#endif + #include #include #include @@ -125,7 +129,8 @@ int testsuite_test(int argc, char** argv) { #if !defined(NO_WOLFSSL_SERVER) && !defined(NO_WOLFSSL_CLIENT) && \ !defined(NO_TLS) && \ - (!defined(WOLF_CRYPTO_CB_ONLY_RSA) && !defined(WOLF_CRYPTO_CB_ONLY_ECC)) + (defined(WOLFSSL_SWDEV) || \ + (!defined(WOLF_CRYPTO_CB_ONLY_RSA) && !defined(WOLF_CRYPTO_CB_ONLY_ECC))) func_args server_args; tcp_ready ready; @@ -191,6 +196,13 @@ int testsuite_test(int argc, char** argv) server_args.signal = &ready; InitTcpReady(&ready); +#ifdef WOLFSSL_SWDEV + if (wc_SwDev_Init() != 0) { + printf("wc_SwDev_Init failed\n"); + return EXIT_FAILURE; + } +#endif + #ifndef NO_CRYPT_TEST /* wc_ test */ #ifdef HAVE_STACK_SIZE @@ -275,6 +287,10 @@ int testsuite_test(int argc, char** argv) return EXIT_FAILURE; #endif +#ifdef WOLFSSL_SWDEV + wc_SwDev_Cleanup(); +#endif + wolfSSL_Cleanup(); FreeTcpReady(&ready); @@ -600,7 +616,8 @@ static int test_ocsp_responder(void) #if !defined(NO_WOLFSSL_SERVER) && !defined(NO_WOLFSSL_CLIENT) && \ !defined(NO_TLS) && \ - (!defined(WOLF_CRYPTO_CB_ONLY_RSA) && !defined(WOLF_CRYPTO_CB_ONLY_ECC)) + (defined(WOLFSSL_SWDEV) || \ + (!defined(WOLF_CRYPTO_CB_ONLY_RSA) && !defined(WOLF_CRYPTO_CB_ONLY_ECC))) /* Perform a basic TLS handshake. * * First connection to echo a file. @@ -856,8 +873,17 @@ int main(int argc, char** argv) wolfSSL_Init(); ChangeToWolfRoot(); +#ifdef WOLFSSL_SWDEV + if (wc_SwDev_Init() != 0) { + printf("wc_SwDev_Init failed\n"); + return EXIT_FAILURE; + } +#endif /* No TLS - only doing cryptographic algorithm testing. */ wolfcrypt_test(&wolfcrypt_test_args); +#ifdef WOLFSSL_SWDEV + wc_SwDev_Cleanup(); +#endif if (wolfcrypt_test_args.return_code != 0) return wolfcrypt_test_args.return_code; diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index a6c8bcb1242..b5388d3e6eb 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -943,7 +943,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t scrypt_test(void); !defined(WOLFSSL_ATECC608A) && !defined(WOLFSSL_MICROCHIP_TA100) && \ !defined(NO_ECC256) && \ defined(HAVE_ECC_VERIFY) && defined(HAVE_ECC_SIGN) && \ - !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(NO_ECC_SECP) && \ + (!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV)) && !defined(NO_ECC_SECP) && \ !defined(WOLFSSL_SE050) /* skip for ATECC508/608A (cannot import private key buffers) and * SE050 (test vector uses a digest size SE050 does not accept) */ @@ -3022,7 +3022,8 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ else TEST_PASS("OPENSSL (PKEY1) passed!\n"); - #if !defined(WOLF_CRYPTO_CB_ONLY_RSA) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) + #if (!defined(WOLF_CRYPTO_CB_ONLY_RSA) || defined(WOLFSSL_SWDEV)) && \ + (!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV)) if ( (ret = openssl_evpSig_test()) != 0) TEST_FAIL("OPENSSL (EVP Sign/Verify) test failed!\n", ret); else @@ -3048,7 +3049,7 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ !defined(WOLFSSL_ATECC608A) && !defined(WOLFSSL_MICROCHIP_TA100) && \ !defined(NO_ECC256) && \ defined(HAVE_ECC_VERIFY) && defined(HAVE_ECC_SIGN) && \ - !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(NO_ECC_SECP) && \ + (!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV)) && !defined(NO_ECC_SECP) && \ !defined(WOLFSSL_SE050) /* skip for ATECC508/608A (cannot import private key buffers) and * SE050 (test vector uses a digest size SE050 does not accept) */ @@ -25393,12 +25394,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t memory_test(void) #endif #endif #if defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG) && \ - !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(NO_ASN_CRYPT) + (!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV)) && \ + !defined(NO_ASN_CRYPT) static const char* eccCaKeyPemFile = CERT_WRITE_TEMP_DIR "ecc-key.pem"; static const char* eccPubKeyDerFile = CERT_WRITE_TEMP_DIR "ecc-public-key.der"; static const char* eccCaKeyTempFile = CERT_WRITE_TEMP_DIR "ecc-key.der"; #if defined(HAVE_PKCS8) && !defined(WC_NO_RNG) && \ - !defined(WOLF_CRYPTO_CB_ONLY_ECC) + (!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV)) static const char* eccPkcs8KeyDerFile = CERT_WRITE_TEMP_DIR "ecc-key-pkcs8.der"; #endif #endif /* HAVE_ECC_KEY_EXPORT */ @@ -26523,7 +26525,7 @@ static wc_test_ret_t rsa_sig_test(RsaKey* key, word32 keyLen, int modLen, WC_RNG if (ret != 0) #elif defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) /* async may not require RNG */ - #if defined(WOLF_CRYPTO_CB_ONLY_RSA) + #if defined(WOLF_CRYPTO_CB_ONLY_RSA) && !defined(WOLFSSL_SWDEV) if (ret != WC_NO_ERR_TRACE(NO_VALID_DEVID)) #else #if defined(WOLFSSL_MICROCHIP_TA100) @@ -37459,7 +37461,7 @@ typedef struct eccVector { word32 sSz; } eccVector; -#if !defined(WOLF_CRYPTO_CB_ONLY_ECC) +#if !defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV) static wc_test_ret_t ecc_test_vector_item(const eccVector* vector) { wc_test_ret_t ret = 0; @@ -38934,7 +38936,7 @@ static wc_test_ret_t ecc_test_make_pub(WC_RNG* rng) } #if defined(HAVE_ECC_KEY_EXPORT) && !defined(NO_ASN_CRYPT) && \ - !defined(WC_NO_RNG) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) + !defined(WC_NO_RNG) && (!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV)) static wc_test_ret_t ecc_test_key_decode(WC_RNG* rng, int keySize) { wc_test_ret_t ret; @@ -39015,7 +39017,7 @@ static wc_test_ret_t ecc_test_key_decode(WC_RNG* rng, int keySize) #endif /* HAVE_ECC_KEY_IMPORT */ #if defined(HAVE_ECC_KEY_EXPORT) && !defined(NO_ASN_CRYPT) && \ - !defined(WC_NO_RNG) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) + !defined(WC_NO_RNG) && (!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV)) static wc_test_ret_t ecc_test_key_gen(WC_RNG* rng, int keySize) { wc_test_ret_t ret = 0; @@ -39645,7 +39647,8 @@ static wc_test_ret_t ecc_test_curve(WC_RNG* rng, int keySize, int curve_id) return ret; } } -#if !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLFSSL_MICROCHIP_TA100) +#if (!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV)) && \ + !defined(WOLFSSL_MICROCHIP_TA100) #if FIPS_VERSION3_GE(6,0,0) skip_A: #endif @@ -39958,7 +39961,7 @@ static wc_test_ret_t ecc_point_test(void) } #endif /* !WOLFSSL_ATECC508A && HAVE_ECC_KEY_IMPORT && HAVE_ECC_KEY_EXPORT */ -#if !defined(NO_SIG_WRAPPER) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) && \ +#if !defined(NO_SIG_WRAPPER) && (!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV)) && \ !defined(NO_ECC_SIGN) static wc_test_ret_t ecc_sig_test(WC_RNG* rng, ecc_key* key) { @@ -40017,7 +40020,8 @@ static wc_test_ret_t ecc_sig_test(WC_RNG* rng, ecc_key* key) #endif #if defined(HAVE_ECC_KEY_IMPORT) && defined(HAVE_ECC_KEY_EXPORT) && \ - !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLFSSL_MICROCHIP_TA100) + (!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV)) && \ + !defined(WOLFSSL_MICROCHIP_TA100) static wc_test_ret_t ecc_exp_imp_test(ecc_key* key) { @@ -40129,6 +40133,8 @@ static wc_test_ret_t ecc_exp_imp_test(ecc_key* key) } #endif /* HAVE_ECC_KEY_IMPORT && HAVE_ECC_KEY_EXPORT */ +/* wc_ecc_mulmod is a raw math primitive stripped by WOLF_CRYPTO_CB_ONLY_ECC; + * swdev operates at the cryptocb dispatch layer and cannot rescue it. */ #if defined(HAVE_ECC_KEY_IMPORT) && !defined(WOLFSSL_VALIDATE_ECC_IMPORT) && \ !defined(WOLFSSL_CRYPTOCELL) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) && \ !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \ @@ -40298,7 +40304,7 @@ static wc_test_ret_t ecc_def_curve_test(WC_RNG *rng) ret = wc_ecc_set_flags(key, 0); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), done); -#ifndef WOLF_CRYPTO_CB_ONLY_ECC +#if !defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV) #ifndef WC_NO_RNG ret = wc_ecc_make_key(rng, ECC_KEYGEN_SIZE, key); #if defined(WOLFSSL_ASYNC_CRYPT) @@ -41545,7 +41551,7 @@ static wc_test_ret_t ecc_test_cert_gen(WC_RNG* rng) #endif /* WOLFSSL_CERT_GEN */ #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - !defined(WOLFSSL_NO_MALLOC) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) && \ + !defined(WOLFSSL_NO_MALLOC) && (!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV)) && \ (!defined(NO_ECC_SECP) || defined(WOLFSSL_CUSTOM_CURVES)) /* Test for the wc_ecc_key_new() and wc_ecc_key_free() functions. */ static wc_test_ret_t ecc_test_allocator(WC_RNG* rng) @@ -42386,7 +42392,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ecc_test(void) } #endif #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && !defined(WOLFSSL_NO_MALLOC) && \ - !defined(WOLF_CRYPTO_CB_ONLY_ECC) && (!defined(NO_ECC_SECP) || \ + (!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV)) && (!defined(NO_ECC_SECP) || \ defined(WOLFSSL_CUSTOM_CURVES)) ret = ecc_test_allocator(&rng); if (ret != 0) { @@ -43244,7 +43250,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ecc_encrypt_test(void) !defined(WOLFSSL_ATECC608A) && !defined(WOLFSSL_MICROCHIP_TA100) && \ !defined(NO_ECC256) && \ defined(HAVE_ECC_VERIFY) && defined(HAVE_ECC_SIGN) && \ - !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(NO_ECC_SECP) && \ + (!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV)) && !defined(NO_ECC_SECP) && \ !defined(WOLFSSL_SE050) #if defined(HAVE_ECC_ENCRYPT) && defined(HAVE_HKDF) && \ @@ -71013,7 +71019,8 @@ static wc_test_ret_t ecc_onlycb_test(myCryptoDevCtx *ctx) ecc_key* pub = (ecc_key *)XMALLOC(sizeof(*pub), HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); byte* out = (byte*)XMALLOC(256, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - #if !defined(WOLFCRYPT_ONLY) && defined(OPENSSL_EXTRA) + #if !defined(WOLFCRYPT_ONLY) && defined(OPENSSL_EXTRA) && \ + defined(USE_CERT_BUFFERS_256) byte* check = (byte*)XMALLOC(256, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); #endif #else @@ -71024,17 +71031,17 @@ static wc_test_ret_t ecc_onlycb_test(myCryptoDevCtx *ctx) #if defined(HAVE_ECC_SIGN) && defined(HAVE_ECC_VERIFY) byte out[256]; #endif - #if !defined(WOLFCRYPT_ONLY) && defined(OPENSSL_EXTRA) + #if !defined(WOLFCRYPT_ONLY) && defined(OPENSSL_EXTRA) && \ + defined(USE_CERT_BUFFERS_256) byte check[256]; #endif #endif -#if !defined(WOLFCRYPT_ONLY) && defined(OPENSSL_EXTRA) +#if !defined(WOLFCRYPT_ONLY) && defined(OPENSSL_EXTRA) && \ + defined(USE_CERT_BUFFERS_256) WOLFSSL_EVP_PKEY* privKey = NULL; WOLFSSL_EVP_PKEY* pubKey = NULL; - #ifdef USE_CERT_BUFFERS_256 ecc_key* pkey; const unsigned char* cp; - #endif WOLFSSL_EVP_MD_CTX mdCtx; const char testData[] = "Hi There"; size_t checkSz = -1; @@ -71179,7 +71186,8 @@ static wc_test_ret_t ecc_onlycb_test(myCryptoDevCtx *ctx) #endif /* HAVE_ECC_DHE */ -#if !defined(WOLFCRYPT_ONLY) && defined(OPENSSL_EXTRA) +#if !defined(WOLFCRYPT_ONLY) && defined(OPENSSL_EXTRA) && \ + defined(USE_CERT_BUFFERS_256) (void)pkey; cp = ecc_clikey_der_256; privKey = d2i_PrivateKey(WC_EVP_PKEY_EC, NULL, &cp, @@ -71275,7 +71283,7 @@ static wc_test_ret_t ecc_onlycb_test(myCryptoDevCtx *ctx) ERROR_OUT(WC_TEST_RET_ENC_NC, exit_onlycb); } else ret = 0; -#endif /* !WOLFCRYPT_ONLY && OPENSSL_EXTRA */ +#endif /* !WOLFCRYPT_ONLY && OPENSSL_EXTRA && USE_CERT_BUFFERS_256 */ (void)keyFormat; (void)encInfo; @@ -71289,14 +71297,16 @@ static wc_test_ret_t ecc_onlycb_test(myCryptoDevCtx *ctx) } XFREE(pub, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); XFREE(out, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - #if !defined(WOLFCRYPT_ONLY) && defined(OPENSSL_EXTRA) + #if !defined(WOLFCRYPT_ONLY) && defined(OPENSSL_EXTRA) && \ + defined(USE_CERT_BUFFERS_256) if (check) { FREE(check, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); } #endif #else wc_ecc_free(key); - #if !defined(WOLFCRYPT_ONLY) && defined(OPENSSL_EXTRA) + #if !defined(WOLFCRYPT_ONLY) && defined(OPENSSL_EXTRA) && \ + defined(USE_CERT_BUFFERS_256) if (privKey) wolfSSL_EVP_PKEY_free(privKey); if (pubKey) @@ -73145,7 +73155,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) ret = ecc_test(); PRIVATE_KEY_LOCK(); #endif -#if defined(WOLF_CRYPTO_CB_ONLY_ECC) +#if defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLFSSL_SWDEV) PRIVATE_KEY_UNLOCK(); if (ret == 0) ret = ecc_onlycb_test(&myCtx); diff --git a/wolfcrypt/test/test.h b/wolfcrypt/test/test.h index 97be48121b7..9c1154fc2d8 100644 --- a/wolfcrypt/test/test.h +++ b/wolfcrypt/test/test.h @@ -287,7 +287,7 @@ extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t scrypt_test(void); #if defined(USE_CERT_BUFFERS_256) && !defined(WOLFSSL_ATECC508A) && \ !defined(WOLFSSL_ATECC608A) && !defined(NO_ECC256) && \ defined(HAVE_ECC_VERIFY) && defined(HAVE_ECC_SIGN) && \ - !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(NO_ECC_SECP) + (!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV)) && !defined(NO_ECC_SECP) /* skip for ATECC508/608A, cannot import private key buffers */ extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ecc_test_buffers(void); #endif From 8f0d4db7d98b2c238de8e62ab0c8756c185f8005 Mon Sep 17 00:00:00 2001 From: rizlik Date: Wed, 22 Apr 2026 13:14:24 +0000 Subject: [PATCH 03/21] tests/swdev: add RSA support to wc_swdev Extend the swdev callback to handle RSA operations: public/private encrypt and decrypt, plus key generation. --- tests/swdev/swdev.c | 42 ++++++++++++++++++++++++++++++++++++++++-- wolfcrypt/test/test.c | 21 +++++++++++---------- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/tests/swdev/swdev.c b/tests/swdev/swdev.c index 6c85e54973a..2b328d3969a 100644 --- a/tests/swdev/swdev.c +++ b/tests/swdev/swdev.c @@ -7,6 +7,9 @@ #include #include +#ifndef NO_RSA +#include +#endif #ifdef HAVE_ECC #include #endif @@ -24,6 +27,31 @@ static int swdev_ensure_init(void) return 0; } +#ifndef NO_RSA +static int swdev_rsa(wc_CryptoInfo* info) +{ + switch (info->pk.rsa.type) { + case RSA_PUBLIC_ENCRYPT: + case RSA_PUBLIC_DECRYPT: + case RSA_PRIVATE_ENCRYPT: + case RSA_PRIVATE_DECRYPT: + return wc_RsaFunction(info->pk.rsa.in, info->pk.rsa.inLen, + info->pk.rsa.out, info->pk.rsa.outLen, info->pk.rsa.type, + info->pk.rsa.key, info->pk.rsa.rng); + default: + return CRYPTOCB_UNAVAILABLE; + } +} + +#ifdef WOLFSSL_KEY_GEN +static int swdev_rsa_keygen(wc_CryptoInfo* info) +{ + return wc_MakeRsaKey(info->pk.rsakg.key, info->pk.rsakg.size, + info->pk.rsakg.e, info->pk.rsakg.rng); +} +#endif +#endif /* !NO_RSA */ + #ifdef HAVE_ECC static int swdev_ecc_keygen(wc_CryptoInfo* info) { @@ -108,9 +136,18 @@ WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, return ret; switch (info->algo_type) { -#ifdef HAVE_ECC +#if !defined(NO_RSA) || defined(HAVE_ECC) case WC_ALGO_TYPE_PK: switch (info->pk.type) { + #ifndef NO_RSA + case WC_PK_TYPE_RSA: + return swdev_rsa(info); + #ifdef WOLFSSL_KEY_GEN + case WC_PK_TYPE_RSA_KEYGEN: + return swdev_rsa_keygen(info); + #endif + #endif /* !NO_RSA */ + #ifdef HAVE_ECC case WC_PK_TYPE_EC_KEYGEN: return swdev_ecc_keygen(info); case WC_PK_TYPE_ECDH: @@ -123,10 +160,11 @@ WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, return swdev_ecc_get_size(info); case WC_PK_TYPE_EC_GET_SIG_SIZE: return swdev_ecc_get_sig_size(info); + #endif /* HAVE_ECC */ default: return CRYPTOCB_UNAVAILABLE; } -#endif /* HAVE_ECC */ +#endif default: return CRYPTOCB_UNAVAILABLE; } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index b5388d3e6eb..a46eec36ac4 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -26586,7 +26586,7 @@ static wc_test_ret_t rsa_sig_test(RsaKey* key, word32 keyLen, int modLen, WC_RNG if (ret != WC_NO_ERR_TRACE(SIG_TYPE_E)) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_rsa_sig); #endif -#if defined(WOLF_CRYPTO_CB_ONLY_RSA) +#if defined(WOLF_CRYPTO_CB_ONLY_RSA) && !defined(WOLFSSL_SWDEV) ret = 0; goto exit_rsa_sig; #endif @@ -27016,7 +27016,7 @@ static wc_test_ret_t rsa_decode_test(RsaKey* keyPub) !defined(WC_NO_RNG) /* Need to create known good signatures to test with this. */ #if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_PUBLIC_ONLY) && \ -!defined(WOLF_CRYPTO_CB_ONLY_RSA) +(!defined(WOLF_CRYPTO_CB_ONLY_RSA) || defined(WOLFSSL_SWDEV)) static wc_test_ret_t rsa_pss_test(WC_RNG* rng, RsaKey* key) { byte digest[WC_MAX_DIGEST_SIZE]; @@ -28308,7 +28308,7 @@ static wc_test_ret_t rsa_keygen_test(WC_RNG* rng) int derSz = 0; #endif -#ifdef WOLF_CRYPTO_CB_ONLY_RSA +#if defined(WOLF_CRYPTO_CB_ONLY_RSA) && !defined(WOLFSSL_SWDEV) if (devId == INVALID_DEVID) { /* must call keygen with devId */ return 0; @@ -28410,7 +28410,7 @@ static wc_test_ret_t rsa_keygen_test(WC_RNG* rng) #if !defined(WC_NO_RSA_OAEP) && !defined(WC_NO_RNG) && \ (!defined(HAVE_FIPS) || \ (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) \ - && !defined(WOLF_CRYPTO_CB_ONLY_RSA) + && (!defined(WOLF_CRYPTO_CB_ONLY_RSA) || defined(WOLFSSL_SWDEV)) static wc_test_ret_t rsa_oaep_padding_test(RsaKey* key, WC_RNG* rng) { wc_test_ret_t ret = 0; @@ -28652,7 +28652,7 @@ static wc_test_ret_t rsa_pkcs1_test(RsaKey* key, WC_RNG* rng, word32 idx = 0; #if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_PUBLIC_ONLY) && \ - !defined(WC_NO_RNG) && !defined(WOLF_CRYPTO_CB_ONLY_RSA) + !defined(WC_NO_RNG) && (!defined(WOLF_CRYPTO_CB_ONLY_RSA) || defined(WOLFSSL_SWDEV)) /* Reload the key so the public-encrypt below is the first operation * against it. Exercises backends that distinguish public-only material * from full-keypair bindings: a public-encrypt on a freshly-loaded key @@ -28758,7 +28758,7 @@ static wc_test_ret_t rsa_pkcs1_test(RsaKey* key, WC_RNG* rng, #if !defined(WC_NO_RNG) && !defined(WC_NO_RSA_OAEP) && \ !defined(WOLFSSL_RSA_VERIFY_ONLY) && defined(WOLFSSL_PUBLIC_MP) && \ - !defined(WOLF_CRYPTO_CB_ONLY_RSA) + (!defined(WOLF_CRYPTO_CB_ONLY_RSA) || defined(WOLFSSL_SWDEV)) idx = (word32)ret; XMEMSET(plain, 0, plainSz); do { @@ -28802,10 +28802,11 @@ static wc_test_ret_t rsa_pkcs1_test(RsaKey* key, WC_RNG* rng, #endif #if (!defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_PUBLIC_ONLY) && \ - !defined(WC_NO_RNG) && !defined(WOLF_CRYPTO_CB_ONLY_RSA)) || \ + !defined(WC_NO_RNG) && \ + (!defined(WOLF_CRYPTO_CB_ONLY_RSA) || defined(WOLFSSL_SWDEV))) || \ (!defined(WC_NO_RNG) && !defined(WC_NO_RSA_OAEP) && \ !defined(WOLFSSL_RSA_VERIFY_ONLY) && defined(WOLFSSL_PUBLIC_MP) && \ - !defined(WOLF_CRYPTO_CB_ONLY_RSA)) + (!defined(WOLF_CRYPTO_CB_ONLY_RSA) || defined(WOLFSSL_SWDEV))) exit_rsa_pkcs1: #endif (void)res; @@ -29333,7 +29334,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rsa_test(void) #if !defined(WC_NO_RSA_OAEP) && !defined(WC_NO_RNG) #if (!defined(HAVE_FIPS) || \ (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) \ - && !defined(WOLF_CRYPTO_CB_ONLY_RSA) + && (!defined(WOLF_CRYPTO_CB_ONLY_RSA) || defined(WOLFSSL_SWDEV)) ret = rsa_oaep_padding_test(key, &rng); if (ret != 0) goto exit_rsa; @@ -29411,7 +29412,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rsa_test(void) !defined(WC_NO_RNG) /* Need to create known good signatures to test with this. */ #if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_PUBLIC_ONLY) && \ - !defined(WOLF_CRYPTO_CB_ONLY_RSA) + (!defined(WOLF_CRYPTO_CB_ONLY_RSA) || defined(WOLFSSL_SWDEV)) ret = rsa_pss_test(&rng, key); if (ret != 0) goto exit_rsa; From 65b49b2fb5b4db5d370af5d786a4af3be56a837e Mon Sep 17 00:00:00 2001 From: rizlik Date: Wed, 22 Apr 2026 13:14:45 +0000 Subject: [PATCH 04/21] _CRYPTO_CB_ONLY_{RSA,ECC,SHA256,AES}: move WOLF_CRYPTO_CB guards to settings.h --- wolfssl/wolfcrypt/settings.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 325627ded25..3a1a4987760 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -5126,6 +5126,22 @@ extern void uITRON4_free(void *p) ; " (WOLF_CRYPTO_CB_COPY/WOLF_CRYPTO_CB_FREE)" \ " require WOLF_CRYPTO_CB" #endif +/* + * WOLF_CRYPTO_CB_ONLY_* assumes no hardware crypto port is compiled in for + * the selected algorithm. Crypto Callback is expected to be the only provider. + */ +#if defined(WOLF_CRYPTO_CB_ONLY_RSA) && !defined(WOLF_CRYPTO_CB) + #error "WOLF_CRYPTO_CB_ONLY_RSA requires WOLF_CRYPTO_CB" +#endif +#if defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB) + #error "WOLF_CRYPTO_CB_ONLY_ECC requires WOLF_CRYPTO_CB" +#endif +#if defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB) + #error "WOLF_CRYPTO_CB_ONLY_SHA256 requires WOLF_CRYPTO_CB" +#endif +#if defined(WOLF_CRYPTO_CB_ONLY_AES) && !defined(WOLF_CRYPTO_CB) + #error "WOLF_CRYPTO_CB_ONLY_AES requires WOLF_CRYPTO_CB" +#endif /* Early Data / Session Rules */ #if !defined(WOLFCRYPT_ONLY) && defined(WOLFSSL_EARLY_DATA) && \ From 61bfff1dac3c8f2bf2d4196bcd67f6f580b370f7 Mon Sep 17 00:00:00 2001 From: rizlik Date: Wed, 29 Apr 2026 15:02:47 +0000 Subject: [PATCH 05/21] WOLF_CRYPTO_CB_ONLY_SHA256: strip software SHA-256 and dispatch via swdev Add WOLF_CRYPTO_CB_ONLY_SHA256: when set, the SHA-256 software. wc_Sha256FinalRaw is reduced to a stub returning NO_VALID_DEVID, and sha256.h force-defines WOLFSSL_NO_HASH_RAW so the constant-time TLS HMAC path falls back to its backend-opaque variant. Incompatible with WOLFSSL_SHA224, which aliases the SHA-256 statics; #error guard added. Add wc_swdev support for SHA-256 for testing. --- .github/workflows/cryptocb-only.yml | 7 +++ tests/api.c | 2 + tests/swdev/swdev.c | 68 +++++++++++++++++++++++++ tests/swdev/user_settings.h | 1 + wolfcrypt/src/cryptocb.c | 1 + wolfcrypt/src/sha256.c | 78 +++++++++++++++++++++++++++-- wolfcrypt/test/test.c | 67 ++++++++++++++++++++++++- wolfssl/wolfcrypt/sha256.h | 6 +++ 8 files changed, 224 insertions(+), 6 deletions(-) diff --git a/.github/workflows/cryptocb-only.yml b/.github/workflows/cryptocb-only.yml index 4dc323fec27..4753d018db1 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 79f1bed2d56..f5d046f3fc8 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 2b328d3969a..4067a26dbec 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 bf364459a8f..aaf16c0e254 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 0036556ba96..bbefe6b3e1d 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 93a079a507c..5e7b8d01acc 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 a46eec36ac4..43c26e718ae 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -5968,7 +5968,8 @@ static wc_test_ret_t sha256_large_hash_test(wc_Sha256* sha) #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 @@ static wc_test_ret_t ecc_onlycb_test(myCryptoDevCtx *ctx) } #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 dd69f57603c..ea354695f98 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) From c5ef060139bb5b339d188a1f3234a564b4d0e694 Mon Sep 17 00:00:00 2001 From: rizlik Date: Wed, 29 Apr 2026 15:06:36 +0000 Subject: [PATCH 06/21] WOLF_CRYPTO_CB_ONLY_AES: add support + swdev for testing Modes (CTR, GCM, CCM, etc.) can be supported either directly or fallback to invoking the crypto callback with a "direct" (ECB) mode. Software implementation and AES tables are stripped under CB_ONLY_AES. wc_swdev gains AES support so WOLF_CRYPTO_CB_ONLY_AES builds can be tested. crypto find cb support added to wc_AesSetKey in order to support current CI tests that use INVALID_DEVID. --- .github/workflows/cryptocb-only.yml | 13 ++ tests/api.c | 8 +- tests/swdev/swdev.c | 277 ++++++++++++++++++++++++++++ tests/swdev/user_settings.h | 1 + wolfcrypt/src/aes.c | 84 ++++++++- wolfcrypt/src/cryptocb.c | 6 +- wolfcrypt/test/test.c | 69 ++++++- wolfssl/wolfcrypt/cryptocb.h | 10 +- wolfssl/wolfcrypt/settings.h | 4 + 9 files changed, 458 insertions(+), 14 deletions(-) diff --git a/.github/workflows/cryptocb-only.yml b/.github/workflows/cryptocb-only.yml index 4753d018db1..b6ba4cc12bf 100644 --- a/.github/workflows/cryptocb-only.yml +++ b/.github/workflows/cryptocb-only.yml @@ -35,6 +35,19 @@ jobs: - name: SHA256 extra_config: --disable-sha224 cppflags: -DWOLF_CRYPTO_CB_ONLY_SHA256 + # WOLF_CRYPTO_CB_ONLY_AES: strips software AES; swdev provides the + # software path via cryptocb. + - name: AES + cppflags: -DWOLF_CRYPTO_CB_ONLY_AES + # All four 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. + - name: ALL + extra_config: --disable-sha224 + cppflags: >- + -DWOLF_CRYPTO_CB_ONLY_ECC -DWOLF_CRYPTO_CB_ONLY_RSA + -DWOLF_CRYPTO_CB_ONLY_SHA256 -DWOLF_CRYPTO_CB_ONLY_AES 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 f5d046f3fc8..bd55810dc11 100644 --- a/tests/api.c +++ b/tests/api.c @@ -30609,7 +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_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES) && \ !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, @@ -31613,7 +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_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES) && \ !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA) /* TODO: Add crypto callback API tests */ @@ -39857,7 +39857,7 @@ static int test_pkcs7_padding(void) /* Encode EncryptedData */ XMEMSET(&pkcs7, 0, sizeof(pkcs7)); - ExpectIntEQ(wc_PKCS7_Init(&pkcs7, NULL, 0), 0); + ExpectIntEQ(wc_PKCS7_Init(&pkcs7, NULL, INVALID_DEVID), 0); pkcs7.content = plaintext; pkcs7.contentSz = sizeof(plaintext); pkcs7.contentOID = DATA; @@ -39886,7 +39886,7 @@ static int test_pkcs7_padding(void) /* Decrypt modified ciphertext - must fail, not succeed */ XMEMSET(&pkcs7, 0, sizeof(pkcs7)); - ExpectIntEQ(wc_PKCS7_Init(&pkcs7, NULL, 0), 0); + ExpectIntEQ(wc_PKCS7_Init(&pkcs7, NULL, INVALID_DEVID), 0); pkcs7.encryptionKey = key; pkcs7.encryptionKeySz = sizeof(key); diff --git a/tests/swdev/swdev.c b/tests/swdev/swdev.c index 4067a26dbec..d402207b54d 100644 --- a/tests/swdev/swdev.c +++ b/tests/swdev/swdev.c @@ -16,6 +16,9 @@ #ifndef NO_SHA256 #include #endif +#ifndef NO_AES +#include +#endif static int swdev_initialized = 0; @@ -179,6 +182,253 @@ static int swdev_sha256(wc_CryptoInfo* info) } #endif /* !NO_SHA256 */ +#ifndef NO_AES +/* Rebuild a software AES shadow from the caller's raw devKey, since the + * caller's Aes has no software round-key schedule under CB_ONLY_AES. */ +static int swdev_aes_shadow_init(Aes* shadow, const Aes* aes, int dir) +{ + int ret; + + if (shadow == NULL || aes == NULL) + return BAD_FUNC_ARG; + if (aes->keylen <= 0 || aes->keylen > (int)sizeof(aes->devKey)) + return BAD_FUNC_ARG; + + ret = wc_AesInit(shadow, aes->heap, INVALID_DEVID); + if (ret != 0) + return ret; + + ret = wc_AesSetKey(shadow, (const byte*)aes->devKey, + (word32)aes->keylen, (const byte*)aes->reg, dir); + if (ret != 0) { + wc_AesFree(shadow); + return ret; + } + + XMEMCPY(shadow->tmp, aes->tmp, sizeof(shadow->tmp)); +#if defined(WOLFSSL_AES_COUNTER) || defined(WOLFSSL_AES_CFB) || \ + defined(WOLFSSL_AES_OFB) || defined(WOLFSSL_AES_XTS) || \ + defined(WOLFSSL_AES_CTS) + shadow->left = aes->left; +#endif + + return 0; +} + +static void swdev_aes_shadow_sync(Aes* dst, const Aes* src) +{ + XMEMCPY(dst->reg, src->reg, sizeof(dst->reg)); + XMEMCPY(dst->tmp, src->tmp, sizeof(dst->tmp)); +#if defined(WOLFSSL_AES_COUNTER) || defined(WOLFSSL_AES_CFB) || \ + defined(WOLFSSL_AES_OFB) || defined(WOLFSSL_AES_XTS) || \ + defined(WOLFSSL_AES_CTS) + dst->left = src->left; +#endif +} + +#ifdef HAVE_AES_CBC +static int swdev_aes_cbc(wc_CryptoInfo* info) +{ + Aes* aes = info->cipher.aescbc.aes; + byte* out = info->cipher.aescbc.out; + const byte* in = info->cipher.aescbc.in; + word32 sz = info->cipher.aescbc.sz; + Aes shadow; + int ret; + + ret = swdev_aes_shadow_init(&shadow, aes, + info->cipher.enc ? AES_ENCRYPTION : AES_DECRYPTION); + if (ret != 0) + return ret; + + if (info->cipher.enc) + ret = wc_AesCbcEncrypt(&shadow, out, in, sz); +#ifdef HAVE_AES_DECRYPT + else + ret = wc_AesCbcDecrypt(&shadow, out, in, sz); +#else + else + ret = CRYPTOCB_UNAVAILABLE; +#endif + swdev_aes_shadow_sync(aes, &shadow); + wc_AesFree(&shadow); + return ret; +} +#endif /* HAVE_AES_CBC */ + +#ifdef WOLFSSL_AES_COUNTER +static int swdev_aes_ctr(wc_CryptoInfo* info) +{ + Aes* aes = info->cipher.aesctr.aes; + Aes shadow; + int ret; + + ret = swdev_aes_shadow_init(&shadow, aes, AES_ENCRYPTION); + if (ret != 0) + return ret; + + ret = wc_AesCtrEncrypt(&shadow, info->cipher.aesctr.out, + info->cipher.aesctr.in, info->cipher.aesctr.sz); + swdev_aes_shadow_sync(aes, &shadow); + wc_AesFree(&shadow); + return ret; +} +#endif + +#if defined(HAVE_AES_ECB) || defined(WOLFSSL_AES_DIRECT) +static int swdev_aes_ecb(wc_CryptoInfo* info) +{ + Aes* aes = info->cipher.aesecb.aes; + byte* out = info->cipher.aesecb.out; + const byte* in = info->cipher.aesecb.in; + word32 sz = info->cipher.aesecb.sz; + Aes shadow; + int ret; + + ret = swdev_aes_shadow_init(&shadow, aes, + info->cipher.enc ? AES_ENCRYPTION : AES_DECRYPTION); + if (ret != 0) + return ret; + +#ifdef HAVE_AES_ECB + if (info->cipher.enc) + ret = wc_AesEcbEncrypt(&shadow, out, in, sz); +#ifdef HAVE_AES_DECRYPT + else + ret = wc_AesEcbDecrypt(&shadow, out, in, sz); +#else + else + ret = CRYPTOCB_UNAVAILABLE; +#endif +#elif defined(WOLFSSL_AES_DIRECT) + if (sz != WC_AES_BLOCK_SIZE) { + ret = CRYPTOCB_UNAVAILABLE; + } + else if (info->cipher.enc) { + ret = wc_AesEncryptDirect(&shadow, out, in); + } +#ifdef HAVE_AES_DECRYPT + else { + ret = wc_AesDecryptDirect(&shadow, out, in); + } +#else + else { + ret = CRYPTOCB_UNAVAILABLE; + } +#endif +#else + (void)out; + (void)in; + (void)sz; + ret = CRYPTOCB_UNAVAILABLE; +#endif + + wc_AesFree(&shadow); + return ret; +} +#endif /* HAVE_AES_ECB || WOLFSSL_AES_DIRECT */ + +#ifdef HAVE_AESGCM +static int swdev_aes_gcm(wc_CryptoInfo* info) +{ + Aes* aes = info->cipher.enc ? info->cipher.aesgcm_enc.aes : + info->cipher.aesgcm_dec.aes; + Aes shadow; + int ret; + + if (aes == NULL || aes->keylen <= 0 || aes->keylen > (int)sizeof(aes->devKey)) + return BAD_FUNC_ARG; + + ret = wc_AesInit(&shadow, aes->heap, INVALID_DEVID); + if (ret != 0) + return ret; + + ret = wc_AesGcmSetKey(&shadow, (const byte*)aes->devKey, (word32)aes->keylen); + if (ret != 0) { + wc_AesFree(&shadow); + return ret; + } + + if (info->cipher.enc) { + ret = wc_AesGcmEncrypt(&shadow, + info->cipher.aesgcm_enc.out, info->cipher.aesgcm_enc.in, + info->cipher.aesgcm_enc.sz, + info->cipher.aesgcm_enc.iv, info->cipher.aesgcm_enc.ivSz, + info->cipher.aesgcm_enc.authTag, + info->cipher.aesgcm_enc.authTagSz, + info->cipher.aesgcm_enc.authIn, + info->cipher.aesgcm_enc.authInSz); + } + else { + ret = wc_AesGcmDecrypt(&shadow, info->cipher.aesgcm_dec.out, + info->cipher.aesgcm_dec.in, info->cipher.aesgcm_dec.sz, + info->cipher.aesgcm_dec.iv, info->cipher.aesgcm_dec.ivSz, + info->cipher.aesgcm_dec.authTag, + info->cipher.aesgcm_dec.authTagSz, + info->cipher.aesgcm_dec.authIn, + info->cipher.aesgcm_dec.authInSz); + } + + wc_AesFree(&shadow); + return ret; +} +#endif /* HAVE_AESGCM */ + +#ifdef HAVE_AESCCM +static int swdev_aes_ccm(wc_CryptoInfo* info) +{ + Aes* aes = info->cipher.enc ? info->cipher.aesccm_enc.aes : + info->cipher.aesccm_dec.aes; + Aes shadow; + int ret; + + if (aes == NULL || aes->keylen <= 0 || aes->keylen > (int)sizeof(aes->devKey)) + return BAD_FUNC_ARG; + + ret = wc_AesInit(&shadow, aes->heap, INVALID_DEVID); + if (ret != 0) + return ret; + + ret = wc_AesCcmSetKey(&shadow, (const byte*)aes->devKey, (word32)aes->keylen); + if (ret != 0) { + wc_AesFree(&shadow); + return ret; + } + + if (info->cipher.enc) { + ret = wc_AesCcmEncrypt(&shadow, + info->cipher.aesccm_enc.out, info->cipher.aesccm_enc.in, + info->cipher.aesccm_enc.sz, + info->cipher.aesccm_enc.nonce, + info->cipher.aesccm_enc.nonceSz, + info->cipher.aesccm_enc.authTag, + info->cipher.aesccm_enc.authTagSz, + info->cipher.aesccm_enc.authIn, + info->cipher.aesccm_enc.authInSz); + } +#ifdef HAVE_AES_DECRYPT + else { + ret = wc_AesCcmDecrypt(&shadow, info->cipher.aesccm_dec.out, + info->cipher.aesccm_dec.in, info->cipher.aesccm_dec.sz, + info->cipher.aesccm_dec.nonce, + info->cipher.aesccm_dec.nonceSz, + info->cipher.aesccm_dec.authTag, + info->cipher.aesccm_dec.authTagSz, + info->cipher.aesccm_dec.authIn, + info->cipher.aesccm_dec.authInSz); + } +#else + else { + ret = CRYPTOCB_UNAVAILABLE; + } +#endif + + wc_AesFree(&shadow); + return ret; +} +#endif /* HAVE_AESCCM */ +#endif /* !NO_AES */ + WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, void* ctx) { @@ -233,6 +483,33 @@ WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, return CRYPTOCB_UNAVAILABLE; } #endif +#ifndef NO_AES + case WC_ALGO_TYPE_CIPHER: + switch (info->cipher.type) { + #ifdef HAVE_AES_CBC + case WC_CIPHER_AES_CBC: + return swdev_aes_cbc(info); + #endif + #ifdef WOLFSSL_AES_COUNTER + case WC_CIPHER_AES_CTR: + return swdev_aes_ctr(info); + #endif + #if defined(HAVE_AES_ECB) || defined(WOLFSSL_AES_DIRECT) + case WC_CIPHER_AES_ECB: + return swdev_aes_ecb(info); + #endif + #ifdef HAVE_AESGCM + case WC_CIPHER_AES_GCM: + return swdev_aes_gcm(info); + #endif + #ifdef HAVE_AESCCM + case WC_CIPHER_AES_CCM: + return swdev_aes_ccm(info); + #endif + default: + return CRYPTOCB_UNAVAILABLE; + } +#endif /* !NO_AES */ default: return CRYPTOCB_UNAVAILABLE; } diff --git a/tests/swdev/user_settings.h b/tests/swdev/user_settings.h index aaf16c0e254..e6a55019ec5 100644 --- a/tests/swdev/user_settings.h +++ b/tests/swdev/user_settings.h @@ -16,6 +16,7 @@ #undef WOLF_CRYPTO_CB_ONLY_RSA #undef WOLF_CRYPTO_CB_ONLY_ECC #undef WOLF_CRYPTO_CB_ONLY_SHA256 +#undef WOLF_CRYPTO_CB_ONLY_AES #ifndef WOLF_CRYPTO_CB #error "wc_swdev requires the main build to define WOLF_CRYPTO_CB" diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index a38e2007e4f..56335545a16 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -1263,6 +1263,9 @@ static WARN_UNUSED_RESULT int wc_AesDecrypt(Aes* aes, const byte* inBlock, } #endif +#elif defined(WOLF_CRYPTO_CB_ONLY_AES) + /* No software implementation AES T-tables, S-box, Rcon and the C key + * schedule are stripped. */ #else /* using wolfCrypt software implementation */ @@ -4115,6 +4118,51 @@ WC_ALL_ARGS_NOT_NULL static WARN_UNUSED_RESULT int wc_AesDecrypt( #endif /* NEED_AES_TABLES */ +#ifdef WOLF_CRYPTO_CB_ONLY_AES +/* Under WOLF_CRYPTO_CB_ONLY_AES the per-block primitive is a thin shim over + * the cryptocb ECB callback. When the callback returns CRYPTOCB_UNAVAILABLE + * there is no software fallback, so the operation fails with NO_VALID_DEVID. */ +static WARN_UNUSED_RESULT int wc_AesEncrypt(Aes* aes, const byte* inBlock, + byte* outBlock) +{ + int ret; + + if (aes == NULL || inBlock == NULL || outBlock == NULL) + return BAD_FUNC_ARG; +#ifdef WC_DEBUG_CIPHER_LIFECYCLE + ret = wc_debug_CipherLifecycleCheck(aes->CipherLifecycleTag, 0); + if (ret < 0) + return ret; +#endif + + ret = wc_CryptoCb_AesEcbEncrypt(aes, outBlock, inBlock, WC_AES_BLOCK_SIZE); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + return NO_VALID_DEVID; +} + +#ifdef HAVE_AES_DECRYPT +static WARN_UNUSED_RESULT int wc_AesDecrypt(Aes* aes, const byte* inBlock, + byte* outBlock) +{ + int ret; + + if (aes == NULL || inBlock == NULL || outBlock == NULL) + return BAD_FUNC_ARG; +#ifdef WC_DEBUG_CIPHER_LIFECYCLE + ret = wc_debug_CipherLifecycleCheck(aes->CipherLifecycleTag, 0); + if (ret < 0) + return ret; +#endif + + ret = wc_CryptoCb_AesEcbDecrypt(aes, outBlock, inBlock, WC_AES_BLOCK_SIZE); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + return NO_VALID_DEVID; +} +#endif /* HAVE_AES_DECRYPT */ +#endif /* WOLF_CRYPTO_CB_ONLY_AES */ + #ifndef WC_AES_HAVE_PREFETCH_ARG #ifndef AesEncrypt_preFetchOpt #define AesEncrypt_preFetchOpt(aes, inBlock, outBlock, do_preFetch) \ @@ -5009,7 +5057,10 @@ static void AesSetKey_C(Aes* aes, const byte* key, word32 keySz, int dir) } #ifdef WOLF_CRYPTO_CB - if (aes->devId != INVALID_DEVID) { + #ifndef WOLF_CRYPTO_CB_FIND + if (aes->devId != INVALID_DEVID) + #endif + { #ifdef WOLF_CRYPTO_CB_AES_SETKEY ret = wc_CryptoCb_AesSetKey(aes, userKey, keylen); if (ret == 0) { @@ -5112,8 +5163,10 @@ static void AesSetKey_C(Aes* aes, const byte* key, word32 keySz, int dir) (defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_AES)) || \ defined(WOLFSSL_NXP_HASHCRYPT_AES) #ifdef WOLF_CRYPTO_CB + #ifndef WOLF_CRYPTO_CB_FIND if (aes->devId != INVALID_DEVID) #endif + #endif { if (keylen > sizeof(aes->devKey)) { return BAD_FUNC_ARG; @@ -5122,6 +5175,22 @@ static void AesSetKey_C(Aes* aes, const byte* key, word32 keySz, int dir) } #endif + #ifdef WOLF_CRYPTO_CB_ONLY_AES + /* No software AES schedule under CB_ONLY: aes->key[] (round keys) are + * unused because the static wc_AesEncrypt/wc_AesDecrypt are cryptocb- + * ECB shims. aes->rounds is still populated because wc_AesGetKeySize() + * reads it as the source of truth for the configured key size. */ + aes->keylen = (int)keylen; + aes->rounds = (keylen / 4) + 6; + #if defined(WOLFSSL_AES_COUNTER) || defined(WOLFSSL_AES_CFB) || \ + defined(WOLFSSL_AES_OFB) || defined(WOLFSSL_AES_XTS) || \ + defined(WOLFSSL_AES_CTS) + aes->left = 0; + #endif + (void)dir; + return wc_AesSetIV(aes, iv); + #endif + #if defined(AES_MAX_KEY_SIZE) && AES_MAX_KEY_SIZE < 256 if (checkKeyLen) { /* Check key length only when AES_MAX_KEY_SIZE doesn't allow @@ -7719,6 +7788,11 @@ int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len) #endif XMEMSET(iv, 0, WC_AES_BLOCK_SIZE); ret = wc_AesSetKey(aes, key, len, iv, AES_ENCRYPTION); +#ifdef WOLF_CRYPTO_CB_ONLY_AES + /* Device handles GCM end-to-end; GHASH H / M0 setup below is dead state + * under CB_ONLY (no host-side software path consumes aes->gcm.H or M0). */ + return ret; +#endif #ifdef WOLFSSL_AESGCM_STREAM aes->gcmKeySet = 1; #endif @@ -14109,6 +14183,11 @@ static WARN_UNUSED_RESULT int _AesEcbEncrypt( /* fall-through when unavailable */ } #endif +#ifdef WOLF_CRYPTO_CB_ONLY_AES + /* No software fallback: the per-block loop below would only re-invoke + * cryptocb ECB and propagate UNAVAILABLE; short-circuit instead. */ + return NO_VALID_DEVID; +#endif #ifdef WOLFSSL_IMXRT_DCP if (aes->keylen == 16) return DCPAesEcbEncrypt(aes, out, in, sz); @@ -14198,6 +14277,9 @@ static WARN_UNUSED_RESULT int _AesEcbDecrypt( /* fall-through when unavailable */ } #endif +#ifdef WOLF_CRYPTO_CB_ONLY_AES + return NO_VALID_DEVID; +#endif #ifdef WOLFSSL_IMXRT_DCP if (aes->keylen == 16) return DCPAesEcbDecrypt(aes, out, in, sz); diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index bbefe6b3e1d..c006e92ae72 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -53,6 +53,7 @@ Crypto Callback Build Options: * 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 + * WOLF_CRYPTO_CB_ONLY_AES: Use only callbacks for AES default: off */ #include @@ -1724,7 +1725,8 @@ int wc_CryptoCb_AesCtrEncrypt(Aes* aes, byte* out, return wc_CryptoCb_TranslateErrorCode(ret); } #endif /* WOLFSSL_AES_COUNTER */ -#ifdef HAVE_AES_ECB +#if defined(HAVE_AES_ECB) || defined(WOLFSSL_AES_DIRECT) || \ + defined(WOLF_CRYPTO_CB_ONLY_AES) int wc_CryptoCb_AesEcbEncrypt(Aes* aes, byte* out, const byte* in, word32 sz) { @@ -1788,7 +1790,7 @@ int wc_CryptoCb_AesEcbDecrypt(Aes* aes, byte* out, return wc_CryptoCb_TranslateErrorCode(ret); } -#endif /* HAVE_AES_ECB */ +#endif /* HAVE_AES_ECB || WOLFSSL_AES_DIRECT || WOLF_CRYPTO_CB_ONLY_AES */ #ifdef WOLF_CRYPTO_CB_AES_SETKEY int wc_CryptoCb_AesSetKey(Aes* aes, const byte* key, word32 keySz) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 43c26e718ae..59cf40570a9 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -64922,7 +64922,7 @@ static wc_test_ret_t getFirmwareKey(wc_PKCS7* pkcs7, byte* key, word32 keySz) return MEMORY_E; } - wc_PKCS7_Init(envPkcs7, NULL, 0); + wc_PKCS7_Init(envPkcs7, NULL, INVALID_DEVID); ret = wc_PKCS7_SetWrapCEKCb(envPkcs7, myCEKwrapFunc); if (ret == 0) { /* expecting FIRMWARE_PKG_DATA content */ @@ -71368,6 +71368,58 @@ static wc_test_ret_t sha256_onlycb_test(myCryptoDevCtx *ctx) } #endif /* WOLF_CRYPTO_CB_ONLY_SHA256 */ +#ifdef WOLF_CRYPTO_CB_ONLY_AES +/* Exercise AES dispatch under CB_ONLY_AES: cb-handled then cb-delegated. */ +static wc_test_ret_t aes_onlycb_test(myCryptoDevCtx *ctx) +{ + wc_test_ret_t ret = 0; +#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128) + Aes aes; + const byte key[16] = { + 0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6, + 0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c + }; + const byte iv[WC_AES_BLOCK_SIZE] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f + }; + const byte plain[WC_AES_BLOCK_SIZE] = { + 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96, + 0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a + }; + byte out[WC_AES_BLOCK_SIZE]; + + ret = wc_AesInit(&aes, HEAP_HINT, devId); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_AesSetKey(&aes, key, sizeof(key), iv, AES_ENCRYPTION); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + + /* cb handles the op, expects 0(success) */ + ctx->exampleVar = 99; + ret = wc_AesCbcEncrypt(&aes, out, plain, sizeof(plain)); + 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_AesCbcEncrypt(&aes, out, plain, sizeof(plain)); + 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_AesFree(&aes); +#endif /* !NO_AES && HAVE_AES_CBC && WOLFSSL_AES_128 */ + (void)ctx; + return ret; +} +#endif /* WOLF_CRYPTO_CB_ONLY_AES */ + /* Example crypto dev callback function that calls software version */ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) { @@ -71899,6 +71951,10 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) #endif /* HAVE_AESGCM */ #ifdef HAVE_AES_CBC if (info->cipher.type == WC_CIPHER_AES_CBC) { + #if defined(WOLF_CRYPTO_CB_ONLY_AES) + if (myCtx->exampleVar == 99) + return 0; + #endif if (info->cipher.enc) { /* set devId to invalid, so software is used */ info->cipher.aescbc.aes->devId = INVALID_DEVID; @@ -73225,6 +73281,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) ret = sha256_onlycb_test(&myCtx); PRIVATE_KEY_LOCK(); #endif +#if defined(WOLF_CRYPTO_CB_ONLY_AES) && !defined(WOLFSSL_SWDEV) + PRIVATE_KEY_UNLOCK(); + if (ret == 0) + ret = aes_onlycb_test(&myCtx); + PRIVATE_KEY_LOCK(); +#endif #ifdef WOLFSSL_HAVE_MLKEM if (ret == 0) ret = mlkem_test(); @@ -73251,7 +73313,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) if (ret == 0) ret = curve25519_test(); #endif -#ifndef NO_AES +#if !defined(NO_AES) && !defined(WOLF_CRYPTO_CB_ONLY_AES) + /* CB_ONLY_AES skips these (aes_onlycb_test covers that path). */ #ifdef HAVE_AESGCM if (ret == 0) ret = aesgcm_test(); @@ -73268,7 +73331,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) if (ret == 0) ret = aesccm_test(); #endif -#endif /* !NO_AES */ +#endif /* !NO_AES && !WOLF_CRYPTO_CB_ONLY_AES */ #ifndef NO_DES3 if (ret == 0) ret = des3_test(); diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index eee9e231823..38a3d8fab77 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -414,14 +414,15 @@ typedef struct wc_CryptoInfo { word32 sz; } aesctr; #endif /* WOLFSSL_AES_COUNTER */ - #if defined(HAVE_AES_ECB) + #if defined(HAVE_AES_ECB) || defined(WOLFSSL_AES_DIRECT) || \ + defined(WOLF_CRYPTO_CB_ONLY_AES) struct { Aes* aes; byte* out; const byte* in; word32 sz; } aesecb; - #endif /* HAVE_AES_ECB */ + #endif /* HAVE_AES_ECB || WOLFSSL_AES_DIRECT || WOLF_CRYPTO_CB_ONLY_AES */ #ifndef NO_DES3 struct { Des3* des; @@ -827,12 +828,13 @@ WOLFSSL_LOCAL int wc_CryptoCb_AesCbcDecrypt(Aes* aes, byte* out, WOLFSSL_LOCAL int wc_CryptoCb_AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz); #endif /* WOLFSSL_AES_COUNTER */ -#ifdef HAVE_AES_ECB +#if defined(HAVE_AES_ECB) || defined(WOLFSSL_AES_DIRECT) || \ + defined(WOLF_CRYPTO_CB_ONLY_AES) WOLFSSL_LOCAL int wc_CryptoCb_AesEcbEncrypt(Aes* aes, byte* out, const byte* in, word32 sz); WOLFSSL_LOCAL int wc_CryptoCb_AesEcbDecrypt(Aes* aes, byte* out, const byte* in, word32 sz); -#endif /* HAVE_AES_ECB */ +#endif /* HAVE_AES_ECB || WOLFSSL_AES_DIRECT || WOLF_CRYPTO_CB_ONLY_AES */ #ifdef WOLF_CRYPTO_CB_AES_SETKEY WOLFSSL_API int wc_CryptoCb_AesSetKey(Aes* aes, const byte* key, word32 keySz); #endif /* WOLF_CRYPTO_CB_AES_SETKEY */ diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 3a1a4987760..ca6711dd9f6 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -5078,6 +5078,10 @@ extern void uITRON4_free(void *p) ; #error "AES-GCM streaming (WOLFSSL_AESGCM_STREAM)" \ " requires AES-GCM (HAVE_AESGCM)" #endif +#if defined(WOLFSSL_AESGCM_STREAM) && defined(WOLF_CRYPTO_CB_ONLY_AES) + #error "AES-GCM streaming (WOLFSSL_AESGCM_STREAM)" \ + " is not supported with WOLF_CRYPTO_CB_ONLY_AES" +#endif #if defined(WOLFSSL_AESXTS_STREAM) && !defined(WOLFSSL_AES_XTS) #error "AES-XTS streaming (WOLFSSL_AESXTS_STREAM)" \ " requires AES-XTS (WOLFSSL_AES_XTS)" From ade53b0c5966a6077a99b35b370341791f4878a0 Mon Sep 17 00:00:00 2001 From: rizlik Date: Thu, 30 Apr 2026 16:24:04 +0200 Subject: [PATCH 07/21] CRYPTO_CB_ONLY_SHA256: fix: guard Sha256FinalRaw under CB_ONLY_SHA256 --- wolfcrypt/src/sha256.c | 4 ++-- wolfssl/wolfcrypt/sha256.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/sha256.c b/wolfcrypt/src/sha256.c index 5e7b8d01acc..e5be2bcc8a2 100644 --- a/wolfcrypt/src/sha256.c +++ b/wolfcrypt/src/sha256.c @@ -1797,7 +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 +#ifndef WOLF_CRYPTO_CB_ONLY_SHA256 int wc_Sha256FinalRaw(wc_Sha256* sha256, byte* hash) { #ifdef LITTLE_ENDIAN_ORDER @@ -1821,7 +1821,7 @@ static WC_INLINE int Transform_Sha256_Len(wc_Sha256* sha256, const byte* data, return 0; } -#endif /* !WOLFSSL_NO_HASH_RAW */ +#endif /* !WOLF_CRYPTO_CB_ONLY_SHA256 */ int wc_Sha256Final(wc_Sha256* sha256, byte* hash) { diff --git a/wolfssl/wolfcrypt/sha256.h b/wolfssl/wolfcrypt/sha256.h index ea354695f98..18b2c1c91d8 100644 --- a/wolfssl/wolfcrypt/sha256.h +++ b/wolfssl/wolfcrypt/sha256.h @@ -262,7 +262,8 @@ WOLFSSL_API int wc_InitSha256(wc_Sha256* sha); WOLFSSL_API int wc_InitSha256_ex(wc_Sha256* sha, void* heap, int devId); WOLFSSL_API int wc_Sha256Update(wc_Sha256* sha, const byte* data, word32 len); -#if !defined(WOLFSSL_KCAPI_HASH) && !defined(WOLFSSL_AFALG_HASH) +#if !defined(WOLFSSL_KCAPI_HASH) && !defined(WOLFSSL_AFALG_HASH) && \ + !defined(WOLF_CRYPTO_CB_ONLY_SHA256) WOLFSSL_API int wc_Sha256FinalRaw(wc_Sha256* sha256, byte* hash); #endif WOLFSSL_API int wc_Sha256Final(wc_Sha256* sha256, byte* hash); From df2fd4ec065c3fdff7bf4137f3481efbfa7024c0 Mon Sep 17 00:00:00 2001 From: rizlik Date: Thu, 30 Apr 2026 17:02:41 +0200 Subject: [PATCH 08/21] swdev: refcount swdev Init/Cleanup --- tests/api.c | 4 +--- tests/swdev/swdev_loader.c | 28 ++++++++++++++++------------ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/tests/api.c b/tests/api.c index bd55810dc11..7530b58e513 100644 --- a/tests/api.c +++ b/tests/api.c @@ -40796,9 +40796,7 @@ TEST_CASE testCases[] = { static void TestSetup(void) { -#ifdef WOLFSSL_SWDEV - (void)wc_SwDev_Init(); -#endif +/* Stub, for now. Add common test setup code here. */ } static void TestCleanup(void) diff --git a/tests/swdev/swdev_loader.c b/tests/swdev/swdev_loader.c index a1af81db068..0abda7e0849 100644 --- a/tests/swdev/swdev_loader.c +++ b/tests/swdev/swdev_loader.c @@ -11,13 +11,14 @@ /* resolved at link time from swdev.o */ extern int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, void* ctx); -static int swdev_registered = 0; +/* Init always (re)registers because wolfCrypt_Cleanup wipes the cryptocb + * table; only the final Cleanup unregisters. */ +static wolfSSL_Atomic_Int swdev_refCount = WOLFSSL_ATOMIC_INITIALIZER(0); int wc_SwDev_Init(void) { int ret; - /* always re-register: cryptocb table is wiped by wolfCrypt_Cleanup */ ret = wc_CryptoCb_RegisterDevice(WC_SWDEV_ID, wc_SwDev_Callback, NULL); if (ret != 0) return ret; @@ -26,21 +27,24 @@ int wc_SwDev_Init(void) wc_CryptoCb_SetDeviceFindCb(wc_SwDev_FindCb); #endif - swdev_registered = 1; + (void)wolfSSL_Atomic_Int_FetchAdd(&swdev_refCount, 1); return 0; } void wc_SwDev_Cleanup(void) { - if (!swdev_registered) - return; - -#ifdef WOLF_CRYPTO_CB_FIND - wc_CryptoCb_SetDeviceFindCb(NULL); -#endif - - wc_CryptoCb_UnRegisterDevice(WC_SWDEV_ID); - swdev_registered = 0; + int my_refCount = wolfSSL_Atomic_Int_SubFetch(&swdev_refCount, 1); + + if (my_refCount == 0) { + #ifdef WOLF_CRYPTO_CB_FIND + wc_CryptoCb_SetDeviceFindCb(NULL); + #endif + wc_CryptoCb_UnRegisterDevice(WC_SWDEV_ID); + } + else if (my_refCount < 0) { + /* called more times than Init; restore floor */ + (void)wolfSSL_Atomic_Int_AddFetch(&swdev_refCount, 1); + } } #ifdef WOLF_CRYPTO_CB_FIND From 438e512334caf1ea91ad71547f98e2638f9bc711 Mon Sep 17 00:00:00 2001 From: rizlik Date: Thu, 30 Apr 2026 17:03:01 +0200 Subject: [PATCH 09/21] test: use XFREE to pair XMALLOC --- wolfcrypt/test/test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 59cf40570a9..769a2f7f8fa 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -71303,7 +71303,7 @@ static wc_test_ret_t ecc_onlycb_test(myCryptoDevCtx *ctx) #if !defined(WOLFCRYPT_ONLY) && defined(OPENSSL_EXTRA) && \ defined(USE_CERT_BUFFERS_256) if (check) { - FREE(check, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(check, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); } #endif #else From c926aafa1ba4f77bcdda5b90aed4003566c6ffde Mon Sep 17 00:00:00 2001 From: rizlik Date: Tue, 5 May 2026 15:30:58 +0200 Subject: [PATCH 10/21] swdev: add copyright headers --- tests/swdev/swdev.c | 23 ++++++++++++++++++++++- tests/swdev/swdev.h | 23 ++++++++++++++++++++++- tests/swdev/swdev_loader.c | 23 ++++++++++++++++++++++- tests/swdev/swdev_loader.h | 23 ++++++++++++++++++++++- 4 files changed, 88 insertions(+), 4 deletions(-) diff --git a/tests/swdev/swdev.c b/tests/swdev/swdev.c index d402207b54d..ff4c0f5d999 100644 --- a/tests/swdev/swdev.c +++ b/tests/swdev/swdev.c @@ -1,4 +1,25 @@ -/* tests/swdev/swdev.c -- wc_swdev callback. */ +/* swdev.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* wc_swdev callback. */ #include "swdev.h" diff --git a/tests/swdev/swdev.h b/tests/swdev/swdev.h index 7003fcacaf2..b974f496f26 100644 --- a/tests/swdev/swdev.h +++ b/tests/swdev/swdev.h @@ -1,4 +1,25 @@ -/* tests/swdev/swdev.h -- sole exported interface. */ +/* swdev.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* sole exported interface. */ #ifndef WC_SWDEV_H #define WC_SWDEV_H diff --git a/tests/swdev/swdev_loader.c b/tests/swdev/swdev_loader.c index 0abda7e0849..8d4c1f82b75 100644 --- a/tests/swdev/swdev_loader.c +++ b/tests/swdev/swdev_loader.c @@ -1,4 +1,25 @@ -/* tests/swdev/swdev_loader.c -- main-side loader for wc_swdev. */ +/* swdev_loader.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* main-side loader for wc_swdev. */ #include "swdev_loader.h" diff --git a/tests/swdev/swdev_loader.h b/tests/swdev/swdev_loader.h index 49c9c49e2fd..59a9e6237ae 100644 --- a/tests/swdev/swdev_loader.h +++ b/tests/swdev/swdev_loader.h @@ -1,4 +1,25 @@ -/* tests/swdev/swdev_loader.h -- test harness interface to register wc_swdev. */ +/* swdev_loader.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* test harness interface to register wc_swdev. */ #ifndef WC_SWDEV_LOADER_H #define WC_SWDEV_LOADER_H From 799f7d438b21e9a1d6d03f3dd4325f72df312488 Mon Sep 17 00:00:00 2001 From: rizlik Date: Tue, 5 May 2026 17:35:09 +0200 Subject: [PATCH 11/21] swdev: support user_settings.h based main library builds --- configure.ac | 13 +++++++++---- tests/swdev/Makefile | 39 ++++++++++++++++++++++++++++++++----- tests/swdev/user_settings.h | 15 +++++++++++--- 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index 5807a198c3e..ae3e235e47a 100644 --- a/configure.ac +++ b/configure.ac @@ -10650,15 +10650,15 @@ fi # wc_swdev: software crypto-callback device for testing AC_ARG_ENABLE([swdev], - [AS_HELP_STRING([--enable-swdev],[Build wc_swdev software crypto-callback for tests (default: disabled). Requires --enable-cryptocb, forces WOLF_CRYPTO_CB_FIND, and currently supports in-tree builds only.])], + [AS_HELP_STRING([--enable-swdev],[Build wc_swdev software crypto-callback for tests (default: disabled). Requires --enable-cryptocb])], [ ENABLED_SWDEV=$enableval ], [ ENABLED_SWDEV=no ] ) if test "$ENABLED_SWDEV" = "yes" then - if test "$ENABLED_CRYPTOCB" != "yes"; then - AC_MSG_ERROR([--enable-swdev requires --enable-cryptocb]) + if test "$ENABLED_CRYPTOCB" != "yes" && test "$enable_usersettings" != "yes"; then + AC_MSG_ERROR([--enable-swdev requires --enable-cryptocb (or --enable-usersettings with WOLF_CRYPTO_CB defined in user_settings.h)]) fi if test "x$srcdir" != "x."; then AC_MSG_ERROR([--enable-swdev currently supports in-tree builds only]) @@ -11924,9 +11924,14 @@ fi if test "x$ENABLED_USERSETTINGS" = "xyes" then # Replace all options and just use WOLFSSL_USER_SETTINGS and - # WOLFSSL_USER_SETTINGS_ASM. + # WOLFSSL_USER_SETTINGS_ASM. Re-append build-system flags that affect + # preprocessor guards in test files and must survive the reset. AM_CFLAGS="-DWOLFSSL_USER_SETTINGS -DWOLFSSL_USER_SETTINGS_ASM" AM_CCASFLAGS="-DWOLFSSL_USER_SETTINGS -DWOLFSSL_USER_SETTINGS_ASM" + AS_IF([test "x$ENABLED_SWDEV" = "xyes"],[ + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SWDEV -DWOLF_CRYPTO_CB_FIND" + AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_SWDEV -DWOLF_CRYPTO_CB_FIND" + ]) # Generate assembly-safe user_settings_asm.h (just preprocessor directives # from user_settings.h). diff --git a/tests/swdev/Makefile b/tests/swdev/Makefile index 1c0ce6a5738..561e1f9bbdf 100644 --- a/tests/swdev/Makefile +++ b/tests/swdev/Makefile @@ -31,13 +31,42 @@ SWDEV_ASM_SRCS = $(PARENT_ASM_SRCS) # -I$(SRCDIR) routes settings.h to the swdev's user_settings.h. # No BUILDING_WOLFSSL so WOLFSSL_API/LOCAL stay empty; then -fvisibility=hidden # hides every emitted symbol. +# -I$(SRCDIR) is placed FIRST so that tests/swdev/user_settings.h wins over +# any user_settings.h in the parent's include path. CPPFLAGS_SWDEV = \ - $(PARENT_CPPFLAGS) \ -DWOLFSSL_USER_SETTINGS \ -I$(SRCDIR) \ + $(PARENT_CPPFLAGS) \ -I$(WOLFROOT) \ -I$(WOLFROOT)/wolfssl +# Ask the compiler (via -E -H) where it would find user_settings.h under the +# parent's exact flags (no -I$(SRCDIR) added so we get the parent's file, not +# ours), then pass that path into swdev/user_settings.h as a string macro so it +# can #include the right file. +ifneq ($(filter -DWOLFSSL_USER_SETTINGS,$(PARENT_BUILD_CFLAGS) $(PARENT_CPPFLAGS)),) +PARENT_USER_SETTINGS_H := $(strip $(shell \ + printf '\043include \n' | \ + $(CC) $(PARENT_BUILD_CFLAGS) $(PARENT_CFLAGS) $(PARENT_CPPFLAGS) \ + -I$(WOLFROOT) \ + -x c -E -H -o /dev/null - 2>&1 | \ + awk '/user_settings\.h$$/ { sub(/^\.+ /, ""); print; exit }')) +ifeq ($(PARENT_USER_SETTINGS_H),) +$(warning swdev: parent declares WOLFSSL_USER_SETTINGS but compiler could \ + not locate user_settings.h; ensure -I is in CPPFLAGS or CFLAGS) +endif +ifneq ($(PARENT_USER_SETTINGS_H),) +CPPFLAGS_SWDEV += -DSWDEV_PARENT_USER_SETTINGS_H=\"$(PARENT_USER_SETTINGS_H)\" +endif +endif + +# Choose between options.h and parent user_settings.h +ifeq ($(PARENT_USER_SETTINGS_H),) +SWDEV_CFG_PREREQ = $(WOLFROOT)/wolfssl/options.h +else +SWDEV_CFG_PREREQ = $(PARENT_USER_SETTINGS_H) +endif + # -fvisibility=hidden + -fno-common mark every symbol hidden at the ELF # level (ABI-safe: attribute only, no struct layout impact). Optimization # level and other flags are inherited from the parent build (PARENT_*_CFLAGS) @@ -64,16 +93,16 @@ ALL_OBJS = $(CRYPT_OBJS) $(SSL_OBJS) $(ASM_OBJS) $(LOCAL_OBJS) .PHONY: all clean all: $(BUILDDIR)/swdev.o -$(BUILDDIR)/wc/%.o: $(WOLFROOT)/wolfcrypt/src/%.c $(SRCDIR)/user_settings.h $(WOLFROOT)/wolfssl/options.h | $(BUILDDIR)/wc +$(BUILDDIR)/wc/%.o: $(WOLFROOT)/wolfcrypt/src/%.c $(SRCDIR)/user_settings.h $(SWDEV_CFG_PREREQ) | $(BUILDDIR)/wc $(CC) $(CPPFLAGS_SWDEV) $(CFLAGS_SWDEV) -c $< -o $@ -$(BUILDDIR)/wc/%.o: $(WOLFROOT)/wolfcrypt/src/%.S $(SRCDIR)/user_settings.h $(WOLFROOT)/wolfssl/options.h | $(BUILDDIR)/wc +$(BUILDDIR)/wc/%.o: $(WOLFROOT)/wolfcrypt/src/%.S $(SRCDIR)/user_settings.h $(SWDEV_CFG_PREREQ) | $(BUILDDIR)/wc $(CCAS) $(CPPFLAGS_SWDEV) $(CCASFLAGS_SWDEV) -c $< -o $@ -$(BUILDDIR)/ssl/%.o: $(WOLFROOT)/src/%.c $(SRCDIR)/user_settings.h $(WOLFROOT)/wolfssl/options.h | $(BUILDDIR)/ssl +$(BUILDDIR)/ssl/%.o: $(WOLFROOT)/src/%.c $(SRCDIR)/user_settings.h $(SWDEV_CFG_PREREQ) | $(BUILDDIR)/ssl $(CC) $(CPPFLAGS_SWDEV) $(CFLAGS_SWDEV) -c $< -o $@ -$(BUILDDIR)/local/%.o: $(SRCDIR)/%.c $(SRCDIR)/swdev.h $(SRCDIR)/user_settings.h $(WOLFROOT)/wolfssl/options.h | $(BUILDDIR)/local +$(BUILDDIR)/local/%.o: $(SRCDIR)/%.c $(SRCDIR)/swdev.h $(SRCDIR)/user_settings.h $(SWDEV_CFG_PREREQ) | $(BUILDDIR)/local $(CC) $(CPPFLAGS_SWDEV) $(CFLAGS_SWDEV) -c $< -o $@ $(BUILDDIR)/swdev.partial.o: $(ALL_OBJS) diff --git a/tests/swdev/user_settings.h b/tests/swdev/user_settings.h index e6a55019ec5..09073ea2b9e 100644 --- a/tests/swdev/user_settings.h +++ b/tests/swdev/user_settings.h @@ -6,12 +6,21 @@ * the other. The only macros that may differ between the two compilations * are the WOLF_CRYPTO_CB_ONLY_* gates below -- those strip the software * implementations from the main library so every operation routes through - * the crypto callback; swdev needs the software paths intact. Every other - * setting is inherited from wolfssl/options.h so layouts stay in sync. */ + * the crypto callback; swdev needs the software paths intact. + * + * Config source depends on how the parent library was built: + * - autotools build: wolfssl/options.h carries the full feature set. + * - WOLFSSL_USER_SETTINGS: the parent's user_settings.h is the source of + * truth; The swdev Makefile locates that file via a compiler probe (-E -H) + * and passes its absolute path as SWDEV_PARENT_USER_SETTINGS_H. */ #ifndef WC_SWDEV_USER_SETTINGS_H #define WC_SWDEV_USER_SETTINGS_H -#include +#ifdef SWDEV_PARENT_USER_SETTINGS_H + #include SWDEV_PARENT_USER_SETTINGS_H +#else + #include +#endif #undef WOLF_CRYPTO_CB_ONLY_RSA #undef WOLF_CRYPTO_CB_ONLY_ECC From 6d4fa5919c119651f49f4fd5d08a28f5b60c03ab Mon Sep 17 00:00:00 2001 From: rizlik Date: Wed, 6 May 2026 08:36:50 +0200 Subject: [PATCH 12/21] tests:api: skip TLS_CALLBACK_TEST under CRYPTO_CB_ONLY_* --- tests/api.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/api.c b/tests/api.c index 7530b58e513..699d72e19f6 100644 --- a/tests/api.c +++ b/tests/api.c @@ -6371,7 +6371,10 @@ static void test_client_reuse_WOLFSSLobj(void* args, cbType cb, /* Generic TLS client / server with callbacks for API unit tests * Used by SNI / ALPN / crypto callback helper functions */ #if defined(HAVE_IO_TESTS_DEPENDENCIES) && \ - (defined(HAVE_SNI) || defined(HAVE_ALPN) || defined(WOLF_CRYPTO_CB) || \ + (defined(HAVE_SNI) || defined(HAVE_ALPN) || \ + (defined(WOLF_CRYPTO_CB) && \ + !defined(WOLF_CRYPTO_CB_ONLY_RSA) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) && \ + !defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES)) || \ defined(HAVE_ALPN_PROTOS_SUPPORT)) || defined(WOLFSSL_STATIC_MEMORY) #define ENABLE_TLS_CALLBACK_TEST #endif @@ -30609,8 +30612,8 @@ 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_AES) && \ - !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA) + (!defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES) && \ + !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, int* keyFormat) @@ -31613,8 +31616,8 @@ static int test_wc_CryptoCb(void) { EXPECT_DECLS; #if defined(WOLF_CRYPTO_CB) && \ - !defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES) && \ - !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA) + (!defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES) && \ + !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA)) /* TODO: Add crypto callback API tests */ #ifdef HAVE_IO_TESTS_DEPENDENCIES From 71819bcb44fbb7b24e5fbf80487f59d90e88f583 Mon Sep 17 00:00:00 2001 From: rizlik Date: Wed, 6 May 2026 09:42:26 +0200 Subject: [PATCH 13/21] swdev: pair internal wolfCrypt_Init() with wolfCrypt_Cleanup() --- tests/swdev/Makefile | 8 +++++--- tests/swdev/swdev.c | 8 ++++++++ tests/swdev/swdev.h | 3 ++- tests/swdev/swdev_loader.c | 4 +++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/tests/swdev/Makefile b/tests/swdev/Makefile index 561e1f9bbdf..971beb6e1e7 100644 --- a/tests/swdev/Makefile +++ b/tests/swdev/Makefile @@ -116,10 +116,12 @@ $(BUILDDIR)/swdev.o: $(BUILDDIR)/swdev.partial.o @# visibility("default") and overrides the command-line @# -fvisibility=hidden. --keep-global-symbol sidesteps that by matching @# on symbol name directly. - $(OBJCOPY) --keep-global-symbol=wc_SwDev_Callback $< $@ - @# Sanity-check: only wc_SwDev_Callback may be externally visible. + $(OBJCOPY) --keep-global-symbol=wc_SwDev_Callback \ + --keep-global-symbol=wc_SwDev_InternalCleanup $< $@ + @# Sanity-check: only the two swdev entry points may be externally visible. @visible=$$( $(NM) --extern-only --defined-only $@ | awk '{print $$3}' \ - | grep -v '^wc_SwDev_Callback$$' || true); \ + | grep -v '^wc_SwDev_Callback$$' \ + | grep -v '^wc_SwDev_InternalCleanup$$' || true); \ if [ -n "$$visible" ]; then \ echo "error: unexpected externally-visible symbols in $@:"; \ echo "$$visible"; \ diff --git a/tests/swdev/swdev.c b/tests/swdev/swdev.c index ff4c0f5d999..981e55ec145 100644 --- a/tests/swdev/swdev.c +++ b/tests/swdev/swdev.c @@ -54,6 +54,14 @@ static int swdev_ensure_init(void) return 0; } +WC_SWDEV_EXPORT void wc_SwDev_InternalCleanup(void) +{ + if (swdev_initialized) { + wolfCrypt_Cleanup(); + swdev_initialized = 0; + } +} + #ifndef NO_RSA static int swdev_rsa(wc_CryptoInfo* info) { diff --git a/tests/swdev/swdev.h b/tests/swdev/swdev.h index b974f496f26..50f02b9f66d 100644 --- a/tests/swdev/swdev.h +++ b/tests/swdev/swdev.h @@ -38,8 +38,9 @@ extern "C" { #define WC_SWDEV_EXPORT #endif -WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, +WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, void* ctx); +WC_SWDEV_EXPORT void wc_SwDev_InternalCleanup(void); #ifdef __cplusplus } diff --git a/tests/swdev/swdev_loader.c b/tests/swdev/swdev_loader.c index 8d4c1f82b75..ee6f8596888 100644 --- a/tests/swdev/swdev_loader.c +++ b/tests/swdev/swdev_loader.c @@ -30,7 +30,8 @@ #endif /* resolved at link time from swdev.o */ -extern int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, void* ctx); +extern int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, void* ctx); +extern void wc_SwDev_InternalCleanup(void); /* Init always (re)registers because wolfCrypt_Cleanup wipes the cryptocb * table; only the final Cleanup unregisters. */ @@ -61,6 +62,7 @@ void wc_SwDev_Cleanup(void) wc_CryptoCb_SetDeviceFindCb(NULL); #endif wc_CryptoCb_UnRegisterDevice(WC_SWDEV_ID); + wc_SwDev_InternalCleanup(); } else if (my_refCount < 0) { /* called more times than Init; restore floor */ From 31891eae8f4fe988770e433e59e0c228e0794010 Mon Sep 17 00:00:00 2001 From: rizlik Date: Fri, 8 May 2026 09:50:35 +0200 Subject: [PATCH 14/21] swdev: always add swdev files to EXTRA_DISK --- wolfcrypt/test/include.am | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/wolfcrypt/test/include.am b/wolfcrypt/test/include.am index e647b979742..c0070dbaf02 100644 --- a/wolfcrypt/test/include.am +++ b/wolfcrypt/test/include.am @@ -46,13 +46,6 @@ $(top_builddir)/tests/swdev/build/swdev.o: $(top_builddir)/wolfssl/options.h FOR FORCE: -EXTRA_DIST += tests/swdev/swdev.c \ - tests/swdev/swdev.h \ - tests/swdev/swdev_loader.c \ - tests/swdev/swdev_loader.h \ - tests/swdev/user_settings.h \ - tests/swdev/Makefile - CLEANFILES += $(top_builddir)/tests/swdev/build/swdev.o \ $(top_builddir)/tests/swdev/build/swdev.partial.o @@ -71,6 +64,13 @@ wolfcrypt_test_libwolfcrypttest_la_LIBADD = src/libwolfssl@LIBSUFFIX@.la wolfcrypt_test_libwolfcrypttest_la_DEPENDENCIES = src/libwolfssl@LIBSUFFIX@.la endif +EXTRA_DIST += tests/swdev/swdev.c \ + tests/swdev/swdev.h \ + tests/swdev/swdev_loader.c \ + tests/swdev/swdev_loader.h \ + tests/swdev/user_settings.h \ + tests/swdev/Makefile + EXTRA_DIST += wolfcrypt/test/test.sln EXTRA_DIST += wolfcrypt/test/test.vcproj EXTRA_DIST += wolfcrypt/test/test-VS2022.sln From b1a3d72854d4bad3464328464256a7558f7abeff Mon Sep 17 00:00:00 2001 From: rizlik Date: Tue, 12 May 2026 18:54:00 +0200 Subject: [PATCH 15/21] github ci: minor rewording --- .github/workflows/cryptocb-only.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/cryptocb-only.yml b/.github/workflows/cryptocb-only.yml index b6ba4cc12bf..d71a8b09475 100644 --- a/.github/workflows/cryptocb-only.yml +++ b/.github/workflows/cryptocb-only.yml @@ -29,9 +29,7 @@ jobs: - 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). + # the software path via cryptocb. SHA-224 not yet supported. - name: SHA256 extra_config: --disable-sha224 cppflags: -DWOLF_CRYPTO_CB_ONLY_SHA256 @@ -53,9 +51,7 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 env: - # Common feature set for every entry. SHA-224 is left at the platform - # default (on for x86_64/aarch64); entries that need it off pass - # --disable-sha224 in extra_config. + # Common feature set for every entry. BASE_CONFIG: >- --enable-swdev --enable-cryptocb --enable-ecc --enable-rsa --enable-dh --enable-aesgcm --enable-aesccm --enable-aesctr --enable-aescfb From c84ea8df8868d23b0b4762d77c510077bf79a2f0 Mon Sep 17 00:00:00 2001 From: rizlik Date: Tue, 12 May 2026 18:54:22 +0200 Subject: [PATCH 16/21] tests: api: remove extra wolfSSL_cleanup() --- tests/api/test_hmac.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/api/test_hmac.c b/tests/api/test_hmac.c index 9961c55b016..b2c83f2794f 100644 --- a/tests/api/test_hmac.c +++ b/tests/api/test_hmac.c @@ -749,7 +749,6 @@ int test_tls_hmac_size_overflow(void) wolfSSL_free(ssl); wolfSSL_CTX_free(ctx); - wolfSSL_Cleanup(); #endif /* !NO_HMAC && !WOLFSSL_AEAD_ONLY && !NO_TLS && NO_OLD_TLS && * !NO_WOLFSSL_CLIENT */ return EXPECT_RESULT(); From a98d4798b16a0d2afefe143a4e8fce70f4b209b9 Mon Sep 17 00:00:00 2001 From: rizlik Date: Tue, 12 May 2026 18:54:55 +0200 Subject: [PATCH 17/21] tests: swdev: api: init/deinit swdev in TestSetup/TestCleanup --- tests/api.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/api.c b/tests/api.c index 699d72e19f6..7c143077b90 100644 --- a/tests/api.c +++ b/tests/api.c @@ -40799,7 +40799,11 @@ TEST_CASE testCases[] = { static void TestSetup(void) { -/* Stub, for now. Add common test setup code here. */ +#ifdef WOLFSSL_SWDEV + /* Re-arm the swdev cryptocb registration in case the previous test + * tore down wolfCrypt and wiped gCryptoDev. */ + (void)wc_SwDev_Init(); +#endif } static void TestCleanup(void) @@ -40808,6 +40812,9 @@ static void TestCleanup(void) /* Clear any errors added to the error queue during the test run. */ wolfSSL_ERR_clear_error(); #endif /* OPENSSL_EXTRA || DEBUG_WOLFSSL_VERBOSE */ +#ifdef WOLFSSL_SWDEV + wc_SwDev_Cleanup(); +#endif } void ApiTest_StopOnFail(void) From cf6c645d73339243f9e38356f4b5e4376a27ace9 Mon Sep 17 00:00:00 2001 From: rizlik Date: Tue, 12 May 2026 19:22:17 +0200 Subject: [PATCH 18/21] aes: CRYPTO_ONLY_AES: do keyscheduling to support GCM on ECB-only device --- wolfcrypt/src/aes.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 56335545a16..e872856dca0 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -7789,8 +7789,14 @@ int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len) XMEMSET(iv, 0, WC_AES_BLOCK_SIZE); ret = wc_AesSetKey(aes, key, len, iv, AES_ENCRYPTION); #ifdef WOLF_CRYPTO_CB_ONLY_AES - /* Device handles GCM end-to-end; GHASH H / M0 setup below is dead state - * under CB_ONLY (no host-side software path consumes aes->gcm.H or M0). */ + /* do key scheduling so that ECB-only devices can still do GCM */ + if (ret == 0) { + ret = wc_CryptoCb_AesEcbEncrypt(aes, aes->gcm.H, iv, WC_AES_BLOCK_SIZE); +#if defined(GCM_TABLE) || defined(GCM_TABLE_4BIT) + if (ret == 0) + GenerateM0(&aes->gcm); +#endif + } return ret; #endif #ifdef WOLFSSL_AESGCM_STREAM From e03bc94742a77ae5a2921e64aa40da59b5ce8050 Mon Sep 17 00:00:00 2001 From: rizlik Date: Tue, 12 May 2026 19:21:42 +0200 Subject: [PATCH 19/21] swdev: add AES-ECB only testing option --- .github/workflows/cryptocb-only.yml | 7 +++++++ tests/swdev/swdev.c | 11 ++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cryptocb-only.yml b/.github/workflows/cryptocb-only.yml index d71a8b09475..101c74dffcc 100644 --- a/.github/workflows/cryptocb-only.yml +++ b/.github/workflows/cryptocb-only.yml @@ -37,6 +37,13 @@ jobs: # software path via cryptocb. - name: AES cppflags: -DWOLF_CRYPTO_CB_ONLY_AES + # Same as AES but tells swdev to refuse AES-GCM (SWDEV_AES_ONLYECB). + # That forces the parent's CB_ONLY_AES host-side GCM software path: + # GHASH runs on the host while AES-CTR blocks dispatch back through + # cryptocb ECB. The AES entry above instead has swdev handle GCM + # end-to-end, so the host-side GCM path is otherwise uncovered. + - name: AES_GCM_via_ECB + cppflags: -DWOLF_CRYPTO_CB_ONLY_AES -DSWDEV_AES_ONLYECB # All four 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 diff --git a/tests/swdev/swdev.c b/tests/swdev/swdev.c index 981e55ec145..18bcfaed1bf 100644 --- a/tests/swdev/swdev.c +++ b/tests/swdev/swdev.c @@ -357,7 +357,12 @@ static int swdev_aes_ecb(wc_CryptoInfo* info) } #endif /* HAVE_AES_ECB || WOLFSSL_AES_DIRECT */ -#ifdef HAVE_AESGCM +/* SWDEV_AES_ONLYECB: when defined, swdev's AES backend returns + * CRYPTOCB_UNAVAILABLE for AES-GCM so the parent's CB_ONLY_AES host-side + * GCM software path runs (GHASH on the host; AES-CTR blocks dispatch back + * through cryptocb ECB). Without this macro, swdev handles GCM end-to-end + * and the host-side software path is never exercised. */ +#if defined(HAVE_AESGCM) && !defined(SWDEV_AES_ONLYECB) static int swdev_aes_gcm(wc_CryptoInfo* info) { Aes* aes = info->cipher.enc ? info->cipher.aesgcm_enc.aes : @@ -401,7 +406,7 @@ static int swdev_aes_gcm(wc_CryptoInfo* info) wc_AesFree(&shadow); return ret; } -#endif /* HAVE_AESGCM */ +#endif /* HAVE_AESGCM && !SWDEV_AES_ONLYECB */ #ifdef HAVE_AESCCM static int swdev_aes_ccm(wc_CryptoInfo* info) @@ -527,7 +532,7 @@ WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, case WC_CIPHER_AES_ECB: return swdev_aes_ecb(info); #endif - #ifdef HAVE_AESGCM + #if defined(HAVE_AESGCM) && !defined(SWDEV_AES_ONLYECB) case WC_CIPHER_AES_GCM: return swdev_aes_gcm(info); #endif From 6c2040adbac001ec88b783def83768dbc4083a72 Mon Sep 17 00:00:00 2001 From: rizlik Date: Tue, 12 May 2026 19:28:48 +0200 Subject: [PATCH 20/21] swdev: add README.md --- tests/swdev/README.md | 161 ++++++++++++++++++++++++++++++++++++++ wolfcrypt/test/include.am | 3 +- 2 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 tests/swdev/README.md diff --git a/tests/swdev/README.md b/tests/swdev/README.md new file mode 100644 index 00000000000..80b097299f4 --- /dev/null +++ b/tests/swdev/README.md @@ -0,0 +1,161 @@ +# wc_swdev: Software CryptoCb Device for Tests + +`wc_swdev` is a **test-only** software backend used to exercise builds +that strip a wolfCrypt algorithm in favor of CryptoCb dispatch. It is +compiled separately from the main library, linked into the test +programs only, and exposes exactly two C symbols. **It is not a +production component and must not be linked into shipping binaries.** + +The four switches it supports are: + +| Macro | Strips | Test target | +|--------------------------------|----------------|--------------------| +| `WOLF_CRYPTO_CB_ONLY_RSA` | software RSA | RSA via CryptoCb | +| `WOLF_CRYPTO_CB_ONLY_ECC` | software ECC | ECC via CryptoCb | +| `WOLF_CRYPTO_CB_ONLY_SHA256` | software SHA-256 | SHA-256 via CryptoCb | +| `WOLF_CRYPTO_CB_ONLY_AES` | software AES | AES via CryptoCb | + +When a test program calls e.g. `wc_AesCbcEncrypt()` against a libwolfssl +built with `-DWOLF_CRYPTO_CB_ONLY_AES`, the software AES path is gone; +the call routes through the CryptoCb dispatch layer. swdev registers +itself as that callback, executes the operation against its own +internal copy of the AES code, and returns the result. + +## Architecture + +``` + +-----------------------------------------------------------+ + | TEST PROGRAM (testwolfcrypt, unit.test, examples/...) | + | | + | wolfCrypt_Init() | + | wc_SwDev_Init() -- registers swdev device + a | + | WOLF_CRYPTO_CB_FIND hook | + | ... wc_AesCbcEncrypt(), wc_Sha256Update(), etc. ... | + | wc_SwDev_Cleanup() | + | wolfCrypt_Cleanup() | + +-----------------------------------------------------------+ + | ^ + | call into LIBWOLFSSL | result + v | + +-----------------------------------------------------------+ + | LIBWOLFSSL (compiled with -DWOLF_CRYPTO_CB_ONLY_AES, | + | -DWOLF_CRYPTO_CB_ONLY_SHA256, ...) | + | | + | wc_AesCbcEncrypt() | + | - software AES is #ifdef'd out | + | - dispatch via wc_CryptoCb_AesCbc...() | + +-----------------------------------------------------------+ + | ^ + | CryptoCb dispatch | + v | + +-----------------------------------------------------------+ + | tests/swdev/build/swdev.o | + | (single relocatable .o, only 2 visible symbols) | + | | + | wc_SwDev_Callback(devId, info, ctx) | + | - swdev_ensure_init() lazy wolfCrypt_Init | + | - switch (info->algo_type): | + | PK -> RSA / ECC software impl | + | HASH -> SHA-256 software impl | + | CIPHER -> AES (CBC/CTR/ECB/GCM/CCM) software impl | + | | + | swdev was compiled WITHOUT the WOLF_CRYPTO_CB_ONLY_* | + | gates, so its private copy of wolfcrypt still has the | + | full software implementations. | + +-----------------------------------------------------------+ +``` + +## How the Two-Compile Trick Works + +The whole mechanism rests on compiling the wolfcrypt sources twice: + +1. **libwolfssl** is built normally with the user's `_ONLY_*` flags + set, so its software RSA/ECC/SHA-256/AES paths are gone. +2. **swdev** recompiles the same source set under + `tests/swdev/user_settings.h`, which `#undef`s all four `_ONLY_*` + macros. swdev therefore contains the full software implementations. + +To prevent symbol collisions when both are linked into the same test +binary, `tests/swdev/Makefile` does the following: + +- Compiles every swdev TU with `-fvisibility=hidden -fno-common`. +- Drops `-DBUILDING_WOLFSSL` so `WOLFSSL_API` does not re-promote + symbols to default visibility. +- Links all swdev objects with `ld -r` into a single relocatable + `swdev.partial.o`. +- Runs `objcopy --keep-global-symbol=wc_SwDev_Callback + --keep-global-symbol=wc_SwDev_InternalCleanup` to localize every + remaining global except the two intended exports. + +The Makefile then enforces the invariant directly: + +```sh +nm --extern-only --defined-only build/swdev.o +``` + +must list **only** `wc_SwDev_Callback` and `wc_SwDev_InternalCleanup`. +The build fails loudly otherwise (see `tests/swdev/Makefile:122-129`). +If you add a third `WC_SWDEV_EXPORT` API, update the keep-list in the +Makefile too. + +## ABI Constraint + +swdev and libwolfssl share C structs across the CryptoCb boundary +(`wc_Sha256`, `Aes`, `RsaKey`, `ecc_key`, ...). One compilation +allocates them, the other operates on them. They must therefore be +ABI-identical. The `_ONLY_*` macros only gate function bodies, not +struct layouts, so flipping them between the two compiles is safe. +**Do not introduce other macros that change struct layout into +`tests/swdev/user_settings.h`.** + +## Building + +`wc_swdev` is enabled with the `--enable-swdev` configure flag. + +```sh +./autogen.sh +./configure --enable-swdev --enable-cryptocb \ + \ + CPPFLAGS="-DWOLF_CRYPTO_CB_ONLY_ECC \ + -DWOLF_CRYPTO_CB_ONLY_RSA \ + -DWOLF_CRYPTO_CB_ONLY_SHA256 \ + -DWOLF_CRYPTO_CB_ONLY_AES" \ + --disable-sha224 +make +make check +``` + +Notes: + +- `--enable-swdev` requires `--enable-cryptocb`, or `--enable-usersettings` + with `WOLF_CRYPTO_CB` defined in the user's `user_settings.h`. +- `--enable-swdev` defines `WOLFSSL_SWDEV` and `WOLF_CRYPTO_CB_FIND` + automatically; see `configure.ac`. +- `--enable-swdev` currently supports **in-tree builds only**. + Out-of-tree (VPATH) builds fail at configure time. swdev is built + from `wolfcrypt/test/include.am` and inherits `PARENT_SRCS`, + `PARENT_BUILD_CFLAGS`, etc., from the parent build. +- `--disable-sha224` is required when `WOLF_CRYPTO_CB_ONLY_SHA256` is + set: SHA-224 is unsupported for now. + +For the full CI matrix that exercises each `_ONLY_*` macro, see +`.github/workflows/cryptocb-only.yml`. + +## Files + +| File | Role | +|---------------------|---------------------------------------------------------------| +| `swdev.h` | Public swdev interface (the two exported symbols) | +| `swdev.c` | CryptoCb dispatcher: PK / HASH / CIPHER algorithms | +| `swdev_loader.h` | Test-harness API: `wc_SwDev_Init`, `wc_SwDev_Cleanup` | +| `swdev_loader.c` | Refcounted Init/Cleanup; registers the callback + Find hook | +| `user_settings.h` | `#undef`s the `WOLF_CRYPTO_CB_ONLY_*` gates for swdev's TU | +| `Makefile` | Two-compile + objcopy + symbol-invariant check | + +## Production Use + +**None.** swdev exists only to make the `WOLF_CRYPTO_CB_ONLY_*` builds +testable on a generic Linux runner. Real deployments are expected to +provide their own CryptoCb backed by a hardware engine (TPM, HSM, SoC +crypto block, etc.). swdev is not API-stable, not benchmarked, and not +audited as a production cryptographic provider. diff --git a/wolfcrypt/test/include.am b/wolfcrypt/test/include.am index c0070dbaf02..359bca42e8e 100644 --- a/wolfcrypt/test/include.am +++ b/wolfcrypt/test/include.am @@ -69,7 +69,8 @@ EXTRA_DIST += tests/swdev/swdev.c \ tests/swdev/swdev_loader.c \ tests/swdev/swdev_loader.h \ tests/swdev/user_settings.h \ - tests/swdev/Makefile + tests/swdev/Makefile \ + tests/swdev/README.md EXTRA_DIST += wolfcrypt/test/test.sln EXTRA_DIST += wolfcrypt/test/test.vcproj From cbaf9c154a670493ed2aaaad48add93d076009e0 Mon Sep 17 00:00:00 2001 From: rizlik Date: Tue, 12 May 2026 19:48:36 +0200 Subject: [PATCH 21/21] cryptocb: don't declare wc_Sha256Trasnform under ONLY_SHA256 --- wolfssl/wolfcrypt/sha256.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wolfssl/wolfcrypt/sha256.h b/wolfssl/wolfcrypt/sha256.h index 18b2c1c91d8..05732d45b22 100644 --- a/wolfssl/wolfcrypt/sha256.h +++ b/wolfssl/wolfcrypt/sha256.h @@ -269,7 +269,8 @@ WOLFSSL_API int wc_Sha256FinalRaw(wc_Sha256* sha256, byte* hash); WOLFSSL_API int wc_Sha256Final(wc_Sha256* sha256, byte* hash); WOLFSSL_API void wc_Sha256Free(wc_Sha256* sha256); #if (defined(OPENSSL_EXTRA) || defined(HAVE_CURL)) && \ - !defined(WOLFSSL_KCAPI_HASH) && !defined(WOLFSSL_AFALG_HASH) + !defined(WOLFSSL_KCAPI_HASH) && !defined(WOLFSSL_AFALG_HASH) && \ + !defined(WOLF_CRYPTO_CB_ONLY_SHA256) WOLFSSL_API int wc_Sha256Transform(wc_Sha256* sha, const unsigned char* data); #endif #if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_FULL_HASH)