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
172 changes: 82 additions & 90 deletions .github/workflows/mpfs-athena-compile.yml
Original file line number Diff line number Diff line change
@@ -1,27 +1,12 @@
name: "Microchip PolarFire SoC Athena port"

# Keeps the PolarFire SoC Athena F5200 crypto callback port compiling against
# the real Microchip CAL. The port is only built when --with-mpfs-athena names a
# CAL directory, so no other job compiles a line of it: without this guard a
# rename in the CAL headers, or a refactor in aes.c, sha512.c or cryptocb.h,
# would break it silently until someone next built for the board.
#
# Nothing is faked: the CAL ships in a public GitHub repository, headers and
# archive both, so this compiles against the genuine vendor headers at a pinned
# commit and then checks that every CAL symbol the port references is really
# defined in the archive.
#
# The compile is a host build, not a cross build, which is a deliberate choice.
# Both CAL archives are soft-float lp64, and Ubuntu's riscv64 glibc is built
# lp64d only - there is no gnu/stubs-lp64.h - so -mabi=lp64 cannot be satisfied
# by crossbuild-essential-riscv64, and a bare-metal toolchain would make this
# job depend on how a libc happens to be packaged. None of that is what the job
# is guarding: the breakage it catches is a CAL header rename, or a refactor in
# aes.c, sha512.c or cryptocb.h, and the host compiler sees all of it. The
# target ABI is proven by building for the board, not here.
#
# Functional correctness is validated on an MPFS250TS Video Kit; see
# wolfcrypt/src/port/microchip/README.md.
# Compiles the PolarFire SoC Athena F5200 port, which no other job builds,
# against the genuine Microchip CAL headers at a pinned commit, in every
# configuration below, and checks each CAL symbol it references is defined in
# the archive. A host build on purpose: both CAL archives are soft-float lp64,
# which Ubuntu's riscv64 glibc cannot link, and what this guards (CAL header
# renames, refactors of wolfCrypt or cryptocb.h) the host compiler sees.
# Functional validation is on an MPFS250TS Video Kit; see the port's README.

# START OF COMMON SECTION
on:
Expand Down Expand Up @@ -55,32 +40,10 @@ env:

jobs:
compile:
name: ${{ matrix.leg }}
name: Compile every configuration
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
runs-on: ubuntu-24.04
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
# The algorithm gates are passed per leg rather than set in the
# generated user_settings.h: a -U on the command line is processed
# before the header is read, so a header that defined them would
# quietly put every algorithm back and both "only" legs would build
# both paths.
#
# Both engines, which is the ordinary build.
- leg: sha384-and-aesctr
extra: '-DWOLFSSL_SHA512 -DWOLFSSL_SHA384 -DWOLFSSL_AES_COUNTER'
# The port advertises independent algorithm gates, so each has to
# build on its own: an AES-only build has no WC_SHA384_DIGEST_SIZE,
# and a SHA-only build compiles no cipher path.
- leg: aesctr-only
extra: '-DWOLFSSL_AES_COUNTER'
- leg: sha384-only
extra: '-DWOLFSSL_SHA512 -DWOLFSSL_SHA384'
- leg: no-selftest
extra: '-DWOLFSSL_SHA512 -DWOLFSSL_SHA384 -DWOLFSSL_AES_COUNTER -DWC_MPFS_ATHENA_NO_SELFTEST'
steps:
- uses: actions/checkout@v4
name: Checkout wolfSSL
Expand All @@ -99,71 +62,100 @@ jobs:
test -f services/crypto/calini.h
test -f services/crypto/mpfs-rv64imac-user-crypto-lib.a

- name: Compile the port
- name: Compile and check each configuration
run: |
set -e
CAL="$GITHUB_WORKSPACE/hss/services/crypto"
mkdir -p "$GITHUB_WORKSPACE/cfg"
CFG="$GITHUB_WORKSPACE/cfg"
OUT="$GITHUB_WORKSPACE/obj"
mkdir -p "$CFG" "$OUT"

# Minimal configuration; the algorithm gates come from the matrix.
cat > "$GITHUB_WORKSPACE/cfg/user_settings.h" <<'EOF'
# Algorithm gates come from each leg, so each can be left out.
cat > "$CFG/user_settings.h" <<'EOF'
#ifndef CI_USER_SETTINGS_H
#define CI_USER_SETTINGS_H
#define WOLFSSL_MICROCHIP_MPFS
#define WOLFSSL_MPFS_ATHENA
/* WOLFSSL_SHA512/WOLFSSL_SHA384/WOLFSSL_AES_COUNTER come from the
* matrix leg, so each one can genuinely be left out. */
/* Deliberately NOT WOLFSSL_AES_DIRECT: the port must not depend on
* it, since wc_AesSetKeyDirect is declared only when it is set. */
#define SINGLE_THREADED
#define NO_FILESYSTEM
#define NO_WOLFSSL_DIR
/* The first targets have no heap, so this is the static-pool leg. */
/* The first targets have no heap: static pools unless CI_HEAP. */
#ifndef CI_HEAP
#define WOLFSSL_NO_MALLOC
#define NO_WOLFSSL_MEMORY
#endif
#define WC_NO_HARDEN
#if !defined(HAVE_ECC) && !defined(CI_RSA)
#define NO_BIG_INT
#endif
#ifndef CI_RSA
#define NO_RSA
#endif
#define NO_DH
#define NO_DSA
#endif
EOF

cc -c \
-Wall -Wextra -Werror \
-I. -I"$GITHUB_WORKSPACE/cfg" -I"$CAL" \
-DWOLFSSL_USER_SETTINGS ${{ matrix.extra }} \
wolfcrypt/src/port/microchip/mpfs_athena.c \
-o "$GITHUB_WORKSPACE/mpfs_athena.o"
nm --defined-only "$CAL/mpfs-rv64imac-user-crypto-lib.a" \
| awk '{print $3}' | sort -u > "$OUT/cal_defined"

- name: Check every CAL symbol resolves in the archive
run: |
set -e
CAL="$GITHUB_WORKSPACE/hss/services/crypto"
OBJ="$GITHUB_WORKSPACE/mpfs_athena.o"
# nm reads the rv64 archive on any host: ELF is ELF.
nm --defined-only \
"$CAL/mpfs-rv64imac-user-crypto-lib.a" \
| awk '{print $3}' | sort -u > /tmp/cal_defined
# name | flags | r to compile random.c too
# Each leg is built without and with the opt-in self-test.
LEGS=$(cat <<'EOF'
sha384-and-aesctr | -DWOLFSSL_SHA512 -DWOLFSSL_SHA384 -DWOLFSSL_AES_COUNTER | r
aesctr-only | -DWOLFSSL_AES_COUNTER -DWC_MPFS_ATHENA_NO_SHA256 |
sha384-only | -DWOLFSSL_SHA512 -DWOLFSSL_SHA384 |
aesecb-only | -DHAVE_AES_ECB -DWC_MPFS_ATHENA_NO_SHA256 |
aesxts | -DWOLFSSL_SHA512 -DWOLFSSL_SHA384 -DWOLFSSL_AES_COUNTER -DHAVE_AES_ECB -DWOLFSSL_AES_XTS -DWOLFSSL_AES_DIRECT -DWC_MPFS_ATHENA_AES_MIN_SZ=512 |
sha2-all | -DWOLFSSL_SHA224 -DWOLFSSL_SHA512 -DWOLFSSL_SHA384 -DCI_HEAP -DWOLFSSL_SMALL_STACK -DWOLFSSL_SMALL_STACK_CACHE -DWOLFSSL_HASH_KEEP -DWOLFSSL_HASH_FLAGS |
aes-all | -DHAVE_AES_CBC -DHAVE_AESGCM -DHAVE_AES_KEYWRAP -DWOLFSSL_AES_KEYWRAP_PADDING -DWOLFSSL_CMAC -DWOLFSSL_AES_DIRECT -DWOLFSSL_AES_COUNTER -DHAVE_AES_ECB -DWOLFSSL_AES_XTS -DWC_MPFS_ATHENA_GCM_MIN_SZ=64 |
rng-drbg | -DWC_MPFS_ATHENA_RNG_DRBG | r
custom-rng | -DWC_NO_HASHDRBG -DCUSTOM_RAND_GENERATE_BLOCK=my_rng -DWOLFSSL_SHA512 -DWOLFSSL_SHA384 -DHAVE_AES_ECB |
custom-seed | -DCUSTOM_RAND_GENERATE_SEED=wc_MpfsAthena_GenerateSeed -DWOLFSSL_SHA512 -DWOLFSSL_SHA384 | r
ecc-all | -DHAVE_ECC -DHAVE_ECC192 -DHAVE_ECC224 -DHAVE_ECC384 -DHAVE_ECC521 -DWOLFSSL_SHA512 -DWOLFSSL_SHA384 |
ecc-verify-only | -DHAVE_ECC -DNO_ECC_SIGN -DNO_ECC_DHE |
ecc-sign-only | -DHAVE_ECC -DNO_ECC_VERIFY -DNO_ECC_DHE |
ecc-dhe-only | -DHAVE_ECC -DNO_ECC_SIGN -DNO_ECC_VERIFY |
ecc-no-asn | -DHAVE_ECC -DHAVE_ECC384 -DNO_ASN -DWOLFSSL_SHA512 -DWOLFSSL_SHA384 |
ecc-blind-set-k | -DHAVE_ECC -DWOLFSSL_ECC_BLIND_K -DWOLFSSL_ECDSA_SET_K -DWOLFSSL_ECDSA_DETERMINISTIC_K |
rsa | -DCI_RSA -DCI_HEAP -DWOLFSSL_SMALL_STACK -DWOLF_CRYPTO_CB_RSA_PAD |
rsa-public-only | -DCI_RSA -DWOLFSSL_RSA_PUBLIC_ONLY -DWC_MPFS_ATHENA_RSA_PUBLIC |
all-opted-out | -DCI_RSA -DHAVE_ECC -DHAVE_AESGCM -DWOLFSSL_CMAC -DWOLFSSL_AES_DIRECT -DHAVE_AES_KEYWRAP -DWOLFSSL_SHA512 -DWOLFSSL_SHA384 -DWC_MPFS_ATHENA_NO_SHA256 -DWC_MPFS_ATHENA_NO_SHA512 -DWC_MPFS_ATHENA_NO_CBC -DWC_MPFS_ATHENA_NO_GCM -DWC_MPFS_ATHENA_NO_KEYWRAP -DWC_MPFS_ATHENA_NO_CMAC -DWC_MPFS_ATHENA_NO_RNG -DWC_MPFS_ATHENA_NO_ECC -DWC_MPFS_ATHENA_NO_RSA |
EOF
)

# A missing CAL symbol is a link error on the board but compiles
# cleanly here, so it has to be checked explicitly.
missing=0
for sym in $(nm --undefined-only "$OBJ" \
| awk '{print $2}' | grep -E '^(CAL|aesf5200|shaf5200)'); do
if grep -qx "$sym" /tmp/cal_defined; then
echo " ok $sym"
else
echo " MISSING $sym"
missing=1
fail=0
while IFS='|' read -r name flags rnd; do
name=$(echo $name)
rnd=$(echo $rnd)
[ -n "$name" ] || continue
for kat in "" "-DWC_MPFS_ATHENA_SELFTEST"; do
leg="$name${kat:+ +selftest}"
obj="$OUT/port.o"
if ! cc -c -Wall -Wextra -Werror -I. -I"$CFG" -I"$CAL" \
-DWOLFSSL_USER_SETTINGS $flags $kat \
wolfcrypt/src/port/microchip/mpfs_athena.c -o "$obj" \
2> "$OUT/err.txt"; then
echo "FAIL compile $leg"; cat "$OUT/err.txt"; fail=1; continue
fi
done
test "$missing" -eq 0

- name: Confirm the port was actually compiled in
run: |
set -e
# An empty object means a gate compiled the whole port out, which has
# happened: without WOLF_CRYPTO_CB the file is one big #if.
nm --defined-only "$GITHUB_WORKSPACE/mpfs_athena.o" \
| grep -q 'wc_MpfsAthena_CryptoDevCb'
if [ "$rnd" = "r" ] && ! cc -c -Wall -Wextra -Werror -I. \
-I"$CFG" -I"$CAL" -DWOLFSSL_USER_SETTINGS $flags $kat \
wolfcrypt/src/random.c -o "$OUT/random.o" \
2> "$OUT/err.txt"; then
echo "FAIL random.c $leg"; cat "$OUT/err.txt"; fail=1; continue
fi
# A gate that compiles the whole port out leaves no callback.
if ! nm --defined-only "$obj" | grep -q wc_MpfsAthena_CryptoDevCb
then
echo "FAIL empty $leg"; fail=1; continue
fi
# A missing CAL symbol only fails at the board's link.
miss=$(nm --undefined-only "$obj" | awk '{print $2}' \
| grep -E '^(CAL|aesf5200|shaf5200|uiROMMods$)' \
| grep -vxF -f "$OUT/cal_defined" || true)
if [ -n "$miss" ]; then
echo "FAIL symbols $leg:" $miss; fail=1; continue
fi
echo "ok $leg"
done
done <<< "$LEGS"
exit $fail
14 changes: 7 additions & 7 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -12573,13 +12573,13 @@ fi

if test "x$ENABLED_MPFS_ATHENA" = "xyes"
then
# The port offloads what the ordinary wolfCrypt gates turn on, so without
# these it would compile to nothing.
if test "x$ENABLED_SHA384" = "xno"; then
AC_MSG_ERROR([--with-mpfs-athena needs SHA-384; drop --disable-sha384])
fi
if test "x$ENABLED_AESCTR" = "xno"; then
AC_MSG_ERROR([--with-mpfs-athena needs AES-CTR; add --enable-aesctr])
# AES-XTS reaches the engine only through the bulk ECB call that
# HAVE_AES_ECB compiles in; without it every XTS block is its own engine
# transaction, slower than software.
if test "x$ENABLED_AESXTS" = "xyes" && test "x$ENABLED_AESECB" = "xno"; then
ENABLED_AESECB=yes
AM_CFLAGS="$AM_CFLAGS -DHAVE_AES_ECB"
AM_CCASFLAGS="$AM_CCASFLAGS -DHAVE_AES_ECB"
fi
fi

Expand Down
7 changes: 7 additions & 0 deletions wolfcrypt/benchmark/benchmark.c
Original file line number Diff line number Diff line change
Expand Up @@ -5344,6 +5344,13 @@ int benchmark_free(void)
printf("%serror %d with wolfCrypt_Cleanup\n", err_prefix, ret);
}

#ifdef WOLFSSL_STATIC_MEMORY
/* The next benchmark_init() loads the pool again from its start, which
* would partition over this heap's structures if the hint were kept. */
wc_UnloadStaticMemory(HEAP_HINT);
HEAP_HINT = NULL;
#endif

return ret;
}

Expand Down
21 changes: 21 additions & 0 deletions wolfcrypt/src/aes.c
Original file line number Diff line number Diff line change
Expand Up @@ -10017,6 +10017,9 @@ static void GMULT(byte *x, byte m[256][WC_AES_BLOCK_SIZE],
XMEMCPY(x, Z + 1, WC_AES_BLOCK_SIZE);
#endif
#else
/* The 64-bit word path reads Z at odd offsets, so it needs unaligned loads
* just as the 32-bit one does. */
#ifndef WOLFSSL_USE_ALIGN
byte* Z = ws->b;
byte a;
word64* pZ;
Expand All @@ -10043,6 +10046,24 @@ static void GMULT(byte *x, byte m[256][WC_AES_BLOCK_SIZE],
pZ = (word64*)(Z + 1);
pm = (word64*)(m[x[0]]);
px[0] = pZ[0] ^ pm[0]; px[1] = pZ[1] ^ pm[1];
#else
byte* Z = ws->b;
byte a;
int i;

XMEMCPY(Z + 16, m[x[15]], WC_AES_BLOCK_SIZE);
a = Z[16 + 15];
Z[15] = R[a][0];
Z[16] ^= R[a][1];
for (i = 14; i > 0; i--) {
xorbuf(Z + i + 1, m[x[i]], WC_AES_BLOCK_SIZE);
a = Z[16 + i];
Z[i] = R[a][0];
Z[i+1] ^= R[a][1];
}
xorbuf(Z + 1, m[x[0]], WC_AES_BLOCK_SIZE);
XMEMCPY(x, Z + 1, WC_AES_BLOCK_SIZE);
#endif
#endif
}
#endif
Expand Down
Loading
Loading