diff --git a/configure.ac b/configure.ac index 21a2a808b3..703bd92689 100644 --- a/configure.ac +++ b/configure.ac @@ -3621,6 +3621,72 @@ then fi +# wolfHAL hardware abstraction layer crypto-callback port. +# Include-path only: wolfHAL builds no archive (its drivers compile per-board), +# so the application compiles and links wolfHAL itself. +# Example: +# "./configure --with-wolfhal=../wolfHAL --with-wolfhal-board=stm32wb_nucleo" +ENABLED_WOLFHAL="no" +ENABLED_WOLFHAL_BOARD="" +trywolfhaldir="" +AC_ARG_WITH([wolfhal], + [AS_HELP_STRING([--with-wolfhal=PATH],[PATH to the wolfHAL source tree (default ../wolfHAL)])], + [ + AC_MSG_CHECKING([for wolfHAL]) + if test "x$withval" != "xno" ; then + trywolfhaldir=$withval + fi + if test "x$withval" = "xyes" ; then + trywolfhaldir="../wolfHAL" + fi + if test -e $trywolfhaldir/wolfHAL/crypto/crypto.h + then + AM_CFLAGS="$AM_CFLAGS -I$trywolfhaldir" + else + AC_MSG_ERROR([Could not find wolfHAL headers under $trywolfhaldir]) + fi + # wolfHAL objects are compiled by the application, so the library is + # left with unresolved whal_* references. A shared object cannot carry + # those, and the bundled examples/tests cannot link them either. + enable_shared=no + enable_static=yes + ENABLED_WOLFHAL="yes" + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WOLFHAL" + AC_MSG_RESULT([yes]) + ] +) + +AC_ARG_WITH([wolfhal-board], + [AS_HELP_STRING([--with-wolfhal-board=PATH], + [PATH to the directory holding your board.h. Required with + --with-wolfhal.])], + [ + if test "x$withval" != "xno" ; then + ENABLED_WOLFHAL_BOARD=$withval + fi + ] +) + +if test "x$ENABLED_WOLFHAL" = "xyes" +then + if test "x$ENABLED_WOLFHAL_BOARD" = "x" + then + AC_MSG_ERROR([--with-wolfhal requires --with-wolfhal-board=PATH to the directory holding your board.h]) + fi + AC_MSG_CHECKING([for board.h in $ENABLED_WOLFHAL_BOARD]) + if test -e "$ENABLED_WOLFHAL_BOARD/board.h" + then + AC_MSG_RESULT([yes]) + else + AC_MSG_ERROR([No board.h in $ENABLED_WOLFHAL_BOARD]) + fi + AM_CFLAGS="$AM_CFLAGS -I$ENABLED_WOLFHAL_BOARD" +elif test "x$ENABLED_WOLFHAL_BOARD" != "x" +then + AC_MSG_ERROR([--with-wolfhal-board requires --with-wolfhal=PATH]) +fi + + # NXP SE050 # Example: "./configure --with-se050=/home/pi/simw_top" ENABLED_SE050="no" @@ -10390,6 +10456,7 @@ AC_ARG_ENABLE([examples], AS_IF([test "x$ENABLED_FILESYSTEM" = "xno"], [ENABLED_EXAMPLES="no"]) AS_IF([test "x$ENABLED_CRYPTONLY" = "xyes"], [ENABLED_EXAMPLES="no"]) +AS_IF([test "x$ENABLED_WOLFHAL" = "xyes"], [ENABLED_EXAMPLES="no"]) # Enable wolfCrypt test and benchmark @@ -10404,6 +10471,7 @@ AC_ARG_ENABLE([crypttests], [ ENABLED_CRYPT_TESTS=$enableval ], [ ENABLED_CRYPT_TESTS=$ENABLED_CRYPT_TESTS_DEFAULT ] ) +AS_IF([test "x$ENABLED_WOLFHAL" = "xyes"], [ENABLED_CRYPT_TESTS="no"]) AC_SUBST([ENABLED_CRYPT_TESTS]) if test "$ENABLED_CRYPT_TESTS" = "no" @@ -11296,7 +11364,7 @@ AC_ARG_ENABLE([cryptocb-sw-test], [ ENABLED_CRYPTOCB_SW_TEST=yes ] ) -if test "x$ENABLED_PKCS11" = "xyes" || test "x$ENABLED_WOLFTPM" = "xyes" || test "$ENABLED_CAAM" != "no" || test "x$ENABLED_RTL8735B" != "xno" +if test "x$ENABLED_PKCS11" = "xyes" || test "x$ENABLED_WOLFTPM" = "xyes" || test "$ENABLED_CAAM" != "no" || test "x$ENABLED_RTL8735B" != "xno" || test "x$ENABLED_WOLFHAL" = "xyes" then ENABLED_CRYPTOCB=yes fi @@ -13119,6 +13187,7 @@ AM_CONDITIONAL([BUILD_SE050],[test "x$ENABLED_SE050" = "xyes"]) AM_CONDITIONAL([BUILD_STSAFE],[test "x$ENABLED_STSAFE" != "xno"]) AM_CONDITIONAL([BUILD_RTL8735B],[test "x$ENABLED_RTL8735B" != "xno"]) AM_CONDITIONAL([BUILD_TROPIC01],[test "x$ENABLED_TROPIC01" = "xyes"]) +AM_CONDITIONAL([BUILD_WOLFHAL],[test "x$ENABLED_WOLFHAL" = "xyes"]) AM_CONDITIONAL([BUILD_KDF],[test "x$ENABLED_KDF" = "xyes"]) AM_CONDITIONAL([BUILD_HMAC],[test "x$ENABLED_HMAC" = "xyes"]) AM_CONDITIONAL([BUILD_ERROR_STRINGS],[test "x$ENABLED_ERROR_STRINGS" = "xyes"]) @@ -13728,6 +13797,7 @@ echo " * NXP SE050: $ENABLED_SE050" echo " * STMicro STSAFE: $ENABLED_STSAFE" echo " * RealTek RTL8735B HUK: $ENABLED_RTL8735B" echo " * TROPIC01: $ENABLED_TROPIC01" +echo " * wolfHAL: $ENABLED_WOLFHAL" echo " * Maxim Integrated MAXQ10XX: $ENABLED_MAXQ10XX" echo " * PSA: $ENABLED_PSA" echo " * System CA certs: $ENABLED_SYS_CA_CERTS" diff --git a/wolfcrypt/src/include.am b/wolfcrypt/src/include.am index fdd356e9ae..415c0e2de2 100644 --- a/wolfcrypt/src/include.am +++ b/wolfcrypt/src/include.am @@ -127,6 +127,8 @@ EXTRA_DIST += wolfcrypt/src/port/ti/ti-aes.c \ wolfcrypt/src/port/realtek/README.md \ wolfcrypt/src/port/tropicsquare/tropic01.c \ wolfcrypt/src/port/tropicsquare/README.md \ + wolfcrypt/src/port/wolfHAL/wolfhal.c \ + wolfcrypt/src/port/wolfHAL/README.md \ wolfcrypt/src/port/af_alg/afalg_aes.c \ wolfcrypt/src/port/af_alg/afalg_hash.c \ wolfcrypt/src/port/kcapi/kcapi_aes.c \ @@ -267,6 +269,10 @@ if BUILD_RTL8735B src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/realtek/rtl8735b.c endif +if BUILD_WOLFHAL +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/wolfHAL/wolfhal.c +endif + if BUILD_PSA src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/psa/psa.c src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/psa/psa_hash.c diff --git a/wolfcrypt/src/port/wolfHAL/README.md b/wolfcrypt/src/port/wolfHAL/README.md new file mode 100644 index 0000000000..e7b99e7075 --- /dev/null +++ b/wolfcrypt/src/port/wolfHAL/README.md @@ -0,0 +1,76 @@ +# wolfHAL port + +Routes wolfCrypt AES (ECB/CBC/GCM/CCM) and RNG to a board's hardware through +[wolfHAL](https://github.com/wolfSSL/wolfHAL) and the wolfSSL crypto callback +framework. Anything the hardware does not cover returns `CRYPTOCB_UNAVAILABLE` +and falls back to software. + +## Building + +```sh +./configure --with-wolfhal=/path/to/wolfHAL \ + --with-wolfhal-board=/path/to/your/board +make +``` + +`--with-wolfhal` points at the wolfHAL source tree; `--with-wolfhal-board` +points at the directory holding your `board.h`. The port forces a static-only +build: wolfHAL's objects are compiled by your application, so `libwolfssl.a` +is left with unresolved `whal_*` references for your final link to satisfy. +That also means wolfSSL's bundled examples and crypt tests are disabled. + +## board.h + +`board.h` is yours, not wolfSSL's — the same arrangement `settings.h` has with +`user_settings.h`. Both wolfHAL and wolfSSL find it by quoted include off your +`-I` path: + +* wolfHAL's driver TUs (`src/crypto/stm32wb_aes.c`, `src/rng/stm32wb_rng.c`) + expand the `WHAL_CFG_*_DEV` initializers in it to define their device + singletons. +* wolfSSL's `wolfhal.c` reads it for the wolfHAL platform driver headers and + for one device macro per algorithm: + `WC_WOLFHAL_AES_{ECB,CBC,GCM,CCM}_DEV` and `WC_WOLFHAL_RNG_DEV`. The + `BOARD_AES_*_DEV` / `BOARD_RNG_DEV` names a stock wolfHAL `board.h` already + uses are accepted directly, so an in-tree wolfHAL board needs no additions. + +Only the modes `board.h` names a device for are offloaded. A mode wolfSSL is +built with but `board.h` does not name is left to wolfCrypt's software +implementation — so hardware that covers, say, only GCM needs just +`WC_WOLFHAL_AES_GCM_DEV`, and a build with CBC enabled still links and runs. + +`WC_WOLFHAL_RNG_DEV` is the exception. `wc_wolfHAL_GenerateBlock()` is wired in +as `CUSTOM_RAND_GENERATE_BLOCK`, which replaces the entropy source outright +rather than sitting behind a dispatch that can decline, so defining +`WOLFSSL_WOLFHAL_RNG` without a device is a build error. + +Because the `BOARD_*_DEV` names are accepted, a stock `board.h` from wolfHAL's +`boards/` directory works as-is: + +```sh +./configure --with-wolfhal=../wolfHAL \ + --with-wolfhal-board=../wolfHAL/boards/stm32wb55xx_nucleo +``` + +Use one of those as the starting point for a board wolfHAL does not already +cover. + +## Runtime + +`wolfCrypt_Init()` registers the device at `WOLFSSL_WOLFHAL_DEVID` (default +`0x5748`), and `wolfhal_settings.h` maps `WC_USE_DEVID` to it so unmodified +wolfCrypt callers route through the hardware. Call `whal_Board_Init()` — which +brings up the peripherals — *before* `wolfCrypt_Init()`. To register at a +different or additional devId, call `wc_wolfHAL_RegisterDevice()` yourself. + +Setting either devId macro alone makes the other follow it, so the two cannot +silently diverge. Setting both to different values is the multi-device case: +wolfHAL registers at `WOLFSSL_WOLFHAL_DEVID`, unqualified callers reach +`WC_USE_DEVID`. + +Define `WOLFSSL_WOLFHAL_RNG` to build `wc_wolfHAL_GenerateBlock()`, and wire it +up in `user_settings.h` with: + +```c +#define CUSTOM_RAND_GENERATE_BLOCK wc_wolfHAL_GenerateBlock +``` diff --git a/wolfcrypt/src/port/wolfHAL/wolfhal.c b/wolfcrypt/src/port/wolfHAL/wolfhal.c new file mode 100644 index 0000000000..921bca1edf --- /dev/null +++ b/wolfcrypt/src/port/wolfHAL/wolfhal.c @@ -0,0 +1,328 @@ +/* wolfhal.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 + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifdef WOLFSSL_WOLFHAL + +/* Application-supplied, on the include path — same contract settings.h has + * with user_settings.h. Must come first: it brings in the wolfHAL platform + * driver headers (and with them the direct API mapping defines) and names the + * device for each algorithm. See wolfhal.h for what it has to provide. */ +#include "board.h" + +#include +#include +#include +#include +#include + +#include + +/* A stock wolfHAL board.h already names its devices BOARD_*_DEV. Accept those + * so such a board needs no wolfSSL-specific additions. */ +#if !defined(WC_WOLFHAL_AES_ECB_DEV) && defined(BOARD_AES_ECB_DEV) + #define WC_WOLFHAL_AES_ECB_DEV BOARD_AES_ECB_DEV +#endif +#if !defined(WC_WOLFHAL_AES_CBC_DEV) && defined(BOARD_AES_CBC_DEV) + #define WC_WOLFHAL_AES_CBC_DEV BOARD_AES_CBC_DEV +#endif +#if !defined(WC_WOLFHAL_AES_GCM_DEV) && defined(BOARD_AES_GCM_DEV) + #define WC_WOLFHAL_AES_GCM_DEV BOARD_AES_GCM_DEV +#endif +#if !defined(WC_WOLFHAL_AES_CCM_DEV) && defined(BOARD_AES_CCM_DEV) + #define WC_WOLFHAL_AES_CCM_DEV BOARD_AES_CCM_DEV +#endif +#if !defined(WC_WOLFHAL_RNG_DEV) && defined(BOARD_RNG_DEV) + #define WC_WOLFHAL_RNG_DEV BOARD_RNG_DEV +#endif + +/* Offload gates. A mode is dispatched to hardware only when wolfCrypt enables it + * and board.h names a device for it. Anything else stays out of the dispatch, + * returns CRYPTOCB_UNAVAILABLE, and falls back to software — so a board offloads + * the subset its hardware covers without constraining the wolfSSL build. */ +#if defined(WOLF_CRYPTO_CB) && !defined(NO_AES) + #if defined(HAVE_AES_CBC) && defined(WC_WOLFHAL_AES_CBC_DEV) + #define WC_WOLFHAL_OFFLOAD_AES_CBC + #endif + #if defined(HAVE_AESGCM) && defined(WC_WOLFHAL_AES_GCM_DEV) + #define WC_WOLFHAL_OFFLOAD_AES_GCM + #endif + #if defined(HAVE_AESCCM) && defined(WC_WOLFHAL_AES_CCM_DEV) + #define WC_WOLFHAL_OFFLOAD_AES_CCM + #endif + #if defined(HAVE_AES_ECB) && defined(WC_WOLFHAL_AES_ECB_DEV) + #define WC_WOLFHAL_OFFLOAD_AES_ECB + #endif +#endif + +/* No fallback for the RNG: CUSTOM_RAND_GENERATE_BLOCK replaces the entropy + * source outright rather than sitting behind a dispatch that can decline, so + * there is nothing to fall back to. */ +#if defined(WOLFSSL_WOLFHAL_RNG) && !defined(WC_WOLFHAL_RNG_DEV) + #error "board.h must define WC_WOLFHAL_RNG_DEV (or BOARD_RNG_DEV)" +#endif + +static int wc_wolfHAL_TranslateError(whal_Error err) +{ + switch (err) { + case WHAL_SUCCESS: return 0; + case WHAL_EINVAL: return BAD_FUNC_ARG; + case WHAL_ENOTSUP: return CRYPTOCB_UNAVAILABLE; + case WHAL_EHARDWARE: return WC_HW_E; + case WHAL_ETIMEOUT: return WC_TIMEOUT_E; + default: return WC_HW_E; + } +} + +#ifdef WOLF_CRYPTO_CB +#ifndef NO_AES + +#ifdef WC_WOLFHAL_OFFLOAD_AES_CBC +static int wc_wolfHAL_AesCbc(wc_CryptoInfo* info) +{ + Aes* aes = info->cipher.aescbc.aes; + const byte* in = info->cipher.aescbc.in; + byte* out = info->cipher.aescbc.out; + word32 sz = info->cipher.aescbc.sz; + whal_Error err; + + /* wolfHAL is stateless across calls, so aes->reg must carry the last + * ciphertext block into the next call. On decrypt capture it up front — + * wolfCrypt permits in-place operation (in == out). aes->tmp is the same + * scratch the software path uses for this. */ + if (!info->cipher.enc && sz >= WC_AES_BLOCK_SIZE) + XMEMCPY(aes->tmp, in + sz - WC_AES_BLOCK_SIZE, WC_AES_BLOCK_SIZE); + + err = whal_AesCbc_Oneshot(WC_WOLFHAL_AES_CBC_DEV, + info->cipher.enc ? WHAL_CRYPTO_ENCRYPT : WHAL_CRYPTO_DECRYPT, + (const byte*)aes->devKey, (size_t)aes->keylen, + (const byte*)aes->reg, + in, out, (size_t)sz); + if (err != WHAL_SUCCESS) + return wc_wolfHAL_TranslateError(err); + + if (sz >= WC_AES_BLOCK_SIZE) { + if (info->cipher.enc) + XMEMCPY(aes->reg, out + sz - WC_AES_BLOCK_SIZE, WC_AES_BLOCK_SIZE); + else + XMEMCPY(aes->reg, aes->tmp, WC_AES_BLOCK_SIZE); + } + + return 0; +} +#endif /* WC_WOLFHAL_OFFLOAD_AES_CBC */ + +#ifdef WC_WOLFHAL_OFFLOAD_AES_GCM +static int wc_wolfHAL_AesGcmEncrypt(wc_CryptoInfo* info) +{ + Aes* aes = info->cipher.aesgcm_enc.aes; + whal_Error err; + + err = whal_AesGcm_Oneshot(WC_WOLFHAL_AES_GCM_DEV, WHAL_CRYPTO_ENCRYPT, + (const byte*)aes->devKey, (size_t)aes->keylen, + info->cipher.aesgcm_enc.iv, (size_t)info->cipher.aesgcm_enc.ivSz, + info->cipher.aesgcm_enc.authIn, (size_t)info->cipher.aesgcm_enc.authInSz, + info->cipher.aesgcm_enc.in, info->cipher.aesgcm_enc.out, + (size_t)info->cipher.aesgcm_enc.sz, + info->cipher.aesgcm_enc.authTag, + (size_t)info->cipher.aesgcm_enc.authTagSz); + + return wc_wolfHAL_TranslateError(err); +} + +static int wc_wolfHAL_AesGcmDecrypt(wc_CryptoInfo* info) +{ + Aes* aes = info->cipher.aesgcm_dec.aes; + word32 tagSz = info->cipher.aesgcm_dec.authTagSz; + byte computedTag[WC_AES_BLOCK_SIZE]; + word32 i, diff = 0; + whal_Error err; + + if (tagSz > sizeof(computedTag)) + return BAD_FUNC_ARG; + + /* wolfHAL always emits the tag rather than checking it, so the compare + * stays here: constant-time, and fail-closed on mismatch. */ + err = whal_AesGcm_Oneshot(WC_WOLFHAL_AES_GCM_DEV, WHAL_CRYPTO_DECRYPT, + (const byte*)aes->devKey, (size_t)aes->keylen, + info->cipher.aesgcm_dec.iv, (size_t)info->cipher.aesgcm_dec.ivSz, + info->cipher.aesgcm_dec.authIn, (size_t)info->cipher.aesgcm_dec.authInSz, + info->cipher.aesgcm_dec.in, info->cipher.aesgcm_dec.out, + (size_t)info->cipher.aesgcm_dec.sz, + computedTag, (size_t)tagSz); + if (err != WHAL_SUCCESS) + return wc_wolfHAL_TranslateError(err); + + for (i = 0; i < tagSz; i++) + diff |= computedTag[i] ^ info->cipher.aesgcm_dec.authTag[i]; + if (diff != 0) { + if (info->cipher.aesgcm_dec.out != NULL && info->cipher.aesgcm_dec.sz > 0) + XMEMSET(info->cipher.aesgcm_dec.out, 0, info->cipher.aesgcm_dec.sz); + return AES_GCM_AUTH_E; + } + return 0; +} +#endif /* WC_WOLFHAL_OFFLOAD_AES_GCM */ + +#ifdef WC_WOLFHAL_OFFLOAD_AES_CCM +static int wc_wolfHAL_AesCcmEncrypt(wc_CryptoInfo* info) +{ + Aes* aes = info->cipher.aesccm_enc.aes; + whal_Error err; + + err = whal_AesCcm_Oneshot(WC_WOLFHAL_AES_CCM_DEV, WHAL_CRYPTO_ENCRYPT, + (const byte*)aes->devKey, (size_t)aes->keylen, + info->cipher.aesccm_enc.nonce, (size_t)info->cipher.aesccm_enc.nonceSz, + info->cipher.aesccm_enc.authIn, (size_t)info->cipher.aesccm_enc.authInSz, + info->cipher.aesccm_enc.in, info->cipher.aesccm_enc.out, + (size_t)info->cipher.aesccm_enc.sz, + info->cipher.aesccm_enc.authTag, + (size_t)info->cipher.aesccm_enc.authTagSz); + + return wc_wolfHAL_TranslateError(err); +} + +static int wc_wolfHAL_AesCcmDecrypt(wc_CryptoInfo* info) +{ + Aes* aes = info->cipher.aesccm_dec.aes; + word32 tagSz = info->cipher.aesccm_dec.authTagSz; + byte computedTag[WC_AES_BLOCK_SIZE]; + word32 i, diff = 0; + whal_Error err; + + if (tagSz > sizeof(computedTag)) + return BAD_FUNC_ARG; + + err = whal_AesCcm_Oneshot(WC_WOLFHAL_AES_CCM_DEV, WHAL_CRYPTO_DECRYPT, + (const byte*)aes->devKey, (size_t)aes->keylen, + info->cipher.aesccm_dec.nonce, (size_t)info->cipher.aesccm_dec.nonceSz, + info->cipher.aesccm_dec.authIn, (size_t)info->cipher.aesccm_dec.authInSz, + info->cipher.aesccm_dec.in, info->cipher.aesccm_dec.out, + (size_t)info->cipher.aesccm_dec.sz, + computedTag, (size_t)tagSz); + if (err != WHAL_SUCCESS) + return wc_wolfHAL_TranslateError(err); + + for (i = 0; i < tagSz; i++) + diff |= computedTag[i] ^ info->cipher.aesccm_dec.authTag[i]; + if (diff != 0) { + if (info->cipher.aesccm_dec.out != NULL && info->cipher.aesccm_dec.sz > 0) + XMEMSET(info->cipher.aesccm_dec.out, 0, info->cipher.aesccm_dec.sz); + return AES_CCM_AUTH_E; + } + return 0; +} +#endif /* WC_WOLFHAL_OFFLOAD_AES_CCM */ + +#ifdef WC_WOLFHAL_OFFLOAD_AES_ECB +static int wc_wolfHAL_AesEcb(wc_CryptoInfo* info) +{ + Aes* aes = info->cipher.aesecb.aes; + whal_Error err; + + err = whal_AesEcb_Oneshot(WC_WOLFHAL_AES_ECB_DEV, + info->cipher.enc ? WHAL_CRYPTO_ENCRYPT : WHAL_CRYPTO_DECRYPT, + (const byte*)aes->devKey, (size_t)aes->keylen, + info->cipher.aesecb.in, info->cipher.aesecb.out, + (size_t)info->cipher.aesecb.sz); + + return wc_wolfHAL_TranslateError(err); +} +#endif /* WC_WOLFHAL_OFFLOAD_AES_ECB */ + +#endif /* !NO_AES */ + +int wc_wolfHAL_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) +{ + (void)devId; + (void)ctx; + + if (info == NULL) + return BAD_FUNC_ARG; + + if (info->algo_type == WC_ALGO_TYPE_CIPHER) { +#ifndef NO_AES + switch (info->cipher.type) { + #ifdef WC_WOLFHAL_OFFLOAD_AES_CBC + case WC_CIPHER_AES_CBC: + return wc_wolfHAL_AesCbc(info); + #endif + #ifdef WC_WOLFHAL_OFFLOAD_AES_GCM + case WC_CIPHER_AES_GCM: + if (info->cipher.enc) + return wc_wolfHAL_AesGcmEncrypt(info); + else + return wc_wolfHAL_AesGcmDecrypt(info); + #endif + #ifdef WC_WOLFHAL_OFFLOAD_AES_CCM + case WC_CIPHER_AES_CCM: + if (info->cipher.enc) + return wc_wolfHAL_AesCcmEncrypt(info); + else + return wc_wolfHAL_AesCcmDecrypt(info); + #endif + #ifdef WC_WOLFHAL_OFFLOAD_AES_ECB + case WC_CIPHER_AES_ECB: + return wc_wolfHAL_AesEcb(info); + #endif + default: + break; + } +#endif /* !NO_AES */ + } + + return CRYPTOCB_UNAVAILABLE; +} + +int wc_wolfHAL_RegisterDevice(int devId) +{ + WOLFSSL_MSG("wolfHAL: registering crypto device"); + + /* Peripheral bring-up (whal_Crypto_Init / whal_Rng_Init) is the board's + * job — whal_Board_Init() must have run before this point. */ + return wc_CryptoCb_RegisterDevice(devId, wc_wolfHAL_CryptoDevCb, NULL); +} + +void wc_wolfHAL_UnRegisterDevice(int devId) +{ + wc_CryptoCb_UnRegisterDevice(devId); +} +#endif /* WOLF_CRYPTO_CB */ + +#ifdef WOLFSSL_WOLFHAL_RNG +int wc_wolfHAL_GenerateBlock(byte* output, word32 sz) +{ + whal_Error err; + + if (output == NULL) + return BAD_FUNC_ARG; + + err = whal_Rng_Generate(WC_WOLFHAL_RNG_DEV, output, (size_t)sz); + return wc_wolfHAL_TranslateError(err); +} +#endif /* WOLFSSL_WOLFHAL_RNG */ + +#endif /* WOLFSSL_WOLFHAL */ diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index 99be1cb3d9..df650e74bf 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -198,6 +198,10 @@ Threading/Mutex options: #include #endif +#if defined(WOLFSSL_WOLFHAL) + #include +#endif + #ifdef HAVE_INTEL_QA_SYNC #include #endif @@ -583,6 +587,17 @@ int wolfCrypt_Init(void) WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif + + /* Register the wolfHAL device so wolfCrypt operations route to the board's + * crypto accelerator. The board's peripherals must already be brought up + * by the application with whal_Board_Init(). */ + #if defined(WOLFSSL_WOLFHAL) && defined(WOLF_CRYPTO_CB) + ret = wc_wolfHAL_RegisterDevice(WOLFSSL_WOLFHAL_DEVID); + if (ret != 0) { + WOLFSSL_MSG("wolfHAL init failed"); + WOLFCRYPT_INIT_RAISE_BAD_STATE(); + } + #endif #if defined(MAX3266X_RTC) ret = wc_MXC_RTC_Init(); if (ret != 0) { diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index d10b3cb3dd..993e2b5f7c 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/wolfssl/wolfcrypt/include.am @@ -116,6 +116,8 @@ noinst_HEADERS+= \ wolfssl/wolfcrypt/port/st/stsafe.h \ wolfssl/wolfcrypt/port/realtek/rtl8735b.h \ wolfssl/wolfcrypt/port/tropicsquare/tropic01.h \ + wolfssl/wolfcrypt/port/wolfHAL/wolfhal.h \ + wolfssl/wolfcrypt/port/wolfHAL/wolfhal_settings.h \ wolfssl/wolfcrypt/port/Espressif/esp-sdk-lib.h \ wolfssl/wolfcrypt/port/Espressif/esp32-crypt.h \ wolfssl/wolfcrypt/port/Espressif/esp_crt_bundle.h \ @@ -238,6 +240,11 @@ if BUILD_TROPIC01 nobase_include_HEADERS+= wolfssl/wolfcrypt/port/tropicsquare/tropic01.h endif +if BUILD_WOLFHAL +nobase_include_HEADERS+= wolfssl/wolfcrypt/port/wolfHAL/wolfhal.h +nobase_include_HEADERS+= wolfssl/wolfcrypt/port/wolfHAL/wolfhal_settings.h +endif + if BUILD_MAXQ10XX nobase_include_HEADERS+= wolfssl/wolfcrypt/port/maxim/maxq10xx.h endif diff --git a/wolfssl/wolfcrypt/port/wolfHAL/wolfhal.h b/wolfssl/wolfcrypt/port/wolfHAL/wolfhal.h new file mode 100644 index 0000000000..3a168c31ae --- /dev/null +++ b/wolfssl/wolfcrypt/port/wolfHAL/wolfhal.h @@ -0,0 +1,92 @@ +/* wolfhal.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 + */ + +#ifndef WOLF_CRYPT_PORT_WOLFHAL_H +#define WOLF_CRYPT_PORT_WOLFHAL_H + +#include + +#ifdef WOLFSSL_WOLFHAL + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/* WOLFSSL_WOLFHAL_DEVID and WC_USE_DEVID come from wolfhal_settings.h, which + * settings.h pulls in above. + * + * This header deliberately pulls in no wolfHAL headers, so wc_port.c can + * reach wc_wolfHAL_RegisterDevice() without the BSP on its include path. The + * wolfHAL types are needed only by wolfhal.c, which gets them from board.h. + * + * board.h is supplied by the application, on the include path, in the same + * way settings.h expects a user_settings.h. It must provide: + * + * - the wolfHAL platform driver headers for the part (e.g. + * ), which is what brings the direct API + * mapping defines into scope; + * - the WHAL_CFG_*_DEV initializers wolfHAL's own driver TUs expand to + * define their device singletons; + * - one device macro per algorithm this port dispatches — + * WC_WOLFHAL_AES_{ECB,CBC,GCM,CCM}_DEV and WC_WOLFHAL_RNG_DEV — or the + * BOARD_AES_*_DEV / BOARD_RNG_DEV names a stock wolfHAL board.h already + * uses, which wolfhal.c accepts directly. + * + * Only the modes board.h names a device for are offloaded; the rest fall back to + * wolfCrypt's software implementations. WC_WOLFHAL_RNG_DEV is the exception and + * has no fallback — see wolfhal.c. + */ + +#ifdef WOLF_CRYPTO_CB +struct wc_CryptoInfo; + +/* Register the wolfHAL device with the wolfSSL crypto callback framework. + * The board's peripherals must already be brought up by the application with + * whal_Board_Init(). Pass the same devId that WC_USE_DEVID is set to so + * wolfSSL routes operations to this device. + * + * wolfCrypt_Init() registers WOLFSSL_WOLFHAL_DEVID automatically; call this + * directly only to register at an additional or different devId. */ +WOLFSSL_API int wc_wolfHAL_RegisterDevice(int devId); + +/* Remove the wolfHAL device from the crypto callback framework. */ +WOLFSSL_API void wc_wolfHAL_UnRegisterDevice(int devId); + +/* Crypto device callback for wolfHAL hardware acceleration */ +WOLFSSL_LOCAL int wc_wolfHAL_CryptoDevCb(int devId, struct wc_CryptoInfo* info, + void* ctx); +#endif + +#ifdef WOLFSSL_WOLFHAL_RNG +/* Generate a block of random data using the wolfHAL RNG device. + * Suitable for use as CUSTOM_RAND_GENERATE_BLOCK. */ +WOLFSSL_API int wc_wolfHAL_GenerateBlock(unsigned char* output, + unsigned int sz); +#endif + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* WOLFSSL_WOLFHAL */ +#endif /* WOLF_CRYPT_PORT_WOLFHAL_H */ diff --git a/wolfssl/wolfcrypt/port/wolfHAL/wolfhal_settings.h b/wolfssl/wolfcrypt/port/wolfHAL/wolfhal_settings.h new file mode 100644 index 0000000000..5c0785ec0f --- /dev/null +++ b/wolfssl/wolfcrypt/port/wolfHAL/wolfhal_settings.h @@ -0,0 +1,72 @@ +/* wolfhal_settings.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 + */ + +/* Compile time configuration for the wolfHAL port. This header holds only + * preprocessor macros and pulls in no wolfHAL or BSP headers, so wolfSSL + * settings.h can include it to map WC_USE_DEVID before the unmodified + * wolfcrypt test and benchmark read it. + * + * WOLFSSL_WOLFHAL enables the port and must be defined in user_settings.h. + * Which AES modes are offloaded follows the usual wolfCrypt feature gates + * (HAVE_AES_CBC, HAVE_AESGCM, HAVE_AESCCM, HAVE_AES_ECB) — the callback + * returns CRYPTOCB_UNAVAILABLE for anything else and wolfCrypt falls back to + * software. + * + * WOLFSSL_WOLFHAL_RNG additionally builds wc_wolfHAL_GenerateBlock(). Wiring + * it in as the entropy source is left to user_settings.h, since it needs a + * prototype visible to random.c: + * #define CUSTOM_RAND_GENERATE_BLOCK wc_wolfHAL_GenerateBlock + */ + +#ifndef WOLF_CRYPT_PORT_WOLFHAL_SETTINGS_H +#define WOLF_CRYPT_PORT_WOLFHAL_SETTINGS_H + +#ifdef WOLFSSL_WOLFHAL + +/* The port routes operations through the wolfSSL crypto callback framework. */ +#ifndef WOLF_CRYPTO_CB + #define WOLF_CRYPTO_CB +#endif + +/* Device id used to register and route to the wolfHAL crypto callback. + * Override by defining WOLFSSL_WOLFHAL_DEVID (or WC_USE_DEVID) in + * user_settings.h before settings.h. Any int other than INVALID_DEVID (-2) is + * valid; this is an identifier, not an address or index. + * + * wolfCrypt_Init() registers at WOLFSSL_WOLFHAL_DEVID and unqualified callers + * route to WC_USE_DEVID, so setting either one alone makes the other follow it. + * Setting both to different values is the deliberate multi-device case. */ +#ifndef WOLFSSL_WOLFHAL_DEVID + #ifdef WC_USE_DEVID + #define WOLFSSL_WOLFHAL_DEVID WC_USE_DEVID + #else + #define WOLFSSL_WOLFHAL_DEVID 0x5748 /* 'WH' for wolfHAL */ + #endif +#endif + +/* Let the unmodified wolfcrypt test and benchmark route every operation + * through this device by giving their devId the wolfHAL value. */ +#ifndef WC_USE_DEVID + #define WC_USE_DEVID WOLFSSL_WOLFHAL_DEVID +#endif + +#endif /* WOLFSSL_WOLFHAL */ +#endif /* WOLF_CRYPT_PORT_WOLFHAL_SETTINGS_H */ diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 696ece0323..a639b3ec5f 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -396,6 +396,13 @@ #include #endif +/* wolfHAL port: enable the crypto callback and map WC_USE_DEVID before the + * rest of settings.h and before the unmodified test and benchmark read it. + * This header is macro only and pulls in no wolfHAL or BSP dependencies. */ +#if defined(WOLFSSL_WOLFHAL) + #include +#endif + /* Forward propagation of the legacy parent gate to the canonical name * (HAVE_DILITHIUM -> WOLFSSL_HAVE_MLDSA). Always active: required so that * a user_settings.h or build flag using only the legacy spelling still