From 7f595dc984603c100d7d594559ab390902fa9dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 7 Sep 2026 07:13:13 +0200 Subject: [PATCH 01/13] settings: detect any M-profile core without UMAAL, not just the Cortex-M3 WOLFSSL_ARM_ARCH_7M selects the UMAAL-free variants in sp_cortexm.c and in the thumb2-* assembly for Poly1305, Curve25519 and ML-KEM. It was derived from __ARM_ARCH_7M__, which names the Cortex-M3 and nothing else. UMAAL is not an ARMv7-M property though, it belongs to the DSP extension, which on ARMv8-M is optional. An ARMv8-M part built without it, such as the Cortex-M33 in the NXP RW612, has no UMAAL and no __ARM_ARCH_7M__ either, so it took the UMAAL path and would not assemble. WOLFSSL_SP_NO_UMAAL is not a way out: it is derived from this symbol and covers only a subset of the sites. Toolchains define __ARM_FEATURE_DSP exactly when the extension is present, so key on its absence on an M-profile core. Verified against gcc for M0, M3, M4, M7, M23, M33 and M33+nodsp: it is set only where UMAAL is genuinely missing. The __ARM_ARCH_7M__ arm stays, so no configuration that worked before changes, and the __ARM_ARCH_PROFILE test matches the one already in cpuid.c. --- wolfssl/wolfcrypt/settings.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index b111438a368..7f032e2e498 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -3016,8 +3016,14 @@ #define HAVE_AESGCM #endif -/* Detect Cortex M3 (no UMAAL) */ -#if defined(__ARM_ARCH_7M__) && !defined(WOLFSSL_ARM_ARCH_7M) +/* Detect an M-profile core without UMAAL, which selects the UMAAL-free + * variants in sp_cortexm.c and the thumb2-* assembly. That is the Cortex-M3, + * and equally any ARMv8-M part built without the optional DSP extension - a + * case __ARM_ARCH_7M__ alone does not catch. Toolchains define + * __ARM_FEATURE_DSP exactly when the extension, and so UMAAL, is present. */ +#if !defined(WOLFSSL_ARM_ARCH_7M) && !defined(__ARM_FEATURE_DSP) && \ + (defined(__ARM_ARCH_7M__) || \ + (defined(__ARM_ARCH_PROFILE) && (__ARM_ARCH_PROFILE == 'M'))) #define WOLFSSL_ARM_ARCH_7M #endif #if defined(WOLFSSL_SP_ARM_CORTEX_M_ASM) && defined(WOLFSSL_ARM_ARCH_7M) From 3362737cab949c1cf4d9ed7e054e851c6bd180b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 7 Sep 2026 16:56:24 +0200 Subject: [PATCH 02/13] settings: keep the Zephyr platform block away from the assembler The WOLFSSL_ZEPHYR block includes , , and , and declares z_realloc. Assembly sources reach settings.h through libwolfssl_sources_asm.h, so all of that was being handed to the assembler, which stops at the first C declaration it meets: stddef.h:160: Error: no such instruction: `typedef long int ptrdiff_t' That makes every wolfSSL .S file unbuildable on Zephyr. It is not specific to one architecture or one algorithm - reproduced on x86_64 with chacha_asm.S, sha256_asm.S, sha512_asm.S and aes_asm.S, and on a Cortex-M33 with thumb2-aes-asm.S, which fails identically: stddef.h:160: Error: bad instruction `typedef int ptrdiff_t' Zephyr ports that use the *_c.c inline-assembly variants never noticed, because those are compiled as C. Guard the block with __ASSEMBLER__, matching what settings.h already does for the STM32MP13 header. Assembly still gets the feature macros from user_settings.h; it just no longer gets the C declarations. No effect on any C translation unit - __ASSEMBLER__ is only defined when the compiler driver is assembling. --- wolfssl/wolfcrypt/settings.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 7f032e2e498..ba9a66bf3c0 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -3105,6 +3105,10 @@ #endif /*(WOLFSSL_APACHE_MYNEWT)*/ #ifdef WOLFSSL_ZEPHYR +/* Assembly sources reach settings.h through libwolfssl_sources_asm.h and need + * only the feature macros. The Zephyr headers below, and the z_realloc + * prototype, are C - without this guard the assembler is handed . */ +#ifndef __ASSEMBLER__ #ifdef __cplusplus } /* extern "C" */ #endif @@ -3177,6 +3181,7 @@ #define CONFIG_NET_SOCKETS_POSIX_NAMES #endif #endif +#endif /* !__ASSEMBLER__ */ #endif /* WOLFSSL_ZEPHYR */ #ifdef WOLFSSL_IMX6 From 4bc21657126c2e7d791445d106f6debcfbb28979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 7 Sep 2026 16:56:36 +0200 Subject: [PATCH 03/13] sp_x86_64: spell the register bindings __asm__ so strict ISO C accepts them The nine div-word helpers bind a variable to rax with the bare asm keyword: register sp_digit r asm("rax"); asm is a GNU extension, not an ISO C keyword, so it is unavailable under -std=c17 and the file will not compile: sp_x86_64.c:597: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'asm' Zephyr compiles with -std=c17, which is how this surfaced, but any strict-ISO build hits it. __asm__ is the alternate spelling GCC and Clang keep available regardless of -std, and it is what the very next line of each of these functions already uses for the statement asm - so this only makes the two consistent. --- wolfcrypt/src/sp_x86_64.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/wolfcrypt/src/sp_x86_64.c b/wolfcrypt/src/sp_x86_64.c index 220550e4e6c..48c1bd2da83 100644 --- a/wolfcrypt/src/sp_x86_64.c +++ b/wolfcrypt/src/sp_x86_64.c @@ -594,7 +594,7 @@ static WC_INLINE sp_digit div_2048_word_16(sp_digit d1, sp_digit d0, static WC_INLINE sp_digit div_2048_word_16(sp_digit d1, sp_digit d0, sp_digit div) { - register sp_digit r asm("rax"); + register sp_digit r __asm__("rax"); __asm__ __volatile__ ( "divq %3" : "=a" (r) @@ -1277,7 +1277,7 @@ static WC_INLINE sp_digit div_2048_word_32(sp_digit d1, sp_digit d0, static WC_INLINE sp_digit div_2048_word_32(sp_digit d1, sp_digit d0, sp_digit div) { - register sp_digit r asm("rax"); + register sp_digit r __asm__("rax"); __asm__ __volatile__ ( "divq %3" : "=a" (r) @@ -3482,7 +3482,7 @@ static WC_INLINE sp_digit div_3072_word_24(sp_digit d1, sp_digit d0, static WC_INLINE sp_digit div_3072_word_24(sp_digit d1, sp_digit d0, sp_digit div) { - register sp_digit r asm("rax"); + register sp_digit r __asm__("rax"); __asm__ __volatile__ ( "divq %3" : "=a" (r) @@ -4165,7 +4165,7 @@ static WC_INLINE sp_digit div_3072_word_48(sp_digit d1, sp_digit d0, static WC_INLINE sp_digit div_3072_word_48(sp_digit d1, sp_digit d0, sp_digit div) { - register sp_digit r asm("rax"); + register sp_digit r __asm__("rax"); __asm__ __volatile__ ( "divq %3" : "=a" (r) @@ -6176,7 +6176,7 @@ static WC_INLINE sp_digit div_4096_word_64(sp_digit d1, sp_digit d0, static WC_INLINE sp_digit div_4096_word_64(sp_digit d1, sp_digit d0, sp_digit div) { - register sp_digit r asm("rax"); + register sp_digit r __asm__("rax"); __asm__ __volatile__ ( "divq %3" : "=a" (r) @@ -24637,7 +24637,7 @@ static WC_INLINE sp_digit div_256_word_4(sp_digit d1, sp_digit d0, static WC_INLINE sp_digit div_256_word_4(sp_digit d1, sp_digit d0, sp_digit div) { - register sp_digit r asm("rax"); + register sp_digit r __asm__("rax"); __asm__ __volatile__ ( "divq %3" : "=a" (r) @@ -49485,7 +49485,7 @@ static WC_INLINE sp_digit div_384_word_6(sp_digit d1, sp_digit d0, static WC_INLINE sp_digit div_384_word_6(sp_digit d1, sp_digit d0, sp_digit div) { - register sp_digit r asm("rax"); + register sp_digit r __asm__("rax"); __asm__ __volatile__ ( "divq %3" : "=a" (r) @@ -90454,7 +90454,7 @@ static WC_INLINE sp_digit div_521_word_9(sp_digit d1, sp_digit d0, static WC_INLINE sp_digit div_521_word_9(sp_digit d1, sp_digit d0, sp_digit div) { - register sp_digit r asm("rax"); + register sp_digit r __asm__("rax"); __asm__ __volatile__ ( "divq %3" : "=a" (r) @@ -92647,7 +92647,7 @@ static WC_INLINE sp_digit div_1024_word_16(sp_digit d1, sp_digit d0, static WC_INLINE sp_digit div_1024_word_16(sp_digit d1, sp_digit d0, sp_digit div) { - register sp_digit r asm("rax"); + register sp_digit r __asm__("rax"); __asm__ __volatile__ ( "divq %3" : "=a" (r) From d069f5d269d4224bb6bbfda11321666a833ba52c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 7 Sep 2026 17:04:57 +0200 Subject: [PATCH 04/13] cpuid: only report vector ISAs the OS has enabled state for CPUID's AVX and AVX-512 bits say the silicon has the unit. Executing one of those instructions also requires the OS to have turned on extended state: CR4.OSXSAVE, plus the matching XCR0 components - SSE and AVX for VEX encodings, and opmask, ZMM_Hi256 and Hi16_ZMM on top of those for EVEX. An OS that does not context-switch those registers leaves them clear, and the instruction then raises #UD no matter what CPUID advertises. cpuid_set_flags() tested the feature bits alone, so on such a system wolfSSL set CPUID_AVX1/AVX2/VAES/AVX512* and dispatched to implementations the CPU would refuse. Zephyr is one such system - its x86 context switch is fxsave/fxrstor and it never sets CR4.OSXSAVE - and the result is an immediate crash the first time SHA-256 or AES-GCM picks a vector path: os: Invalid opcode >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0 Gate each family on OSXSAVE plus the XCR0 components it actually needs, the sequence Intel documents for this. The AVX-512 dispatch sites are the reason the masks have to differ: AesEcbEncryptBlocks(), AES_GCM_init_*, chacha_avx512_beneficial() and poly1305_use_avx512() all branch on IS_INTEL_AVX512 && IS_INTEL_VAES without consulting AVX1 or AVX2, so gating only the 256-bit flags would leave the 512-bit paths reachable on exactly the systems this is meant to protect. Keeping them on one gate would also be wrong in the other direction, since 0x06 does not cover the ZMM state. VAES is VEX or EVEX encoded, so it is gated with the AVX state; the AVX-512 dispatch sites test it alongside CPUID_AVX512, which carries the stricter mask. Where an OS does enable XSAVE, which is every mainstream one, nothing changes. XGETBV is itself only legal once OSXSAVE is set, so the two tests have to stay in that order. --- wolfcrypt/src/cpuid.c | 89 +++++++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 20 deletions(-) diff --git a/wolfcrypt/src/cpuid.c b/wolfcrypt/src/cpuid.c index fd8ec2d0088..d7ece10d894 100644 --- a/wolfcrypt/src/cpuid.c +++ b/wolfcrypt/src/cpuid.c @@ -85,6 +85,20 @@ #define cpuid(a,b,c) __cpuidex((int*)a,b,c) #endif /* _MSC_VER */ + /* Read XCR0. Only valid once CPUID.1:ECX.OSXSAVE[27] is known set. */ + #ifndef _MSC_VER + static WC_INLINE word32 cpuid_xgetbv0(void) + { + word32 eax, edx; + __asm__ __volatile__ ("xgetbv" + : "=a" (eax), "=d" (edx) : "c" (0)); + (void)edx; + return eax; + } + #else + #define cpuid_xgetbv0() ((word32)_xgetbv(0)) + #endif /* _MSC_VER */ + #define EAX 0 #define EBX 1 #define ECX 2 @@ -116,6 +130,31 @@ XMEMCMP((char *)&(reg[ECX]), "cAMD", 4) == 0); } + /* XCR0 state-component masks. AVX needs the SSE and AVX regions; AVX-512 + * also needs opmask, ZMM_Hi256 and Hi16_ZMM on top of them. */ + #define WC_XCR0_AVX 0x06 + #define WC_XCR0_AVX512 0xe6 + + /* Return 1 when the OS has enabled XSAVE and every state component in + * 'mask'. CPUID's feature bits only say the silicon has the unit; + * executing the instruction also needs CR4.OSXSAVE and the matching XCR0 + * bits, which an OS that does not context-switch those registers leaves + * clear. Without this test wolfSSL dispatches the vector code on such a + * system and it faults with #UD. */ + static int cpuid_os_state_enabled(word32 mask) + { + unsigned int reg[5]; + + XMEMSET(reg, '\0', sizeof(reg)); + cpuid(reg, 1, 0); + + /* CPUID.1:ECX.OSXSAVE[27] - XGETBV is illegal when this is clear. */ + if (((reg[ECX] >> 27) & 0x1) == 0) + return 0; + + return (cpuid_xgetbv0() & mask) == mask; + } + static cpuid_flags_t cpuid_flag(word32 leaf, word32 sub, word32 num, word32 bit) { @@ -139,8 +178,13 @@ #endif cpuid_flags_t new_cpuid_flags = 0, old_cpuid_flags = WC_CPUID_INITIALIZER; - if (cpuid_flag(1, 0, ECX, 28)) { new_cpuid_flags |= CPUID_AVX1 ; } - if (cpuid_flag(7, 0, EBX, 5)) { new_cpuid_flags |= CPUID_AVX2 ; } + int os_avx = cpuid_os_state_enabled(WC_XCR0_AVX); + int os_avx512 = cpuid_os_state_enabled(WC_XCR0_AVX512); + + if (os_avx) { + if (cpuid_flag(1, 0, ECX, 28)) { new_cpuid_flags |= CPUID_AVX1; } + if (cpuid_flag(7, 0, EBX, 5)) { new_cpuid_flags |= CPUID_AVX2; } + } if (cpuid_flag(7, 0, EBX, 8)) { new_cpuid_flags |= CPUID_BMI2 ; } if (cpuid_flag(1, 0, ECX, 30)) { new_cpuid_flags |= CPUID_RDRAND; } if (cpuid_flag(7, 0, EBX, 18)) { new_cpuid_flags |= CPUID_RDSEED; } @@ -149,25 +193,30 @@ if (cpuid_flag(1, 0, ECX, 22)) { new_cpuid_flags |= CPUID_MOVBE ; } if (cpuid_flag(7, 0, EBX, 3)) { new_cpuid_flags |= CPUID_BMI1 ; } if (cpuid_flag(7, 0, EBX, 29)) { new_cpuid_flags |= CPUID_SHA ; } - if (cpuid_flag(7, 0, ECX, 9)) { new_cpuid_flags |= CPUID_VAES ; } - if (cpuid_flag(7, 0, EBX, 16)) { new_cpuid_flags |= CPUID_AVX512; } - if (cpuid_flag(7, 0, ECX, 1)) { - new_cpuid_flags |= CPUID_AVX512_VBMI; - } - if (cpuid_flag(7, 0, ECX, 6)) { - new_cpuid_flags |= CPUID_AVX512_VBMI2; - } - if (cpuid_flag(7, 0, EBX, 21)) { - new_cpuid_flags |= CPUID_AVX512_IFMA; - } - if (cpuid_flag(7, 0, EBX, 31)) { - new_cpuid_flags |= CPUID_AVX512_VL; - } - if (cpuid_flag(7, 0, EBX, 17)) { - new_cpuid_flags |= CPUID_AVX512_DQ; + /* VAES is VEX/EVEX encoded, so it needs the AVX state too. */ + if (os_avx && cpuid_flag(7, 0, ECX, 9)) { + new_cpuid_flags |= CPUID_VAES; } - if (cpuid_flag(7, 0, EBX, 30)) { - new_cpuid_flags |= CPUID_AVX512_BW; + if (os_avx512) { + if (cpuid_flag(7, 0, EBX, 16)) { new_cpuid_flags |= CPUID_AVX512; } + if (cpuid_flag(7, 0, ECX, 1)) { + new_cpuid_flags |= CPUID_AVX512_VBMI; + } + if (cpuid_flag(7, 0, ECX, 6)) { + new_cpuid_flags |= CPUID_AVX512_VBMI2; + } + if (cpuid_flag(7, 0, EBX, 21)) { + new_cpuid_flags |= CPUID_AVX512_IFMA; + } + if (cpuid_flag(7, 0, EBX, 31)) { + new_cpuid_flags |= CPUID_AVX512_VL; + } + if (cpuid_flag(7, 0, EBX, 17)) { + new_cpuid_flags |= CPUID_AVX512_DQ; + } + if (cpuid_flag(7, 0, EBX, 30)) { + new_cpuid_flags |= CPUID_AVX512_BW; + } } if (cpuid_is_intel()) { new_cpuid_flags |= CPUID_INTEL ; } if (cpuid_is_amd()) { new_cpuid_flags |= CPUID_AMD ; } From ab9a0651c0529652ec4fd55819e8b851d9661797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 8 Sep 2026 09:19:34 +0200 Subject: [PATCH 05/13] armv8: enable the crypto extension for the assembly that needs it The ARMv8 AES and SHA-256 ports emit aese, aesmc and the sha256 crypto instructions with no .arch or .arch_extension directive of their own, so they assemble only when the command line already names a CPU that has the extension. Built against plain ARMv8-A, which is what -mcpu=cortex-a53 gives you, the assembler refuses them: armv8-aes-asm.S: Error: selected processor does not support `aese v0.16b,v1.16b' Zephyr is one caller that lands there. It derives -mcpu from the board's Kconfig and has no symbol for the crypto extension, so there is nothing for a build system layered on top to key on, and naming a CPU in the module would retarget the library on every board that is not that CPU. Anything else compiling for the base architecture meets the same wall. A file-scope .arch_extension crypto applies to the rest of the translation unit, so one directive per file does what would otherwise take sixty inline copies. All three outputs carry it - bare in the GNU assembler file, wrapped in __asm__() in the C file, and a comment in the armasm64 file, which assembles these instructions unconditionally. Each sits inside the existing WOLFSSL_ARMASM_NO_HW_CRYPTO guard, so a build that has opted out of the hardware paths never asks for an extension it will not use. Regenerated from the scripts repository, which carries the matching change. Verified on qemu_cortex_a53 under Zephyr: wolfcrypt_test passes 43 of 43 with 2723 aese instructions in the image, where before neither file assembled. --- wolfcrypt/src/port/arm/armv8-aes-asm.S | 1 + wolfcrypt/src/port/arm/armv8-aes-asm.asm | 1 + wolfcrypt/src/port/arm/armv8-aes-asm_c.c | 1 + wolfcrypt/src/port/arm/armv8-sha256-asm.S | 1 + wolfcrypt/src/port/arm/armv8-sha256-asm.asm | 1 + wolfcrypt/src/port/arm/armv8-sha256-asm_c.c | 1 + 6 files changed, 6 insertions(+) diff --git a/wolfcrypt/src/port/arm/armv8-aes-asm.S b/wolfcrypt/src/port/arm/armv8-aes-asm.S index 6895ef04e8f..e75f4e526ee 100644 --- a/wolfcrypt/src/port/arm/armv8-aes-asm.S +++ b/wolfcrypt/src/port/arm/armv8-aes-asm.S @@ -35,6 +35,7 @@ #ifndef WOLFSSL_ARMASM_INLINE #if !defined(NO_AES) && defined(WOLFSSL_ARMASM) #ifndef WOLFSSL_ARMASM_NO_HW_CRYPTO +.arch_extension crypto #ifndef __APPLE__ .text .globl AES_set_key_AARCH64 diff --git a/wolfcrypt/src/port/arm/armv8-aes-asm.asm b/wolfcrypt/src/port/arm/armv8-aes-asm.asm index 80ddad8cde1..f4d69a8111c 100644 --- a/wolfcrypt/src/port/arm/armv8-aes-asm.asm +++ b/wolfcrypt/src/port/arm/armv8-aes-asm.asm @@ -25,6 +25,7 @@ ; ../wolfssl/wolfcrypt/src/port/arm/armv8-aes-asm.asm IF :LNOT::DEF:NO_AES :LAND: {TRUE} IF :LNOT::DEF:WOLFSSL_ARMASM_NO_HW_CRYPTO +; .arch_extension crypto AREA |.text|, CODE, READONLY ALIGN 4 EXPORT AES_set_key_AARCH64 diff --git a/wolfcrypt/src/port/arm/armv8-aes-asm_c.c b/wolfcrypt/src/port/arm/armv8-aes-asm_c.c index a39acf46bae..bed06e982e3 100644 --- a/wolfcrypt/src/port/arm/armv8-aes-asm_c.c +++ b/wolfcrypt/src/port/arm/armv8-aes-asm_c.c @@ -38,6 +38,7 @@ #if !defined(NO_AES) && defined(WOLFSSL_ARMASM) #ifndef WOLFSSL_ARMASM_NO_HW_CRYPTO +__asm__(".arch_extension crypto"); void AES_set_key_AARCH64(const byte* userKey, int keylen, byte* key, int dir) { __asm__ __volatile__ ( diff --git a/wolfcrypt/src/port/arm/armv8-sha256-asm.S b/wolfcrypt/src/port/arm/armv8-sha256-asm.S index f8c26311b57..9a97d5b0950 100644 --- a/wolfcrypt/src/port/arm/armv8-sha256-asm.S +++ b/wolfcrypt/src/port/arm/armv8-sha256-asm.S @@ -1058,6 +1058,7 @@ L_sha256_len_neon_start: .size Transform_Sha256_Len_neon,.-Transform_Sha256_Len_neon #endif /* __APPLE__ */ #ifndef WOLFSSL_ARMASM_NO_HW_CRYPTO +.arch_extension crypto #ifndef __APPLE__ .text .section .rodata diff --git a/wolfcrypt/src/port/arm/armv8-sha256-asm.asm b/wolfcrypt/src/port/arm/armv8-sha256-asm.asm index 454fe592d32..f60d0e90d7d 100644 --- a/wolfcrypt/src/port/arm/armv8-sha256-asm.asm +++ b/wolfcrypt/src/port/arm/armv8-sha256-asm.asm @@ -1019,6 +1019,7 @@ L_sha256_len_neon_start ret ENDP IF :LNOT::DEF:WOLFSSL_ARMASM_NO_HW_CRYPTO +; .arch_extension crypto AREA |.rodata|, DATA, READONLY, ALIGN=4 ALIGN 8 L_SHA256_trans_crypto_len_k diff --git a/wolfcrypt/src/port/arm/armv8-sha256-asm_c.c b/wolfcrypt/src/port/arm/armv8-sha256-asm_c.c index 42b3a2b563e..0b6356ea054 100644 --- a/wolfcrypt/src/port/arm/armv8-sha256-asm_c.c +++ b/wolfcrypt/src/port/arm/armv8-sha256-asm_c.c @@ -1024,6 +1024,7 @@ void Transform_Sha256_Len_neon(wc_Sha256* sha256, const byte* data, word32 len) } #ifndef WOLFSSL_ARMASM_NO_HW_CRYPTO +__asm__(".arch_extension crypto"); XALIGNED(8) static const word32 L_SHA256_trans_crypto_len_k[] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, From 5ddbe55b829f7e732c16789cdd5ada4725499ce2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 8 Sep 2026 10:26:43 +0200 Subject: [PATCH 06/13] armv8: enable the SHA-3 extension for every assembler, not just Apple's The SHA-3, SHA-512 and FrodoKEM ARM64 ports guard their .arch_extension sha3 with __APPLE__, on the assumption that every other assembler learns about the extension from the command line. That does not hold. Assembling for plain ARMv8-A with the GNU assembler: armv8-sha3-asm.S: Error: selected processor does not support `eor3 v31.16b,v0.16b,v5.16b,v10.16b' Emit the directive unconditionally. It is a no-op where the extension is already enabled, so the Apple path is unchanged. Regenerated from the scripts repository, which carries the matching change. --- wolfcrypt/src/port/arm/armv8-frodokem-asm.S | 2 -- wolfcrypt/src/port/arm/armv8-frodokem-asm_c.c | 2 -- wolfcrypt/src/port/arm/armv8-sha3-asm.S | 2 -- wolfcrypt/src/port/arm/armv8-sha3-asm_c.c | 2 -- wolfcrypt/src/port/arm/armv8-sha512-asm.S | 2 -- wolfcrypt/src/port/arm/armv8-sha512-asm_c.c | 2 -- 6 files changed, 12 deletions(-) diff --git a/wolfcrypt/src/port/arm/armv8-frodokem-asm.S b/wolfcrypt/src/port/arm/armv8-frodokem-asm.S index 1e5188193fe..aba36e6d8bd 100644 --- a/wolfcrypt/src/port/arm/armv8-frodokem-asm.S +++ b/wolfcrypt/src/port/arm/armv8-frodokem-asm.S @@ -326,9 +326,7 @@ _frodokem_sha3_x2_crypto: adrp x1, L_sha3_aarch64_r@PAGE add x1, x1, L_sha3_aarch64_r@PAGEOFF #endif /* __APPLE__ */ -#ifdef __APPLE__ .arch_extension sha3 -#endif /* __APPLE__ */ ld4 {v0.d, v1.d, v2.d, v3.d}[0], [x0], #32 ld4 {v4.d, v5.d, v6.d, v7.d}[0], [x0], #32 ld4 {v8.d, v9.d, v10.d, v11.d}[0], [x0], #32 diff --git a/wolfcrypt/src/port/arm/armv8-frodokem-asm_c.c b/wolfcrypt/src/port/arm/armv8-frodokem-asm_c.c index 40bd4de1271..000f471aecd 100644 --- a/wolfcrypt/src/port/arm/armv8-frodokem-asm_c.c +++ b/wolfcrypt/src/port/arm/armv8-frodokem-asm_c.c @@ -272,9 +272,7 @@ void frodokem_sha3_x2_crypto(word64* state) { const word64* r = L_sha3_aarch64_r; __asm__ __volatile__ ( -#ifdef __APPLE__ ".arch_extension sha3\n\t" -#endif /* __APPLE__ */ "ld4 {v0.d, v1.d, v2.d, v3.d}[0], [%x[state]], #32\n\t" "ld4 {v4.d, v5.d, v6.d, v7.d}[0], [%x[state]], #32\n\t" "ld4 {v8.d, v9.d, v10.d, v11.d}[0], [%x[state]], #32\n\t" diff --git a/wolfcrypt/src/port/arm/armv8-sha3-asm.S b/wolfcrypt/src/port/arm/armv8-sha3-asm.S index c9ad4a5f333..021f6a513fa 100644 --- a/wolfcrypt/src/port/arm/armv8-sha3-asm.S +++ b/wolfcrypt/src/port/arm/armv8-sha3-asm.S @@ -89,9 +89,7 @@ _BlockSha3_crypto: adrp x1, L_SHA3_transform_crypto_r@PAGE add x1, x1, L_SHA3_transform_crypto_r@PAGEOFF #endif /* __APPLE__ */ -#ifdef __APPLE__ .arch_extension sha3 -#endif /* __APPLE__ */ ld4 {v0.d, v1.d, v2.d, v3.d}[0], [x0], #32 ld4 {v4.d, v5.d, v6.d, v7.d}[0], [x0], #32 ld4 {v8.d, v9.d, v10.d, v11.d}[0], [x0], #32 diff --git a/wolfcrypt/src/port/arm/armv8-sha3-asm_c.c b/wolfcrypt/src/port/arm/armv8-sha3-asm_c.c index 264be7b156e..0386dfd2445 100644 --- a/wolfcrypt/src/port/arm/armv8-sha3-asm_c.c +++ b/wolfcrypt/src/port/arm/armv8-sha3-asm_c.c @@ -57,9 +57,7 @@ void BlockSha3_crypto(word64* state) { const word64* r = L_SHA3_transform_crypto_r; __asm__ __volatile__ ( -#ifdef __APPLE__ ".arch_extension sha3\n\t" -#endif /* __APPLE__ */ "ld4 {v0.d, v1.d, v2.d, v3.d}[0], [%x[state]], #32\n\t" "ld4 {v4.d, v5.d, v6.d, v7.d}[0], [%x[state]], #32\n\t" "ld4 {v8.d, v9.d, v10.d, v11.d}[0], [%x[state]], #32\n\t" diff --git a/wolfcrypt/src/port/arm/armv8-sha512-asm.S b/wolfcrypt/src/port/arm/armv8-sha512-asm.S index 2e894827c84..298e19b3c0d 100644 --- a/wolfcrypt/src/port/arm/armv8-sha512-asm.S +++ b/wolfcrypt/src/port/arm/armv8-sha512-asm.S @@ -1136,9 +1136,7 @@ _Transform_Sha512_Len_crypto: adrp x4, L_SHA512_trans_crypto_len_k@PAGE add x4, x4, L_SHA512_trans_crypto_len_k@PAGEOFF #endif /* __APPLE__ */ -#ifdef __APPLE__ .arch_extension sha3 -#endif /* __APPLE__ */ # Load K into vector registers ld1 {v8.2d, v9.2d, v10.2d, v11.2d}, [x4], #0x40 ld1 {v12.2d, v13.2d, v14.2d, v15.2d}, [x4], #0x40 diff --git a/wolfcrypt/src/port/arm/armv8-sha512-asm_c.c b/wolfcrypt/src/port/arm/armv8-sha512-asm_c.c index 852e3c3ffdf..c7e9eac1a92 100644 --- a/wolfcrypt/src/port/arm/armv8-sha512-asm_c.c +++ b/wolfcrypt/src/port/arm/armv8-sha512-asm_c.c @@ -1050,9 +1050,7 @@ void Transform_Sha512_Len_crypto(wc_Sha512* sha512, const byte* data, { const word64* k = L_SHA512_trans_crypto_len_k; __asm__ __volatile__ ( -#ifdef __APPLE__ ".arch_extension sha3\n\t" -#endif /* __APPLE__ */ /* Load K into vector registers */ "ld1 {v8.2d, v9.2d, v10.2d, v11.2d}, [%[k]], #0x40\n\t" "ld1 {v12.2d, v13.2d, v14.2d, v15.2d}, [%[k]], #0x40\n\t" From 71977136561bbaac69e938df292b1f51d4f0ab7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 8 Sep 2026 17:08:47 +0200 Subject: [PATCH 07/13] armv8: keep the ML-KEM constants inside their feature guard L_mlkem_aarch64_consts sat outside the WOLFSSL_HAVE_MLKEM conditional while every other constant in the file - zetas, zetas_inv, q - sat inside it. With ML-KEM off the C output then declares a static const nothing references, and a -Werror build stops: armv8-mlkem-asm_c.c:37: error: 'L_mlkem_aarch64_consts' defined but not used [-Werror=unused-const-variable=] Zephyr compiles wolfSSL with -Werror, so this made armv8-mlkem-asm_c.c unbuildable on any aarch64 target that does not enable ML-KEM - which is every one of them by default. The cause is in the generator: Kyber_ARM64_Neon_ASM#initialize emitted the constant, but write() is what opens the guard, and it runs later. Fixed there by moving the emission into a define_consts() called from write(), mirroring the existing define_q(); these files are the regenerated result. All three outputs change by the same three-line move and nothing else. --- wolfcrypt/src/port/arm/armv8-mlkem-asm.S | 2 +- wolfcrypt/src/port/arm/armv8-mlkem-asm.asm | 2 +- wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/wolfcrypt/src/port/arm/armv8-mlkem-asm.S b/wolfcrypt/src/port/arm/armv8-mlkem-asm.S index 14010de9035..2e40f00d822 100644 --- a/wolfcrypt/src/port/arm/armv8-mlkem-asm.S +++ b/wolfcrypt/src/port/arm/armv8-mlkem-asm.S @@ -33,6 +33,7 @@ #ifdef WOLFSSL_ARMASM #ifdef __aarch64__ #ifndef WOLFSSL_ARMASM_INLINE +#ifdef WOLFSSL_HAVE_MLKEM #ifndef __APPLE__ .text .section .rodata @@ -49,7 +50,6 @@ #endif /* __APPLE__ */ L_mlkem_aarch64_consts: .short 0x0d01,0xf301,0x4ebf,0x0549,0x5049,0x0000,0x0000,0x0000 -#ifdef WOLFSSL_HAVE_MLKEM #ifndef __APPLE__ .text .section .rodata diff --git a/wolfcrypt/src/port/arm/armv8-mlkem-asm.asm b/wolfcrypt/src/port/arm/armv8-mlkem-asm.asm index d72216929d1..1c3cc6d4d75 100644 --- a/wolfcrypt/src/port/arm/armv8-mlkem-asm.asm +++ b/wolfcrypt/src/port/arm/armv8-mlkem-asm.asm @@ -23,11 +23,11 @@ ; cd ../scripts ; ruby ./kyber/kyber.rb arm64 \ ; ../wolfssl/wolfcrypt/src/port/arm/armv8-mlkem-asm.asm + IF :DEF:WOLFSSL_HAVE_MLKEM AREA |.rodata|, DATA, READONLY, ALIGN=4 ALIGN 8 L_mlkem_aarch64_consts DCW 0x0d01, 0xf301, 0x4ebf, 0x0549, 0x5049, 0x0000, 0x0000, 0x0000 - IF :DEF:WOLFSSL_HAVE_MLKEM AREA |.rodata|, DATA, READONLY, ALIGN=4 ALIGN 8 L_mlkem_aarch64_zetas diff --git a/wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c b/wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c index 2b1f5b40b0f..e3c7884139c 100644 --- a/wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c +++ b/wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c @@ -34,13 +34,13 @@ #ifdef WOLFSSL_ARMASM #ifdef __aarch64__ #ifdef WOLFSSL_ARMASM_INLINE +#include + +#ifdef WOLFSSL_HAVE_MLKEM XALIGNED(4) static const word16 L_mlkem_aarch64_consts[] = { 0x0d01, 0xf301, 0x4ebf, 0x0549, 0x5049, 0x0000, 0x0000, 0x0000, }; -#include - -#ifdef WOLFSSL_HAVE_MLKEM XALIGNED(4) static const word16 L_mlkem_aarch64_zetas[] = { 0x08ed, 0x0a0b, 0x0b9a, 0x0714, 0x05d5, 0x058e, 0x011f, 0x00ca, 0x0c56, 0x026e, 0x0629, 0x00b6, 0x03c2, 0x084f, 0x073f, 0x05bc, From 9232649f268ddc1fe8836ac008cc8fa667143783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 8 Sep 2026 17:09:01 +0200 Subject: [PATCH 08/13] ecc: give the curve ceiling the bit custom curves need A WOLFSSL_CUSTOM_CURVES build fails at runtime on its own largest enabled curve. Enabling Brainpool with sizes 256, 384 and 512 gives ecc_test_curve_size 64 failed! (WC_KEY_SIZE_E, -234) and it is not a bp512 quirk: a bp256-only build fails on bp256, a bp256+bp384 build on bp384. Every time it is the largest curve in the set. The ceiling is off by exactly one bit. Under custom curves ECC_KEY_MAX_BITS() takes the "dp->size * 8 + 1" variant, for orders a bit larger than their prime, but MAX_ECC_BITS_NEEDED is the plain curve size. MP_BITS_CNT() rounds up to whole digits, so that single bit puts the key one digit past the ceiling and MP_BITS_OVER_MAX() rejects it. Carry the same bit in the ceiling via MAX_ECC_BITS_EXTRA, and compare against it in the guard that rejects a too-small user MAX_ECC_BITS. Second, MAX_ECC_BITS_USE derived from MAX_ECC_BITS_NEEDED, so the overridable MAX_ECC_BITS never reached the runtime guard - defining it larger changed the key struct but not the check, and there was no way to size the working values for a curve that is not compiled in. Derive it from MAX_ECC_BITS instead; ecc.h already refuses a value below what the enabled curves need, so this only ever widens, and it is what an arbitrary curve passed to wc_ecc_set_custom_curve() needs. Both are no-ops for a build without custom curves. --- wolfcrypt/src/ecc.c | 8 ++++++-- wolfssl/wolfcrypt/ecc.h | 14 ++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 37b64a89efe..766c77e95a9 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -349,10 +349,14 @@ ECC Curve Sizes: #define HAVE_ECC_CHECK_PUBKEY_ORDER #endif -#if defined(WOLFSSL_SP_MATH_ALL) && SP_INT_BITS < MAX_ECC_BITS_NEEDED +/* MAX_ECC_BITS is MAX_ECC_BITS_NEEDED unless the user raised it, and ecc.h + * rejects a smaller one, so this is the ceiling the caller actually asked for. + * Raising it sizes the working values for a curve that is not compiled in, + * which is what an arbitrary curve passed to wc_ecc_set_custom_curve needs. */ +#if defined(WOLFSSL_SP_MATH_ALL) && SP_INT_BITS < MAX_ECC_BITS #define MAX_ECC_BITS_USE SP_INT_BITS #else -#define MAX_ECC_BITS_USE MAX_ECC_BITS_NEEDED +#define MAX_ECC_BITS_USE MAX_ECC_BITS #endif #if !defined(WOLFSSL_CUSTOM_CURVES) && (ECC_MIN_KEY_SZ > 160) && \ diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index d3785827f40..5a3ce363dca 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -128,10 +128,20 @@ #define MAX_ECC_BITS_NEEDED 112 #endif +/* A custom-curve build takes the ECC_KEY_MAX_BITS variant that adds a bit for + * an order larger than the prime, so the ceiling has to carry that bit too - + * without it the largest curve compiled in does not fit the ceiling its own + * size derives. */ +#ifdef WOLFSSL_CUSTOM_CURVES + #define MAX_ECC_BITS_EXTRA 1 +#else + #define MAX_ECC_BITS_EXTRA 0 +#endif + #ifndef MAX_ECC_BITS - #define MAX_ECC_BITS MAX_ECC_BITS_NEEDED + #define MAX_ECC_BITS (MAX_ECC_BITS_NEEDED + MAX_ECC_BITS_EXTRA) #else - #if MAX_ECC_BITS_NEEDED > MAX_ECC_BITS + #if (MAX_ECC_BITS_NEEDED + MAX_ECC_BITS_EXTRA) > MAX_ECC_BITS #error configured MAX_ECC_BITS is less than required by enabled curves. #endif #endif From 7ec130a2a4b7ecf3aa09e7aa82802f761a42d9cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Sun, 30 Aug 2026 11:39:02 +0200 Subject: [PATCH 09/13] zephyr: select ECC curves through Kconfig The module hard-coded ECC_USER_CURVES with SECP256R1 and nothing else, so an application needing P-384, P-521 or a Brainpool curve had to patch user_settings.h. Each curve is now its own Kconfig option under WOLFSSL_ECC, with P-256 the default so existing configurations are unaffected. Two dependencies are encoded here rather than left for the next person to hit, because both fail in a way that does not point at the cause. Brainpool needs custom-curve support. Its curves are not prime-field NIST curves, and ecc.c refuses to build them without WOLFSSL_CUSTOM_CURVES. Custom curves in turn cannot coexist with the per-curve SP math this module selects, because SP's fast paths are written per curve and cannot represent an arbitrary one. Asking for Brainpool therefore moves the whole build onto the generic SP variant, which costs size and costs speed on the common curves. That is a real trade-off, and it is why Brainpool is opt-in. Brainpool also selects P-521, which is worth spelling out because it looks like overreach. On the generic variant an operation needs digit headroom above the modulus, so the enabled-curve ceiling has to be strictly larger than the largest Brainpool curve reachable; when it is not, that curve fails at runtime with WC_KEY_SIZE_E. Measured on native_sim: brainpoolP256r1 fails with a 256-bit ceiling, brainpoolP384r1 with a 384-bit one and brainpoolP512r1 with a 512-bit one - each time the largest curve in the set. The ceiling is MAX_ECC_BITS_NEEDED, which ecc.c derives from the enabled HAVE_ECCxxx set alone, so no other knob raises it. Brainpool stops at 512 bits, which makes P-521 the only size that lifts the ceiling without bringing a new Brainpool curve along with it. P-256 keeps its inverted sense: it is the one curve wolfCrypt enables by default, so it is turned off by defining NO_ECC256 rather than by omission. Verified on frdm_rw612. With P-384 and P-521 selected, all three curves generate a key and round-trip a signature on device; with the defaults the image is unchanged at P-256 only and 20 KB smaller, since neither the extra curves nor the generic math are pulled in. --- zephyr/Kconfig | 62 +++++++++++++++++++++++++++++++++++++++++- zephyr/user_settings.h | 58 +++++++++++++++++++++++++++++++++------ 2 files changed, 110 insertions(+), 10 deletions(-) diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 1e96b8bf46b..d658a9b5a11 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -178,7 +178,63 @@ config WOLFSSL_ECC bool "wolfCrypt ECC support" default y help - Enable ECC (HAVE_ECC, SECP256R1). + Enable ECC (HAVE_ECC). At least one curve must be selected below - a + build with none is rejected, because wolfCrypt has no curve table to + size its types from. + +if WOLFSSL_ECC + +config WOLFSSL_ECC_256 + bool "SECP256R1 (P-256)" + default y + help + Enable the NIST P-256 curve. This is the curve TLS uses by default, so + leave it on unless you know the whole application avoids it. + +config WOLFSSL_ECC_384 + bool "SECP384R1 (P-384)" + help + Enable the NIST P-384 curve (HAVE_ECC384 and the SP implementation + behind WOLFSSL_SP_384). + + Enabling a curve larger than P-256 raises MAX_ECC_BYTES, so every ECC + key, signature buffer and temporary grows accordingly - including on the + stack. Size thread stacks for the largest curve selected. + +config WOLFSSL_ECC_512 + bool "512-bit curves" + help + Enable the 512-bit curve size (HAVE_ECC512). There is no NIST curve at + this size - it exists for brainpoolP512r1, so it is only useful together + with WOLFSSL_ECC_BRAINPOOL. SP math has no implementation at this size, + so selecting it forces the generic SP variant. + +config WOLFSSL_ECC_521 + bool "SECP521R1 (P-521)" + help + Enable the NIST P-521 curve (HAVE_ECC521 and the SP implementation + behind WOLFSSL_SP_521). This sets the largest MAX_ECC_BYTES of any + supported curve. + + Its SP implementation is also the most stack-hungry: a thread signing on + P-521 overflowed a 16 KB stack during bring-up and needed roughly three + times that. Raise CONFIG_MAIN_STACK_SIZE and any relevant thread stack, + or set WOLFSSL_SMALL_STACK to move the intermediates onto the heap. + +config WOLFSSL_ECC_BRAINPOOL + bool "Brainpool curves" + help + Enable the Brainpool curve family (HAVE_ECC_BRAINPOOL). Each curve also + needs its matching size enabled: brainpoolP256r1 needs WOLFSSL_ECC_256, + brainpoolP384r1 needs WOLFSSL_ECC_384 and brainpoolP512r1 needs + WOLFSSL_ECC_512. + + Implies WOLFSSL_CUSTOM_CURVES, which wolfCrypt requires for any + non-prime-field curve, and that moves the whole build onto the generic + SP variant - slower and larger on the common curves, which is why this + is opt-in. + +endif # WOLFSSL_ECC config WOLFSSL_CHACHA_POLY bool "wolfCrypt ChaCha20-Poly1305 support" @@ -282,6 +338,10 @@ config WOLFSSL_INSTALL_PATH installed. Make sure this option is properly set when WOLFSSL_LIBRARY is enabled otherwise the build will fail. +module = WOLFSSL +module-str = wolfssl +source "subsys/logging/Kconfig.template.log_config" + config APP_LINK_WITH_WOLFSSL bool "Link 'app' with WOLFSSL" default y diff --git a/zephyr/user_settings.h b/zephyr/user_settings.h index caacdd2e116..737ed965ce7 100644 --- a/zephyr/user_settings.h +++ b/zephyr/user_settings.h @@ -303,16 +303,41 @@ extern "C" { /* ECC */ #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) */ + #define ECC_USER_CURVES /* only the curves selected below */ #define ECC_TIMING_RESISTANT /* Enable Timing Resistance */ + #if defined(CONFIG_WOLFSSL_ECC_256) + #undef NO_ECC256 + #else + #define NO_ECC256 + #endif + #if defined(CONFIG_WOLFSSL_ECC_384) + #define HAVE_ECC384 + #endif + #if defined(CONFIG_WOLFSSL_ECC_512) + #define HAVE_ECC512 + #endif + #if defined(CONFIG_WOLFSSL_ECC_521) + #define HAVE_ECC521 + #endif + /* Brainpool curves are not prime-field NIST curves, and wolfCrypt refuses + * to build them without custom-curve support - a hard #error in ecc.c. */ + #if defined(CONFIG_WOLFSSL_ECC_BRAINPOOL) + #define WOLFSSL_CUSTOM_CURVES + #define HAVE_ECC_BRAINPOOL + #endif + + #if defined(NO_ECC256) && !defined(HAVE_ECC384) && \ + !defined(HAVE_ECC512) && !defined(HAVE_ECC521) + /* Otherwise MAX_ECC_BITS_NEEDED never gets defined and the failure + * surfaces as an undeclared identifier inside ecc.h, pointing nowhere + * near the configuration choice that caused it. */ + #error "CONFIG_WOLFSSL_ECC requires at least one curve to be selected" + #endif + //#define ECC_SHAMIR /* Optional ECC calculation speed improvement if not using SP implementation */ - //#define WOLFSSL_CUSTOM_CURVES /* enable other curves (not just prime) */ //#define HAVE_ECC_SECPR2 //#define HAVE_ECC_SECPR3 - //#define HAVE_ECC_BRAINPOOL - //#define HAVE_ECC_KOBLITZ //#define HAVE_ECC_CDH /* Co-factor */ //#define HAVE_COMP_KEY /* Compressed key support */ //#define FP_ECC /* Fixed point caching - speed repeated operations against same key */ @@ -520,7 +545,14 @@ extern "C" { /* Math Options */ /* Multi-precision - generic math for all keys sizes and curves */ #if 1 - #define WOLFSSL_SP_MATH /* no multi-precision math, only single */ + /* SP has no implementation for the 512-bit size and no path for an + * arbitrary curve. Neither is a build failure - every operation fails at + * runtime with WC_KEY_SIZE_E - so move to the generic variant instead. */ + #if defined(WOLFSSL_CUSTOM_CURVES) || defined(HAVE_ECC512) + #define WOLFSSL_SP_MATH_ALL + #else + #define WOLFSSL_SP_MATH /* no multi-precision math, only single */ + #endif #elif 1 /* wolf mp math (sp_int.c) */ #define WOLFSSL_SP_MATH_ALL /* use SP math for all key sizes and curves */ @@ -563,9 +595,17 @@ extern "C" { #if 1 #ifdef HAVE_ECC #define WOLFSSL_HAVE_SP_ECC - //#define WOLFSSL_SP_NO_256 - //#define WOLFSSL_SP_384 - //#define WOLFSSL_SP_521 + /* Selecting a curve without its SP switch leaves it in wolfCrypt's + * table with no math behind it and no build diagnostic. */ + #if defined(NO_ECC256) + #define WOLFSSL_SP_NO_256 + #endif + #if defined(HAVE_ECC384) + #define WOLFSSL_SP_384 + #endif + #if defined(HAVE_ECC521) + #define WOLFSSL_SP_521 + #endif #endif #ifndef NO_RSA #define WOLFSSL_HAVE_SP_RSA From ae86a476acc8c1b5d51a50d1ed1f399aac3e6583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Sun, 30 Aug 2026 17:28:08 +0200 Subject: [PATCH 10/13] zephyr: cover the ECC curve options with Twister The curve Kconfigs decide which curves wolfCrypt compiles and which SP implementation backs them, and getting that pairing wrong fails at runtime with WC_KEY_SIZE_E rather than at build time. Two wolfssl_test scenarios pin the combinations that matter: the NIST curves on their per-curve SP paths with no custom curve in sight, and the Brainpool set that forces the generic backend and depends on the curve ceiling P-521 provides. --- .../samples/wolfssl_test/prj-ecc-custom.conf | 17 ++++++++++++++++ zephyr/samples/wolfssl_test/prj-ecc-nist.conf | 20 +++++++++++++++++++ zephyr/samples/wolfssl_test/sample.yaml | 14 +++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 zephyr/samples/wolfssl_test/prj-ecc-custom.conf create mode 100644 zephyr/samples/wolfssl_test/prj-ecc-nist.conf diff --git a/zephyr/samples/wolfssl_test/prj-ecc-custom.conf b/zephyr/samples/wolfssl_test/prj-ecc-custom.conf new file mode 100644 index 00000000000..4055b192c76 --- /dev/null +++ b/zephyr/samples/wolfssl_test/prj-ecc-custom.conf @@ -0,0 +1,17 @@ +# The custom-curve path: Brainpool requires WOLFSSL_CUSTOM_CURVES, which +# cannot coexist with the per-curve SP backend, so the module moves the whole +# build onto the generic one. Covers the 512 size, which exists only for +# brainpoolP512r1, and does so without P-521 - the curve ceiling now carries +# the extra bit custom curves need instead of borrowing it from a larger curve. +# Layered on top of prj.conf via CONF_FILE in sample.yaml. + +CONFIG_WOLFSSL_ECC=y +CONFIG_WOLFSSL_ECC_256=y +CONFIG_WOLFSSL_ECC_384=y +CONFIG_WOLFSSL_ECC_512=y +CONFIG_WOLFSSL_ECC_BRAINPOOL=y + +CONFIG_MAIN_STACK_SIZE=65536 + +# The generic backend allocates more per operation than the per-curve one. +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=65536 diff --git a/zephyr/samples/wolfssl_test/prj-ecc-nist.conf b/zephyr/samples/wolfssl_test/prj-ecc-nist.conf new file mode 100644 index 00000000000..2d1886da409 --- /dev/null +++ b/zephyr/samples/wolfssl_test/prj-ecc-nist.conf @@ -0,0 +1,20 @@ +# P-256 plus the two larger NIST curves, WITHOUT any custom-curve option. +# +# This combination is the one worth pinning: each larger curve needs its own +# SP implementation switch, and selecting the curve alone leaves it in +# wolfCrypt's table with no math behind it - a build that succeeds and then +# fails at runtime with WC_KEY_SIZE_E. Enabling Brainpool here would mask +# exactly that, because it forces the generic SP backend, which handles every +# curve. +# Layered on top of prj.conf via CONF_FILE in sample.yaml. + +CONFIG_WOLFSSL_ECC=y +CONFIG_WOLFSSL_ECC_256=y +CONFIG_WOLFSSL_ECC_384=y +CONFIG_WOLFSSL_ECC_521=y + +# P-521's SP path is markedly more stack-hungry than the smaller curves. +CONFIG_MAIN_STACK_SIZE=65536 + +# PKCS12 in the full suite needs more heap than the base sample allows. +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=65536 diff --git a/zephyr/samples/wolfssl_test/sample.yaml b/zephyr/samples/wolfssl_test/sample.yaml index e9fbbcdd24d..72091dcc989 100644 --- a/zephyr/samples/wolfssl_test/sample.yaml +++ b/zephyr/samples/wolfssl_test/sample.yaml @@ -19,3 +19,17 @@ tests: extra_args: CONF_FILE="prj-no-malloc.conf" integration_platforms: - qemu_x86 + sample.crypto.wolfssl_test_ecc_nist: + timeout: 400 + platform_allow: qemu_x86 + extra_args: CONF_FILE="prj.conf;prj-ecc-nist.conf" + integration_platforms: + - qemu_x86 + sample.crypto.wolfssl_test_ecc_custom: + # Brainpool forces the generic SP backend, which is slower than the + # per-curve one, and this runs the whole suite over every curve under QEMU. + timeout: 600 + platform_allow: qemu_x86 + extra_args: CONF_FILE="prj.conf;prj-ecc-custom.conf" + integration_platforms: + - qemu_x86 From 084e456f055853e73ff7c818c815fc18618a9ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 7 Sep 2026 07:14:47 +0200 Subject: [PATCH 11/13] zephyr: make the feature Kconfigs mean nothing when a settings file is used The build-profile options only write the module's user_settings.h, which is never read when the application supplies its own settings file. So CONFIG_WOLFSSL_ECC_384=y alongside a settings file was accepted and silently ignored, and the same went for every other feature option. They now depend on not having one, and disappear from the menu instead. This needs a tracking bool because WOLFSSL_SETTINGS_FILE is a string symbol and Kconfig evaluates a string in a logical context as always-false, which would have made every one of these dependencies quietly unsatisfiable. FIPS is gated on the master switch rather than on each version. WOLFCRYPT_FIPS writes HAVE_FIPS into user_settings.h, so it belongs under the rule; putting the dependency on the choice members alone would leave the version prompt visible with nothing selectable and its default unreachable, while CMake still compiled the FIPS bundle. Kconfig.tls-generic is left alone here. Only two of its 53 symbols reach any code, so gating the rest would make dead options look conditional; the commit after this one deletes the file and rehomes those two with the dependency. wolfssl_tls_sock's no-malloc scenario was setting five of those options next to a settings file, so they now name symbols that are not visible. Drop them and say why they are gone. Options that drive the build rather than the wolfCrypt configuration, meaning the implementation choice, the assembly port and the install path, are untouched and stay selectable either way. --- zephyr/Kconfig | 32 ++++++++++++++++++- .../wolfssl_tls_sock/prj-no-malloc.conf | 5 --- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/zephyr/Kconfig b/zephyr/Kconfig index d658a9b5a11..9f0d1e41ff1 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -61,11 +61,19 @@ config WOLFSSL_SETTINGS_FILE special TLS usage, use available Kconfig settings, or select an alternative config. +config WOLFSSL_HAS_SETTINGS_FILE + bool + default y if WOLFSSL_SETTINGS_FILE != "" + help + Set when the application supplies its own wolfSSL settings file. + That file is authoritative, so every option that works by writing a + define into the module's user_settings.h depends on this being clear. + rsource "Kconfig.tls-generic" config WOLFCRYPT_FIPS bool "wolfCrypt FIPS support" - depends on WOLFSSL_BUILTIN + depends on WOLFSSL_BUILTIN && !WOLFSSL_HAS_SETTINGS_FILE help Enable the wolfCrypt FIPS 140-3 module boundary. Requires the wolfSSL FIPS bundle (fips.c, fips_test.c, wolfcrypt_first.c, wolfcrypt_last.c) @@ -113,6 +121,7 @@ endchoice config WOLFSSL_CRYPTO_ONLY bool "Build wolfCrypt only (no TLS layer)" + depends on !WOLFSSL_HAS_SETTINGS_FILE depends on WOLFSSL_BUILTIN help Define WOLFCRYPT_ONLY: compile only the wolfCrypt crypto library and @@ -120,6 +129,7 @@ config WOLFSSL_CRYPTO_ONLY config WOLFSSL_SINGLE_THREADED bool "wolfCrypt single-threaded" + depends on !WOLFSSL_HAS_SETTINGS_FILE depends on WOLFSSL_BUILTIN default y if !MULTITHREADING help @@ -130,52 +140,62 @@ config WOLFSSL_SINGLE_THREADED config WOLFSSL_DTLS bool "wolfSSL DTLS support" + depends on !WOLFSSL_HAS_SETTINGS_FILE help Enable DTLS support config WOLFSSL_ALPN bool "wolfSSL ALPN support" + depends on !WOLFSSL_HAS_SETTINGS_FILE help Enable ALPN support config WOLFSSL_PSK bool "wolfSSL PSK support" + depends on !WOLFSSL_HAS_SETTINGS_FILE help Enable PSK support config WOLFSSL_MLKEM bool "wolfSSL PQC ML-KEM support" + depends on !WOLFSSL_HAS_SETTINGS_FILE help Enable PQC ML-KEM support for Key Exchange config WOLFSSL_MLDSA bool "wolfSSL PQC ML-DSA support" + depends on !WOLFSSL_HAS_SETTINGS_FILE help Enable PQC ML-DSA (Dilithium) signatures. config WOLFSSL_LMS bool "wolfSSL LMS/HSS hash-based signatures" + depends on !WOLFSSL_HAS_SETTINGS_FILE help Enable LMS/HSS stateful hash-based signature verification (verify-only). config WOLFSSL_XMSS bool "wolfSSL XMSS/XMSS^MT hash-based signatures" + depends on !WOLFSSL_HAS_SETTINGS_FILE help Enable XMSS/XMSS^MT stateful hash-based signature verification (verify-only). config WOLFSSL_FALCON bool "wolfSSL PQC Falcon signatures" + depends on !WOLFSSL_HAS_SETTINGS_FILE help Enable PQC Falcon (FN-DSA) signatures. config WOLFSSL_RSA bool "wolfCrypt RSA support" + depends on !WOLFSSL_HAS_SETTINGS_FILE default y help Enable RSA (define RSA support; NO_RSA when off). config WOLFSSL_ECC bool "wolfCrypt ECC support" + depends on !WOLFSSL_HAS_SETTINGS_FILE default y help Enable ECC (HAVE_ECC). At least one curve must be selected below - a @@ -238,36 +258,42 @@ endif # WOLFSSL_ECC config WOLFSSL_CHACHA_POLY bool "wolfCrypt ChaCha20-Poly1305 support" + depends on !WOLFSSL_HAS_SETTINGS_FILE default y help Enable ChaCha20 and Poly1305 (HAVE_CHACHA, HAVE_POLY1305). config WOLFSSL_CURVE25519 bool "wolfCrypt Curve25519 / Ed25519 support" + depends on !WOLFSSL_HAS_SETTINGS_FILE default n help Enable Curve25519 and Ed25519 (HAVE_CURVE25519, HAVE_ED25519). config WOLFSSL_SNI bool "wolfSSL Server Name Indication (SNI)" + depends on !WOLFSSL_HAS_SETTINGS_FILE default y help Enable TLS Server Name Indication (HAVE_SNI). config WOLFSSL_SESSION_CACHE bool "wolfSSL TLS session cache" + depends on !WOLFSSL_HAS_SETTINGS_FILE default y help Enable the TLS session cache (SMALL_SESSION_CACHE; NO_SESSION_CACHE off). config WOLFSSL_SESSION_TICKET bool "wolfSSL TLS session tickets" + depends on !WOLFSSL_HAS_SETTINGS_FILE default y help Enable TLS session tickets (HAVE_SESSION_TICKET, TLS 1.3 resumption). config WOLFSSL_MAX_FRAGMENT_LEN int + depends on !WOLFSSL_HAS_SETTINGS_FILE default 3 range 1 6 help @@ -276,21 +302,25 @@ config WOLFSSL_MAX_FRAGMENT_LEN config WOLFSSL_SESSION_EXPORT bool "wolfSSL session export support" + depends on !WOLFSSL_HAS_SETTINGS_FILE help Enable external session cache (HAVE_EXT_CACHE) config WOLFSSL_KEEP_PEER_CERT bool "wolfSSL keep peer certificate support" + depends on !WOLFSSL_HAS_SETTINGS_FILE help Retain peer certificate after handshake (KEEP_PEER_CERT) config WOLFSSL_ALWAYS_VERIFY_CB bool "wolfSSL always invoke verify callback" + depends on !WOLFSSL_HAS_SETTINGS_FILE help Invoke verify callback on success as well as failure (WOLFSSL_ALWAYS_VERIFY_CB) config WOLFSSL_OPENSSL_EXTRA_X509_SMALL bool "wolfSSL minimal X509 compat APIs" + depends on !WOLFSSL_HAS_SETTINGS_FILE help Define OPENSSL_EXTRA_X509_SMALL. Exposes a small subset of X509 helpers (wolfSSL_X509_free, wolfSSL_get_verify_result, ...) without diff --git a/zephyr/samples/wolfssl_tls_sock/prj-no-malloc.conf b/zephyr/samples/wolfssl_tls_sock/prj-no-malloc.conf index d14a77e3b54..2126c4c6035 100644 --- a/zephyr/samples/wolfssl_tls_sock/prj-no-malloc.conf +++ b/zephyr/samples/wolfssl_tls_sock/prj-no-malloc.conf @@ -40,8 +40,3 @@ CONFIG_WOLFSSL_SETTINGS_FILE="user_settings-no-malloc.h" CONFIG_WOLFSSL=y CONFIG_WOLFSSL_BUILTIN=y -CONFIG_WOLFSSL_TLS_VERSION_1_2=y -CONFIG_WOLFSSL_KEY_EXCHANGE_ALL_ENABLED=y -CONFIG_WOLFSSL_CIPHER_ALL_ENABLED=y -CONFIG_WOLFSSL_MAC_ALL_ENABLED=y -CONFIG_WOLFSSL_HMAC_DRBG_ENABLED=y From 243822200d6ca0a10fca189a76f6521c39243add Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 8 Sep 2026 17:10:14 +0200 Subject: [PATCH 12/13] zephyr: delete the dead TLS Kconfig inherited from mbedTLS Kconfig.tls-generic is a copy of Zephyr's mbedTLS Kconfig.tls-generic with the symbol prefix renamed, which is why a wolfSSL module carries options named after mbedTLS internals - ECP is their elliptic-curve-over-prime-field module and DP their domain parameters, neither of which means anything here. Renaming the prefix was all that happened: nothing was wired up behind it. Of the 53 config symbols in the file, exactly two reach any code, WOLFSSL_TLS_VERSION_1_2 and _1_3. Checked every symbol against the whole workspace - all .c, .h, .cmake, CMakeLists.txt, Kconfig and .conf files under zephyr/ and modules/crypto/wolfssl. The other 51 appear only in that file. Setting CONFIG_WOLFSSL_ECP_DP_SECP384R1_ENABLED=y has always done precisely nothing, and unlike the options the previous commit gated, these do nothing whether or not a settings file is present. Three of them are worse than inert. WOLFSSL_TLS_VERSION_1_0, _1_1 and _1_3 select WOLFSSL_ALLOW_TLSV10_ENABLED, WOLFSSL_NO_OLD_TLS_DISABLED and WOLFSSL_TLS13_ENABLED, none of which is defined anywhere. Kconfig accepts a select of an undefined symbol silently, so the reader sees a mechanism that does not exist. user_settings.h even tested CONFIG_WOLFSSL_TLS13_ENABLED alongside the real symbol; that half of the condition could never be true. Delete the file and move the two live symbols into the module's own Kconfig, next to WOLFSSL_DTLS where the other protocol options are, keeping the settings-file dependency. The dead selects go with it, as do the four dead options the two TLS samples were setting and the stale entry in .wolfssl_known_macro_extras. The ECC curve options that replaced the WOLFSSL_ECP_DP_* ones - and that do reach user_settings.h - went in earlier in this branch. --- .wolfssl_known_macro_extras | 1 - zephyr/Kconfig | 17 +- zephyr/Kconfig.tls-generic | 267 --------------------- zephyr/samples/wolfssl_tls_sock/prj.conf | 4 - zephyr/samples/wolfssl_tls_thread/prj.conf | 4 - zephyr/user_settings.h | 2 +- 6 files changed, 16 insertions(+), 279 deletions(-) delete mode 100644 zephyr/Kconfig.tls-generic diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 6ab44d93c9c..5f3185ed338 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -224,7 +224,6 @@ CONFIG_WOLFSSL_SINGLE_THREADED CONFIG_WOLFSSL_SNI CONFIG_WOLFSSL_TARGET_HOST CONFIG_WOLFSSL_TARGET_PORT -CONFIG_WOLFSSL_TLS13_ENABLED CONFIG_WOLFSSL_TLS_VERSION_1_2 CONFIG_WOLFSSL_TLS_VERSION_1_3 CONFIG_WOLFSSL_XMSS diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 9f0d1e41ff1..32a5efa1a06 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -69,8 +69,6 @@ config WOLFSSL_HAS_SETTINGS_FILE That file is authoritative, so every option that works by writing a define into the module's user_settings.h depends on this being clear. -rsource "Kconfig.tls-generic" - config WOLFCRYPT_FIPS bool "wolfCrypt FIPS support" depends on WOLFSSL_BUILTIN && !WOLFSSL_HAS_SETTINGS_FILE @@ -138,6 +136,21 @@ config WOLFSSL_SINGLE_THREADED on when the kernel has no threading (!MULTITHREADING), so consumers such as wolfPSA do not need to select it themselves. +config WOLFSSL_TLS_VERSION_1_2 + bool "TLS 1.2" + depends on !WOLFSSL_HAS_SETTINGS_FILE + default y + help + Enable TLS 1.2. Clearing this and WOLFSSL_TLS_VERSION_1_3 leaves the + build with no TLS version at all, which only makes sense alongside + WOLFSSL_CRYPTO_ONLY. + +config WOLFSSL_TLS_VERSION_1_3 + bool "TLS 1.3" + depends on !WOLFSSL_HAS_SETTINGS_FILE + help + Enable TLS 1.3 (WOLFSSL_TLS13). + config WOLFSSL_DTLS bool "wolfSSL DTLS support" depends on !WOLFSSL_HAS_SETTINGS_FILE diff --git a/zephyr/Kconfig.tls-generic b/zephyr/Kconfig.tls-generic deleted file mode 100644 index bc46a8fd47d..00000000000 --- a/zephyr/Kconfig.tls-generic +++ /dev/null @@ -1,267 +0,0 @@ -# Kconfig.tls - TLS/DTLS related options - -# -# Copyright (c) 2018 Intel Corporation -# Copyright (c) 2018 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: Apache-2.0 -# - -menu "TLS configuration" - -menu "Supported TLS version" - -config WOLFSSL_TLS_VERSION_1_0 - bool "Enable support for TLS 1.0" - select WOLFSSL_ALLOW_TLSV10_ENABLED - -config WOLFSSL_TLS_VERSION_1_1 - bool "Enable support for TLS 1.1" - select WOLFSSL_NO_OLD_TLS_DISABLED - -config WOLFSSL_TLS_VERSION_1_2 - bool "Enable support for TLS 1.2" - default y - -config WOLFSSL_TLS_VERSION_1_3 - bool "Enable support for TLS 1.3" - select WOLFSSL_TLS13_ENABLED - -endmenu - -menu "Ciphersuite configuration" - -comment "Supported key exchange modes" - -config WOLFSSL_KEY_EXCHANGE_ALL_ENABLED - bool "Enable all available ciphersuite modes" - select WOLFSSL_KEY_EXCHANGE_PSK_ENABLED - select WOLFSSL_KEY_EXCHANGE_DHE_PSK_ENABLED - select WOLFSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED - select WOLFSSL_KEY_EXCHANGE_RSA_PSK_ENABLED - select WOLFSSL_KEY_EXCHANGE_RSA_ENABLED - select WOLFSSL_KEY_EXCHANGE_DHE_RSA_ENABLED - select WOLFSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED - select WOLFSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED - select WOLFSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED - select WOLFSSL_KEY_EXCHANGE_ECDH_ECDSA_ENABLED - select WOLFSSL_KEY_EXCHANGE_ECDH_RSA_ENABLED - select WOLFSSL_KEY_EXCHANGE_ECJPAKE_ENABLED - -config WOLFSSL_KEY_EXCHANGE_PSK_ENABLED - bool "Enable the PSK based ciphersuite modes" - -config WOLFSSL_KEY_EXCHANGE_DHE_PSK_ENABLED - bool "Enable the DHE-PSK based ciphersuite modes" - -config WOLFSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED - bool "Enable the ECDHE-PSK based ciphersuite modes" - -config WOLFSSL_KEY_EXCHANGE_RSA_PSK_ENABLED - bool "Enable the RSA-PSK based ciphersuite modes" - -config WOLFSSL_KEY_EXCHANGE_RSA_ENABLED - bool "Enable the RSA-only based ciphersuite modes" - default y - -config WOLFSSL_KEY_EXCHANGE_DHE_RSA_ENABLED - bool "Enable the DHE-RSA based ciphersuite modes" - -config WOLFSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED - bool "Enable the ECDHE-RSA based ciphersuite modes" - -config WOLFSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED - bool "Enable the ECDHE-ECDSA based ciphersuite modes" - -config WOLFSSL_KEY_EXCHANGE_ECDH_ECDSA_ENABLED - bool "Enable the ECDH-ECDSA based ciphersuite modes" - -config WOLFSSL_KEY_EXCHANGE_ECDH_RSA_ENABLED - bool "Enable the ECDH-RSA based ciphersuite modes" - -config WOLFSSL_KEY_EXCHANGE_ECJPAKE_ENABLED - bool "Enable the ECJPAKE based ciphersuite modes" - -if WOLFSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED || \ - WOLFSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED || \ - WOLFSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED || \ - WOLFSSL_KEY_EXCHANGE_ECDH_ECDSA_ENABLED || \ - WOLFSSL_KEY_EXCHANGE_ECDH_RSA_ENABLED || \ - WOLFSSL_KEY_EXCHANGE_ECJPAKE_ENABLED - -comment "Supported elliptic curves" - -config WOLFSSL_ECP_ALL_ENABLED - bool "Enable all available elliptic curves" - select WOLFSSL_ECP_DP_SECP192R1_ENABLED - select WOLFSSL_ECP_DP_SECP192R1_ENABLED - select WOLFSSL_ECP_DP_SECP224R1_ENABLED - select WOLFSSL_ECP_DP_SECP256R1_ENABLED - select WOLFSSL_ECP_DP_SECP384R1_ENABLED - select WOLFSSL_ECP_DP_SECP521R1_ENABLED - select WOLFSSL_ECP_DP_SECP192K1_ENABLED - select WOLFSSL_ECP_DP_SECP224K1_ENABLED - select WOLFSSL_ECP_DP_SECP256K1_ENABLED - select WOLFSSL_ECP_DP_BP256R1_ENABLED - select WOLFSSL_ECP_DP_BP384R1_ENABLED - select WOLFSSL_ECP_DP_BP512R1_ENABLED - select WOLFSSL_ECP_DP_CURVE25519_ENABLED - select WOLFSSL_ECP_DP_CURVE448_ENABLED - select WOLFSSL_ECP_NIST_OPTIM - -config WOLFSSL_ECP_DP_SECP192R1_ENABLED - bool "Enable SECP192R1 elliptic curve" - -config WOLFSSL_ECP_DP_SECP224R1_ENABLED - bool "Enable SECP224R1 elliptic curve" - -config WOLFSSL_ECP_DP_SECP256R1_ENABLED - bool "Enable SECP256R1 elliptic curve" - -config WOLFSSL_ECP_DP_SECP384R1_ENABLED - bool "Enable SECP384R1 elliptic curve" - -config WOLFSSL_ECP_DP_SECP521R1_ENABLED - bool "Enable SECP521R1 elliptic curve" - -config WOLFSSL_ECP_DP_SECP192K1_ENABLED - bool "Enable SECP192K1 elliptic curve" - -config WOLFSSL_ECP_DP_SECP224K1_ENABLED - bool "Enable SECP224K1 elliptic curve" - -config WOLFSSL_ECP_DP_SECP256K1_ENABLED - bool "Enable SECP256K1 elliptic curve" - -config WOLFSSL_ECP_DP_BP256R1_ENABLED - bool "Enable BP256R1 elliptic curve" - -config WOLFSSL_ECP_DP_BP384R1_ENABLED - bool "Enable BP384R1 elliptic curve" - -config WOLFSSL_ECP_DP_BP512R1_ENABLED - bool "Enable BP512R1 elliptic curve" - -config WOLFSSL_ECP_DP_CURVE25519_ENABLED - bool "Enable CURVE25519 elliptic curve" - -config WOLFSSL_ECP_DP_CURVE448_ENABLED - bool "Enable CURVE448 elliptic curve" - -config WOLFSSL_ECP_NIST_OPTIM - bool "Enable NSIT curves optimization" - -endif - -comment "Supported cipher modes" - -config WOLFSSL_CIPHER_ALL_ENABLED - bool "Enable all available ciphers" - select WOLFSSL_CIPHER_AES_ENABLED - select WOLFSSL_CIPHER_CAMELLIA_ENABLED - select WOLFSSL_CIPHER_DES_ENABLED - select WOLFSSL_CIPHER_ARC4_ENABLED - select WOLFSSL_CIPHER_CHACHA20_ENABLED - select WOLFSSL_CIPHER_BLOWFISH_ENABLED - select WOLFSSL_CIPHER_CCM_ENABLED - select WOLFSSL_CIPHER_MODE_XTS_ENABLED - select WOLFSSL_CIPHER_MODE_GCM_ENABLED - select WOLFSSL_CIPHER_CBC_ENABLED - select WOLFSSL_CHACHAPOLY_AEAD_ENABLED - -config WOLFSSL_CIPHER_AES_ENABLED - bool "Enable the AES block cipher" - default y - -config WOLFSSL_AES_ROM_TABLES - depends on WOLFSSL_CIPHER_AES_ENABLED - bool "Use precomputed AES tables stored in ROM." - default y - -config WOLFSSL_CIPHER_CAMELLIA_ENABLED - bool "Enable the Camellia block cipher" - -config WOLFSSL_CIPHER_DES_ENABLED - bool "Enable the DES block cipher" - default y - -config WOLFSSL_CIPHER_ARC4_ENABLED - bool "Enable the ARC4 stream cipher" - -config WOLFSSL_CIPHER_CHACHA20_ENABLED - bool "Enable the ChaCha20 stream cipher" - -config WOLFSSL_CIPHER_BLOWFISH_ENABLED - bool "Enable the Blowfish block cipher" - -config WOLFSSL_CIPHER_CCM_ENABLED - bool "Enable the Counter with CBC-MAC (CCM) mode for 128-bit block cipher" - depends on WOLFSSL_CIPHER_AES_ENABLED || WOLFSSL_CIPHER_CAMELLIA_ENABLED - -config WOLFSSL_CIPHER_MODE_XTS_ENABLED - bool "Enable Xor-encrypt-xor with ciphertext stealing mode (XTS) for AES" - depends on WOLFSSL_CIPHER_AES_ENABLED || WOLFSSL_CIPHER_CAMELLIA_ENABLED - -config WOLFSSL_CIPHER_MODE_GCM_ENABLED - bool "Enable the Galois/Counter Mode (GCM) for AES" - depends on WOLFSSL_CIPHER_AES_ENABLED || WOLFSSL_CIPHER_CAMELLIA_ENABLED - -config WOLFSSL_CIPHER_CBC_ENABLED - bool "Enable Cipher Block Chaining mode (CBC) for symmetric ciphers" - default y - -config WOLFSSL_CHACHAPOLY_AEAD_ENABLED - bool "Enable the ChaCha20-Poly1305 AEAD algorithm" - depends on WOLFSSL_CIPHER_CHACHA20_ENABLED || WOLFSSL_MAC_POLY1305_ENABLED - -comment "Supported message authentication methods" - -config WOLFSSL_MAC_ALL_ENABLED - bool "Enable all available MAC methods" - select WOLFSSL_MAC_MD4_ENABLED - select WOLFSSL_MAC_MD5_ENABLED - select WOLFSSL_MAC_SHA1_ENABLED - select WOLFSSL_MAC_SHA256_ENABLED - select WOLFSSL_MAC_SHA512_ENABLED - select WOLFSSL_MAC_POLY1305_ENABLED - -config WOLFSSL_MAC_MD4_ENABLED - bool "Enable the MD4 hash algorithm" - -config WOLFSSL_MAC_MD5_ENABLED - bool "Enable the MD5 hash algorithm" - default y - -config WOLFSSL_MAC_SHA1_ENABLED - bool "Enable the SHA1 hash algorithm" - default y - -config WOLFSSL_MAC_SHA256_ENABLED - bool "Enable the SHA-224 and SHA-256 hash algorithms" - default y - -config WOLFSSL_MAC_SHA512_ENABLED - bool "Enable the SHA-384 and SHA-512 hash algorithms" - -config WOLFSSL_MAC_POLY1305_ENABLED - bool "Enable the Poly1305 MAC algorithm" - -endmenu - -comment "Random number generators" - -config WOLFSSL_HMAC_DRBG_ENABLED - bool "Enable the HMAC_DRBG random generator" - default y - -comment "Other configurations" - -config WOLFSSL_HAVE_ASM - bool "Enable use of assembly code" - default y - help - Enable use of assembly code in wolfSSL. This improves the performances - of asymmetric cryptography, however this might have an impact on the - code size. - -endmenu diff --git a/zephyr/samples/wolfssl_tls_sock/prj.conf b/zephyr/samples/wolfssl_tls_sock/prj.conf index 998475f52f2..a4e0e61b37e 100644 --- a/zephyr/samples/wolfssl_tls_sock/prj.conf +++ b/zephyr/samples/wolfssl_tls_sock/prj.conf @@ -41,8 +41,4 @@ CONFIG_WOLFSSL=y CONFIG_WOLFSSL_BUILTIN=y CONFIG_WOLFSSL_TLS_VERSION_1_3=y -CONFIG_WOLFSSL_KEY_EXCHANGE_ALL_ENABLED=y -CONFIG_WOLFSSL_CIPHER_ALL_ENABLED=y -CONFIG_WOLFSSL_MAC_ALL_ENABLED=y -CONFIG_WOLFSSL_HMAC_DRBG_ENABLED=y CONFIG_WOLFSSL_MLKEM=y diff --git a/zephyr/samples/wolfssl_tls_thread/prj.conf b/zephyr/samples/wolfssl_tls_thread/prj.conf index b2b48c98c15..4c6910f2a42 100644 --- a/zephyr/samples/wolfssl_tls_thread/prj.conf +++ b/zephyr/samples/wolfssl_tls_thread/prj.conf @@ -31,8 +31,4 @@ CONFIG_WOLFSSL=y CONFIG_WOLFSSL_BUILTIN=y CONFIG_WOLFSSL_TLS_VERSION_1_3=y -CONFIG_WOLFSSL_KEY_EXCHANGE_ALL_ENABLED=y -CONFIG_WOLFSSL_CIPHER_ALL_ENABLED=y -CONFIG_WOLFSSL_MAC_ALL_ENABLED=y -CONFIG_WOLFSSL_HMAC_DRBG_ENABLED=y CONFIG_WOLFSSL_MLKEM=y diff --git a/zephyr/user_settings.h b/zephyr/user_settings.h index 737ed965ce7..4c92fdf50f0 100644 --- a/zephyr/user_settings.h +++ b/zephyr/user_settings.h @@ -185,7 +185,7 @@ extern "C" { //#define NO_WOLFSSL_CLIENT /* Optionally disable TLS client code */ /* TLS v1.3 */ -#if defined(CONFIG_WOLFSSL_TLS_VERSION_1_3) || defined(CONFIG_WOLFSSL_TLS13_ENABLED) +#ifdef CONFIG_WOLFSSL_TLS_VERSION_1_3 #define WOLFSSL_TLS13 #endif From ee24352ed9307d62ed2174b74349e905cec9093f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 7 Sep 2026 07:15:05 +0200 Subject: [PATCH 13/13] zephyr: replace the assembly options with a single arch-derived one Four options guarded the assembly - WOLFCRYPT_ARMASM, its THUMB2 companion, WOLFCRYPT_INTELASM, and nothing at all for the single-precision math - and between them they could not express a working configuration on any target. WOLFCRYPT_ARMASM_THUMB2 selected the thumb2-* sources but nothing anywhere defined WOLFSSL_ARMASM_THUMB2, so every caller still took the ARMv8 path and the link failed on AES_*_AARCH32. It also needs WOLFSSL_ARMASM_NO_HW_CRYPTO, since Cortex-M has no AES or SHA extension and the Thumb2 code is the whole of it. The single-precision assembly had no option at all: WOLFSSL_SP_ARM_CORTEX_M_ASM sat commented out inside an #if 0 while sp_cortexm.c was already in the source list. WOLFCRYPT_INTELASM was worse: it named the 32-bit source pair while user_settings.h declared WOLFSSL_X86_64_BUILD, so aes_asm.S compiled to an empty object behind its WOLFSSL_X86_BUILD guard and aes_gcm_x86_asm.S emitted 32-bit code into a 64-bit build. It could not have produced a working image. Only one combination is ever right for a given board, so the four collapse into WOLFCRYPT_ASM and the module derives the rest from the CPU Zephyr reports: ARMv7-M and ARMv8-M mainline take Thumb2 plus the Cortex-M math, AArch64 the ARMv8 and ARM64 ones, other 32-bit ARM the ARMv8-32 and ARM32 ones, and x86_64 the Intel symmetric set with its correct 64-bit filenames. ARMv6-M and ARMv8-M baseline deliberately get no symmetric assembly. The Thumb2 port uses UBFX and LDRD, neither of which those cores have, so keying it on CONFIG_CPU_CORTEX_M would hand an M0 or M23 board code that cannot assemble. They still get the Thumb math, which is the only thing wolfCrypt ships for that profile - the same split the SP half already made. Each ARM port sets two single-precision macros, not one. WOLFSSL_SP__ASM compiles sp_.c, the per-size backend for the RSA, DH and ECC sizes it covers; the unsuffixed WOLFSSL_SP_ enables the inline-asm word primitives inside sp_int.c, which is what the generic WOLFSSL_SP_MATH_ALL path uses for every other size and curve. sp_int.c's own header block names them as separate features and configure.ac sets them from separate options, neither implying the other. Defining only the _ASM half - which is what this module did - left Brainpool, custom curves and any uncovered RSA or DH size running with no assembly at all. The x86_64 set carries fe_x25519_asm.S but not the AES pair. curve25519.c takes the Intel path whenever USE_INTEL_SPEEDUP is defined, so omitting the former is a link error the moment an application enables the curve; the latter define nothing but _aesni entry points whose callers sit behind WOLFSSL_AESNI, which this module does not set, so they were bytes with no reachable caller. 32-bit x86 is not offered. Only the AES sources have an implementation at that width; sha256_asm.S, chacha_asm.S and poly1305_asm.S are all guarded to WOLFSSL_X86_64_BUILD and would contribute nothing. The x86_64 single-precision assembly is not offered either, and that one is worth recording. sp_x86_64_asm.S is AVX throughout - over fifteen hundred VEX instructions - and sp_x86_64.c calls into it unconditionally, with no CPUID dispatch and no scalar counterpart. Zephyr's x86 context switch is fxsave/fxrstor and it never sets CR4.OSXSAVE, so YMM state is neither saved nor enabled and those instructions fault. The symmetric sources are fine because they pick their implementation from CPUID at run time and now fall back correctly. Both set(TOOLCHAIN_C_FLAGS ...) calls go as well. They could never have had an effect: Zephyr applies that variable globally at zephyr/CMakeLists.txt:425 and only add_subdirectory's modules at line 788, so the assignment ran after the flags were consumed, and a plain set() in a subdirectory scope never reached the parent either. Confirmed by forcing the assignment to run unconditionally and finding neither -mcpu=cortex-a53+crypto nor -mstrict-align anywhere in the resulting compile database. HAVE___UINT128_T is defined wherever the compiler has the type. Every 64-bit single-precision backend works in 128-bit intermediates; an autoconf build learns the type is available from a configure probe, but with user settings nobody sets it and sp_int.c fails on an undeclared sp_int_word. AArch64 needs this as much as x86_64 does - qemu_cortex_a53 stops there before it ever reaches the assembler. One wolfssl_test scenario per port now covers the option in CI rather than by hand: qemu_x86_64 for Intel, qemu_cortex_a53 for AArch64, and mps2/an521/cpu0, a Cortex-M33, for Thumb2. The aarch64 one earned its keep immediately by catching an unused-constant error in the generated ML-KEM assembly, fixed earlier in this branch. Measured on frdm_rw612 with the benchmark, ops/sec: ECDSA P-256 sign 16 to 136, verify 10 to 102, RSA-2048 public 86 to 194. Thumb2 is worth 1.5x on AES-CBC and 1.3x on ChaCha20, and costs about 5% on SHA-256. wolfcrypt_test passes on frdm_rw612 and on all three QEMU targets with the option set. --- zephyr/CMakeLists.txt | 76 +++++++++-------------- zephyr/Kconfig | 62 +++++++++++++----- zephyr/samples/wolfssl_benchmark/prj.conf | 5 +- zephyr/samples/wolfssl_test/sample.yaml | 38 ++++++++++++ zephyr/user_settings.h | 65 ++++++++++++------- 5 files changed, 161 insertions(+), 85 deletions(-) diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 39f5c58d805..e2a94b70197 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -136,53 +136,39 @@ if(CONFIG_WOLFSSL) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/st/stm32.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/realtek/rtl8735b.c) - if(CONFIG_WOLFCRYPT_ARMASM) - # tested with board: "qemu_kvm_arm64" - if(CONFIG_WOLFCRYPT_ARMASM_THUMB2) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/thumb2-aes-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/thumb2-chacha-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/thumb2-curve25519_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/thumb2-mlkem-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/thumb2-poly1305-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/thumb2-sha256-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/thumb2-sha3-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/thumb2-sha512-asm_c.c) - else() - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/armv8-aes-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/armv8-chacha-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/armv8-curve25519_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/armv8-poly1305-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/armv8-sha512-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/armv8-sha3-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/armv8-sha256-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/armv8-32-aes-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/armv8-32-chacha-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/armv8-32-curve25519_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/armv8-32-mlkem-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/armv8-32-poly1305-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/armv8-32-sha512-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/armv8-32-sha3-asm_c.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm/armv8-32-sha256-asm_c.c) + if(CONFIG_WOLFCRYPT_ASM) + set(WOLF_ARM_ASM_DIR ${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/port/arm) + + # Thumb2 needs UBFX and LDRD, so it is a mainline-only port; ARMv6-M and + # ARMv8-M baseline keep the C code here and take only the SP speedup. + if(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + set(WOLF_ARM_ASM_PREFIX thumb2) + elseif(CONFIG_ARM64) + set(WOLF_ARM_ASM_PREFIX armv8) + elseif(CONFIG_ARM AND NOT CONFIG_CPU_CORTEX_M) + set(WOLF_ARM_ASM_PREFIX armv8-32) endif() - - # Note: The cmake/gcc-m-cpu.cmake make need updated to add "+crypto -mstrict-align" - set(TOOLCHAIN_C_FLAGS "-mcpu=cortex-a53+crypto -mstrict-align") - endif() - - if(CONFIG_WOLFCRYPT_INTELASM) - # tested with board: "qemu_x86_64" - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/sha256_asm.S) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/sha512_asm.S) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/sha3_asm.S) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/chacha_asm.S) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/poly1305_asm.S) - - # AESNI - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/aes_asm.S) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/aes_gcm_x86_asm.S) - set(TOOLCHAIN_C_FLAGS "-march=native -maes -msse4 -mpclmul ") + if(DEFINED WOLF_ARM_ASM_PREFIX) + foreach(f aes chacha mlkem poly1305 sha256 sha3 sha512) + zephyr_library_sources( + ${WOLF_ARM_ASM_DIR}/${WOLF_ARM_ASM_PREFIX}-${f}-asm_c.c) + endforeach() + # curve25519 is the one port whose file has no "-asm" infix. + zephyr_library_sources( + ${WOLF_ARM_ASM_DIR}/${WOLF_ARM_ASM_PREFIX}-curve25519_c.c) + elseif(CONFIG_X86_64) + # fe_x25519_asm.S is here because curve25519.c takes the Intel path + # whenever USE_INTEL_SPEEDUP is set, so leaving it out is a link error + # the moment an application enables the curve. The AES sources are not: + # everything they define is an _aesni entry point, and their callers sit + # behind WOLFSSL_AESNI, which this module does not define. + foreach(f sha256_asm sha512_asm sha3_asm chacha_asm poly1305_asm + fe_x25519_asm) + zephyr_library_sources( + ${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/${f}.S) + endforeach() + endif() endif() zephyr_library_link_libraries(wolfSSL) diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 32a5efa1a06..416d4198c94 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -339,24 +339,54 @@ config WOLFSSL_OPENSSL_EXTRA_X509_SMALL helpers (wolfSSL_X509_free, wolfSSL_get_verify_result, ...) without the rest of OPENSSL_EXTRA. -config WOLFCRYPT_ARMASM - bool "wolfCrypt ARM Assembly support" - depends on WOLFSSL_BUILTIN - help - wolfCrypt ARM (ARMv8/ARMv7) assembly support for AES, SHA-2, SHA-3, - ChaCha20/Poly1305 and Curve25519 - -config WOLFCRYPT_ARMASM_THUMB2 - bool "wolfCrypt ARM Thumb2 Assembly support" - depends on WOLFCRYPT_ARMASM +config WOLFCRYPT_ASM + bool "wolfCrypt assembly optimisations" + depends on WOLFSSL_BUILTIN && !WOLFSSL_HAS_SETTINGS_FILE + depends on ARM || ARM64 || X86_64 help - Enable Thumb2 assembly optimizations for ARM processors - -config WOLFCRYPT_INTELASM - bool "wolfCrypt Intel Assembly support" - depends on WOLFSSL_BUILTIN + Use the hand-written assembly for the symmetric algorithms (AES, + SHA-2, SHA-3, ChaCha20/Poly1305, Curve25519) and, on ARM, for the + single-precision math behind RSA, DH and ECC. + + The port follows the CPU Zephyr reports: + + ARMv7-M / ARMv8-M mainline thumb2 symmetric, Cortex-M math + ARMv6-M / ARMv8-M baseline math only, Thumb variant + 32-bit Cortex-A / Cortex-R armv8-32 symmetric, ARM32 math + AArch64 armv8 symmetric, ARM64 math + x86_64 symmetric only + + ARMv6-M and ARMv8-M baseline get no symmetric assembly because the + Thumb2 port uses UBFX and LDRD, which those cores lack. On the + mainline cores the math assembly prefers UMAAL, part of the DSP + extension; a part built without it takes the slower UMAAL-free + variant of the same routines. + + x86_64 gets no single-precision assembly: sp_x86_64_asm.S is AVX + throughout and sp_x86_64.c calls it without a CPUID check, while + Zephyr's x86 context switch never enables the YMM state. Its + symmetric AVX1/AVX2 paths are safe because they are chosen at run + time by CPUID, which this module also teaches to check that the OS + enabled the vector state. + + 32-bit x86 is not offered: only the AES sources have an + implementation at that width, and the rest are guarded to x86_64. + +config WOLFCRYPT_SP_SMALL + bool "Smaller single-precision math" + depends on WOLFSSL_BUILTIN && !WOLFSSL_HAS_SETTINGS_FILE + default y help - wolfCrypt Intel Aassembly support (AVX/AVX2/AESNI) + Build the space-optimised variant of the single-precision math + backend. Turning it off trades a markedly larger image for faster + RSA, DH and ECC. + + Independent of WOLFCRYPT_ASM, which picks the backend while this + picks the variant within it: the assembly sources carry both a + loop-based and an unrolled form of each routine. Leaving this on + therefore keeps the smaller, slower half of the assembly, so + turning it off is what makes WOLFCRYPT_ASM pay off on a part with + the flash to spare. config WOLFSSL_NO_HAVE_MIN_MAX bool "Force wolfSSL to use its own min/max" diff --git a/zephyr/samples/wolfssl_benchmark/prj.conf b/zephyr/samples/wolfssl_benchmark/prj.conf index a29977e91d2..b4d9b2dd57b 100644 --- a/zephyr/samples/wolfssl_benchmark/prj.conf +++ b/zephyr/samples/wolfssl_benchmark/prj.conf @@ -28,6 +28,5 @@ CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_ENTROPY_GENERATOR=y CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR=y -# Optional ARM or Intel Assembly -#CONFIG_WOLFCRYPT_ARMASM=y -#CONFIG_WOLFCRYPT_INTELASM=y +# Optional ARM assembly +#CONFIG_WOLFCRYPT_ASM=y diff --git a/zephyr/samples/wolfssl_test/sample.yaml b/zephyr/samples/wolfssl_test/sample.yaml index 72091dcc989..94ef2814de4 100644 --- a/zephyr/samples/wolfssl_test/sample.yaml +++ b/zephyr/samples/wolfssl_test/sample.yaml @@ -33,3 +33,41 @@ tests: extra_args: CONF_FILE="prj.conf;prj-ecc-custom.conf" integration_platforms: - qemu_x86 + # One scenario per assembly port CONFIG_WOLFCRYPT_ASM can select, so a + # regression in the generated sources or in the arch dispatch fails here + # rather than on hardware. + sample.crypto.wolfssl_test_asm_x86_64: + # qemu_x86_64 advertises no AVX, so this also exercises the CPUID fallback + # that keeps the Intel sources off a CPU whose OS never enabled the vector + # state. + timeout: 400 + platform_allow: qemu_x86_64 + extra_configs: + - CONFIG_WOLFCRYPT_ASM=y + - CONFIG_MAIN_STACK_SIZE=65536 + - CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=65536 + integration_platforms: + - qemu_x86_64 + sample.crypto.wolfssl_test_asm_aarch64: + # The ARMv8 symmetric port plus the ARM64 math one. Covers the crypto and + # SHA-3 extension directives the generated .S files carry, which a plain + # ARMv8-A -mcpu rejects without them. + timeout: 900 + platform_allow: qemu_cortex_a53 + extra_configs: + - CONFIG_WOLFCRYPT_ASM=y + - CONFIG_MAIN_STACK_SIZE=65536 + - CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=65536 + integration_platforms: + - qemu_cortex_a53 + sample.crypto.wolfssl_test_asm_thumb2: + # AN521 is a Cortex-M33, so this is the Thumb2 symmetric port plus the + # Cortex-M math one - the pair every ARMv8-M mainline target takes. + timeout: 1800 + platform_allow: mps2/an521/cpu0 + extra_configs: + - CONFIG_WOLFCRYPT_ASM=y + - CONFIG_MAIN_STACK_SIZE=65536 + - CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=65536 + integration_platforms: + - mps2/an521/cpu0 diff --git a/zephyr/user_settings.h b/zephyr/user_settings.h index 4c92fdf50f0..47b4e2ce8af 100644 --- a/zephyr/user_settings.h +++ b/zephyr/user_settings.h @@ -617,17 +617,31 @@ extern "C" { #define WOLFSSL_HAVE_SP_DH #endif - #define WOLFSSL_SP_SMALL /* use smaller version of code */ + #ifdef CONFIG_WOLFCRYPT_SP_SMALL + #define WOLFSSL_SP_SMALL /* use smaller version of code */ + #endif //#define WOLFSSL_SP_NO_MALLOC /* disable heap in wolf/SP math */ //#define SP_DIV_WORD_USE_DIV /* no div64 */ - #if 0 - /* optional speedup with inline assembly */ - //#define WOLFSSL_SP_ARM_CORTEX_M_ASM /* Cortex-M3+ */ - //#define WOLFSSL_SP_ARM_THUMB_ASM /* Cortex-M0+ thumb */ - //#define WOLFSSL_SP_ARM32_ASM /* Cortex-R */ - //#define WOLFSSL_SP_ARM64_ASM /* Cortex-A */ - //#define WOLFSSL_SP_USE_UDIV + /* Assembly speedup, keyed on the CPU Zephyr reports. Anything not named + * here keeps the C backend. Each pair is two separate backends: the _ASM + * macro compiles sp_.c for the RSA, DH and ECC sizes it covers, the + * other the word primitives sp_int.c uses for everything else. */ + #ifdef CONFIG_WOLFCRYPT_ASM + #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) + #define WOLFSSL_SP_ARM_THUMB_ASM + #define WOLFSSL_SP_ARM_THUMB + #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + #define WOLFSSL_SP_ARM_CORTEX_M_ASM + #define WOLFSSL_SP_ARM_CORTEX_M + #elif defined(CONFIG_ARM64) + #define WOLFSSL_SP_ARM64_ASM + #define WOLFSSL_SP_ARM64 + #elif defined(CONFIG_CPU_AARCH32_CORTEX_R) || \ + defined(CONFIG_CPU_AARCH32_CORTEX_A) + #define WOLFSSL_SP_ARM32_ASM + #define WOLFSSL_SP_ARM32 + #endif #endif #endif @@ -635,27 +649,36 @@ extern "C" { /* Assembly Speedups for Symmetric Algorithms */ /* ------------------------------------------------------------------------- */ -#ifdef CONFIG_WOLFCRYPT_ARMASM +#ifdef CONFIG_WOLFCRYPT_ASM +/* Mirrors the source selection in CMakeLists.txt. ARMv6-M and ARMv8-M + * baseline are absent from both: the Thumb2 port uses UBFX and LDRD, which + * those cores do not have, so they keep the C code and the SP speedup only. */ +#if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) || defined(CONFIG_ARM64) || \ + (defined(CONFIG_ARM) && !defined(CONFIG_CPU_CORTEX_M)) #define WOLFSSL_ARMASM #define WOLFSSL_NO_HASH_RAW #define WOLFSSL_ARMASM_INLINE /* use inline .c versions */ #define WOLFSSL_ARMASM_NO_NEON - /* Default is ARMv8 */ - - #if 0 /* ARMv7 */ - #define WOLFSSL_ARM_ARCH 7 - #define WOLFSSL_ARMASM_NO_HW_CRYPTO /* enable if processor does not support aes/sha instructions */ + /* Without these the Thumb2 sources compile but every caller still takes + * the ARMv8 path, so the port selects files and nothing else. Cortex-M + * has no AES or SHA extension, so Thumb2 is all of it. */ + #ifdef CONFIG_CPU_CORTEX_M + #define WOLFSSL_ARMASM_THUMB2 + #define WOLFSSL_ARMASM_NO_HW_CRYPTO #endif -#endif - -#ifdef CONFIG_WOLFCRYPT_INTELASM +#elif defined(CONFIG_X86_64) #define USE_INTEL_SPEEDUP - #define WOLFSSL_X86_64_BUILD /* 64-bit */ - //#define WOLFSSL_X86_BUILD /* 32-bit */ + #define WOLFSSL_X86_64_BUILD +#endif - /* Issues with building AESNI "_mm_aesimc_si128" always_inline */ - //#define WOLFSSL_AESNI +/* Every 64-bit single-precision backend works in 128-bit intermediates. An + * autoconf build learns the type is available from a configure probe; with + * user settings nobody sets HAVE___UINT128_T, and sp_int.c then fails on an + * undeclared sp_int_word. */ +#if defined(__SIZEOF_INT128__) && !defined(HAVE___UINT128_T) + #define HAVE___UINT128_T 1 +#endif #endif