diff --git a/.github/workflows/zephyr.yml b/.github/workflows/zephyr.yml index c987502a842..1e35851395a 100644 --- a/.github/workflows/zephyr.yml +++ b/.github/workflows/zephyr.yml @@ -98,6 +98,16 @@ jobs: ./zephyr/scripts/twister -T modules/crypto/wolfssl --test zephyr/samples/wolfssl_test/sample.crypto.wolfssl_test_no_malloc -vvv rm -rf zephyr/twister-out + - name: Run wolfssl condvar ztest + # Native k_condvar / k_mutex / k_thread threading test (no POSIX). Runs + # on native_sim (introduced in Zephyr 3.4), so skip the 2.7.4 entry. + if: ${{ matrix.config.zephyr-ref != 'v2.7.4' }} + id: wolfssl-condvar + working-directory: zephyr + run: | + ./zephyr/scripts/twister -T modules/crypto/wolfssl/zephyr/tests/wolfssl_condvar -p native_sim -vvv + rm -rf zephyr/twister-out + - name: Run wolfssl TLS sock test # Results in a page fault that I can't trace if: ${{ matrix.config.zephyr-ref != 'v2.7.4' }} @@ -118,12 +128,12 @@ jobs: rm -rf zephyr/twister-out - name: Zip failure logs - if: ${{ failure() && (steps.wolfssl-test.outcome == 'failure' || steps.wolfssl-tls-sock.outcome == 'failure' || steps.wolfssl-tls-thread.outcome == 'failure') }} + if: ${{ failure() && (steps.wolfssl-test.outcome == 'failure' || steps.wolfssl-condvar.outcome == 'failure' || steps.wolfssl-tls-sock.outcome == 'failure' || steps.wolfssl-tls-thread.outcome == 'failure') }} run: | zip -9 -r logs.zip zephyr/twister-out - name: Upload failure logs - if: ${{ failure() && (steps.wolfssl-test.outcome == 'failure' || steps.wolfssl-tls-sock.outcome == 'failure' || steps.wolfssl-tls-thread.outcome == 'failure') }} + if: ${{ failure() && (steps.wolfssl-test.outcome == 'failure' || steps.wolfssl-condvar.outcome == 'failure' || steps.wolfssl-tls-sock.outcome == 'failure' || steps.wolfssl-tls-thread.outcome == 'failure') }} uses: actions/upload-artifact@v6 with: name: zephyr-client-test-logs diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index e840d95df9d..43f5abdc62e 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -5322,10 +5322,53 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) #include #endif + #if defined(CONFIG_ENTROPY_HAS_DRIVER) && DT_HAS_CHOSEN(zephyr_entropy) + /* Match the zephyr/-prefixed include layout used above: it did not + * exist before Zephyr 3.1. */ + #if KERNEL_VERSION_NUMBER >= 0x30100 + #include + #include + #else + #include + #include + #endif + #endif + int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) { + /* Seed the DRBG straight from the hardware entropy driver when the platform + * exposes one (a zephyr,entropy chosen node), so wolfCrypt gets + * cryptographic-quality seed material instead of the general-purpose + * sys_rand_get(). A dead source returns an error, which makes wc_InitRng() + * fail (RNG_FAILURE_E) rather than yield weak output. Boards that set + * CONFIG_ENTROPY_HAS_DRIVER without a chosen entropy node fall back to + * sys_rand_get() rather than failing the build. */ + #if defined(CONFIG_ENTROPY_HAS_DRIVER) && DT_HAS_CHOSEN(zephyr_entropy) + const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy)); + word32 off = 0; + word32 rem; + uint16_t chunk; + + (void)os; + if (!device_is_ready(dev)) { + return RNG_FAILURE_E; + } + /* entropy_get_entropy() takes a uint16_t length; chunk the request so + * any word32 seed size is honored without silent truncation. */ + while (off < sz) { + rem = sz - off; + chunk = (rem > 0xFFFFU) ? (uint16_t)0xFFFFU : (uint16_t)rem; + if (entropy_get_entropy(dev, (uint8_t *)output + off, chunk) != 0) { + return RNG_FAILURE_E; + } + off += chunk; + } + return 0; + #else + (void)os; sys_rand_get(output, sz); return 0; + #endif } #elif defined(WOLFSSL_TELIT_M2MB) diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index 99be1cb3d96..687f2c5f7d4 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -238,7 +238,6 @@ Threading/Mutex options: #if defined(WOLFSSL_ZEPHYR) #if defined(CONFIG_BOARD_NATIVE_POSIX) || defined(CONFIG_BOARD_NATIVE_SIM) #include "native_rtc.h" -#define CONFIG_RTC #endif #endif @@ -4439,16 +4438,13 @@ time_t xilinx_time(time_t * timer) time_t z_time(time_t * timer) { - struct timespec ts; - - #if defined(CONFIG_RTC) && \ - (defined(CONFIG_PICOLIBC) || defined(CONFIG_NEWLIB_LIBC)) - #if defined(CONFIG_BOARD_NATIVE_POSIX) || defined(CONFIG_BOARD_NATIVE_SIM) - /* When using native sim, get time from simulator rtc */ + /* native_sim: read the simulator RTC for a real host wall-clock. The + * real-target RTC/libc gate below is compiled out under the host libc. */ uint32_t nsec = 0; uint64_t sec = 0; + native_rtc_gettime(RTC_CLOCK_PSEUDOHOSTREALTIME, &nsec, &sec); if (timer != NULL) @@ -4458,6 +4454,11 @@ time_t z_time(time_t * timer) #else + struct timespec ts = { 0 }; + + #if defined(CONFIG_RTC) && \ + (defined(CONFIG_PICOLIBC) || defined(CONFIG_NEWLIB_LIBC)) + /* Try to obtain the actual time from an RTC */ static const struct device *rtc = DEVICE_DT_GET(DT_NODELABEL(rtc)); @@ -4476,8 +4477,7 @@ time_t z_time(time_t * timer) return epochTime; } } - #endif /* CONFIG_BOARD_NATIVE_POSIX || CONFIG_BOARD_NATIVE_SIM */ - #endif + #endif /* CONFIG_RTC && (CONFIG_PICOLIBC || CONFIG_NEWLIB_LIBC) */ /* Fallback to uptime since boot. This works for relative times, but * not for ASN.1 date validation */ @@ -4486,6 +4486,8 @@ time_t z_time(time_t * timer) *timer = ts.tv_sec; return ts.tv_sec; + + #endif /* CONFIG_BOARD_NATIVE_POSIX || CONFIG_BOARD_NATIVE_SIM */ } #endif /* WOLFSSL_ZEPHYR */ @@ -5261,8 +5263,78 @@ char* wolfSSL_strnstr(const char* s1, const char* s2, size_t n) } #ifdef WOLFSSL_COND - /* Use the pthreads translation layer for signaling */ + /* Native Zephyr condition variables (k_condvar) over a k_mutex; no POSIX + * pthread layer required. Semantics mirror the pthread implementation. */ + int wolfSSL_CondInit(COND_TYPE* cond) + { + int ret; + if (cond == NULL) + return BAD_FUNC_ARG; + + ret = wc_InitMutex(&cond->mutex); + if (ret == 0) { + /* k_condvar_init always returns 0 on Zephyr. */ + (void)k_condvar_init(&cond->cond); + } + + return ret; + } + + int wolfSSL_CondFree(COND_TYPE* cond) + { + if (cond == NULL) + return BAD_FUNC_ARG; + + /* k_condvar has no destroy; just release the backing mutex. */ + return wc_FreeMutex(&cond->mutex); + } + + int wolfSSL_CondStart(COND_TYPE* cond) + { + if (cond == NULL) + return BAD_FUNC_ARG; + + if (wc_LockMutex(&cond->mutex) != 0) + return BAD_MUTEX_E; + + return 0; + } + + int wolfSSL_CondSignal(COND_TYPE* cond) + { + if (cond == NULL) + return BAD_FUNC_ARG; + + /* Caller holds cond->mutex; wake a single waiter. */ + (void)k_condvar_signal(&cond->cond); + + return 0; + } + + int wolfSSL_CondWait(COND_TYPE* cond) + { + if (cond == NULL) + return BAD_FUNC_ARG; + + /* Atomically releases the mutex, blocks, and re-acquires it on wake, + * matching pthread_cond_wait semantics. */ + if (k_condvar_wait(&cond->cond, &cond->mutex, K_FOREVER) != 0) + return BAD_MUTEX_E; + + return 0; + } + + int wolfSSL_CondEnd(COND_TYPE* cond) + { + if (cond == NULL) + return BAD_FUNC_ARG; + + if (wc_UnLockMutex(&cond->mutex) != 0) + return BAD_MUTEX_E; + + return 0; + } #endif /* WOLFSSL_COND */ #elif defined(WOLFSSL_PTHREADS) || \ diff --git a/wolfssl/wolfcrypt/mem_track.h b/wolfssl/wolfcrypt/mem_track.h index be2a1c35292..24a6e096edf 100644 --- a/wolfssl/wolfcrypt/mem_track.h +++ b/wolfssl/wolfcrypt/mem_track.h @@ -484,7 +484,7 @@ static WC_INLINE int CleanupMemoryTracker(void) #include #endif -typedef void* (*thread_func)(void* args); +typedef THREAD_RETURN (*thread_func)(void* args); #define STACK_CHECK_VAL 0x01 struct stack_size_debug_context { @@ -620,7 +620,7 @@ static WC_INLINE int StackSizeCheck_Rebaseline(void) * ./configure --enable-stacksize=verbose [...] */ -static void* debug_stack_size_verbose_shim( +static THREAD_RETURN debug_stack_size_verbose_shim( struct stack_size_debug_context *shim_args) { StackSizeCheck_myStack = shim_args->myStack; @@ -733,7 +733,112 @@ int StackSizeHWMReset(void) #endif /* HAVE_STACK_SIZE_VERBOSE */ -#ifdef HAVE_PTHREAD +#if defined(__ZEPHYR__) + +static WC_INLINE int StackSizeCheck(struct func_args* args, thread_func tf) +{ + size_t i; + int ret; + int err; + struct k_thread* tid = NULL; + k_thread_stack_t* threadStack = NULL; + unsigned char* myStack = NULL; + +#ifdef HAVE_STACK_SIZE_VERBOSE + struct stack_size_debug_context shim_args; +#endif + + tid = (struct k_thread*)XMALLOC( + Z_KERNEL_STACK_SIZE_ADJUST(sizeof(struct k_thread)), + wolfsslThreadHeapHint, DYNAMIC_TYPE_TMP_BUFFER); + if (tid == NULL) { + printf("error: XMALLOC tid failed"); + ret = MEMORY_E; + goto out; + } + +#ifndef WOLFSSL_ZEPHYR_STACK_SZ + #define WOLFSSL_ZEPHYR_STACK_SZ (48*1024) +#endif + + threadStack = (void*)XMALLOC( + Z_KERNEL_STACK_SIZE_ADJUST(WOLFSSL_ZEPHYR_STACK_SZ), + wolfsslThreadHeapHint, DYNAMIC_TYPE_TMP_BUFFER); + if (threadStack == NULL) { + printf("error: k_thread_stack_alloc threadStack failed"); + ret = MEMORY_E; + goto out; + } + + myStack = K_THREAD_STACK_BUFFER(threadStack); + XMEMSET(myStack, STACK_CHECK_VAL, WOLFSSL_ZEPHYR_STACK_SZ); + +#ifdef HAVE_STACK_SIZE_VERBOSE + StackSizeCheck_stackSizeHWM = 0; + shim_args.myStack = myStack; + shim_args.stackSize = WOLFSSL_ZEPHYR_STACK_SZ; + shim_args.stackSizeHWM_ptr = &StackSizeCheck_stackSizeHWM; + shim_args.fn = tf; + shim_args.args = args; + + /* k_thread_create does not return any error codes */ + /* Casting to k_thread_entry_t should be fine since we just ignore the + * extra arguments being passed in */ + k_thread_create(tid, threadStack, WOLFSSL_ZEPHYR_STACK_SZ, + (k_thread_entry_t)debug_stack_size_verbose_shim, (void *)&shim_args, + NULL, NULL, 5, 0, K_NO_WAIT); +#else + /* k_thread_create does not return any error codes */ + /* Casting to k_thread_entry_t should be fine since we just ignore the + * extra arguments being passed in */ + k_thread_create(tid, threadStack, WOLFSSL_ZEPHYR_STACK_SZ, + (k_thread_entry_t)tf, args, NULL, NULL, 5, 0, K_NO_WAIT); + +#endif + + err = k_thread_join(tid, K_FOREVER); + if (err != 0) { + printf("k_thread_join failed\n"); + ret = MEMORY_E; + goto out; + } + + + for (i = 0; i < WOLFSSL_ZEPHYR_STACK_SZ; i++) { + if (myStack[i] != STACK_CHECK_VAL) { + break; + } + } + +#ifdef HAVE_STACK_SIZE_VERBOSE + printf("stack used = %lu\n", StackSizeCheck_stackSizeHWM > (WOLFSSL_ZEPHYR_STACK_SZ - i) + ? (unsigned long)StackSizeCheck_stackSizeHWM + : (unsigned long)(WOLFSSL_ZEPHYR_STACK_SZ - i)); + StackSizeCheck_myStack = NULL; + StackSizeCheck_stackOffsetPointer = NULL; +#else + { + size_t used = WOLFSSL_ZEPHYR_STACK_SZ - i; + printf("stack used = %lu\n", (unsigned long)used); + } +#endif + +out: + XFREE(tid, wolfsslThreadHeapHint, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(threadStack, wolfsslThreadHeapHint, + DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +#define StackSizeCheck_launch(args, tf, threadId, stack_context) \ + ((void)(args), (void)(tf), (void)(threadId), (void)(stack_context), \ + (NOT_COMPILED_IN)) + +#define StackSizeCheck_reap(threadId, stack_context) \ + ((void)(threadId), (void)(stack_context), (NOT_COMPILED_IN)) + +#elif defined(HAVE_PTHREAD) static WC_INLINE int StackSizeCheck(struct func_args* args, thread_func tf) { diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index af98e43ba30..0802044bc7b 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -1958,6 +1958,19 @@ WOLFSSL_API word32 CheckRunTimeSettings(void); } THREAD_TYPE; #define WOLFSSL_THREAD extern void* wolfsslThreadHeapHint; + /* Native Zephyr condition variable (k_condvar) built on a k_mutex; no + * POSIX pthread layer required. Only reached when !SINGLE_THREADED, so + * wolfSSL_Mutex is k_mutex and is already included. + * k_condvar was introduced in Zephyr 2.4, so gate the capability on the + * kernel version: an older target builds without condition-variable + * support (WOLFSSL_COND undefined), exactly as it did before. */ + #if KERNEL_VERSION_NUMBER >= 0x20400 + typedef struct COND_TYPE { + wolfSSL_Mutex mutex; + struct k_condvar cond; + } COND_TYPE; + #define WOLFSSL_COND + #endif #elif defined(NETOS) typedef UINT THREAD_RETURN; typedef struct { diff --git a/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index e84b724ae0d..3d3faf24ac6 100644 --- a/wolfssl/wolfcrypt/wc_port.h +++ b/wolfssl/wolfcrypt/wc_port.h @@ -320,25 +320,23 @@ #else #include #endif - /* Include sys/types.h early so host libc sets __timer_t_defined - * before Zephyr's posix_types.h can define a conflicting timer_t */ + /* Include sys/types.h early so host libc sets __timer_t_defined before any + * later Zephyr posix_types.h (pulled in by an application POSIX layer, e.g. + * CONFIG_POSIX_API) can define a conflicting timer_t. wolfCrypt itself does + * not include posix_types.h on Zephyr; this include is purely defensive. */ #include #ifndef SINGLE_THREADED - #if !defined(CONFIG_PTHREAD_IPC) && !defined(CONFIG_POSIX_THREADS) - #error "Threading needs CONFIG_PTHREAD_IPC / CONFIG_POSIX_THREADS" - #endif + /* wolfCrypt's threading primitives on Zephyr are backed by native + * kernel objects: k_mutex for wolfSSL_Mutex, k_thread for thread + * creation, and k_condvar for condition variables. These all come from + * and do NOT require the POSIX compatibility layer, + * so a multi-threaded wolfCrypt build does not need + * CONFIG_POSIX_THREADS / CONFIG_PTHREAD_IPC and pulls in no pthread + * headers of its own. */ #if KERNEL_VERSION_NUMBER >= 0x30100 #include - #ifndef CONFIG_ARCH_POSIX - #include - #include - #endif #else #include - #ifndef CONFIG_ARCH_POSIX - #include - #include - #endif #endif #endif diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index f13d724a7a8..719c4098bda 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -56,6 +56,7 @@ if(CONFIG_WOLFSSL) endif() zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/arc4.c) + zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/ascon.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/asm.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/asn.c) #zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/async.c) @@ -122,6 +123,8 @@ if(CONFIG_WOLFSSL) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/wc_pkcs11.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/wc_port.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/wc_slhdsa.c) + zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/wc_xmss.c) + zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/wc_xmss_impl.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/wolfevent.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/wolfmath.c) diff --git a/zephyr/Kconfig b/zephyr/Kconfig index e6cb1cb0603..1e96b8bf46b 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -67,8 +67,66 @@ config WOLFCRYPT_FIPS bool "wolfCrypt FIPS support" depends on WOLFSSL_BUILTIN help - Enables FIPS support in wolfCrypt. Requires the wolfSSL FIPS ready - download that includes fips.c/fips_test.c. + Enable the wolfCrypt FIPS 140-3 module boundary. Requires the wolfSSL + FIPS bundle (fips.c, fips_test.c, wolfcrypt_first.c, wolfcrypt_last.c) + dropped into wolfcrypt/src/ - the CMake FIPS-boundary block compiles them. + Select the version that matches the bundle under "wolfCrypt FIPS version". + +choice + prompt "wolfCrypt FIPS version" + depends on WOLFCRYPT_FIPS + default WOLFCRYPT_FIPS_V6 + help + Select the FIPS module version. It must match the dropped-in bundle: the + in-core integrity check and the in-boundary algorithm set are keyed to the + version, so a mismatch fails the power-on self test. Values mirror + configure.ac's --enable-fips=VERSION mapping. + +config WOLFCRYPT_FIPS_V2 + bool "FIPS 140-2 (Cert #3389)" + help + Legacy FIPS 140-2 validated module (HAVE_FIPS_VERSION 2.0.0). + +config WOLFCRYPT_FIPS_V5 + bool "FIPS 140-3 (Cert #4718)" + help + wolfCrypt FIPS 140-3 validated module, Certificate #4718 (version 5.2.1). + +config WOLFCRYPT_FIPS_V6 + bool "FIPS 140-3 (SRTP-KDF full submission)" + help + wolfCrypt FIPS 140-3 SRTP-KDF full submission (version 6.0.0). + +config WOLFCRYPT_FIPS_V7 + bool "FIPS 140-3 (v7 full submission)" + help + wolfCrypt FIPS 140-3 v7 full submission (version 7.0.0). + +config WOLFCRYPT_FIPS_READY + bool "FIPS Ready (in-tree, uncertified)" + help + FIPS-Ready in-tree sources, feature locked (version 8.0.0 - kept one ahead + of the latest submission). Carries the newest in-boundary algorithms but is + not yet NIST-certified; use it for pre-certification integration. + +endchoice + +config WOLFSSL_CRYPTO_ONLY + bool "Build wolfCrypt only (no TLS layer)" + depends on WOLFSSL_BUILTIN + help + Define WOLFCRYPT_ONLY: compile only the wolfCrypt crypto library and + leave the wolfSSL TLS layer out of the build. + +config WOLFSSL_SINGLE_THREADED + bool "wolfCrypt single-threaded" + depends on WOLFSSL_BUILTIN + default y if !MULTITHREADING + help + Define SINGLE_THREADED: build wolfCrypt without internal locking, for a + single-threaded system or when the caller serializes all access. Defaults + on when the kernel has no threading (!MULTITHREADING), so consumers such + as wolfPSA do not need to select it themselves. config WOLFSSL_DTLS bool "wolfSSL DTLS support" @@ -90,6 +148,68 @@ config WOLFSSL_MLKEM help Enable PQC ML-KEM support for Key Exchange +config WOLFSSL_MLDSA + bool "wolfSSL PQC ML-DSA support" + help + Enable PQC ML-DSA (Dilithium) signatures. + +config WOLFSSL_LMS + bool "wolfSSL LMS/HSS hash-based signatures" + help + Enable LMS/HSS stateful hash-based signature verification (verify-only). + +config WOLFSSL_XMSS + bool "wolfSSL XMSS/XMSS^MT hash-based signatures" + help + Enable XMSS/XMSS^MT stateful hash-based signature verification (verify-only). + +config WOLFSSL_FALCON + bool "wolfSSL PQC Falcon signatures" + help + Enable PQC Falcon (FN-DSA) signatures. + +config WOLFSSL_RSA + bool "wolfCrypt RSA support" + default y + help + Enable RSA (define RSA support; NO_RSA when off). + +config WOLFSSL_ECC + bool "wolfCrypt ECC support" + default y + help + Enable ECC (HAVE_ECC, SECP256R1). + +config WOLFSSL_CHACHA_POLY + bool "wolfCrypt ChaCha20-Poly1305 support" + default y + help + Enable ChaCha20 and Poly1305 (HAVE_CHACHA, HAVE_POLY1305). + +config WOLFSSL_CURVE25519 + bool "wolfCrypt Curve25519 / Ed25519 support" + default n + help + Enable Curve25519 and Ed25519 (HAVE_CURVE25519, HAVE_ED25519). + +config WOLFSSL_SNI + bool "wolfSSL Server Name Indication (SNI)" + default y + help + Enable TLS Server Name Indication (HAVE_SNI). + +config WOLFSSL_SESSION_CACHE + bool "wolfSSL TLS session cache" + default y + help + Enable the TLS session cache (SMALL_SESSION_CACHE; NO_SESSION_CACHE off). + +config WOLFSSL_SESSION_TICKET + bool "wolfSSL TLS session tickets" + default y + help + Enable TLS session tickets (HAVE_SESSION_TICKET, TLS 1.3 resumption). + config WOLFSSL_MAX_FRAGMENT_LEN int default 3 diff --git a/zephyr/tests/wolfssl_condvar/CMakeLists.txt b/zephyr/tests/wolfssl_condvar/CMakeLists.txt new file mode 100644 index 00000000000..cf26ca03b2c --- /dev/null +++ b/zephyr/tests/wolfssl_condvar/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(wolfssl_condvar) + +target_sources(app PRIVATE src/main.c) +add_definitions(-DWOLFSSL_USER_SETTINGS) diff --git a/zephyr/tests/wolfssl_condvar/prj.conf b/zephyr/tests/wolfssl_condvar/prj.conf new file mode 100644 index 00000000000..eba974c0b58 --- /dev/null +++ b/zephyr/tests/wolfssl_condvar/prj.conf @@ -0,0 +1,13 @@ +# wolfCrypt native Zephyr condition-variable / thread ztest. +# Multi-threaded (default, SINGLE_THREADED not set) so the k_condvar-backed +# wolfSSL_Cond* path is compiled, and DELIBERATELY no CONFIG_POSIX_API / +# CONFIG_POSIX_THREADS / CONFIG_PTHREAD_IPC: the whole point is that the native +# k_mutex/k_thread/k_condvar primitives work without the POSIX layer. +CONFIG_ZTEST=y +CONFIG_MAIN_STACK_SIZE=16384 +CONFIG_ZTEST_STACK_SIZE=16384 +# wolfSSL_NewThread allocates its ~48KB thread stack from the heap. +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=131072 + +CONFIG_WOLFSSL=y +CONFIG_WOLFSSL_BUILTIN=y diff --git a/zephyr/tests/wolfssl_condvar/src/main.c b/zephyr/tests/wolfssl_condvar/src/main.c new file mode 100644 index 00000000000..0cd5c8040c2 --- /dev/null +++ b/zephyr/tests/wolfssl_condvar/src/main.c @@ -0,0 +1,91 @@ +/* main.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 + */ + +/* + * Exercises wolfCrypt's native Zephyr threading primitives -- the k_condvar + * backed wolfSSL_Cond* API and wolfSSL_NewThread/wolfSSL_JoinThread -- on a + * multi-threaded, POSIX-free build (see prj.conf: no CONFIG_POSIX_THREADS / + * CONFIG_PTHREAD_IPC). Covers the producer/consumer wakeup handshake (the + * atomic release/re-acquire semantics of wolfSSL_CondWait and signalling under + * the lock) and the NULL-pointer guards of all six condition-variable calls. + */ + +#include +#include + +#include +#include +#include +#include + +static COND_TYPE g_cond; +static volatile int g_predicate; + +/* Publish the predicate under the lock, then wake the waiter. */ +static THREAD_RETURN WOLFSSL_THREAD condvar_signaler(void* arg) +{ + (void)arg; + + /* Yield so the consumer generally reaches wolfSSL_CondWait() first. The + * handshake must still be correct if it does not, because the consumer + * re-checks the predicate under the lock before each wait. */ + k_msleep(50); + + (void)wolfSSL_CondStart(&g_cond); + g_predicate = 1; + (void)wolfSSL_CondSignal(&g_cond); + (void)wolfSSL_CondEnd(&g_cond); +} + +ZTEST(wolfssl_condvar, test_producer_consumer_wakeup) +{ + THREAD_TYPE thread; + + g_predicate = 0; + + zassert_equal(wolfSSL_CondInit(&g_cond), 0, "CondInit"); + zassert_equal(wolfSSL_NewThread(&thread, condvar_signaler, NULL), 0, + "NewThread"); + + /* wolfSSL_CondWait must atomically release the mutex, block, and + * re-acquire it on wake; loop guards against spurious wakeups. */ + zassert_equal(wolfSSL_CondStart(&g_cond), 0, "CondStart"); + while (!g_predicate) { + zassert_equal(wolfSSL_CondWait(&g_cond), 0, "CondWait"); + } + zassert_equal(g_predicate, 1, "predicate observed set after wake"); + zassert_equal(wolfSSL_CondEnd(&g_cond), 0, "CondEnd"); + + zassert_equal(wolfSSL_JoinThread(thread), 0, "JoinThread"); + zassert_equal(wolfSSL_CondFree(&g_cond), 0, "CondFree"); +} + +ZTEST(wolfssl_condvar, test_null_guards) +{ + zassert_equal(wolfSSL_CondInit(NULL), BAD_FUNC_ARG, "CondInit NULL"); + zassert_equal(wolfSSL_CondFree(NULL), BAD_FUNC_ARG, "CondFree NULL"); + zassert_equal(wolfSSL_CondStart(NULL), BAD_FUNC_ARG, "CondStart NULL"); + zassert_equal(wolfSSL_CondSignal(NULL), BAD_FUNC_ARG, "CondSignal NULL"); + zassert_equal(wolfSSL_CondWait(NULL), BAD_FUNC_ARG, "CondWait NULL"); + zassert_equal(wolfSSL_CondEnd(NULL), BAD_FUNC_ARG, "CondEnd NULL"); +} + +ZTEST_SUITE(wolfssl_condvar, NULL, NULL, NULL, NULL, NULL); diff --git a/zephyr/tests/wolfssl_condvar/testcase.yaml b/zephyr/tests/wolfssl_condvar/testcase.yaml new file mode 100644 index 00000000000..fb1092c2266 --- /dev/null +++ b/zephyr/tests/wolfssl_condvar/testcase.yaml @@ -0,0 +1,32 @@ +common: + tags: + - wolfssl + - threading + harness: ztest +tests: + crypto.wolfssl.condvar: + # native_sim only: the test builds wolfCrypt multi-threaded with no POSIX. + # wc_port.c's z_time() reads the native_sim simulator RTC (native_rtc_gettime) + # for a real wall clock; non-native boards would need the POSIX clock enabled, + # so restrict to native_sim rather than fail elsewhere. Allow both the plain + # board (older Zephyr / x86 CI, where native_sim/native/64 does not exist) and + # the hardware-model-v2 64-bit variant (aarch64 host). + platform_allow: + - native_sim + - native_sim/native/64 + integration_platforms: + - native_sim + - native_sim/native/64 + crypto.wolfssl.condvar_crypto_only: + # Same threaded condvar test with the WOLFSSL_CRYPTO_ONLY build-profile knob + # set (WOLFCRYPT_ONLY, no TLS layer), giving that knob explicit build+run + # coverage in the module: the native k_mutex/k_thread/k_condvar path must + # still work in a crypto-only image. + platform_allow: + - native_sim + - native_sim/native/64 + integration_platforms: + - native_sim + - native_sim/native/64 + extra_configs: + - CONFIG_WOLFSSL_CRYPTO_ONLY=y diff --git a/zephyr/user_settings.h b/zephyr/user_settings.h index 5198ad5eab8..1056d896de1 100644 --- a/zephyr/user_settings.h +++ b/zephyr/user_settings.h @@ -24,10 +24,17 @@ #ifdef CONFIG_WOLFSSL -/* If a custom user_settings file is provided use it instead. - * CONFIG_WOLFSSL_SETTINGS_FILE is always defined. If it is not explicitly set - * in prj.conf then it is auto-defined to "". This obviously causes issues here. - * That is why we define WOLFSSL_SETTINGS_FILE in CMakeLists.txt. */ +/* The wolfCrypt feature configuration comes from the user's own settings file + * if one was supplied (CONFIG_WOLFSSL_SETTINGS_FILE), otherwise from the module + * default below. CONFIG_WOLFSSL_SETTINGS_FILE is always defined; when it is not + * set in prj.conf it is auto-defined to "", so WOLFSSL_SETTINGS_FILE is only + * defined (in CMakeLists.txt) when a real path was given. A user-supplied + * settings file is authoritative: the build-profile Kconfig knobs + * (WOLFSSL_CRYPTO_ONLY, WOLFSSL_SINGLE_THREADED) shape ONLY the module default + * below and are NOT applied on top of a settings file, so the two config + * interfaces never mix. A consumer like wolfPSA that needs specific wolfCrypt + * options checks for them itself and fails the build if a settings file omits + * them, rather than injecting them here. */ #ifdef WOLFSSL_SETTINGS_FILE #include WOLFSSL_SETTINGS_FILE #else @@ -82,9 +89,38 @@ extern "C" { /* FIPS */ /* ------------------------------------------------------------------------- */ #ifdef CONFIG_WOLFCRYPT_FIPS - /* FIPS Ready */ - #define HAVE_FIPS_VERSION 5 - #define HAVE_FIPS_VERSION_MINOR 3 + /* HAVE_FIPS is the master switch that routes the wolfCrypt algorithms + * through the FIPS module boundary. The version macros below must match the + * dropped-in FIPS bundle (see the CMake FIPS-boundary block); settings.h + * folds them into WOLFSSL_FIPS_VERSION_CODE for the in-boundary gating. */ + #define HAVE_FIPS + /* Version triples mirror configure.ac's --enable-fips=VERSION mapping. */ + #if defined(CONFIG_WOLFCRYPT_FIPS_READY) + /* FIPS Ready: in-tree, feature locked, one ahead of the latest. */ + #define HAVE_FIPS_VERSION 8 + #define HAVE_FIPS_VERSION_MINOR 0 + #define HAVE_FIPS_VERSION_PATCH 0 + #elif defined(CONFIG_WOLFCRYPT_FIPS_V7) + /* FIPS 140-3 v7 full submission. */ + #define HAVE_FIPS_VERSION 7 + #define HAVE_FIPS_VERSION_MINOR 0 + #define HAVE_FIPS_VERSION_PATCH 0 + #elif defined(CONFIG_WOLFCRYPT_FIPS_V6) + /* FIPS 140-3 SRTP-KDF full submission. */ + #define HAVE_FIPS_VERSION 6 + #define HAVE_FIPS_VERSION_MINOR 0 + #define HAVE_FIPS_VERSION_PATCH 0 + #elif defined(CONFIG_WOLFCRYPT_FIPS_V5) + /* FIPS 140-3 Cert #4718 (wolfCrypt 5.2.1). */ + #define HAVE_FIPS_VERSION 5 + #define HAVE_FIPS_VERSION_MINOR 2 + #define HAVE_FIPS_VERSION_PATCH 1 + #elif defined(CONFIG_WOLFCRYPT_FIPS_V2) + /* FIPS 140-2 Cert #3389. */ + #define HAVE_FIPS_VERSION 2 + #define HAVE_FIPS_VERSION_MINOR 0 + #define HAVE_FIPS_VERSION_PATCH 0 + #endif #endif @@ -114,7 +150,9 @@ extern "C" { #define HAVE_EXTENDED_MASTER #define HAVE_ENCRYPT_THEN_MAC #define HAVE_SERVER_RENEGOTIATION_INFO -#define HAVE_SNI /* optional Server Name Indicator (SNI) */ +#if defined(CONFIG_WOLFSSL_SNI) + #define HAVE_SNI /* optional Server Name Indication (SNI) */ +#endif /* ASN */ #define WOLFSSL_ASN_TEMPLATE /* use newer ASN template asn.c code (default) */ @@ -124,14 +162,15 @@ extern "C" { #endif /* Session Cache */ -#if 1 +#if defined(CONFIG_WOLFSSL_SESSION_CACHE) #define SMALL_SESSION_CACHE - #ifdef WOLFSSL_TLS13 - #define HAVE_SESSION_TICKET /* session tickets required for resumption in TLS v1.3 */ - #endif #else #define NO_SESSION_CACHE /* disable session resumption */ #endif +/* TLS 1.3 stateless session tickets -- independent of the internal cache. */ +#if defined(CONFIG_WOLFSSL_SESSION_TICKET) && defined(WOLFSSL_TLS13) + #define HAVE_SESSION_TICKET +#endif /* Session export (external session cache) */ #if defined(CONFIG_WOLFSSL_SESSION_EXPORT) @@ -194,15 +233,27 @@ extern "C" { /* Algorithms */ /* ------------------------------------------------------------------------- */ /* RNG */ +/* wolfCrypt Hash-DRBG (SHA2-256). On Zephyr its seed comes from wc_GenerateSeed() + * (wolfcrypt/src/random.c), which draws from the hardware entropy driver when one + * is present and falls back to sys_rand_get() otherwise -- so no seed callback is + * registered. Guarded by WC_NO_HASHDRBG so a PSA-RNG build + * (CONFIG_MBEDTLS_PSA_CRYPTO_C above) can still disable the internal DRBG and + * route randomness through the PSA provider. */ #ifndef WC_NO_HASHDRBG - #define HAVE_HASHDRBG /* Use DRBG SHA2-256 and seed */ - #ifdef CONFIG_CSPRNG_ENABLED - #define WC_RNG_SEED_CB - #endif + #define HAVE_HASHDRBG +#endif + +/* Build-profile knobs for the module-default config only (a user-supplied + * settings file sets these itself). */ +#ifdef CONFIG_WOLFSSL_CRYPTO_ONLY + #define WOLFCRYPT_ONLY +#endif +#ifdef CONFIG_WOLFSSL_SINGLE_THREADED + #define SINGLE_THREADED #endif /* ECC */ -#if 1 +#if defined(CONFIG_WOLFSSL_ECC) #define HAVE_ECC #define ECC_USER_CURVES /* Enable only ECC curves specific */ #undef NO_ECC256 /* Enable SECP256R1 only (on by default) */ @@ -225,7 +276,7 @@ extern "C" { #define WOLFSSL_OLD_PRIME_CHECK /* Use faster DH prime checking */ /* RSA */ -#if 1 +#if defined(CONFIG_WOLFSSL_RSA) #undef NO_RSA #define WC_RSA_BLINDING //#define WC_RSA_NO_PADDING @@ -256,7 +307,7 @@ extern "C" { #endif /* ChaCha20 / Poly1305 */ -#if 1 +#if defined(CONFIG_WOLFSSL_CHACHA_POLY) #define HAVE_CHACHA #define HAVE_POLY1305 @@ -265,7 +316,7 @@ extern "C" { #endif /* Ed25519 / Curve25519 */ -#if 0 +#if defined(CONFIG_WOLFSSL_CURVE25519) #define HAVE_CURVE25519 #define HAVE_ED25519 /* ED25519 Requires SHA512 */ @@ -358,13 +409,52 @@ extern "C" { #define NO_MD5 //#define NO_DES3 /* Necessary for pkcs12 tests */ -/* PQC ML-KEM */ +/* PQC families -- each independently selectable so a Kconfig-driven build (no + * user-provided settings file) can include only what a consumer needs and keep + * the flash footprint down. All default off. */ #if defined(CONFIG_WOLFSSL_MLKEM) #define WOLFSSL_HAVE_MLKEM #define WOLFSSL_MLKEM_NO_LARGE_CODE #define WOLFSSL_MLKEM_SMALL #define WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM #define WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM + #define WOLFSSL_MLKEM_DYNAMIC_KEYS +#endif + +#if defined(CONFIG_WOLFSSL_MLDSA) + #define WOLFSSL_HAVE_MLDSA + #define WOLFSSL_MLDSA_NO_LARGE_CODE + #define WOLFSSL_MLDSA_SMALL + #define WOLFSSL_MLDSA_VERIFY_SMALL_MEM + #define WOLFSSL_MLDSA_DYNAMIC_KEYS + #define WOLFSSL_MLDSA_SIGN_SMALL_MEM + #define WOLFSSL_MLDSA_MAKE_KEY_SMALL_MEM +#endif + +#if defined(CONFIG_WOLFSSL_LMS) + #define WOLFSSL_HAVE_LMS + #define WOLFSSL_LMS_VERIFY_ONLY +#endif + +#if defined(CONFIG_WOLFSSL_XMSS) + #define WOLFSSL_HAVE_XMSS + #define WOLFSSL_XMSS_VERIFY_ONLY +#endif + +#if defined(CONFIG_WOLFSSL_FALCON) + #define WOLFSSL_EXPERIMENTAL_SETTINGS /* HAVE_FALCON is gated experimental */ + #define HAVE_FALCON + /* Small-memory dynamic signer instead of the fast tree-signer (keeps full + * sign+verify); the default portable integer FPR backend needs no ASM. */ + #define WOLFSSL_FALCON_SIGN_SMALL_MEM +#endif + +/* SHA-3 / SHAKE are required by ML-KEM, ML-DSA, and Falcon; enable them (small + * variant) when any is on, and explicitly disable SHAKE otherwise to keep a + * non-PQC build lean. */ +#if defined(CONFIG_WOLFSSL_MLKEM) || defined(CONFIG_WOLFSSL_MLDSA) || \ + defined(CONFIG_WOLFSSL_FALCON) + #define WOLFSSL_SHA3_SMALL #define WOLFSSL_SHAKE128 #define WOLFSSL_SHAKE256 #else @@ -496,7 +586,8 @@ extern "C" { } #endif -#endif /* CONFIG_WOLFSSL_SETTINGS_FILE */ +#endif /* WOLFSSL_SETTINGS_FILE */ + #endif /* CONFIG_WOLFSSL */ #endif /* USER_SETTINGS_H */ diff --git a/zephyr/zephyr_init.c b/zephyr/zephyr_init.c index 1516264eb5f..033f436d41f 100644 --- a/zephyr/zephyr_init.c +++ b/zephyr/zephyr_init.c @@ -19,4 +19,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -/* Not needed. Keeping file for backwards compatibility. */ +/* The wolfSSL Zephyr module needs no boot-time SYS_INIT hook. wolfCrypt's + * Hash-DRBG is seeded on demand by wc_GenerateSeed() -- which on Zephyr draws + * from the hardware entropy driver when one is present (see + * wolfcrypt/src/random.c) -- and wolfCrypt_Init()/wolfSSL_Init() run lazily + * from the first library call. This translation unit is kept (it is referenced + * by the module CMakeLists) as the place for any future module init. */