From ab1684114ea1ca18eca5f5acf4617359cdb1016c 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/15] 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 the thumb2 assembly, but was derived from __ARM_ARCH_7M__, which names the Cortex-M3 alone. UMAAL belongs to the DSP extension, optional on ARMv8-M, so a part like the Cortex-M33 in the NXP RW612 has neither UMAAL nor __ARM_ARCH_7M__ and took the UMAAL path anyway. Key on the absence of __ARM_FEATURE_DSP, which toolchains define exactly when the extension is present. Verified with gcc for M0, M3, M4, M7, M23, M33 and M33+nodsp. The __ARM_ARCH_7M__ arm stays, so nothing that worked before changes. --- 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 3a91bdd1f89424c6cd6e9652d154545b9be2a493 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/15] settings: keep the Zephyr platform block away from the assembler The WOLFSSL_ZEPHYR block includes and friends and declares z_realloc. Assembly reaches settings.h through libwolfssl_sources_asm.h, so the assembler got all of it and stopped at the first C declaration: stddef.h:160: Error: no such instruction: `typedef long int ptrdiff_t' That makes every wolfSSL .S file unbuildable on Zephyr, on any architecture - reproduced on x86_64 and on a Cortex-M33. Ports using the *_c.c inline variants never noticed, since those are compiled as C. Guard the block with __ASSEMBLER__, as settings.h already does for the STM32MP13 header. No effect on any C translation unit. --- 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 c765935ed4b16a00872fe8cad379c66213c22f6e 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/15] 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, which is a GNU extension rather than an ISO C one and so is unavailable under -std=c17: sp_x86_64.c:597: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'asm' Zephyr compiles with -std=c17, but any strict-ISO build hits it. __asm__ is the spelling GCC and Clang keep regardless of -std, and is what the next line of each function already uses. --- 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 649707509019f8f5533c848b5ed0f001f1f3d833 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/15] 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 those instructions also needs the OS to have enabled extended state - CR4.OSXSAVE plus the matching XCR0 components - and an OS that does not context-switch those registers leaves them clear, so the instruction raises #UD whatever CPUID says. cpuid_set_flags() tested the feature bits alone. Zephyr is such a system: its x86 context switch is fxsave/fxrstor and it never sets CR4.OSXSAVE, so the first vector SHA-256 or AES-GCM path crashes. Gate each family on OSXSAVE plus the XCR0 components it needs, in the order Intel documents - XGETBV is only legal once OSXSAVE is set. The masks have to differ because the AVX-512 dispatch sites 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 protects. Nothing changes where an OS enables XSAVE, which is every mainstream one. --- 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 61ccaec7a1747daf6d8be8f7c37eeecd54ec43e8 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/15] armv8: enable the crypto extension for the assembly that needs it The ARMv8 AES and SHA-256 ports emit aese, aesmc and the sha256 instructions with no directive of their own, so they assemble only when the command line already names a CPU that has the extension: armv8-aes-asm.S: Error: selected processor does not support `aese v0.16b,v1.16b' Zephyr lands there: it derives -mcpu from the board and has no symbol for the extension, and naming a CPU in the module would retarget every other board. Add .arch_extension crypto. The .S and .asm outputs carry one at file scope; the C output cannot, because clang gives each __asm__ block a fresh subtarget, so there it leads every block, as the SHA-3 ports already do. All three sit inside WOLFSSL_ARMASM_NO_HW_CRYPTO, and that guard now carries the whole safety argument, which is the part worth recording. The directive removes the assembler's refusal, so setting the macro becomes the integrator's job rather than something the toolchain enforces: with no ID registers to read, cpuid.c reports AES, PMULL and SHA-256 present whenever it is unset, and a base-ARMv8 build then dispatches them on a core where FEAT_AES is optional. FrodoKEM's aese deliberately gets no directive for the same reason - it has no such guard to opt out through. Regenerated from the scripts repository, which carries the matching change. --- 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 | 33 +++++++++++++++++++++ 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, 38 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..52e7ae18fb8 100644 --- a/wolfcrypt/src/port/arm/armv8-aes-asm_c.c +++ b/wolfcrypt/src/port/arm/armv8-aes-asm_c.c @@ -41,6 +41,7 @@ void AES_set_key_AARCH64(const byte* userKey, int keylen, byte* key, int dir) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "cmp %x[keylen], #24\n\t" "b.lt L_aes_set_key_arm64_crypto_start_128_%=\n\t" "b.gt L_aes_set_key_arm64_crypto_start_256_%=\n\t" @@ -591,6 +592,7 @@ void AES_set_key_AARCH64(const byte* userKey, int keylen, byte* key, int dir) void AES_encrypt_AARCH64(const byte* inBlock, byte* outBlock, byte* key, int nr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v0.16b}, [%x[inBlock]]\n\t" "ld1 {v1.2d, v2.2d, v3.2d, v4.2d}, [%x[key]], #0x40\n\t" "aese v0.16b, v1.16b\n\t" @@ -648,6 +650,7 @@ void AES_encrypt_AARCH64(const byte* inBlock, byte* outBlock, byte* key, int nr) void AES_decrypt_AARCH64(const byte* inBlock, byte* outBlock, byte* key, int nr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v0.16b}, [%x[inBlock]]\n\t" "ld1 {v1.2d, v2.2d, v3.2d, v4.2d}, [%x[key]], #0x40\n\t" "aesd v0.16b, v1.16b\n\t" @@ -704,6 +707,7 @@ void AES_encrypt_blocks_AARCH64(const byte* in, byte* out, word32 sz, byte* key, int nr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v16.2d, v17.2d, v18.2d, v19.2d}, [%x[key]], #0x40\n\t" "ld1 {v20.2d, v21.2d, v22.2d, v23.2d}, [%x[key]], #0x40\n\t" "ld1 {v24.2d, v25.2d, v26.2d}, [%x[key]], #48\n\t" @@ -1925,6 +1929,7 @@ void AES_decrypt_blocks_AARCH64(const byte* in, byte* out, word32 sz, byte* key, int nr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v16.2d, v17.2d, v18.2d, v19.2d}, [%x[key]], #0x40\n\t" "ld1 {v20.2d, v21.2d, v22.2d, v23.2d}, [%x[key]], #0x40\n\t" "ld1 {v24.2d, v25.2d, v26.2d}, [%x[key]], #48\n\t" @@ -3148,6 +3153,7 @@ void AES_CBC_encrypt_AARCH64(const byte* in, byte* out, word32 sz, byte* reg, byte* key, int nr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v16.2d, v17.2d, v18.2d, v19.2d}, [%x[key]], #0x40\n\t" "ld1 {v20.2d, v21.2d, v22.2d, v23.2d}, [%x[key]], #0x40\n\t" "ld1 {v0.2d}, [%x[reg]]\n\t" @@ -3286,6 +3292,7 @@ void AES_CBC_decrypt_AARCH64(const byte* in, byte* out, word32 sz, byte* reg, byte* key, int nr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v16.2d, v17.2d, v18.2d, v19.2d}, [%x[key]], #0x40\n\t" "ld1 {v20.2d, v21.2d, v22.2d, v23.2d}, [%x[key]], #0x40\n\t" "ld1 {v0.2d}, [%x[reg]]\n\t" @@ -3544,6 +3551,7 @@ void AES_CTR_encrypt_AARCH64(const byte* in, byte* out, word32 sz, byte* reg, byte* key, byte* tmp, word32* left, word32 nr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v0.2d, v1.2d, v2.2d, v3.2d}, [%x[key]], #0x40\n\t" "ld1 {v4.2d, v5.2d, v6.2d, v7.2d}, [%x[key]], #0x40\n\t" "ld1 {v15.2d}, [%x[reg]]\n\t" @@ -5211,6 +5219,7 @@ void AES_GCM_set_key_AARCH64(const byte* nonce, const byte* key, byte* gcm_h, int nr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v0.16b}, [%x[nonce]]\n\t" "ld1 {v1.2d, v2.2d, v3.2d, v4.2d}, [%x[key]], #0x40\n\t" "aese v0.16b, v1.16b\n\t" @@ -5265,6 +5274,7 @@ void AES_GCM_encrypt_AARCH64(const byte* in, byte* out, word32 sz, word32 aadSz, byte* key, byte* gcm_h, byte* tmp, byte* reg, int nr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "movi v27.16b, #0x87\n\t" "eor v26.16b, v26.16b, v26.16b\n\t" "ushr v27.2d, v27.2d, #56\n\t" @@ -10140,6 +10150,7 @@ int AES_GCM_decrypt_AARCH64(const byte* in, byte* out, word32 sz, int nr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "movi v27.16b, #0x87\n\t" "eor v26.16b, v26.16b, v26.16b\n\t" "ushr v27.2d, v27.2d, #56\n\t" @@ -15068,6 +15079,7 @@ void AES_GCM_encrypt_AARCH64_EOR3(const byte* in, byte* out, word32 sz, word32 aadSz, byte* key, byte* gcm_h, byte* tmp, byte* reg, int nr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "movi v27.16b, #0x87\n\t" "eor v26.16b, v26.16b, v26.16b\n\t" "ushr v27.2d, v27.2d, #56\n\t" @@ -19837,6 +19849,7 @@ int AES_GCM_decrypt_AARCH64_EOR3(const byte* in, byte* out, word32 sz, int nr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "movi v27.16b, #0x87\n\t" "eor v26.16b, v26.16b, v26.16b\n\t" "ushr v27.2d, v27.2d, #56\n\t" @@ -24656,6 +24669,7 @@ void AES_GCM_init_AARCH64(byte* key, int nr, const byte* nonce, word32 nonceSz, byte* gcm_h, byte* counter, byte* initCtr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "movi v6.16b, #0x87\n\t" "ld1 {v5.2d}, [%x[gcm_h]]\n\t" "ushr v6.2d, v6.2d, #56\n\t" @@ -24833,6 +24847,7 @@ void AES_GCM_init_AARCH64(byte* key, int nr, const byte* nonce, word32 nonceSz, void AES_GCM_ghash_block_AARCH64(const byte* data, byte* tag, byte* gcm_h) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v6.2d}, [%x[tag]]\n\t" "movi v7.16b, #0x87\n\t" "ld1 {v5.2d}, [%x[gcm_h]]\n\t" @@ -24867,6 +24882,7 @@ void AES_GCM_aad_update_AARCH64(const byte* aadt, word32 abytes, byte* tag, byte* gcm_h) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v20.2d}, [%x[tag]]\n\t" "movi v21.16b, #0x87\n\t" "ld1 {v12.2d}, [%x[gcm_h]]\n\t" @@ -25213,6 +25229,7 @@ void AES_GCM_encrypt_block_AARCH64(const byte* key, int nr, byte* out, const byte* in, byte* counter) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v5.2d}, [%x[counter]]\n\t" "ld1 {v4.2d}, [%x[in]]\n\t" "mov w5, v5.s[3]\n\t" @@ -25273,6 +25290,7 @@ void AES_GCM_encrypt_update_AARCH64(const byte* key, int nr, byte* out, const byte* in, word32 nbytes, byte* tag, byte* h, byte* counter) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v13.2d}, [%x[counter]]\n\t" "movi v27.16b, #0x87\n\t" "ld1 {v26.2d}, [%x[tag]]\n\t" @@ -29100,6 +29118,7 @@ void AES_GCM_encrypt_final_AARCH64(byte* tag, byte* authTag, word32 tbytes, word32 nbytes, word32 abytes, byte* h, byte* initCtr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v5.2d}, [%x[tag]]\n\t" "movi v6.16b, #0x87\n\t" "ld1 {v4.2d}, [%x[h]]\n\t" @@ -29180,6 +29199,7 @@ void AES_GCM_decrypt_update_AARCH64(const byte* key, int nr, byte* out, const byte* in, word32 nbytes, byte* tag, byte* h, byte* counter) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v13.2d}, [%x[counter]]\n\t" "movi v27.16b, #0x87\n\t" "ld1 {v26.2d}, [%x[tag]]\n\t" @@ -33009,6 +33029,7 @@ void AES_GCM_decrypt_final_AARCH64(byte* tag, const byte* authTag, int* res) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v5.2d}, [%x[tag]]\n\t" "movi v6.16b, #0x87\n\t" "ld1 {v4.2d}, [%x[h]]\n\t" @@ -33115,6 +33136,7 @@ void AES_GCM_init_AARCH64_EOR3(byte* key, int nr, const byte* nonce, word32 nonceSz, byte* gcm_h, byte* counter, byte* initCtr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "movi v6.16b, #0x87\n\t" "ld1 {v5.2d}, [%x[gcm_h]]\n\t" "ushr v6.2d, v6.2d, #56\n\t" @@ -33289,6 +33311,7 @@ void AES_GCM_init_AARCH64_EOR3(byte* key, int nr, const byte* nonce, void AES_GCM_ghash_block_AARCH64_EOR3(const byte* data, byte* tag, byte* gcm_h) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v6.2d}, [%x[tag]]\n\t" "movi v7.16b, #0x87\n\t" "ld1 {v5.2d}, [%x[gcm_h]]\n\t" @@ -33322,6 +33345,7 @@ void AES_GCM_aad_update_AARCH64_EOR3(const byte* aadt, word32 abytes, byte* tag, byte* gcm_h) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v20.2d}, [%x[tag]]\n\t" "movi v21.16b, #0x87\n\t" "ld1 {v12.2d}, [%x[gcm_h]]\n\t" @@ -33650,6 +33674,7 @@ void AES_GCM_encrypt_block_AARCH64_EOR3(const byte* key, int nr, byte* out, const byte* in, byte* counter) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v5.2d}, [%x[counter]]\n\t" "ld1 {v4.2d}, [%x[in]]\n\t" "mov w5, v5.s[3]\n\t" @@ -33710,6 +33735,7 @@ void AES_GCM_encrypt_update_AARCH64_EOR3(const byte* key, int nr, byte* out, const byte* in, word32 nbytes, byte* tag, byte* h, byte* counter) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v13.2d}, [%x[counter]]\n\t" "movi v27.16b, #0x87\n\t" "ld1 {v26.2d}, [%x[tag]]\n\t" @@ -37453,6 +37479,7 @@ void AES_GCM_encrypt_final_AARCH64_EOR3(byte* tag, byte* authTag, word32 tbytes, word32 nbytes, word32 abytes, byte* h, byte* initCtr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v5.2d}, [%x[tag]]\n\t" "movi v6.16b, #0x87\n\t" "ld1 {v4.2d}, [%x[h]]\n\t" @@ -37532,6 +37559,7 @@ void AES_GCM_decrypt_update_AARCH64_EOR3(const byte* key, int nr, byte* out, const byte* in, word32 nbytes, byte* tag, byte* h, byte* counter) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v13.2d}, [%x[counter]]\n\t" "movi v27.16b, #0x87\n\t" "ld1 {v26.2d}, [%x[tag]]\n\t" @@ -41277,6 +41305,7 @@ void AES_GCM_decrypt_final_AARCH64_EOR3(byte* tag, const byte* authTag, int* res) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v5.2d}, [%x[tag]]\n\t" "movi v6.16b, #0x87\n\t" "ld1 {v4.2d}, [%x[h]]\n\t" @@ -41386,6 +41415,7 @@ void AES_XTS_encrypt_AARCH64(const byte* in, byte* out, word32 sz, const byte* i, byte* key, byte* key2, byte* tmp, int nr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v16.2d, v17.2d, v18.2d, v19.2d}, [%x[key2]], #0x40\n\t" "ld1 {v20.2d, v21.2d, v22.2d, v23.2d}, [%x[key2]], #0x40\n\t" "ld1 {v4.16b}, [%x[i]]\n\t" @@ -42410,6 +42440,7 @@ void AES_XTS_decrypt_AARCH64(const byte* in, byte* out, word32 sz, const byte* i, byte* key, byte* key2, byte* tmp, int nr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v16.2d, v17.2d, v18.2d, v19.2d}, [%x[key2]], #0x40\n\t" "ld1 {v20.2d, v21.2d, v22.2d, v23.2d}, [%x[key2]], #0x40\n\t" "ld1 {v4.16b}, [%x[i]]\n\t" @@ -43531,6 +43562,7 @@ void AES_GCMSIV_polyval_pmull(unsigned char* s, const unsigned char* h, const unsigned char* data, unsigned int blocks) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "movi v2.16b, #0\n\t" "ld1 {v1.16b}, [%x[h]]\n\t" "ld1 {v0.16b}, [%x[s]]\n\t" @@ -44061,6 +44093,7 @@ void AES_GCMSIV_ctr_aarch64(const unsigned char* in, unsigned char* out, unsigned long length, const unsigned char* KS, int nr, unsigned char* ctr) { __asm__ __volatile__ ( + ".arch_extension crypto\n\t" "ld1 {v15.2d}, [%x[ctr]]\n\t" "mov w7, v15.s[0]\n\t" "lsr x6, %x[length], #4\n\t" 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..b6a9e3f948e 100644 --- a/wolfcrypt/src/port/arm/armv8-sha256-asm_c.c +++ b/wolfcrypt/src/port/arm/armv8-sha256-asm_c.c @@ -1050,6 +1050,7 @@ void Transform_Sha256_Len_crypto(wc_Sha256* sha256, const byte* data, { const word32* k = L_SHA256_trans_crypto_len_k; __asm__ __volatile__ ( + ".arch_extension crypto\n\t" /* Load K into vector registers */ "ld1 {v8.4s, v9.4s, v10.4s, v11.4s}, [%[k]], #0x40\n\t" "ld1 {v12.4s, v13.4s, v14.4s, v15.4s}, [%[k]], #0x40\n\t" From 97fab88396b024ddad59d12b60d029e14333b480 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/15] 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__, assuming every other assembler learns the extension from the command line. It does not hold: armv8-sha3-asm.S: Error: selected processor does not support `eor3 v31.16b,v0.16b,v5.16b,v10.16b' Emit it unconditionally; it is a no-op where the extension is already on, so the Apple path is unchanged. The AES port needs it too and had none: its AES-GCM EOR3 variants emit eor3, while the only directive in the file is the crypto one added earlier in this branch, which does not cover sha3. Regenerated from the scripts repository, which carries the matching change. --- wolfcrypt/src/port/arm/armv8-aes-asm.S | 2 ++ wolfcrypt/src/port/arm/armv8-aes-asm.asm | 2 ++ wolfcrypt/src/port/arm/armv8-aes-asm_c.c | 10 ++++++++++ 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 -- 9 files changed, 14 insertions(+), 12 deletions(-) diff --git a/wolfcrypt/src/port/arm/armv8-aes-asm.S b/wolfcrypt/src/port/arm/armv8-aes-asm.S index e75f4e526ee..7de05295d18 100644 --- a/wolfcrypt/src/port/arm/armv8-aes-asm.S +++ b/wolfcrypt/src/port/arm/armv8-aes-asm.S @@ -14911,6 +14911,7 @@ L_aes_gcm_decrypt_arm64_crypto_done: #endif /* __APPLE__ */ #endif /* HAVE_AES_DECRYPT || HAVE_AESGCM_DECRYPT */ #ifdef WOLFSSL_ARMASM_CRYPTO_SHA3 +.arch_extension sha3 #ifndef __APPLE__ .text .globl AES_GCM_encrypt_AARCH64_EOR3 @@ -32807,6 +32808,7 @@ L_aes_gcm_decrypt_final_arm64_crypto_tag_loaded: #endif /* __APPLE__ */ #endif /* HAVE_AES_DECRYPT || HAVE_AESGCM_DECRYPT */ #ifdef WOLFSSL_ARMASM_CRYPTO_SHA3 +.arch_extension sha3 #ifndef __APPLE__ .text .globl AES_GCM_init_AARCH64_EOR3 diff --git a/wolfcrypt/src/port/arm/armv8-aes-asm.asm b/wolfcrypt/src/port/arm/armv8-aes-asm.asm index f4d69a8111c..29fd7aee5ca 100644 --- a/wolfcrypt/src/port/arm/armv8-aes-asm.asm +++ b/wolfcrypt/src/port/arm/armv8-aes-asm.asm @@ -14769,6 +14769,7 @@ L_aes_gcm_decrypt_arm64_crypto_done ENDP ENDIF IF :DEF:WOLFSSL_ARMASM_CRYPTO_SHA3 +; .arch_extension sha3 AREA |.text|, CODE, READONLY ALIGN 4 EXPORT AES_GCM_encrypt_AARCH64_EOR3 @@ -32545,6 +32546,7 @@ L_aes_gcm_decrypt_final_arm64_crypto_tag_loaded ENDP ENDIF IF :DEF:WOLFSSL_ARMASM_CRYPTO_SHA3 +; .arch_extension sha3 AREA |.text|, CODE, READONLY ALIGN 4 EXPORT AES_GCM_init_AARCH64_EOR3 diff --git a/wolfcrypt/src/port/arm/armv8-aes-asm_c.c b/wolfcrypt/src/port/arm/armv8-aes-asm_c.c index 52e7ae18fb8..a5efad2975d 100644 --- a/wolfcrypt/src/port/arm/armv8-aes-asm_c.c +++ b/wolfcrypt/src/port/arm/armv8-aes-asm_c.c @@ -15080,6 +15080,7 @@ void AES_GCM_encrypt_AARCH64_EOR3(const byte* in, byte* out, word32 sz, { __asm__ __volatile__ ( ".arch_extension crypto\n\t" + ".arch_extension sha3\n\t" "movi v27.16b, #0x87\n\t" "eor v26.16b, v26.16b, v26.16b\n\t" "ushr v27.2d, v27.2d, #56\n\t" @@ -19850,6 +19851,7 @@ int AES_GCM_decrypt_AARCH64_EOR3(const byte* in, byte* out, word32 sz, { __asm__ __volatile__ ( ".arch_extension crypto\n\t" + ".arch_extension sha3\n\t" "movi v27.16b, #0x87\n\t" "eor v26.16b, v26.16b, v26.16b\n\t" "ushr v27.2d, v27.2d, #56\n\t" @@ -33137,6 +33139,7 @@ void AES_GCM_init_AARCH64_EOR3(byte* key, int nr, const byte* nonce, { __asm__ __volatile__ ( ".arch_extension crypto\n\t" + ".arch_extension sha3\n\t" "movi v6.16b, #0x87\n\t" "ld1 {v5.2d}, [%x[gcm_h]]\n\t" "ushr v6.2d, v6.2d, #56\n\t" @@ -33312,6 +33315,7 @@ void AES_GCM_ghash_block_AARCH64_EOR3(const byte* data, byte* tag, byte* gcm_h) { __asm__ __volatile__ ( ".arch_extension crypto\n\t" + ".arch_extension sha3\n\t" "ld1 {v6.2d}, [%x[tag]]\n\t" "movi v7.16b, #0x87\n\t" "ld1 {v5.2d}, [%x[gcm_h]]\n\t" @@ -33346,6 +33350,7 @@ void AES_GCM_aad_update_AARCH64_EOR3(const byte* aadt, word32 abytes, byte* tag, { __asm__ __volatile__ ( ".arch_extension crypto\n\t" + ".arch_extension sha3\n\t" "ld1 {v20.2d}, [%x[tag]]\n\t" "movi v21.16b, #0x87\n\t" "ld1 {v12.2d}, [%x[gcm_h]]\n\t" @@ -33675,6 +33680,7 @@ void AES_GCM_encrypt_block_AARCH64_EOR3(const byte* key, int nr, byte* out, { __asm__ __volatile__ ( ".arch_extension crypto\n\t" + ".arch_extension sha3\n\t" "ld1 {v5.2d}, [%x[counter]]\n\t" "ld1 {v4.2d}, [%x[in]]\n\t" "mov w5, v5.s[3]\n\t" @@ -33736,6 +33742,7 @@ void AES_GCM_encrypt_update_AARCH64_EOR3(const byte* key, int nr, byte* out, { __asm__ __volatile__ ( ".arch_extension crypto\n\t" + ".arch_extension sha3\n\t" "ld1 {v13.2d}, [%x[counter]]\n\t" "movi v27.16b, #0x87\n\t" "ld1 {v26.2d}, [%x[tag]]\n\t" @@ -37480,6 +37487,7 @@ void AES_GCM_encrypt_final_AARCH64_EOR3(byte* tag, byte* authTag, word32 tbytes, { __asm__ __volatile__ ( ".arch_extension crypto\n\t" + ".arch_extension sha3\n\t" "ld1 {v5.2d}, [%x[tag]]\n\t" "movi v6.16b, #0x87\n\t" "ld1 {v4.2d}, [%x[h]]\n\t" @@ -37560,6 +37568,7 @@ void AES_GCM_decrypt_update_AARCH64_EOR3(const byte* key, int nr, byte* out, { __asm__ __volatile__ ( ".arch_extension crypto\n\t" + ".arch_extension sha3\n\t" "ld1 {v13.2d}, [%x[counter]]\n\t" "movi v27.16b, #0x87\n\t" "ld1 {v26.2d}, [%x[tag]]\n\t" @@ -41306,6 +41315,7 @@ void AES_GCM_decrypt_final_AARCH64_EOR3(byte* tag, const byte* authTag, { __asm__ __volatile__ ( ".arch_extension crypto\n\t" + ".arch_extension sha3\n\t" "ld1 {v5.2d}, [%x[tag]]\n\t" "movi v6.16b, #0x87\n\t" "ld1 {v4.2d}, [%x[h]]\n\t" 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 109ba7d16311434c8898d52879a122f3eaba0c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Wed, 9 Sep 2026 08:26:24 +0200 Subject: [PATCH 07/15] armv8: enable the SHA-3 extension the ML-KEM assembly needs The ARM64 ML-KEM port emits eor3, which is not in the base ARMv8-A a toolchain may be invoked with, and the file carries no directive: armv8-mlkem-asm.S: Error: selected processor does not support `eor3 v31.16b,v0.16b,v5.16b,v10.16b' The directive sits inside WOLFSSL_ARMASM_CRYPTO_SHA3, the guard selecting the variant that needs it, so a build that has not opted in never asks for it. The same file's sqrdmlsh deliberately gets none. RDMA is opt-out (WOLFSSL_AARCH64_NO_SQRDMLSH) where SHA-3 is opt-in, and on a target with no way to read the ID registers cpuid.c reports it present whenever that macro is unset. A directive there would turn a build the assembler correctly rejects into an image that traps on the first sqrdmlsh, so the mnemonic is left to answer to -mcpu. --- wolfcrypt/src/port/arm/armv8-mlkem-asm.S | 1 + wolfcrypt/src/port/arm/armv8-mlkem-asm.asm | 1 + wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c | 3 +++ 3 files changed, 5 insertions(+) diff --git a/wolfcrypt/src/port/arm/armv8-mlkem-asm.S b/wolfcrypt/src/port/arm/armv8-mlkem-asm.S index 14010de9035..fe2c9333c4d 100644 --- a/wolfcrypt/src/port/arm/armv8-mlkem-asm.S +++ b/wolfcrypt/src/port/arm/armv8-mlkem-asm.S @@ -9765,6 +9765,7 @@ L_sha3_aarch64_r: .quad 0x8000000080008081,0x8000000000008080 .quad 0x0000000080000001,0x8000000080008008 #ifdef WOLFSSL_ARMASM_CRYPTO_SHA3 +.arch_extension sha3 #ifndef __APPLE__ .text .globl mlkem_sha3_blocksx3_crypto diff --git a/wolfcrypt/src/port/arm/armv8-mlkem-asm.asm b/wolfcrypt/src/port/arm/armv8-mlkem-asm.asm index d72216929d1..dfa38028993 100644 --- a/wolfcrypt/src/port/arm/armv8-mlkem-asm.asm +++ b/wolfcrypt/src/port/arm/armv8-mlkem-asm.asm @@ -9216,6 +9216,7 @@ L_sha3_aarch64_r DCQ 0x8000000080008081, 0x8000000000008080 DCQ 0x0000000080000001, 0x8000000080008008 IF :DEF:WOLFSSL_ARMASM_CRYPTO_SHA3 +; .arch_extension sha3 AREA |.text|, CODE, READONLY ALIGN 4 EXPORT mlkem_sha3_blocksx3_crypto diff --git a/wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c b/wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c index 2b1f5b40b0f..97986ef5405 100644 --- a/wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c +++ b/wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c @@ -9124,6 +9124,7 @@ void mlkem_sha3_blocksx3_crypto(word64* state) { const word64* r = L_sha3_aarch64_r; __asm__ __volatile__ ( + ".arch_extension sha3\n\t" "stp x29, x30, [sp, #-64]!\n\t" "add x29, sp, #0\n\t" "str %x[state], [x29, #40]\n\t" @@ -9423,6 +9424,7 @@ void mlkem_shake128_blocksx3_seed_crypto(word64* state, byte* seed) { const word64* r = L_sha3_aarch64_r; __asm__ __volatile__ ( + ".arch_extension sha3\n\t" "stp x29, x30, [sp, #-64]!\n\t" "add x29, sp, #0\n\t" "str %x[state], [x29, #40]\n\t" @@ -9744,6 +9746,7 @@ void mlkem_shake256_blocksx3_seed_crypto(word64* state, byte* seed) { const word64* r = L_sha3_aarch64_r; __asm__ __volatile__ ( + ".arch_extension sha3\n\t" "stp x29, x30, [sp, #-64]!\n\t" "add x29, sp, #0\n\t" "str %x[state], [x29, #40]\n\t" From 190798741d6563ed9ef9dd007ef1ce55c3345cf5 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 08/15] armv8: keep the ML-KEM constants inside their feature guard L_mlkem_aarch64_consts sat outside the WOLFSSL_HAVE_MLKEM conditional while zetas, zetas_inv and q sat inside it. With ML-KEM off the C output declares a static const nothing references: armv8-mlkem-asm_c.c:37: error: 'L_mlkem_aarch64_consts' defined but not used [-Werror=unused-const-variable=] Zephyr compiles with -Werror, so armv8-mlkem-asm_c.c was unbuildable on any aarch64 target without ML-KEM, which is every one by default. The cause is in the generator: initialize() emitted the constant but write() is what opens the guard and runs later. Fixed there with a define_consts() called from write(), mirroring the existing define_q(); these files are the regenerated result. --- 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 fe2c9333c4d..c10af417373 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 dfa38028993..f9a41ce0415 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 97986ef5405..8788b1b3ea0 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 d9bd3c1b99e67fbe50ac04714afc141285932c0f 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 09/15] ecc: give the curve ceiling the bit its key-size macro adds A WOLFSSL_CUSTOM_CURVES build fails at runtime on its own largest enabled curve: ecc_test_curve_size 64 failed! (WC_KEY_SIZE_E, -234) Not a Brainpool quirk - a bp256-only build fails on bp256, bp256+bp384 on bp384. The ceiling is off by exactly one bit: ECC_KEY_MAX_BITS() takes a "dp->size * 8 + 1" variant for orders a bit larger than their prime, while MAX_ECC_BITS_NEEDED is the plain curve size, and MP_BITS_CNT() rounds up to whole digits, so that bit puts the key one digit past the ceiling. Name it MAX_ECC_BITS_EXTRA and build both sides from it. Custom curves are only one of three ways the variant gets selected: ECC_MIN_KEY_SZ at or below 160 takes it, as does HAVE_ECC_KOBLITZ at or below 224, the default for any Koblitz build. MAX_ECC_BITS keeps meaning the plain size of the largest curve, so a build that pins it to exactly what its curves need still passes the guard that rejects a too-small value. MAX_ECC_BITS_USE also derived from MAX_ECC_BITS_NEEDED, so an overridden MAX_ECC_BITS never reached the runtime guard. Derive it from MAX_ECC_BITS, which only ever widens, and is what an arbitrary curve passed to wc_ecc_set_custom_curve() needs. The SP_INT_BITS clamp above it is unchanged. --- wolfcrypt/src/ecc.c | 29 ++++++++++------------------- wolfssl/wolfcrypt/ecc.h | 11 +++++++++++ 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 37b64a89efe..5ad5e1dcf52 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -349,33 +349,24 @@ 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 the largest curve compiled in unless the user raised it, and + * ecc.h rejects a smaller one. MAX_ECC_BITS_EXTRA is the bit ECC_KEY_MAX_BITS + * adds below, so the working values need room for it too. */ +#if defined(WOLFSSL_SP_MATH_ALL) && \ + SP_INT_BITS < (MAX_ECC_BITS + MAX_ECC_BITS_EXTRA) #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 + MAX_ECC_BITS_EXTRA) #endif -#if !defined(WOLFSSL_CUSTOM_CURVES) && (ECC_MIN_KEY_SZ > 160) && \ - (!defined(HAVE_ECC_KOBLITZ) || (ECC_MIN_KEY_SZ > 224)) - -#define ECC_KEY_MAX_BITS(key) \ - ((((key) == NULL) || ((key)->dp == NULL)) ? MAX_ECC_BITS_USE : \ - ((unsigned)((key)->dp->size * 8))) -#define ECC_KEY_MAX_BITS_NONULLCHECK(key) \ - (((key)->dp == NULL) ? MAX_ECC_BITS_USE : \ - ((unsigned)((key)->dp->size * 8))) - -#else - -/* Add one bit for cases when order is a bit greater than prime. */ +/* MAX_ECC_BITS_EXTRA (ecc.h) is the one bit the builds whose order can be a bit + * greater than the prime need, and the ceiling is sized from the same macro. */ #define ECC_KEY_MAX_BITS(key) \ ((((key) == NULL) || ((key)->dp == NULL)) ? MAX_ECC_BITS_USE : \ - ((unsigned)((key)->dp->size * 8 + 1))) + ((unsigned)((key)->dp->size * 8 + MAX_ECC_BITS_EXTRA))) #define ECC_KEY_MAX_BITS_NONULLCHECK(key) \ (((key)->dp == NULL) ? MAX_ECC_BITS_USE : \ - ((unsigned)((key)->dp->size * 8 + 1))) - -#endif + ((unsigned)((key)->dp->size * 8 + MAX_ECC_BITS_EXTRA))) #ifdef WOLFSSL_ECC_BLIND_K /* Number of digits covered by the fixed-width XORs below. */ diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index d3785827f40..05155a9f29e 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -128,6 +128,17 @@ #define MAX_ECC_BITS_NEEDED 112 #endif +/* The bit ECC_KEY_MAX_BITS adds for an order larger than the prime. It is an + * internal sizing detail rather than part of the curve size a user configures, + * so ecc.c folds it into MAX_ECC_BITS_USE and builds ECC_KEY_MAX_BITS from the + * same macro, and MAX_ECC_BITS keeps meaning the plain largest curve. */ +#if defined(WOLFSSL_CUSTOM_CURVES) || (ECC_MIN_KEY_SZ <= 160) || \ + (defined(HAVE_ECC_KOBLITZ) && (ECC_MIN_KEY_SZ <= 224)) + #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 #else From 93383ede4977c54b6d84d6a68c4cf4d7e7453562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 8 Sep 2026 19:58:02 +0200 Subject: [PATCH 10/15] wolfio: follow Zephyr 4.4's rename of htons() and ntohs() XHTONS and XNTOHS resolve to htons() and ntohs() when the socket I/O layer is compiled in. Zephyr 4.4 renamed those to net_htons() and net_ntohs(), and brings the unprefixed spellings back only under CONFIG_NET_NAMESPACE_COMPAT_MODE: wolfio.h:1060: error: implicit declaration of function 'htons' On a host-libc target such as native_sim it surfaces at link time instead, out of DefTicketEncCb(). That call site uses XHTONS on a session-ticket length field rather than on a socket port, so the macro is doing plain byte-order work; nothing had reached it before because session tickets require TLS 1.3. Zephyr 4.3 and older define the unprefixed names themselves, so neither spelling covers the supported range. Gate on KERNEL_VERSION_NUMBER, the way the 4.1 socket changes already are a few hundred lines above. --- wolfssl/wolfio.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/wolfssl/wolfio.h b/wolfssl/wolfio.h index 2194c254c29..a31d5d4fe92 100644 --- a/wolfssl/wolfio.h +++ b/wolfssl/wolfio.h @@ -1057,7 +1057,13 @@ WOLFSSL_API void wolfSSL_SetIOWriteFlags(WOLFSSL* ssl, int flags); #ifndef XHTONS #if !defined(WOLFSSL_NO_SOCK) && (defined(USE_WOLFSSL_IO) || defined(HAVE_HTTP_CLIENT)) - #define XHTONS(a) htons((a)) + #if defined(WOLFSSL_ZEPHYR) && KERNEL_VERSION_NUMBER >= 0x40400 + /* Zephyr 4.4 renamed htons() to net_htons() and brings the old name + * back only under CONFIG_NET_NAMESPACE_COMPAT_MODE. */ + #define XHTONS(a) net_htons((a)) + #else + #define XHTONS(a) htons((a)) + #endif #else /* we don't have sockets, so define our own htons and ntohs */ #ifdef BIG_ENDIAN_ORDER @@ -1069,7 +1075,13 @@ WOLFSSL_API void wolfSSL_SetIOWriteFlags(WOLFSSL* ssl, int flags); #endif #ifndef XNTOHS #if !defined(WOLFSSL_NO_SOCK) && (defined(USE_WOLFSSL_IO) || defined(HAVE_HTTP_CLIENT)) - #define XNTOHS(a) ntohs((a)) + #if defined(WOLFSSL_ZEPHYR) && KERNEL_VERSION_NUMBER >= 0x40400 + /* Zephyr 4.4 renamed ntohs() to net_ntohs() and brings the old name + * back only under CONFIG_NET_NAMESPACE_COMPAT_MODE. */ + #define XNTOHS(a) net_ntohs((a)) + #else + #define XNTOHS(a) ntohs((a)) + #endif #else /* we don't have sockets, so define our own htons and ntohs */ #ifdef BIG_ENDIAN_ORDER From 28992cf8a4a39f8aed7a0c6539f506be1fd4345b 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 11/15] zephyr: select ECC curves through Kconfig The module hard-coded ECC_USER_CURVES with SECP256R1 alone, so an application needing P-384, P-521 or Brainpool had to patch user_settings.h. Each curve is now its own option under WOLFSSL_ECC, with P-256 the default so existing configurations are unaffected. Two dependencies are encoded rather than left to be rediscovered, since both fail without pointing at the cause. Brainpool needs WOLFSSL_CUSTOM_CURVES, its curves not being prime-field NIST ones; custom curves in turn cannot coexist with the per-curve SP math this module selects, so asking for Brainpool moves the build onto the generic SP variant. That costs size and speed on the common curves, which is why it is opt-in. Brainpool does not drag another curve in with it, though it looks as though it must: on the generic variant the enabled-curve ceiling has to clear the largest Brainpool curve compiled in, and when it does not that curve fails with WC_KEY_SIZE_E. That ceiling was short by one bit, fixed earlier in this branch. Koblitz keeps its commented-out line rather than gaining an option, secp256k1 and secp224k1 having no TLS or wolfPSA use. P-256 keeps its inverted sense, being the one curve wolfCrypt enables by default. Verified on frdm_rw612: with P-384 and P-521 selected all three curves round-trip a signature on device; with the defaults the image is unchanged and 20 KB smaller. --- zephyr/Kconfig | 62 +++++++++++++++++++++++++++++++++++++++++- zephyr/user_settings.h | 57 ++++++++++++++++++++++++++++++++------ 2 files changed, 110 insertions(+), 9 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..ab1dfb93f6f 100644 --- a/zephyr/user_settings.h +++ b/zephyr/user_settings.h @@ -303,15 +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 */ @@ -520,7 +546,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 +596,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 633f75742809ece392da8b34ba0ab9d46cb8140d 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 12/15] 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, and the Brainpool set that forces the generic backend, with no P-521 present to lend it a curve ceiling. --- .github/workflows/zephyr.yml | 14 ++++++++++--- .../samples/wolfssl_test/prj-ecc-custom.conf | 15 ++++++++++++++ zephyr/samples/wolfssl_test/prj-ecc-nist.conf | 20 +++++++++++++++++++ zephyr/samples/wolfssl_test/sample.yaml | 14 +++++++++++++ 4 files changed, 60 insertions(+), 3 deletions(-) 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/.github/workflows/zephyr.yml b/.github/workflows/zephyr.yml index 571106494ab..770b811309a 100644 --- a/.github/workflows/zephyr.yml +++ b/.github/workflows/zephyr.yml @@ -95,10 +95,18 @@ jobs: # Scope -T to the sample directory (not the whole module) so twister does # not load zephyr/tests/*/testcase.yaml. The condvar test's modern # list-form platform_allow is rejected by the 2.7.4 twister schema, and - # this is the only sample step that runs on 2.7.4. Runs both scenarios - # (wolfssl_test and wolfssl_test_no_malloc). + # this is the only sample step that runs on 2.7.4. + # + # Name the two scenarios rather than running the whole sample: the rest + # need a Zephyr these versions predate - hierarchical board names, + # COMMON_LIBC_MALLOC_ARENA_SIZE, and toolchains beyond the x86_64 one + # installed above. --test drops the others before their platform_allow + # is resolved, so an unrecognized board does not abort the run - but + # the yaml is still parsed, so a modern-only key would. run: | - ./zephyr/scripts/twister -T modules/crypto/wolfssl/zephyr/samples/wolfssl_test -vvv + ./zephyr/scripts/twister -T modules/crypto/wolfssl/zephyr/samples/wolfssl_test \ + --test sample.crypto.wolfssl_test \ + --test sample.crypto.wolfssl_test_no_malloc -vvv rm -rf zephyr/twister-out - name: Run wolfssl TLS sock test 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..7dd1057215b --- /dev/null +++ b/zephyr/samples/wolfssl_test/prj-ecc-custom.conf @@ -0,0 +1,15 @@ +# 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. 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 90488d7fa34f0cf26015b87e1fd46e498d9fd0d6 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 13/15] 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, as was every other feature option. They now depend on not having one. 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 each version: on the choice members alone the version prompt would stay visible with nothing selectable, 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, and the commit after this one deletes it. Options that drive the build rather than the wolfCrypt configuration 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 4078ef6d5a05b298f8b211e482a978540cea554b 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 14/15] zephyr: delete the dead TLS Kconfig inherited from mbedTLS Kconfig.tls-generic is a copy of Zephyr's mbedTLS file with the symbol prefix renamed, which is why a wolfSSL module carries options named after mbedTLS internals. Renaming was all that happened: of its 53 config symbols, exactly two reach any code, WOLFSSL_TLS_VERSION_1_2 and _1_3. Checked every symbol against the whole workspace; the other 51 appear only in that file, so CONFIG_WOLFSSL_ECP_DP_SECP384R1_ENABLED=y has always done nothing. Three are worse than inert: WOLFSSL_TLS_VERSION_1_0, _1_1 and _1_3 select symbols that are defined nowhere, and Kconfig accepts that silently, so the reader sees a mechanism that does not exist. Delete the file and move the two live symbols into the module's own Kconfig, next to WOLFSSL_DTLS, keeping the settings-file dependency. The dead selects go with it, as do four dead options the TLS samples were setting and a stale entry in .wolfssl_known_macro_extras. TLS 1.3 gains a default of y. The old file had 1.2 on and 1.3 off, Zephyr's mbedTLS default from 2018, while wolfSSL's own configure enables both. Keeping 1.2 as well preserves interop with the TLS 1.2-only peers embedded deployments still meet; a 1.3-only build works by clearing the 1.2 option. That default is also what first reached DefTicketEncCb(), hence the wolfio byte-order fix earlier in this branch. --- .wolfssl_known_macro_extras | 1 - zephyr/Kconfig | 18 +- zephyr/Kconfig.tls-generic | 267 --------------------- zephyr/include.am | 1 - zephyr/samples/wolfssl_tls_sock/prj.conf | 4 - zephyr/samples/wolfssl_tls_thread/prj.conf | 4 - zephyr/user_settings.h | 2 +- 7 files changed, 17 insertions(+), 280 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..36444928fe8 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,22 @@ 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 + default y + 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/include.am b/zephyr/include.am index 6c602ecd258..49cbb306dd4 100644 --- a/zephyr/include.am +++ b/zephyr/include.am @@ -4,7 +4,6 @@ EXTRA_DIST+= zephyr/CMakeLists.txt EXTRA_DIST+= zephyr/Kconfig -EXTRA_DIST+= zephyr/Kconfig.tls-generic EXTRA_DIST+= zephyr/zephyr_init.c EXTRA_DIST+= zephyr/module.yml EXTRA_DIST+= zephyr/wolfssl/options.h 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 ab1dfb93f6f..90f20632e09 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 cb9556657ce02511cabc5430a8e33a61dc9401c2 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 15/15] 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 defined WOLFSSL_ARMASM_THUMB2, so the link failed on AES_*_AARCH32. WOLFCRYPT_INTELASM named the 32-bit sources while user_settings.h declared WOLFSSL_X86_64_BUILD, so aes_asm.S compiled to an empty object and aes_gcm_x86_asm.S emitted 32-bit code into a 64-bit build. 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. ARMv6-M and ARMv8-M baseline get no symmetric assembly - the Thumb2 port uses UBFX and LDRD, which those cores do not have - and keep the Thumb math. Each ARM port sets two single-precision macros. WOLFSSL_SP__ASM compiles the per-size backend; the unsuffixed WOLFSSL_SP_ enables the inline-asm word primitives in sp_int.c, which is what the generic WOLFSSL_SP_MATH_ALL path uses for every other size and curve. Defining only the _ASM half, as this module did, left Brainpool, custom curves and any uncovered RSA or DH size with no assembly at all. Every ARM profile needs WOLFSSL_ARMASM_NO_HW_CRYPTO unless the toolchain says otherwise. The ARMv8-32 sources carry no .arch_extension, so a plain ARMv7 part rejects aese.8 outright; the AArch64 ones do carry it and always assemble, which moves the failure rather than removing it, since cpuid.c has no ID registers to read here and reports AES, PMULL and SHA-256 present whenever the macro is unset. Key it on __ARM_FEATURE_CRYPTO, and the ARMv8.1 RDMA opt-out on __ARM_FEATURE_QRDMX for the same reason. ML-KEM's small-memory key generation and encapsulation are dropped where the assembly is on for x86_64 or AArch64: wc_mlkem.c rejects that combination with an #error rather than falling back. Neither 32-bit x86 nor the x86_64 single-precision assembly is offered. The latter is worth recording: sp_x86_64_asm.S is AVX throughout and sp_x86_64.c calls into it with no CPUID dispatch and no scalar counterpart, while Zephyr never sets CR4.OSXSAVE, so those instructions fault. Both set(TOOLCHAIN_C_FLAGS ...) calls go: Zephyr applies that variable globally before it add_subdirectory's modules, so the assignment ran after the flags were consumed and never reached the parent scope either. HAVE___UINT128_T is defined wherever the compiler has the type, since with user settings nobody sets it and sp_int.c fails on an undeclared sp_int_word. One wolfssl_test scenario per port covers the option: qemu_x86_64 for Intel, qemu_cortex_a53 for AArch64, and mps2/an521/cpu0 for Thumb2. AArch64 gets a second at -mcpu=cortex-a53+crypto, since the guard above keeps the hardware blocks out of the first and the .arch_extension directives would otherwise never be assembled here. Measured on frdm_rw612, ops/sec: ECDSA P-256 sign 16 to 136, verify 10 to 102, RSA-2048 public 86 to 194. --- .wolfssl_known_macro_extras | 16 ++++- zephyr/CMakeLists.txt | 79 +++++++++------------ zephyr/Kconfig | 62 ++++++++++++----- zephyr/samples/wolfssl_benchmark/prj.conf | 5 +- zephyr/samples/wolfssl_test/sample.yaml | 51 ++++++++++++++ zephyr/user_settings.h | 84 +++++++++++++++++------ 6 files changed, 210 insertions(+), 87 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 5f3185ed338..fc8eeaf971b 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -70,12 +70,17 @@ CONFIG_ARCH_POSIX CONFIG_ARCH_TEGRA CONFIG_ARM CONFIG_ARM64 +CONFIG_ARMV6_M_ARMV8_M_BASELINE +CONFIG_ARMV7_M_ARMV8_M_MAINLINE CONFIG_BOARD_NATIVE_POSIX CONFIG_BOARD_NATIVE_SIM CONFIG_COMPILER_OPTIMIZATION_DEFAULT CONFIG_COMPILER_OPTIMIZATION_NONE CONFIG_COMPILER_OPTIMIZATION_PERF CONFIG_COMPILER_OPTIMIZATION_SIZE +CONFIG_CPU_AARCH32_CORTEX_A +CONFIG_CPU_AARCH32_CORTEX_R +CONFIG_CPU_CORTEX_M CONFIG_CRYPTO_AES CONFIG_CRYPTO_CBC CONFIG_CRYPTO_CCM @@ -171,14 +176,14 @@ CONFIG_TIMER_TASK_STACK_SIZE CONFIG_TLS_STACK_WOLFSSL CONFIG_USE_WOLFSSL_ESP_SDK_TIME CONFIG_USE_WOLFSSL_ESP_SDK_WIFI -CONFIG_WOLFCRYPT_ARMASM +CONFIG_WOLFCRYPT_ASM CONFIG_WOLFCRYPT_FIPS CONFIG_WOLFCRYPT_FIPS_READY CONFIG_WOLFCRYPT_FIPS_V2 CONFIG_WOLFCRYPT_FIPS_V5 CONFIG_WOLFCRYPT_FIPS_V6 CONFIG_WOLFCRYPT_FIPS_V7 -CONFIG_WOLFCRYPT_INTELASM +CONFIG_WOLFCRYPT_SP_SMALL CONFIG_WOLFSSL CONFIG_WOLFSSL_ALLOW_TLS13 CONFIG_WOLFSSL_ALPN @@ -193,6 +198,11 @@ CONFIG_WOLFSSL_CRYPTO_ONLY CONFIG_WOLFSSL_CURVE25519 CONFIG_WOLFSSL_DTLS CONFIG_WOLFSSL_ECC +CONFIG_WOLFSSL_ECC_256 +CONFIG_WOLFSSL_ECC_384 +CONFIG_WOLFSSL_ECC_512 +CONFIG_WOLFSSL_ECC_521 +CONFIG_WOLFSSL_ECC_BRAINPOOL CONFIG_WOLFSSL_ENABLE_KYBER CONFIG_WOLFSSL_EXAMPLE_NAME_ESP32_SSH_SERVER CONFIG_WOLFSSL_EXAMPLE_NAME_ESP8266_SSH_SERVER @@ -1086,6 +1096,7 @@ WOLFSSL_SNIFFER_NO_RECOVERY WOLFSSL_SP_ARM32_UDIV WOLFSSL_SP_FAST_NCT_EXPTMOD WOLFSSL_SP_INT_SQR_VOLATILE +WOLFSSL_SP_USE_UDIV WOLFSSL_SSLKEYLOGFILE_USE_ENV WOLFSSL_STACK_CHECK WOLFSSL_STM32C5 @@ -1234,6 +1245,7 @@ __ARM_ARCH_7M__ __ARM_ARCH_PROFILE __ARM_FEATURE_CRYPTO __ARM_FEATURE_DSP +__ARM_FEATURE_QRDMX __ARM_FEATURE_SIMD32 __ARM_FEATURE_SME __ARM_FEATURE_SVE diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 39f5c58d805..d28559811e3 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -136,53 +136,42 @@ 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, wc_mlkem_asm.S and wc_mldsa_asm.S are here because + # curve25519.c, wc_mlkem_poly.c and wc_mldsa.c all take the Intel path + # whenever USE_INTEL_SPEEDUP is set, so leaving one out is a link error + # the moment an application enables that algorithm. Each is guarded by + # its own feature macro, so it costs an empty object when it is off. + # The AES sources are not here: 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 wc_mlkem_asm wc_mldsa_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 36444928fe8..a8259fef9db 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -340,24 +340,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..64119403d74 100644 --- a/zephyr/samples/wolfssl_test/sample.yaml +++ b/zephyr/samples/wolfssl_test/sample.yaml @@ -33,3 +33,54 @@ 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, at the board's own + # -mcpu. Plain ARMv8-A has no crypto extension, so user_settings.h opts out + # of the hardware paths and this covers the software ones. + 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_aarch64_crypto: + # The same port with the crypto extension named, which is what turns the + # hardware paths on. Covers the .arch_extension directives the generated + # 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 + - CONFIG_COMPILER_OPT="-mcpu=cortex-a53+crypto" + 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 90f20632e09..2dc565335fc 100644 --- a/zephyr/user_settings.h +++ b/zephyr/user_settings.h @@ -490,8 +490,14 @@ extern "C" { #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 + /* The Intel and AArch64 ML-KEM assembly has no small-memory variant of + * key generation or encapsulation, and wc_mlkem.c rejects the pair with an + * #error rather than falling back. */ + #if !defined(CONFIG_WOLFCRYPT_ASM) || \ + !(defined(CONFIG_X86_64) || defined(CONFIG_ARM64)) + #define WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM + #define WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM + #endif #define WOLFSSL_MLKEM_DYNAMIC_KEYS #endif @@ -618,17 +624,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 @@ -636,27 +656,49 @@ 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 */ + /* Without this the Thumb2 sources compile but every caller still takes + * the ARMv8 path, so the port selects files and nothing else. */ + #ifdef CONFIG_CPU_CORTEX_M + #define WOLFSSL_ARMASM_THUMB2 + #endif - #if 0 /* ARMv7 */ - #define WOLFSSL_ARM_ARCH 7 - #define WOLFSSL_ARMASM_NO_HW_CRYPTO /* enable if processor does not support aes/sha instructions */ + /* AArch32 assembles its hardware crypto blocks only when the -mcpu Zephyr + * derives from the board already has the extension; AArch64 carries its + * own .arch_extension and always assembles them, and cpuid.c then claims + * AES, PMULL and SHA-256 unless this is set, so aese traps on a core + * without them. */ + #ifndef __ARM_FEATURE_CRYPTO + #define WOLFSSL_ARMASM_NO_HW_CRYPTO #endif -#endif -#ifdef CONFIG_WOLFCRYPT_INTELASM + /* Nothing probes the CPU on bare metal, so cpuid.c claims RDMA whenever + * this is not set and mlkem_keygen() runs sqrdmlsh on a core without it. */ + #if defined(CONFIG_ARM64) && !defined(__ARM_FEATURE_QRDMX) + #define WOLFSSL_AARCH64_NO_SQRDMLSH + #endif +#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