Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f828948
Add SLH-DSA provider operations
aidangarske Jul 30, 2026
65a6de9
Add SLH-DSA unit coverage
aidangarske Jul 30, 2026
f5e86e7
Run the OpenSSL SLH-DSA KAT vectors
aidangarske Jul 30, 2026
f516840
Add SLH-DSA interoperability coverage
aidangarske Jul 30, 2026
35d664d
Integrate SLH-DSA into builds and CI
aidangarske Jul 30, 2026
85dca06
Run nginx PQC tests in the shared CI container
aidangarske Jul 30, 2026
96fc9cc
Add libacvp PQC integration coverage
aidangarske Jul 30, 2026
33b7cd5
Add maintained OpenSSL provider examples
aidangarske Jul 31, 2026
a7e542a
Address SLH-DSA review findings
aidangarske Jul 31, 2026
1a78bb1
Tighten SLH-DSA decode and signature validation
aidangarske Aug 1, 2026
84afce3
Address SLH-DSA Skoll findings
aidangarske Aug 1, 2026
d50a635
Fix provider example libtool path resolution
aidangarske Aug 1, 2026
fd7cbc4
Resolve provider path from example directory
aidangarske Aug 1, 2026
d3828b1
Pin libacvp OSP patch revision
aidangarske Aug 3, 2026
41bf43e
Track OSP test branch until upstream merge
aidangarske Aug 3, 2026
c7b7db3
Address SLH-DSA security review findings
aidangarske Aug 4, 2026
b347eaa
Complete SLH-DSA review coverage
aidangarske Aug 4, 2026
7533cb4
Complete SLH-DSA review hardening
aidangarske Aug 4, 2026
7f02c93
Use upstream OSP for libacvp tests
aidangarske Aug 4, 2026
3e1b50c
Address SLH-DSA review findings
aidangarske Aug 5, 2026
f5573a6
Deduplicate SLH-DSA keypair import validation and address review nits
aidangarske Aug 7, 2026
6a33aa3
Cover SLH-DSA undersized-buffer and mid-stream domain-change rejects
aidangarske Aug 8, 2026
470cbb7
Address SLH-DSA review feedback
aidangarske Aug 13, 2026
831570b
Fix SLH-DSA verify-only test build
aidangarske Aug 13, 2026
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
5 changes: 3 additions & 2 deletions .github/actions/oras-build-deps/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ runs:
sh="${SCRIPTS_HASH:0:12}"
# extra_key (sanitizer/PQC flags) only changes the wolfSSL build, so
# fold it into the wolfSSL tag only - stock OpenSSL stays shared across
# flag values. Hash it (not a prefix) so flag strings cannot collide.
# flag values. Hash it (not a prefix) so flag strings cannot collide
# and commas in configure values remain valid actions/cache keys.
wsh="$sh"
[ -n "$EXTRA_KEY" ] && wsh="${sh}-$(printf '%s' "$EXTRA_KEY" | sha256sum | cut -c1-12)"
{
Expand Down Expand Up @@ -235,4 +236,4 @@ runs:
uses: actions/cache@v4
with:
path: wolfssl-install
key: wolfssl-install-${{ inputs.variant }}-${{ inputs.wolfssl_fixed_key || steps.wolfssl-ref.outputs.sha }}-${{ hashFiles('scripts/utils-*.sh', 'scripts/build-wolfprovider.sh', 'scripts/patch-*.sh', 'patches/**') }}${{ inputs.extra_key != '' && format('-{0}', inputs.extra_key) || '' }}
key: ${{ steps.tags.outputs.wolfssl_install_tag }}
93 changes: 0 additions & 93 deletions .github/nginx/Dockerfile

This file was deleted.

6 changes: 4 additions & 2 deletions .github/nginx/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
# chain, and that the page is served. Exits non-zero if any group fails; the CI
# step inverts that under WOLFPROV_FORCE_FAIL=1.

O=/opt/wolfProvider/openssl-install
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
WOLFPROV_ROOT=${WOLFPROV_ROOT:-$(cd "${SCRIPT_DIR}/../.." && pwd)}
O=${WOLFPROV_ROOT}/openssl-install
CA=/opt/nginx/cacert/CA.crt
PORT=4433
# NB: not "GROUPS" -- that is a bash special array (the user's group IDs).
KEX_GROUPS="X25519MLKEM768 SecP256r1MLKEM768 SecP384r1MLKEM1024 MLKEM512 MLKEM768 MLKEM1024"

export LD_LIBRARY_PATH="/opt/wolfProvider/wolfprov-install/lib:/opt/wolfProvider/wolfssl-install/lib:${O}/lib:${O}/lib64${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
export LD_LIBRARY_PATH="${WOLFPROV_ROOT}/wolfprov-install/lib:${WOLFPROV_ROOT}/wolfssl-install/lib:${O}/lib:${O}/lib64${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"

echo "Quantum-safe groups under test: ${KEX_GROUPS}"
/opt/nginx/sbin/nginx -c /opt/nginx/conf/nginx.conf
Expand Down
34 changes: 33 additions & 1 deletion .github/scripts/check-workflow-result.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,40 @@ if [ -z "$TEST_SUITE" ]; then
fi

if [ "$WOLFPROV_FORCE_FAIL" = "WOLFPROV_FORCE_FAIL=1" ]; then
# ----- LIBACVP PQC -----
if [ "$TEST_SUITE" = "libacvp-pqc" ]; then
if [ "$TEST_RESULT" -ne 0 ] \
&& [ -f "libacvp-pqc.log" ] \
&& grep -q 'ml_kem_round_trip' libacvp-pqc.log \
&& grep -q 'ml_dsa_round_trip' libacvp-pqc.log \
&& grep -q 'slh_dsa_round_trip' libacvp-pqc.log; then
echo "PASS: libacvp PQC tests failed as expected with force fail enabled"
exit 0
elif [ "$TEST_RESULT" -eq 0 ]; then
echo "FAIL: libacvp PQC tests unexpectedly succeeded with force fail enabled"
exit 1
else
echo "FAIL: libacvp PQC test log does not show all PQC tests"
exit 1
fi
# ----- NGINX PQC -----
elif [ "$TEST_SUITE" = "nginx-pqc" ]; then
if [ "$TEST_RESULT" -ne 0 ] \
&& [ -f "nginx-pqc.log" ] \
&& grep -q '^FAIL:' nginx-pqc.log \
&& grep -q '^One or more quantum-safe groups failed\.$' \
nginx-pqc.log; then
echo "PASS: nginx PQC groups failed as expected with force fail enabled"
exit 0
elif [ "$TEST_RESULT" -eq 0 ]; then
echo "FAIL: nginx PQC tests unexpectedly succeeded with force fail enabled"
exit 1
else
echo "FAIL: nginx PQC log does not show attempted group failures"
exit 1
fi
# ----- CURL -----
if [ "$TEST_SUITE" = "curl" ]; then
elif [ "$TEST_SUITE" = "curl" ]; then
# Under WOLFPROV_FORCE_FAIL=1, wolfProvider deliberately errors on
# every call, so the curl test-suite is expected to fail somewhere.
# We don't pin the exact test numbers (they drift across curl
Expand Down
206 changes: 206 additions & 0 deletions .github/workflows/libacvp-pqc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
name: libacvp PQC Tests

on:
workflow_call:
inputs:
wolfssl_refs_json:
description: "JSON array of wolfssl refs to test; empty = master + latest -stable (pre-PQC-floor refs are dropped)"
required: false
type: string
default: ""
workflow_dispatch: {}

permissions:
contents: read
packages: write

jobs:
discover-versions:
name: Resolve wolfSSL/OpenSSL versions
runs-on: ubuntu-22.04
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
openssl-tag: ${{ steps.set-matrix.outputs.openssl-tag }}
steps:
- name: Resolve wolfSSL refs and latest OpenSSL release
id: set-matrix
env:
INPUT_REFS: ${{ inputs.wolfssl_refs_json }}
run: |
set -euo pipefail
LATEST=$(git ls-remote --tags --refs \
https://github.com/wolfSSL/wolfssl.git 'v*-stable' \
| awk -F/ '{print $NF}' | sort -V | tail -n 1)
if [ -z "${LATEST:-}" ]; then
echo "::error::Could not resolve latest wolfSSL -stable tag"
exit 1
fi
# PQC needs OpenSSL 3.6+, so always build against the latest release.
OSSL=$(git ls-remote --tags --refs \
https://github.com/openssl/openssl.git 'openssl-3.*' \
| awk -F/ '{print $NF}' | grep -E '^openssl-3\.[0-9.]+$' \
| sort -V | tail -n 1)
if [ -z "${OSSL:-}" ]; then
echo "::error::Could not resolve latest OpenSSL release tag"
exit 1
fi
echo "Latest stable wolfSSL: $LATEST"
echo "Latest OpenSSL: $OSSL"
echo "openssl-tag=$OSSL" >> "$GITHUB_OUTPUT"
# Caller can override the ref set (e.g. nightly Wave 2); default is
# master + latest -stable.
if [ -n "${INPUT_REFS:-}" ]; then
REFS=$(printf '%s' "$INPUT_REFS" | jq -r '.[]')
else
REFS=$(printf '%s\n%s\n' "master" "$LATEST")
fi
# PQC needs the wc_MlDsaKey_* seed/message API in v5.9.2-stable.
# master is always eligible; a stable ref must be at the floor or
# newer. A
# pre-floor ref (e.g. v5.8.4-stable from Wave 2) is dropped, since it
# would fail the --enable-pqc gate.
PQC_FLOOR="v5.9.2-stable"
ELIGIBLE=()
for ref in $REFS; do
if [ "$ref" = "master" ]; then
ELIGIBLE+=("$ref")
elif [ "$(printf '%s\n%s\n' "$PQC_FLOOR" "$ref" \
| sort -V | tail -n1)" = "$ref" ]; then
ELIGIBLE+=("$ref")
else
echo "::notice::Skipping pre-PQC-floor wolfSSL ref $ref (floor $PQC_FLOOR)"
fi
done
if [ ${#ELIGIBLE[@]} -eq 0 ]; then
REFS_JSON='[]'
else
REFS_JSON=$(printf '%s\n' "${ELIGIBLE[@]}" | jq -R . | jq -sc .)
fi
echo "Eligible wolfSSL refs: $REFS_JSON"
# Each eligible wolfSSL ref expands to 4 rows: replace-default and
# non-replace, each in normal and force-fail anti-test mode.
MATRIX=$(jq -nc --argjson refs "$REFS_JSON" '
def rows($ref; $lbl):
[ {"replace":true, "ff":"WOLFPROV_FORCE_FAIL=1",
"sfx":" [replace-default] [force-fail]"},
{"replace":true, "ff":"","sfx":" [replace-default]"},
{"replace":false, "ff":"WOLFPROV_FORCE_FAIL=1",
"sfx":" [non-replace] [force-fail]"},
{"replace":false, "ff":"","sfx":" [non-replace]"} ]
| map({"name":($lbl+.sfx), "wolfssl-ref":$ref,
"replace":.replace, "force_fail":.ff});
{ include: ( $refs
| map(rows(.; (if . == "master" then "master"
else "stable (" + . + ")" end)))
| add // [] ) }')
echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT"

libacvp-pqc:
name: ${{ matrix.name }}
needs: discover-versions
runs-on: ubuntu-22.04
timeout-minutes: 60
container:
image: ghcr.io/wolfssl/wolfprovider-test-deps:bookworm
env:
DEBIAN_FRONTEND: noninteractive
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.discover-versions.outputs.matrix) }}
steps:
- name: Checkout wolfProvider
uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Cache build dependencies
id: deps
uses: ./.github/actions/oras-build-deps
with:
variant: libacvp-pqc-bookworm${{ matrix.replace && '-rd' || '' }}
openssl_ref: ${{ needs.discover-versions.outputs.openssl-tag }}
wolfssl_ref: ${{ matrix.wolfssl-ref }}
extra_key: --enable-pqc
cache_openssl_source: ${{ matrix.replace }}
github_token: ${{ secrets.GITHUB_TOKEN }}

- name: Build wolfProvider
run: |
OPENSSL_TAG=${{ needs.discover-versions.outputs.openssl-tag }} \
WOLFSSL_TAG=${{ matrix.wolfssl-ref }} \
./scripts/build-wolfprovider.sh --enable-pqc \
${{ matrix.replace && '--replace-default' || '' }}

- name: Push build dependencies
uses: ./.github/actions/oras-build-deps-push
with:
registry: ${{ steps.deps.outputs.registry }}
openssl_install_tag: ${{ steps.deps.outputs.openssl_install_tag }}
wolfssl_install_tag: ${{ steps.deps.outputs.wolfssl_install_tag }}
openssl_source_tag: ${{ steps.deps.outputs.openssl_source_tag }}
openssl_hit: ${{ steps.deps.outputs.openssl_hit }}
wolfssl_hit: ${{ steps.deps.outputs.wolfssl_hit }}
openssl_source_hit: ${{ steps.deps.outputs.openssl_source_hit }}
cache_openssl_source: ${{ steps.deps.outputs.cache_openssl_source }}

- name: Checkout libacvp v2.3.1
uses: actions/checkout@v4
with:
repository: cisco/libacvp
ref: v2.3.1
path: libacvp
fetch-depth: 1

- name: Checkout OSP
uses: actions/checkout@v4
with:
repository: wolfssl/osp
path: osp
fetch-depth: 1

- name: Build libacvp test suite
working-directory: libacvp
run: |
PATCH=$($GITHUB_WORKSPACE/scripts/resolve-osp-patch.sh \
"$GITHUB_WORKSPACE/osp" libacvp v2.3.1 \
"${{ matrix.wolfssl-ref }}")
patch -p1 < "$PATCH"
autoreconf -fiv
./configure --enable-unit-tests \
--with-ssl-dir="$GITHUB_WORKSPACE/openssl-install" \
--with-libcurl-dir=/usr
make -j"$(nproc)"

- name: Run full libacvp suite with PQC coverage
working-directory: libacvp/test
shell: bash
run: |
export LD_LIBRARY_PATH="$GITHUB_WORKSPACE/wolfprov-install/lib:$GITHUB_WORKSPACE/wolfssl-install/lib:$GITHUB_WORKSPACE/openssl-install/lib:$GITHUB_WORKSPACE/openssl-install/lib64"
export OPENSSL_MODULES="$GITHUB_WORKSPACE/wolfprov-install/lib"
if [ "${{ matrix.replace }}" = "true" ]; then
export OPENSSL_CONF="$GITHUB_WORKSPACE/openssl-install/ssl/openssl.cnf"
else
export OPENSSL_CONF="$GITHUB_WORKSPACE/provider.conf"
fi
set +e
if [ "${{ matrix.force_fail }}" = "WOLFPROV_FORCE_FAIL=1" ]; then
export WOLFPROV_FORCE_FAIL=1
fi
./runtest -g APP_PQC_HANDLER -v 2>&1 | tee libacvp-pqc.log
TEST_RESULT=${PIPESTATUS[0]}
$GITHUB_WORKSPACE/.github/scripts/check-workflow-result.sh \
$TEST_RESULT "${{ matrix.force_fail }}" libacvp-pqc
CHECK_RESULT=$?
if [ $CHECK_RESULT -ne 0 ]; then
exit $CHECK_RESULT
fi
if [ -z "${{ matrix.force_fail }}" ]; then
./runtest -v 2>&1 | tee -a libacvp-pqc.log
TEST_RESULT=${PIPESTATUS[0]}
$GITHUB_WORKSPACE/.github/scripts/check-workflow-result.sh \
$TEST_RESULT "" libacvp-pqc
CHECK_RESULT=$?
if [ $CHECK_RESULT -ne 0 ]; then
exit $CHECK_RESULT
fi
fi
Loading
Loading