Skip to content

Zephyr: make the constant-time AES option cover GHASH and the Arm assembly - #11691

Merged
SparkiDev merged 1 commit into
wolfSSL:masterfrom
Frauschi:zephyr-ghash-ct
Oct 9, 2026
Merged

SparkiDev merged 1 commit into
wolfSSL:masterfrom
Frauschi:zephyr-ghash-ct

Conversation

@Frauschi

@Frauschi Frauschi commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Description

CONFIG_WOLFSSL_AES_CONSTANT_TIME (added for wolfPSA, which requires a constant-time AES) had two holes.

GHASH. The Zephyr module hardcoded GCM_SMALL, whose GMULT() branches on every bit of the hash subkey H. WOLFSSL_AES_TOUCH_LINES and WC_AES_BITSLICED only change the AES block cipher core, so AES-GCM was not constant time with the option on. The only constant-time C GHASH is the masked bitwise multiply wolfCrypt builds when no GCM method is defined.

Assembly. With CONFIG_WOLFCRYPT_ASM on Arm, the Thumb2, ARM32 and AArch64 assembly replaces the C AES core outright and indexes 1 KB T-tables with secret data. The build accepted touch-lines alongside it without a word: on mps2/an521 the image linked AES_encrypt_block and L_AES_Thumb2_te_data. GHASH under the Arm assembly is likewise never the masked multiply.

Changes

  • New WOLFSSL_AES_GCM_GHASH choice: bitwise multiply (constant time, the new default), 4-bit table (GCM_TABLE_4BIT) and 8-bit table (GCM_TABLE). The tables depend on !WOLFSSL_AES_CONSTANT_TIME. GCM_SMALL is no longer offered on plain C builds: it is not constant time either, and in a host autoconf build its GMAC ran at 16.6 MiB/s against 162 MiB/s for the bitwise multiply and 726 MiB/s for the 4-bit table.
  • WOLFSSL_AES_CONSTANT_TIME is no longer available where CONFIG_WOLFCRYPT_ASM builds the Arm symmetric assembly: ARMv7-M and ARMv8-M mainline, 32-bit Cortex-A/R and AArch64, through a hidden WOLFCRYPT_ARM_SYMMETRIC_ASM, which user_settings.h and CMakeLists.txt now test instead of repeating the core list. The GHASH choice defaults to the 4-bit table there; the 8-bit table and GCM_SMALL (no table) stay selectable. AArch64 parts with the crypto extension lose the option too, because Kconfig cannot see that compiler feature. ARMv6-M and ARMv8-M baseline keep it, since they get assembly for the SP math only. x86_64 is unaffected: USE_INTEL_SPEEDUP keeps the C AES core, so touch-lines takes effect.
  • FIPS v2 and v5 pin an aes.c older than the masked multiply (v5 builds it only under AES_GCM_GMULT_CT, v2 not at all). Both keep GCM_SMALL as their default, so a validated build keeps its boundary object. Under v5 the constant-time choice also defines AES_GCM_GMULT_CT; under v2 it is not offered, and neither is the 4-bit table, which v2's aes.c predates. FIPS v6 and later have the masked multiply by default and can still pick GCM_SMALL to keep an existing boundary object.
  • Corrected the option's help, which claimed it had no effect with the assembly core because that core "compiles no software table".

Behaviour change: a configuration that set both CONFIG_WOLFCRYPT_ASM and CONFIG_WOLFSSL_AES_CONSTANT_TIME on one of those Arm cores now gets a Kconfig warning and the constant-time option off, where it used to get table-based AES under a constant-time label. The default GHASH moves from GCM_SMALL to the bitwise multiply (no ASM) or the 4-bit table (Arm ASM).

Testing

  • New wolfssl_test scenarios: ghash_table_4bit, ghash_table_8bit and aes_constant_time on qemu_x86, plus asm_thumb2_ghash_table_8bit (mps2/an521/cpu0) and asm_aarch64_ghash_table_8bit (qemu_cortex_a53).
  • west twister -T zephyr/samples/wolfssl_test on qemu_x86, qemu_x86_64, qemu_cortex_a53 and mps2/an521/cpu0: 13 of 13 pass. The linked symbols confirm each scenario got the GHASH it selected: the masked GMULT with no R table by default, the 64- and 512-byte R tables for the 4-bit and 8-bit choices, and the assembly GCM_gmult_len on Thumb2 and AArch64.
  • FIPS (Kconfig and preprocessed user_settings.h only, no bundle here): v5 defaults to GCM_SMALL and its constant-time choice yields AES_GCM_GMULT_CT; v2 refuses the constant-time choice and the 4-bit table; v6 defaults to constant time, accepts GCM_SMALL, and refuses it alongside constant-time AES.
  • GCM_SMALL under the Thumb2 assembly on mps2/an521/cpu0: passes, linking the C GMULT.
  • Kconfig: constant-time AES with a table GHASH falls back to the bitwise multiply with a warning; constant-time AES with the Arm symmetric assembly is refused with a warning on mps2/an521, and stays available on the ARMv6-M nucleo_g071rb, which then compiles the C AES core and GMULT.

Follow-up

wolfPSA's src/psa_config.h check looks only at the AES core and counts WOLFSSL_ARMASM as a hardware backend, so it still accepts both a non-constant-time GHASH and the table-based Arm assembly. That fix belongs in wolfPSA and will be a separate PR.

Copilot AI balanced review requested due to automatic review settings October 8, 2026 09:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The Arm predicate incorrectly disables constant-time AES on baseline Cortex-M targets that do not compile symmetric assembly.

2 open findings
What changed in this PR

Updates Zephyr’s AES configuration so constant-time mode also covers GHASH and avoids incompatible Arm assembly paths.

Changes:

  • Adds selectable constant-time, 4-bit, and 8-bit GHASH implementations.
  • Restricts constant-time AES with Arm assembly.
  • Adds Zephyr test scenarios and release documentation.
File Description
zephyr/​Kconfig Defines GHASH choices and constant-time constraints.
zephyr/​user_settings.h Maps GHASH selections to wolfCrypt macros.
zephyr/​samples/​wolfssl_test/​sample.yaml Adds configuration test scenarios.
.wolfssl_known_macro_extras Registers new Zephyr macros.
ChangeLog.md Documents the behavior change.

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

Comment thread zephyr/Kconfig Outdated
Comment thread zephyr/Kconfig Outdated
CONFIG_WOLFSSL_AES_CONSTANT_TIME left two holes that the option and
wolfPSA's psa_config.h check both missed.

GHASH. The module hardcoded GCM_SMALL, whose GMULT branches on every bit
of the hash subkey H. WOLFSSL_AES_TOUCH_LINES and WC_AES_BITSLICED only
change the AES block cipher core, so AES-GCM was not constant time with
the option on. The only constant-time C GHASH is the masked bitwise
multiply wolfCrypt builds when no GCM method is defined.

Add a GHASH choice. It defaults to that bitwise multiply, and offers the
4-bit and 8-bit tables as opt-ins that depend on !WOLFSSL_AES_CONSTANT_TIME.
GCM_SMALL is no longer offered on plain C builds: it is not constant
time either, and in a host autoconf build its GMAC ran at 16.6 MiB/s
against 162 MiB/s for the bitwise multiply and 726 MiB/s for the 4-bit
table.

Assembly. With CONFIG_WOLFCRYPT_ASM on Arm the Thumb2, ARM32 and AArch64
assembly replaces the C AES core outright, and it indexes 1 KB T-tables
with secret data. wolfCrypt has no macro to drop only the AES assembly,
and the build accepted touch-lines alongside it without a word: on
mps2/an521 the image linked AES_encrypt_block and L_AES_Thumb2_te_data.
GHASH under the Arm assembly is a table or the bitwise multiply that
branches on H, never the masked one. So the constant-time option is no
longer available where the module builds the Arm symmetric assembly -
ARMv7-M and ARMv8-M mainline, 32-bit Cortex-A/R and AArch64 - and the
GHASH choice defaults to the 4-bit table there, with GCM_SMALL kept as
a tableless option. A hidden WOLFCRYPT_ARM_SYMMETRIC_ASM now holds that
core list, and user_settings.h and CMakeLists.txt test it instead of
repeating the condition. AArch64 parts with the crypto extension lose the
option too, because Kconfig cannot see that compiler feature. ARMv6-M
and ARMv8-M baseline keep it: they get assembly for the SP math only.
x86_64 is unaffected: USE_INTEL_SPEEDUP leaves the C AES core in place,
so touch-lines takes effect.

FIPS v2 and v5 pin an aes.c older than the masked multiply: v5 builds
it only under AES_GCM_GMULT_CT and v2 not at all. Both keep GCM_SMALL as
their default, so a validated build keeps its boundary object. Under v5
the constant-time choice also defines AES_GCM_GMULT_CT; under v2 it is
not offered, and neither is the 4-bit table, which v2's aes.c predates.
FIPS v6 and later have the masked multiply by default and can still
pick GCM_SMALL to keep an existing boundary object.

A configuration that set both options now gets a Kconfig warning and
the option turned off, instead of table-based AES under a constant-time
label.

New wolfssl_test scenarios cover the two tables and the constant-time
AES core on qemu_x86, and the 8-bit table under the Thumb2 and AArch64
assembly. All thirteen wolfssl_test scenarios pass on
qemu_x86, qemu_x86_64, qemu_cortex_a53 and mps2/an521/cpu0, and the
symbols confirm each one linked the GHASH it selected.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Security-sensitive behavior spans multiple architectures and unavailable FIPS source variants, requiring final human validation.

0 open findings

2 resolved since last review

🧠 Review effort: Balanced

@SparkiDev SparkiDev self-assigned this Oct 9, 2026
@SparkiDev
SparkiDev merged commit 9a33474 into wolfSSL:master Oct 9, 2026
382 of 383 checks passed
@Frauschi
Frauschi deleted the zephyr-ghash-ct branch October 9, 2026 06:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants