Files
Marco Oliverio c43ab39306 cryptocb: add WC_PK_TYPE_EC_CHECK_PUB_KEY for ECC key validation offload
Add a crypto-callback operation for validating an ECC key.

Under WOLF_CRYPTO_CB_ONLY_ECC validation now fails closed with
NO_VALID_DEVID when no device handles the operation; previously such
keys were accepted unvalidated. This is a deliberate compatibility
break, documented at the dispatch site.
2026-06-17 15:02:14 +02:00
..
2026-05-13 16:18:52 +02:00

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 #undefs 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:

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.

./autogen.sh
./configure --enable-swdev --enable-cryptocb \
            <other flags> \
            CPPFLAGS="-DWOLF_CRYPTO_CB_ONLY_ECC \
                      -DWOLF_CRYPTO_CB_ONLY_RSA \
                      -DWOLF_CRYPTO_CB_ONLY_SHA256 \
                      -DWOLF_CRYPTO_CB_ONLY_AES"
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.
  • swdev is built from wolfcrypt/test/include.am and inherits PARENT_SRCS, PARENT_BUILD_CFLAGS, etc., from the parent build. Out-of-tree (VPATH) builds work: WOLFBUILD points the sub-make at the build tree for the configure-generated headers (wolfssl/options.h, wolfssl/version.h).

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 #undefs 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.