Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/build-config-matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ jobs:
modifiers: "-HAVE_AES_ECB +WOLFPSA_NO_AES_BITSLICED +WOLFSSL_AES_TOUCH_LINES"
- name: aes-fast
modifiers: "+WOLFPSA_NO_AES_BITSLICED +WOLFPSA_AES_FAST"
- name: aes-fast-gcm-table
modifiers: "+WOLFPSA_NO_AES_BITSLICED +WOLFPSA_AES_FAST +GCM_TABLE_4BIT"
- name: aes-ctr
modifiers: "-WOLFSSL_AES_COUNTER"
- name: aes-cfb
Expand Down Expand Up @@ -109,3 +111,20 @@ jobs:
env:
BUILD_TARGET: ${{ matrix.config.target || 'libwolfpsa.a' }}
run: ./build-test/build-variant.sh "${{ matrix.config.name }}" ${{ matrix.config.modifiers }}

psa-config-policy:
name: psa_config.h policy / wolfSSL ${{ matrix.wolfssl-ref }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
wolfssl-ref: [ master, v5.9.4-stable ]
steps:
- name: Check out wolfPSA
uses: actions/checkout@v4

- name: Clone sibling wolfSSL
run: git clone --depth 1 --branch ${{ matrix.wolfssl-ref }} https://github.com/wolfSSL/wolfssl ../wolfssl

- name: Check accepted and refused configurations
run: ./build-test/psa-config-policy.sh ../wolfssl
95 changes: 95 additions & 0 deletions build-test/psa-config-policy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/bin/sh
#
# Check that src/psa_config.h accepts and refuses the AES and GHASH
# configurations it should, by preprocessing it against the sibling wolfSSL.
# build-test/user_settings.h is the config, so WOLFPSA_NO_AES_BITSLICED can
# take the constant-time AES core away.
#
# Usage: build-test/psa-config-policy.sh [WOLFSSL_PATH]

set -u

repo_root="$(cd "$(dirname "$0")/.." && pwd)"
wolfssl="${1:-${repo_root}/../wolfssl}"
cc="${CC:-cc}"
fails=0

# wolfcrypt/fips.h ships only with a FIPS bundle; an empty one lets the
# HAVE_FIPS cases preprocess against a plain wolfSSL tree.
stub="$(mktemp -d)"
trap 'rm -rf "${stub}"' EXIT
mkdir -p "${stub}/wolfssl/wolfcrypt"
: > "${stub}/wolfssl/wolfcrypt/fips.h"

# check <expected outcome> [-DFLAG ...]
# The outcome is "pass", or a fragment of the wolfPSA #error the build must
# stop on, so a failure for any other reason does not count.
check() {
want="$1"
shift
out="$(echo '#include "psa_config.h"' | "${cc}" -x c -fsyntax-only \
-I"${repo_root}/build-test" -I"${repo_root}/src" -I"${wolfssl}" \
-I"${stub}" \
-DWOLFSSL_USER_SETTINGS -DHAVE_AESGCM -DHAVE_AES_ECB "$@" - 2>&1)"
rc=$?
if [ "${want}" = "pass" ]; then
[ "${rc}" -eq 0 ] && ok=1 || ok=0
else
case "${out}" in
*"wolfPSA: ${want}"*) ok=1 ;;
*) ok=0 ;;
esac
fi
if [ "${ok}" -eq 1 ]; then
echo "ok $*"
else
echo "FAIL expected '${want}': $*"
echo "${out}" | grep -m3 "error"
fails=$((fails + 1))
fi
}

ghash="GHASH is not constant time"
nobs="-DWOLFPSA_NO_AES_BITSLICED"
hwaes="-DWOLF_CRYPTO_CB -DWOLF_CRYPTO_CB_ONLY_AES"
fips2="-DHAVE_FIPS -DHAVE_FIPS_VERSION=2 -DHAVE_FIPS_VERSION_MAJOR=2"
fips5="-DHAVE_FIPS -DHAVE_FIPS_VERSION=5 -DHAVE_FIPS_VERSION_MAJOR=5"
fips6="-DHAVE_FIPS -DHAVE_FIPS_VERSION=6 -DHAVE_FIPS_VERSION_MAJOR=6"

check pass
check pass ${nobs} -DWOLFSSL_AES_TOUCH_LINES
check pass ${nobs} ${hwaes}
check "AES backend is not constant time" ${nobs}
check "AES backend is not constant time" ${nobs} -DWOLFPSA_AES_HW_BACKEND
check "${ghash}" ${nobs} ${hwaes} -DGCM_TABLE
check "${ghash}" -DGCM_SMALL
check "${ghash}" -DGCM_WORD32
check "${ghash}" -DGCM_TABLE
check "${ghash}" -DGCM_TABLE -DWOLFPSA_GHASH_HW_BACKEND
check "${ghash}" -DGCM_TABLE_4BIT
check "${ghash}" -DAES_GCM_GMULT_NCT
check "the masked GHASH needs a 64-bit type" -DNO_64BIT
check "the Arm AES assembly" -DWOLFSSL_ARMASM
check "the PowerPC AES assembly" -DWOLFSSL_PPC64_ASM
check "the PowerPC AES assembly" -DWOLFSSL_PPC32_ASM
check "the RISC-V assembly" -DWOLFSSL_RISCV_ASM
check pass -DWOLFSSL_RISCV_ASM -DWOLFSSL_RISCV_SCALAR_CRYPTO_ASM
check pass -DWOLFSSL_RISCV_ASM -DWOLFSSL_RISCV_VECTOR_CRYPTO_ASM
check pass -DWOLFSSL_RISCV_ASM -DWOLFSSL_RISCV_SCALAR_CRYPTO_ASM -DGCM_TABLE_4BIT

check "FIPS modules before v6" ${fips5}
check "FIPS v2 has no constant-time GHASH" ${fips2} ${nobs} ${hwaes}
check "FIPS v5 masks GHASH only under" ${fips5} ${nobs} ${hwaes}
check pass ${fips5} ${nobs} ${hwaes} -DAES_GCM_GMULT_CT
check pass ${fips6}
check pass -DWOLFPSA_AES_FAST ${fips2}
check pass -DWOLFPSA_AES_FAST ${fips5}

# WOLFPSA_AES_FAST waives each of the refusals above.
for flag in GCM_SMALL GCM_WORD32 GCM_TABLE GCM_TABLE_4BIT AES_GCM_GMULT_NCT \
NO_64BIT WOLFSSL_ARMASM WOLFSSL_PPC64_ASM WOLFSSL_PPC32_ASM \
WOLFSSL_RISCV_ASM; do
check pass -DWOLFPSA_AES_FAST "-D${flag}"
done

[ "${fails}" -eq 0 ]
44 changes: 41 additions & 3 deletions src/psa_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#define WOLFPSA_CONFIG_H

#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/types.h>

#if defined(WOLFSSL_PSA_ENGINE) && !defined(NO_AES)

Expand All @@ -50,7 +51,9 @@
* outside would otherwise satisfy the policy check below on any build. */
#undef WOLFPSA_AES_HW_BACKEND

#if defined(WOLFSSL_ARMASM) || defined(WOLFSSL_RISCV_ASM) || \
#if (defined(WOLFSSL_RISCV_ASM) && \
(defined(WOLFSSL_RISCV_SCALAR_CRYPTO_ASM) || \
defined(WOLFSSL_RISCV_VECTOR_CRYPTO_ASM))) || \
defined(FREESCALE_LTC) || defined(FREESCALE_MMCAU) || \
defined(WOLFSSL_SILABS_SE_ACCEL) || defined(WOLFSSL_PSOC6_CRYPTO) || \
defined(WOLFSSL_AFALG) || defined(WOLFSSL_DEVCRYPTO_AES) || \
Expand All @@ -60,11 +63,46 @@
#define WOLFPSA_AES_HW_BACKEND
#endif

#if !defined(WOLFPSA_AES_FAST) && !defined(WC_AES_BITSLICED) && \
!defined(WOLFSSL_AES_TOUCH_LINES) && !defined(WOLFPSA_AES_HW_BACKEND)
/* The RISC-V crypto extensions run all of GCM in assembly, never the C GHASH. */
#undef WOLFPSA_GHASH_HW_BACKEND
#if defined(WOLFSSL_RISCV_ASM) && \
(defined(WOLFSSL_RISCV_SCALAR_CRYPTO_ASM) || \
defined(WOLFSSL_RISCV_VECTOR_CRYPTO_ASM))
#define WOLFPSA_GHASH_HW_BACKEND
#endif

#ifndef WOLFPSA_AES_FAST
#if defined(WOLFSSL_ARMASM)
#error "wolfPSA: the Arm AES assembly falls back to a T-table core and ignores WOLFSSL_AES_TOUCH_LINES. Define WOLFPSA_AES_FAST, without WOLFSSL_AES_TOUCH_LINES or WC_AES_BITSLICED, to accept it."
#elif defined(WOLFSSL_PPC64_ASM) || defined(WOLFSSL_PPC32_ASM)
#error "wolfPSA: the PowerPC AES assembly falls back to a T-table core and ignores WOLFSSL_AES_TOUCH_LINES. Define WOLFPSA_AES_FAST, without WOLFSSL_AES_TOUCH_LINES or WC_AES_BITSLICED, to accept it."
#elif defined(WOLFSSL_RISCV_ASM) && !defined(WOLFPSA_AES_HW_BACKEND)
#error "wolfPSA: the RISC-V assembly without the scalar or vector crypto extension uses a T-table AES and a branching GHASH. Define WOLFPSA_AES_FAST, without WOLFSSL_AES_TOUCH_LINES or WC_AES_BITSLICED, to accept it."
#elif defined(HAVE_FIPS) && FIPS_VERSION3_LT(6,0,0) && \
!defined(WOLFPSA_AES_HW_BACKEND)
#error "wolfPSA: FIPS modules before v6 have neither WC_AES_BITSLICED nor WOLFSSL_AES_TOUCH_LINES. Define WOLFPSA_AES_FAST, without either of them, to accept the T-table core."
#elif !defined(WC_AES_BITSLICED) && !defined(WOLFSSL_AES_TOUCH_LINES) && \
!defined(WOLFPSA_AES_HW_BACKEND)
#error "wolfPSA: AES backend is not constant time. Select WC_AES_BITSLICED or WOLFSSL_AES_TOUCH_LINES, or define WOLFPSA_AES_FAST to accept the T-table core."
#endif

/* Only the 64-bit GHASH built with no GCM method set is masked; FIPS v5 masks
* it only under AES_GCM_GMULT_CT, and FIPS v2 never does. */
#if defined(HAVE_AESGCM) && !defined(WOLFPSA_GHASH_HW_BACKEND)
#if defined(GCM_SMALL) || defined(GCM_WORD32) || defined(GCM_TABLE) || \
defined(GCM_TABLE_4BIT) || defined(AES_GCM_GMULT_NCT)
#error "wolfPSA: GHASH is not constant time. Leave the GCM method unset and AES_GCM_GMULT_NCT undefined for the masked multiply (an LTC part without its GCM engine sets GCM_TABLE itself), or define WOLFPSA_AES_FAST, without WOLFSSL_AES_TOUCH_LINES or WC_AES_BITSLICED."
#elif !defined(WORD64_AVAILABLE)
#error "wolfPSA: the masked GHASH needs a 64-bit type, and WORD64_AVAILABLE is off (NO_64BIT, or a 16-bit CPU). Remove NO_64BIT, or define WOLFPSA_AES_FAST, without WOLFSSL_AES_TOUCH_LINES or WC_AES_BITSLICED, to accept the branching one."
#elif defined(HAVE_FIPS) && FIPS_VERSION3_LT(5,0,0)
#error "wolfPSA: FIPS v2 has no constant-time GHASH. Define WOLFPSA_AES_FAST, without WOLFSSL_AES_TOUCH_LINES or WC_AES_BITSLICED, to accept it."
#elif defined(HAVE_FIPS) && FIPS_VERSION3_LT(6,0,0) && \
!defined(AES_GCM_GMULT_CT)
#error "wolfPSA: FIPS v5 masks GHASH only under AES_GCM_GMULT_CT. Define it, or define WOLFPSA_AES_FAST, without WOLFSSL_AES_TOUCH_LINES or WC_AES_BITSLICED."
#endif
#endif /* HAVE_AESGCM && !WOLFPSA_GHASH_HW_BACKEND */
#endif /* !WOLFPSA_AES_FAST */

#if defined(WOLFPSA_AES_FAST) && \
(defined(WC_AES_BITSLICED) || defined(WOLFSSL_AES_TOUCH_LINES))
#error "wolfPSA: WOLFPSA_AES_FAST conflicts with WC_AES_BITSLICED/WOLFSSL_AES_TOUCH_LINES"
Expand Down
5 changes: 3 additions & 2 deletions zephyr/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@ config WOLFPSA_AES_FAST
bool "Accept wolfCrypt's T-table AES core (not constant time)"
help
Define WOLFPSA_AES_FAST, which waives src/psa_config.h's requirement for
an AES backend with no secret-indexed table load, and leaves
WOLFSSL_AES_CONSTANT_TIME off by default.
an AES backend and a GHASH with no secret-indexed table load, and leaves
WOLFSSL_AES_CONSTANT_TIME off by default. Builds with the Arm assembly
need it, since that assembly falls back to a T-table core.

The T-table core is wolfCrypt's fastest software AES, and its access
pattern is key- and state-dependent. Enable this only where that timing
Expand Down
10 changes: 9 additions & 1 deletion zephyr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,15 @@ config, wolfPSA's Kconfig turns both on; a settings file must set them itself:
`WOLFPSA_AES_FAST` to waive it and take wolfCrypt's faster T-table core
instead. `zephyr/user_settings_example.h` selects `WOLFSSL_AES_TOUCH_LINES`:
it leaves `sizeof(Aes)` at 416 bytes, where `WC_AES_BITSLICED` would grow it
to 123,296 at the default `WC_AES_BS_WORD_SIZE` of 64.
to 123,296 at the default `WC_AES_BS_WORD_SIZE` of 64. AES-GCM also needs
the masked GHASH, which the wolfSSL module builds by default; a GCM table or
`GCM_SMALL` fails the check unless `WOLFPSA_AES_FAST` is set. The Arm
symmetric assembly (`CONFIG_WOLFCRYPT_ARM_SYMMETRIC_ASM`, which
`CONFIG_WOLFCRYPT_ASM` turns on for AArch64, ARMv7-M, ARMv8-M mainline and
32-bit Cortex-A/R) is not constant time either and needs `WOLFPSA_AES_FAST`.
That one option waives both checks and cannot be combined with
`WOLFSSL_AES_TOUCH_LINES` or `WC_AES_BITSLICED`, so a build refused only for
its GHASH gives up the constant-time AES core as well.
- `WC_ALLOW_ECC_ZERO_HASH` when `HAVE_ECC` is on, because
`psa_sign_hash()`/`psa_verify_hash()` must accept an all-zero digest.

Expand Down
Loading