feat: add CRA Kit scripts for 6 wolfSSL products

Generate auditor-ready SBOM packages for wolfSSH,
wolfTPM, wolfMQTT, wolfHSM, wolfsentry, and wolfBoot.
Each script mirrors the wolfssl SBOM workflow.
pull/577/head
Mark Atwood 2026-06-22 18:37:53 -07:00
parent c77b4a5ac7
commit 8b558f3d5a
6 changed files with 1128 additions and 0 deletions

View File

@ -0,0 +1,230 @@
#!/bin/sh
# Generate wolfBoot component SBOMs via gen-sbom.
#
# wolfBoot is build-configuration-specific: its compiled source list depends
# on TARGET, SIGN, HASH, and EXT_FLASH. This script runs `make -n` against
# the wolfBoot tree to extract the exact set of .c files for the requested
# configuration, then calls gen-sbom directly.
#
# wolfcrypt sources are compiled directly into the wolfBoot image (there is
# no separate wolfssl shared library). They appear in OBJS alongside core
# wolfBoot sources and are therefore included as wolfBoot's own component
# sources, not as a separate dependency.
#
# Required variables:
# WOLFBOOT_DIR=path/to/wolfBoot (source tree root)
# WOLFBOOT_TARGET=<target> (e.g. stm32h7, x86_64_efi)
# WOLFBOOT_SIGN=<scheme> (e.g. ECC256, RSA2048, ED25519)
#
# Optional variables:
# WOLFBOOT_HASH=<hash> (default: SHA256)
# WOLFBOOT_EXT_FLASH=<0|1> (default: 0)
# CRA_PYTHON=python3 (Python interpreter with gen-sbom deps)
# CRA_LICENSE_OVERRIDE=<SPDX-id> (e.g. LicenseRef-wolfBoot-Commercial)
# CRA_LICENSE_TEXT=<path> (required when CRA_LICENSE_OVERRIDE is a
# LicenseRef-* id: plain-text license
# embedded in the SBOM)
# CRA_SBOM_OUT_DIR=<path> (override output directory)
set -eu
SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
KIT_DIR=$(dirname "$SCRIPT_DIR")
# Default wolfBoot directory: sibling of the wolfssl-examples checkout.
# shellcheck disable=SC2015
WOLFBOOT_DIR=${WOLFBOOT_DIR:-$(cd "$KIT_DIR/../../wolfBoot" 2>/dev/null && pwd || true)}
if [ -z "${WOLFBOOT_DIR:-}" ] || [ ! -d "$WOLFBOOT_DIR" ]; then
echo "ERROR: wolfBoot source not found." >&2
echo " Set WOLFBOOT_DIR to your wolfBoot checkout." >&2
exit 1
fi
if [ -z "${WOLFBOOT_TARGET:-}" ]; then
echo "ERROR: WOLFBOOT_TARGET is not set." >&2
echo " Example: WOLFBOOT_TARGET=stm32h7 $0" >&2
exit 1
fi
if [ -z "${WOLFBOOT_SIGN:-}" ]; then
echo "ERROR: WOLFBOOT_SIGN is not set." >&2
echo " Example: WOLFBOOT_SIGN=ECC256 $0" >&2
exit 1
fi
WOLFBOOT_HASH=${WOLFBOOT_HASH:-SHA256}
WOLFBOOT_EXT_FLASH=${WOLFBOOT_EXT_FLASH:-0}
OUT_DIR=${CRA_SBOM_OUT_DIR:-"$KIT_DIR/auditor-packet/wolfboot-component"}
# gen-sbom lives inside the wolfssl submodule under wolfBoot.
GEN_SBOM="$WOLFBOOT_DIR/lib/wolfssl/scripts/gen-sbom"
if [ ! -f "$GEN_SBOM" ]; then
echo "ERROR: gen-sbom not found at $GEN_SBOM" >&2
echo " Ensure the wolfssl submodule is initialized:" >&2
echo " git -C \"$WOLFBOOT_DIR\" submodule update --init lib/wolfssl" >&2
exit 1
fi
# Extract version from wolfBoot's version header.
VERSION=$(sed -n \
's/.*LIBWOLFBOOT_VERSION_STRING[[:space:]]*"\([^"]*\)".*/\1/p' \
"$WOLFBOOT_DIR/include/wolfboot/version.h")
if [ -z "$VERSION" ]; then
echo "ERROR: could not detect wolfBoot version from $WOLFBOOT_DIR/include/wolfboot/version.h" >&2
exit 1
fi
mkdir -p "$OUT_DIR"
CDX_OUT="$OUT_DIR/wolfboot-${VERSION}.cdx.json"
SPDX_OUT="$OUT_DIR/wolfboot-${VERSION}.spdx.json"
echo "wolfBoot tree: $WOLFBOOT_DIR"
echo "Configuration: TARGET=$WOLFBOOT_TARGET SIGN=$WOLFBOOT_SIGN HASH=$WOLFBOOT_HASH EXT_FLASH=$WOLFBOOT_EXT_FLASH"
echo "Version: $VERSION"
echo "Outputs: $CDX_OUT"
echo " $SPDX_OUT"
if [ -n "${CRA_LICENSE_OVERRIDE:-}" ]; then
echo "License override: $CRA_LICENSE_OVERRIDE"
fi
# A LicenseRef-* override requires the license text to be embedded in the SBOM
# (SPDX 2.3 §10.1). gen-sbom hard-fails without it; catch the omission here.
if [ -n "${CRA_LICENSE_OVERRIDE:-}" ]; then
case "$CRA_LICENSE_OVERRIDE" in
LicenseRef-*)
if [ -z "${CRA_LICENSE_TEXT:-}" ]; then
echo "ERROR: CRA_LICENSE_OVERRIDE=$CRA_LICENSE_OVERRIDE is a LicenseRef-* identifier," >&2
echo " but CRA_LICENSE_TEXT is not set. SPDX 2.3 requires the license text to be" >&2
echo " embedded for any LicenseRef-* used in licenseConcluded/licenseDeclared." >&2
echo " Re-run with CRA_LICENSE_TEXT=/path/to/wolfboot-license.txt" >&2
exit 1
fi
if [ ! -f "$CRA_LICENSE_TEXT" ]; then
echo "ERROR: CRA_LICENSE_TEXT=$CRA_LICENSE_TEXT not found." >&2
exit 1
fi
;;
esac
fi
# Canonicalize CRA_LICENSE_TEXT to an absolute path.
if [ -n "${CRA_LICENSE_TEXT:-}" ] && [ -f "$CRA_LICENSE_TEXT" ]; then
CRA_LICENSE_TEXT=$(CDPATH='' cd -- "$(dirname -- "$CRA_LICENSE_TEXT")" && pwd)/$(basename -- "$CRA_LICENSE_TEXT")
fi
# Extract the configuration-specific source list via `make -n`.
#
# `make -n TARGET=... SIGN=...` prints every command make would run without
# executing them. The compiler invocations include every .c file on the
# wolfBoot link line, including both core wolfBoot sources and wolfcrypt
# files compiled inline. grep -oE pulls out every .c argument; sort -u
# deduplicates.
echo "Extracting source list via make -n TARGET=$WOLFBOOT_TARGET SIGN=$WOLFBOOT_SIGN ..."
_srcs_tmp=$(mktemp "${TMPDIR:-/tmp}/wolfboot-sbom-srcs.XXXXXX")
trap 'rm -f "$_srcs_tmp"' EXIT
make --no-print-directory \
-C "$WOLFBOOT_DIR" \
-n \
TARGET="$WOLFBOOT_TARGET" \
SIGN="$WOLFBOOT_SIGN" \
HASH="$WOLFBOOT_HASH" \
EXT_FLASH="$WOLFBOOT_EXT_FLASH" \
2>/dev/null \
| grep -oE '[^ ]+\.c' \
| grep -v '\.h' \
| sort -u > "$_srcs_tmp" || true
if [ ! -s "$_srcs_tmp" ]; then
echo "ERROR: make -n yielded no .c source files for TARGET=$WOLFBOOT_TARGET SIGN=$WOLFBOOT_SIGN." >&2
echo " Check that TARGET and SIGN are valid for this wolfBoot tree." >&2
exit 1
fi
_n=$(wc -l < "$_srcs_tmp" | tr -d ' ')
echo " Extracted $_n source files"
# Resolve paths to absolute: make -n emits relative paths; gen-sbom needs to
# open the files to compute gitoid hashes.
_srcs_abs_tmp=$(mktemp "${TMPDIR:-/tmp}/wolfboot-sbom-srcs-abs.XXXXXX")
trap 'rm -f "$_srcs_tmp" "$_srcs_abs_tmp"' EXIT
while IFS= read -r _src; do
[ -n "$_src" ] || continue
# Paths from make -n are relative to wolfBoot root.
if [ "${_src#/}" = "$_src" ]; then
_abs="$WOLFBOOT_DIR/$_src"
else
_abs="$_src"
fi
# Skip paths that do not exist on disk (generated files, stubs, etc.).
if [ -f "$_abs" ]; then
echo "$_abs"
fi
done < "$_srcs_tmp" > "$_srcs_abs_tmp"
if [ ! -s "$_srcs_abs_tmp" ]; then
echo "ERROR: no source files from make -n exist on disk." >&2
echo " Verify WOLFBOOT_DIR=$WOLFBOOT_DIR and submodules are initialized." >&2
exit 1
fi
_n_abs=$(wc -l < "$_srcs_abs_tmp" | tr -d ' ')
echo " Resolved $_n_abs paths ($(( _n - _n_abs )) non-existent skipped)"
# Preprocess build settings for gen-sbom --options-h.
#
# wolfBoot has no options.h (it is not an autotools project). We use
# cc -dM -E on the host with wolfBoot's include dirs to produce a flat
# #define file that gen-sbom can parse for algorithm enablement.
_defines_tmp=$(mktemp "${TMPDIR:-/tmp}/wolfboot-sbom-defines.XXXXXX")
trap 'rm -f "$_srcs_tmp" "$_srcs_abs_tmp" "$_defines_tmp"' EXIT
CC=${CC:-cc}
echo " Preprocessing build settings via $CC -dM -E ..."
if ! "$CC" -dM -E \
-I"$WOLFBOOT_DIR/include" \
-I"$WOLFBOOT_DIR/lib/wolfssl" \
-I"$WOLFBOOT_DIR/lib/wolfssl/wolfcrypt/src" \
-DWOLFSSL_USER_SETTINGS \
-x c /dev/null > "$_defines_tmp" 2>/dev/null; then
echo "ERROR: $CC -dM -E failed; install a host C compiler or set CC." >&2
exit 1
fi
# Build gen-sbom argument list.
_PYTHON=${CRA_PYTHON:-python3}
command -v "$_PYTHON" >/dev/null 2>&1 || \
{ echo "ERROR: $_PYTHON not found. Set CRA_PYTHON to your Python interpreter." >&2; exit 1; }
# Read absolute source paths into positional parameters.
set --
while IFS= read -r _src; do
[ -n "$_src" ] || continue
set -- "$@" "$_src"
done < "$_srcs_abs_tmp"
_license_override=${CRA_LICENSE_OVERRIDE:-GPL-3.0-only}
set -- "$@" \
--cdx-out "$CDX_OUT" \
--spdx-out "$SPDX_OUT" \
--license-override "$_license_override"
if [ -n "${CRA_LICENSE_TEXT:-}" ]; then
set -- "$@" --license-text "$CRA_LICENSE_TEXT"
fi
echo "==> Running gen-sbom ..."
"$_PYTHON" "$GEN_SBOM" \
--name wolfboot \
--version "$VERSION" \
--supplier "wolfSSL Inc." \
--license-file "$WOLFBOOT_DIR/LICENSE" \
--options-h "$_defines_tmp" \
--srcs "$@"
echo "SBOM written:"
echo " $CDX_OUT"
echo " $SPDX_OUT"

View File

@ -0,0 +1,192 @@
#!/bin/sh
# Generate wolfHSM component SBOM (embedded gen-sbom path).
#
# wolfHSM is a Makefile-only library with no autotools configure step.
# This script always uses the embedded gen-sbom path: it enumerates
# wolfHSM sources directly from the source tree and derives compile-time
# defines via CC -dM -E (or pcpp when available).
#
# Required variables:
# WOLFSSL_DIR=path/to/wolfssl (source tree root; must contain scripts/gen-sbom)
# WOLFHSM_DIR=path/to/wolfHSM (source tree root)
#
# Optional variables:
# CC=<compiler> (default: cc; set for cross builds)
# CRA_PYTHON=python3 (interpreter with pcpp)
# CRA_LICENSE_OVERRIDE=<SPDX> (e.g. LicenseRef-wolfSSL-Commercial)
# CRA_LICENSE_TEXT=<path> (required when CRA_LICENSE_OVERRIDE is LicenseRef-*)
set -eu
# Accumulator for temp files; cleaned up on exit.
_auto_tempfiles=""
trap 'rm -f ${_auto_tempfiles:-}' EXIT
SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
KIT_DIR=$(dirname "$SCRIPT_DIR")
# Locate WOLFSSL_DIR (default: sibling of wolfssl-examples).
# shellcheck disable=SC2015
WOLFSSL_DIR=${WOLFSSL_DIR:-$(cd "$KIT_DIR/../../wolfssl" 2>/dev/null && pwd || true)}
# WOLFHSM_DIR has no sensible default; must be explicit.
WOLFHSM_DIR=${WOLFHSM_DIR:-}
if [ -z "${WOLFSSL_DIR:-}" ] || [ ! -d "$WOLFSSL_DIR" ]; then
echo "ERROR: wolfSSL source not found." >&2
echo " Set WOLFSSL_DIR to your wolfssl checkout." >&2
exit 1
fi
if [ -z "${WOLFHSM_DIR:-}" ] || [ ! -d "$WOLFHSM_DIR" ]; then
echo "ERROR: WOLFHSM_DIR is not set or not a directory." >&2
echo " Set WOLFHSM_DIR to your wolfHSM source tree." >&2
exit 1
fi
GEN="$WOLFSSL_DIR/scripts/gen-sbom"
if [ ! -f "$GEN" ]; then
echo "ERROR: $GEN not found (need wolfSSL with SBOM support)." >&2
exit 1
fi
# Parse version from ChangeLog.md: first line matching "## wolfHSM Release vX.Y.Z"
VERSION=$(sed -n 's/^# wolfHSM Release v\([0-9][0-9.]*\).*/\1/p' \
"$WOLFHSM_DIR/ChangeLog.md" 2>/dev/null | head -1)
if [ -z "$VERSION" ]; then
echo "ERROR: could not parse version from $WOLFHSM_DIR/ChangeLog.md." >&2
exit 1
fi
OUT_DIR=${CRA_SBOM_OUT_DIR:-"$KIT_DIR/auditor-packet/wolfhsm-component"}
mkdir -p "$OUT_DIR"
CDX_OUT="$OUT_DIR/wolfhsm-${VERSION}.cdx.json"
SPDX_OUT="$OUT_DIR/wolfhsm-${VERSION}.spdx.json"
echo "wolfHSM tree: $WOLFHSM_DIR"
echo "wolfSSL tree: $WOLFSSL_DIR"
echo "Version: $VERSION"
echo "Outputs: $CDX_OUT"
echo " $SPDX_OUT"
if [ -n "${CRA_LICENSE_OVERRIDE:-}" ]; then
echo "License override: $CRA_LICENSE_OVERRIDE"
fi
# A LicenseRef-* override requires the licence text to be embedded (SPDX 2.3 §10.1).
if [ -n "${CRA_LICENSE_OVERRIDE:-}" ]; then
case "$CRA_LICENSE_OVERRIDE" in
LicenseRef-*)
if [ -z "${CRA_LICENSE_TEXT:-}" ]; then
echo "ERROR: CRA_LICENSE_OVERRIDE=$CRA_LICENSE_OVERRIDE is a LicenseRef-* identifier," >&2
echo " but CRA_LICENSE_TEXT is not set. SPDX 2.3 requires the licence text" >&2
echo " to be embedded. Re-run with CRA_LICENSE_TEXT=/path/to/license.txt." >&2
exit 1
fi
if [ ! -f "$CRA_LICENSE_TEXT" ]; then
echo "ERROR: CRA_LICENSE_TEXT=$CRA_LICENSE_TEXT not found." >&2
exit 1
fi
;;
esac
fi
# Canonicalize CRA_LICENSE_TEXT to absolute path (subshells resolve relative paths
# against their own CWD; gen-sbom may be invoked from a different directory).
if [ -n "${CRA_LICENSE_TEXT:-}" ] && [ -f "$CRA_LICENSE_TEXT" ]; then
CRA_LICENSE_TEXT=$(CDPATH='' cd -- "$(dirname -- "$CRA_LICENSE_TEXT")" && pwd)/$(basename -- "$CRA_LICENSE_TEXT")
echo "License text: $CRA_LICENSE_TEXT"
fi
# Pick a Python that can `import pcpp`.
_python_with_pcpp() {
for py in ${CRA_PYTHON:-} python3 python; do
[ -n "$py" ] || continue
if command -v "$py" >/dev/null 2>&1 && \
"$py" -c "import pcpp" 2>/dev/null; then
echo "$py"
return 0
fi
done
return 1
}
# Enumerate wolfHSM sources: all *.c directly under src/ (no recursion).
_wolfhsm_srcs() {
find "$WOLFHSM_DIR/src" -maxdepth 1 -name "*.c" | sort
}
echo "==> Embedded path: gen-sbom with CC -dM -E (no user_settings.h)"
# Write collected source paths to a temp file for --srcs-file.
_srcs_file=$(mktemp "${TMPDIR:-/tmp}/wolfhsm-srcs.XXXXXX")
_auto_tempfiles="${_auto_tempfiles:-} $_srcs_file"
_wolfhsm_srcs > "$_srcs_file"
_n=$(wc -l < "$_srcs_file" | tr -d ' ')
echo " Sources: $_n .c files from $WOLFHSM_DIR/src/"
if [ ! -s "$_srcs_file" ]; then
echo "ERROR: no .c files found under $WOLFHSM_DIR/src/." >&2
exit 1
fi
# Build license-override args.
_license_args=""
if [ -n "${CRA_LICENSE_OVERRIDE:-}" ]; then
_license_args="--license-override $CRA_LICENSE_OVERRIDE"
if [ -n "${CRA_LICENSE_TEXT:-}" ]; then
_license_args="$_license_args --license-text $CRA_LICENSE_TEXT"
fi
fi
if _py=$(_python_with_pcpp); then
echo " Using $_py (pcpp) for --user-settings"
# wolfHSM has no user_settings.h equivalent; pass settings.h from wolfssl
# so gen-sbom has a preprocessable configuration source. The include path
# covers wolfHSM headers and the wolfssl tree.
SETTINGS_H="$WOLFSSL_DIR/wolfssl/wolfcrypt/settings.h"
if [ ! -f "$SETTINGS_H" ]; then
echo "ERROR: $SETTINGS_H not found." >&2
exit 1
fi
# shellcheck disable=SC2086
"$_py" "$GEN" \
--name wolfhsm \
--version "$VERSION" \
--supplier "wolfSSL Inc." \
--license-file "$WOLFHSM_DIR/LICENSING" \
--user-settings "$SETTINGS_H" \
--user-settings-include "$WOLFHSM_DIR" \
--user-settings-include "$WOLFSSL_DIR" \
--srcs-file "$_srcs_file" \
--cdx-out "$CDX_OUT" \
--spdx-out "$SPDX_OUT" \
${_license_args}
else
echo "NOTE: pcpp not found; using CC -dM -E -> --options-h"
echo " Install pcpp: python3 -m pip install pcpp"
echo " For cross builds: set CC=<target-compiler>"
CC=${CC:-cc}
_defines=$(mktemp "${TMPDIR:-/tmp}/wolfhsm-defines.XXXXXX")
_auto_tempfiles="${_auto_tempfiles:-} $_defines"
if ! "$CC" -dM -E \
-I"$WOLFHSM_DIR" \
-I"$WOLFSSL_DIR" \
-x c /dev/null >"$_defines" 2>/dev/null; then
echo "ERROR: $CC -dM -E failed; install pcpp or set CC to your cross-compiler." >&2
exit 1
fi
_python=python3
command -v python3 >/dev/null 2>&1 || _python=python
# shellcheck disable=SC2086
"$_python" "$GEN" \
--name wolfhsm \
--version "$VERSION" \
--supplier "wolfSSL Inc." \
--license-file "$WOLFHSM_DIR/LICENSING" \
--options-h "$_defines" \
--srcs-file "$_srcs_file" \
--cdx-out "$CDX_OUT" \
--spdx-out "$SPDX_OUT" \
${_license_args}
fi
echo "Done."

View File

@ -0,0 +1,119 @@
#!/bin/sh
# Generate wolfMQTT component SBOM (autotools make sbom path).
#
# wolfMQTT uses autotools. This script runs `make sbom` inside the wolfMQTT
# source tree and copies the resulting SBOM files to the auditor packet.
#
# Required variables:
# WOLFSSL_DIR=path/to/wolfssl (source tree root; must contain scripts/gen-sbom)
# WOLFMQTT_DIR=path/to/wolfMQTT (source tree root)
#
# Optional variables:
# CRA_LICENSE_OVERRIDE=<SPDX-id> (e.g. LicenseRef-wolfSSL-Commercial)
# CRA_LICENSE_TEXT=<path> (required when CRA_LICENSE_OVERRIDE is LicenseRef-*)
# CRA_SBOM_OUT_DIR=<path> (default: <kit>/auditor-packet/wolfmqtt-component)
set -eu
SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
KIT_DIR=$(dirname "$SCRIPT_DIR")
# shellcheck disable=SC2015
WOLFSSL_DIR=${WOLFSSL_DIR:-$(cd "$KIT_DIR/../../wolfssl" 2>/dev/null && pwd || true)}
WOLFMQTT_DIR=${WOLFMQTT_DIR:-}
if [ -z "${WOLFSSL_DIR:-}" ] || [ ! -d "$WOLFSSL_DIR" ]; then
echo "ERROR: wolfSSL source not found." >&2
echo " Set WOLFSSL_DIR to your wolfssl checkout (contains scripts/gen-sbom)." >&2
exit 1
fi
if [ -z "${WOLFMQTT_DIR:-}" ] || [ ! -d "$WOLFMQTT_DIR" ]; then
echo "ERROR: WOLFMQTT_DIR is not set or not a directory." >&2
echo " Set WOLFMQTT_DIR to your wolfMQTT source tree." >&2
exit 1
fi
GEN="$WOLFSSL_DIR/scripts/gen-sbom"
if [ ! -f "$GEN" ]; then
echo "ERROR: $GEN not found (need wolfSSL with SBOM support)." >&2
exit 1
fi
# Parse version from wolfmqtt/version.h.
VERSION=$(sed -n \
's/.*LIBWOLFMQTT_VERSION_STRING[[:space:]]*"\([^"]*\)".*/\1/p' \
"$WOLFMQTT_DIR/wolfmqtt/version.h" 2>/dev/null || true)
if [ -z "$VERSION" ]; then
echo "ERROR: could not parse version from $WOLFMQTT_DIR/wolfmqtt/version.h." >&2
exit 1
fi
OUT_DIR=${CRA_SBOM_OUT_DIR:-"$KIT_DIR/auditor-packet/wolfmqtt-component"}
mkdir -p "$OUT_DIR"
CDX_OUT="$OUT_DIR/wolfmqtt-${VERSION}.cdx.json"
SPDX_OUT="$OUT_DIR/wolfmqtt-${VERSION}.spdx.json"
echo "wolfMQTT tree: $WOLFMQTT_DIR"
echo "wolfSSL tree: $WOLFSSL_DIR"
echo "Version: $VERSION"
echo "Outputs: $CDX_OUT"
echo " $SPDX_OUT"
if [ -n "${CRA_LICENSE_OVERRIDE:-}" ]; then
echo "License override: $CRA_LICENSE_OVERRIDE"
fi
# A LicenseRef-* override requires the licence text to be embedded (SPDX 2.3 §10.1).
if [ -n "${CRA_LICENSE_OVERRIDE:-}" ]; then
case "$CRA_LICENSE_OVERRIDE" in
LicenseRef-*)
if [ -z "${CRA_LICENSE_TEXT:-}" ]; then
echo "ERROR: CRA_LICENSE_OVERRIDE=$CRA_LICENSE_OVERRIDE is a LicenseRef-* identifier," >&2
echo " but CRA_LICENSE_TEXT is not set. SPDX 2.3 requires the licence text" >&2
echo " to be embedded. Re-run with CRA_LICENSE_TEXT=/path/to/license.txt." >&2
exit 1
fi
if [ ! -f "$CRA_LICENSE_TEXT" ]; then
echo "ERROR: CRA_LICENSE_TEXT=$CRA_LICENSE_TEXT not found." >&2
exit 1
fi
;;
esac
fi
# Canonicalize CRA_LICENSE_TEXT to an absolute path: make sbom runs inside a
# subshell `cd "$WOLFMQTT_DIR"`, where a relative path would resolve against
# the wolfMQTT tree rather than the caller's CWD.
if [ -n "${CRA_LICENSE_TEXT:-}" ] && [ -f "$CRA_LICENSE_TEXT" ]; then
CRA_LICENSE_TEXT=$(CDPATH='' cd -- "$(dirname -- "$CRA_LICENSE_TEXT")" && pwd)/$(basename -- "$CRA_LICENSE_TEXT")
echo "License text: $CRA_LICENSE_TEXT"
fi
echo "==> Autotools path: make sbom"
# Detect whether the wolfMQTT tree is already configured; run ./configure first
# if no Makefile is present.
(cd "$WOLFMQTT_DIR" && {
if [ ! -f Makefile ]; then
echo " Running ./configure first (WOLFSSL_DIR=$WOLFSSL_DIR)..."
./configure --with-wolfssl="$WOLFSSL_DIR"
fi
if [ -n "${CRA_LICENSE_OVERRIDE:-}" ]; then
if [ -n "${CRA_LICENSE_TEXT:-}" ]; then
make sbom WOLFSSL_DIR="$WOLFSSL_DIR" \
SBOM_LICENSE_OVERRIDE="$CRA_LICENSE_OVERRIDE" \
SBOM_LICENSE_TEXT="$CRA_LICENSE_TEXT"
else
make sbom WOLFSSL_DIR="$WOLFSSL_DIR" \
SBOM_LICENSE_OVERRIDE="$CRA_LICENSE_OVERRIDE"
fi
else
make sbom WOLFSSL_DIR="$WOLFSSL_DIR"
fi
cp -f "wolfmqtt-${VERSION}.cdx.json" "$CDX_OUT"
cp -f "wolfmqtt-${VERSION}.spdx.json" "$SPDX_OUT"
if [ -f "wolfmqtt-${VERSION}.spdx" ]; then
cp -f "wolfmqtt-${VERSION}.spdx" "$OUT_DIR/"
fi
})
echo "Done."

View File

@ -0,0 +1,151 @@
#!/bin/sh
# Generate wolfSentry component SBOMs via gen-sbom.
#
# Required variables:
# WOLFSENTRY_DIR=path/to/wolfsentry (source tree root)
#
# gen-sbom location (one required):
# WOLFSSL_DIR=path/to/wolfssl (gen-sbom taken from scripts/gen-sbom)
# CRA_GEN_SBOM=path/to/gen-sbom (direct path; overrides WOLFSSL_DIR)
#
# Optional variables:
# CRA_SBOM_OUT_DIR=<path> (default: $KIT_DIR/auditor-packet/wolfsentry-component)
# CC=<compiler> (default: cc; for -dM -E options dump)
set -eu
SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
KIT_DIR=$(dirname "$SCRIPT_DIR")
# shellcheck disable=SC2015
WOLFSENTRY_DIR=${WOLFSENTRY_DIR:-$(cd "$KIT_DIR/../../wolfsentry" 2>/dev/null && pwd || true)}
OUT_DIR=${CRA_SBOM_OUT_DIR:-"$KIT_DIR/auditor-packet/wolfsentry-component"}
if [ -z "${WOLFSENTRY_DIR:-}" ] || [ ! -d "$WOLFSENTRY_DIR" ]; then
echo "ERROR: wolfSentry source not found." >&2
echo " Set WOLFSENTRY_DIR to your wolfsentry checkout (sibling of wolfssl-examples)." >&2
exit 1
fi
# Resolve gen-sbom: CRA_GEN_SBOM takes precedence, then WOLFSSL_DIR.
if [ -n "${CRA_GEN_SBOM:-}" ]; then
GEN_SBOM="$CRA_GEN_SBOM"
elif [ -n "${WOLFSSL_DIR:-}" ]; then
GEN_SBOM="$WOLFSSL_DIR/scripts/gen-sbom"
else
echo "ERROR: gen-sbom location not specified." >&2
echo " Set WOLFSSL_DIR (path to wolfssl repo) or CRA_GEN_SBOM (direct path to gen-sbom)." >&2
exit 1
fi
if [ ! -f "$GEN_SBOM" ]; then
echo "ERROR: gen-sbom not found: $GEN_SBOM" >&2
exit 1
fi
# Extract version from wolfsentry/wolfsentry.h macros.
HEADER="$WOLFSENTRY_DIR/wolfsentry/wolfsentry.h"
if [ ! -f "$HEADER" ]; then
echo "ERROR: version header not found: $HEADER" >&2
exit 1
fi
VERSION=$(awk '
/WOLFSENTRY_VERSION_MAJOR/ { maj=$3 }
/WOLFSENTRY_VERSION_MINOR/ { min=$3 }
/WOLFSENTRY_VERSION_TINY/ { tiny=$3 }
END { print maj"."min"."tiny }
' "$HEADER")
if [ -z "$VERSION" ] || [ "$VERSION" = ".." ]; then
echo "ERROR: could not extract version from $HEADER" >&2
exit 1
fi
mkdir -p "$OUT_DIR"
CDX_OUT="$OUT_DIR/wolfsentry-${VERSION}.cdx.json"
SPDX_OUT="$OUT_DIR/wolfsentry-${VERSION}.spdx.json"
echo "wolfSentry tree: $WOLFSENTRY_DIR"
echo "Version: $VERSION"
echo "gen-sbom: $GEN_SBOM"
echo "Outputs: $CDX_OUT"
echo " $SPDX_OUT"
# Enumerate all .c sources from $WOLFSENTRY_DIR/src/ (the directory the Makefile
# compiles from; conditional sources like json/ and lwip/ are subdirs of src/).
SRCS=$(find "$WOLFSENTRY_DIR/src" -name "*.c" | sort)
if [ -z "$SRCS" ]; then
echo "ERROR: no .c files found under $WOLFSENTRY_DIR/src/" >&2
exit 1
fi
_n=$(echo "$SRCS" | wc -l | tr -d ' ')
echo "Sources: $_n .c files from $WOLFSENTRY_DIR/src/"
# Dump compiler defines for --options-h (no user_settings.h; wolfsentry is
# configured via Makefile flags, not a settings header).
CC=${CC:-cc}
_defines_h=$(mktemp "${TMPDIR:-/tmp}/wolfsentry-defines.XXXXXX")
trap 'rm -f "$_defines_h"' EXIT
if ! "$CC" -dM -E -I"$WOLFSENTRY_DIR" -x c /dev/null >"$_defines_h" 2>/dev/null; then
echo "ERROR: $CC -dM -E failed; set CC to an available compiler." >&2
exit 1
fi
if ! command -v python3 >/dev/null 2>&1; then
echo "ERROR: python3 not found in PATH." >&2
exit 1
fi
# Build --srcs argument list from the source enumeration.
# shellcheck disable=SC2086
set -- $SRCS
python3 "$GEN_SBOM" \
--name wolfsentry \
--version "$VERSION" \
--supplier "wolfSSL Inc." \
--license-file "$WOLFSENTRY_DIR/LICENSING" \
--options-h "$_defines_h" \
--srcs "$@" \
--cdx-out "$CDX_OUT" \
--spdx-out "$SPDX_OUT"
# Post-process: rewrite pkg:generic/wolfsentry@X -> pkg:github/wolfSSL/wolfsentry@vX
# gen-sbom emits pkg:generic/{name}@{version} for non-wolfssl names; the canonical
# PURL for wolfsentry is the GitHub package form.
if ! CDX_OUT="$CDX_OUT" SPDX_OUT="$SPDX_OUT" VERSION="$VERSION" \
python3 <<'PY'
import json, os, pathlib
cdx = pathlib.Path(os.environ["CDX_OUT"])
spdx = pathlib.Path(os.environ["SPDX_OUT"])
ver = os.environ["VERSION"]
GENERIC = "pkg:generic/wolfsentry@"
GITHUB = "pkg:github/wolfSSL/wolfsentry@v"
def fix(s):
if isinstance(s, str) and s.startswith(GENERIC):
return GITHUB + s[len(GENERIC):]
return s
if cdx.exists():
d = json.loads(cdx.read_text())
comp = d.get("metadata", {}).get("component", {})
comp["purl"] = fix(comp.get("purl", ""))
cdx.write_text(json.dumps(d, indent=2) + "\n")
print(f"Post-processed {cdx.name}: PURL -> {comp['purl']}")
if spdx.exists():
d = json.loads(spdx.read_text())
for pkg in d.get("packages", []):
for ref in pkg.get("externalRefs", []):
if ref.get("referenceType") == "purl":
ref["referenceLocator"] = fix(ref.get("referenceLocator", ""))
spdx.write_text(json.dumps(d, indent=2) + "\n")
print(f"Post-processed {spdx.name}: PURL canonicalized")
PY
then
echo "ERROR: PURL post-processing failed; SBOM may carry pkg:generic PURLs." >&2
exit 1
fi
echo "Done."

View File

@ -0,0 +1,164 @@
#!/bin/sh
# Generate wolfSSH component SBOM (autotools make sbom).
#
# Required variables:
# WOLFSSL_DIR=path/to/wolfssl (source tree root; provides gen-sbom)
# WOLFSSH_DIR=path/to/wolfssh (source tree root)
#
# Optional variables:
# CRA_LICENSE_OVERRIDE=<SPDX-id> (e.g. LicenseRef-wolfSSH-Commercial)
# CRA_LICENSE_TEXT=<path> (required when CRA_LICENSE_OVERRIDE is a
# LicenseRef-* id: plain-text licence embedded
# in the SBOM; make sbom hard-fails without it.)
set -eu
SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
KIT_DIR=$(dirname "$SCRIPT_DIR")
# shellcheck disable=SC2015 # `|| true` is a deliberate set -e guard, not if-then-else
WOLFSSL_DIR=${WOLFSSL_DIR:-$(cd "$KIT_DIR/../../wolfssl" 2>/dev/null && pwd || true)}
WOLFSSH_DIR=${WOLFSSH_DIR:-$(cd "$KIT_DIR/../../wolfSSH" 2>/dev/null && pwd || true)}
OUT_DIR=${CRA_SBOM_OUT_DIR:-"$KIT_DIR/auditor-packet/wolfssh-component"}
if [ -z "${WOLFSSL_DIR:-}" ] || [ ! -d "$WOLFSSL_DIR" ]; then
echo "ERROR: wolfSSL source not found." >&2
echo " Set WOLFSSL_DIR to your wolfssl checkout (sibling of wolfssl-examples)." >&2
exit 1
fi
if [ -z "${WOLFSSH_DIR:-}" ] || [ ! -d "$WOLFSSH_DIR" ]; then
echo "ERROR: wolfSSH source not found." >&2
echo " Set WOLFSSH_DIR to your wolfSSH checkout (sibling of wolfssl-examples)." >&2
exit 1
fi
VERSION=$(sed -n \
's/.*LIBWOLFSSH_VERSION_STRING[[:space:]]*"\([^"]*\)".*/\1/p' \
"$WOLFSSH_DIR/wolfssh/version.h" 2>/dev/null || true)
if [ -z "$VERSION" ]; then
echo "ERROR: could not extract LIBWOLFSSH_VERSION_STRING from $WOLFSSH_DIR/wolfssh/version.h" >&2
exit 1
fi
mkdir -p "$OUT_DIR"
CDX_OUT="$OUT_DIR/wolfssh-${VERSION}.cdx.json"
SPDX_OUT="$OUT_DIR/wolfssh-${VERSION}.spdx.json"
echo "wolfSSL tree: $WOLFSSL_DIR"
echo "wolfSSH tree: $WOLFSSH_DIR"
echo "Outputs: $CDX_OUT"
echo " $SPDX_OUT"
if [ -n "${CRA_LICENSE_OVERRIDE:-}" ]; then
echo "License override: $CRA_LICENSE_OVERRIDE"
fi
# A LicenseRef-* override (e.g. the commercial license) requires the actual
# licence text to be embedded in the SBOM (SPDX 2.3 §10.1). Both gen-sbom and
# `make sbom` hard-fail without it, so catch the omission here with an
# actionable message instead of letting the run die deep in the generator.
if [ -n "${CRA_LICENSE_OVERRIDE:-}" ]; then
case "$CRA_LICENSE_OVERRIDE" in
LicenseRef-*)
if [ -z "${CRA_LICENSE_TEXT:-}" ]; then
echo "ERROR: CRA_LICENSE_OVERRIDE=$CRA_LICENSE_OVERRIDE is a LicenseRef-* identifier," >&2
echo " but CRA_LICENSE_TEXT is not set. SPDX 2.3 requires the licence text to be" >&2
echo " embedded for any LicenseRef-* used in licenseConcluded/licenseDeclared." >&2
echo " Re-run with CRA_LICENSE_TEXT=/path/to/wolfssh-commercial-license.txt." >&2
exit 1
fi
if [ ! -f "$CRA_LICENSE_TEXT" ]; then
echo "ERROR: CRA_LICENSE_TEXT=$CRA_LICENSE_TEXT not found." >&2
exit 1
fi
;;
esac
fi
# Canonicalize CRA_LICENSE_TEXT to an absolute path: make sbom runs inside a
# `cd "$WOLFSSH_DIR"` subshell, where a relative path would resolve against the
# wolfSSH tree rather than the caller's CWD.
if [ -n "${CRA_LICENSE_TEXT:-}" ] && [ -f "$CRA_LICENSE_TEXT" ]; then
CRA_LICENSE_TEXT=$(CDPATH='' cd -- "$(dirname -- "$CRA_LICENSE_TEXT")" && pwd)/$(basename -- "$CRA_LICENSE_TEXT")
echo "License text: $CRA_LICENSE_TEXT"
fi
_run_autotools() {
echo "==> Autotools path: make sbom"
# `make sbom` names its output after the wolfSSH TREE's version
# (PACKAGE_VERSION). Detect mismatches early so the cp below doesn't fail
# with a cryptic "No such file or directory" under `set -eu`.
_tree_ver=$(sed -n \
's/.*LIBWOLFSSH_VERSION_STRING[[:space:]]*"\([^"]*\)".*/\1/p' \
"$WOLFSSH_DIR/wolfssh/version.h" 2>/dev/null || true)
if [ -n "$_tree_ver" ] && [ "$_tree_ver" != "$VERSION" ]; then
echo "ERROR: wolfSSH tree is version $_tree_ver but expected $VERSION." >&2
exit 1
fi
(cd "$WOLFSSH_DIR" && {
if [ ! -f Makefile ]; then
echo " Running ./configure first..."
./configure --with-wolfssl="$WOLFSSL_DIR"
fi
if [ -n "${CRA_LICENSE_OVERRIDE:-}" ]; then
if [ -n "${CRA_LICENSE_TEXT:-}" ]; then
make sbom WOLFSSL_DIR="$WOLFSSL_DIR" \
SBOM_LICENSE_OVERRIDE="$CRA_LICENSE_OVERRIDE" \
SBOM_LICENSE_TEXT="$CRA_LICENSE_TEXT"
else
make sbom WOLFSSL_DIR="$WOLFSSL_DIR" \
SBOM_LICENSE_OVERRIDE="$CRA_LICENSE_OVERRIDE"
fi
else
make sbom WOLFSSL_DIR="$WOLFSSL_DIR"
fi
cp -f "wolfssh-${VERSION}.cdx.json" "$CDX_OUT"
cp -f "wolfssh-${VERSION}.spdx.json" "$SPDX_OUT"
if [ -f "wolfssh-${VERSION}.spdx" ]; then
cp -f "wolfssh-${VERSION}.spdx" "$OUT_DIR/"
fi
})
}
_run_autotools
# ---- Post-process: defensive PURL canonicalization ----
# Current gen-sbom already emits pkg:github/wolfSSL/wolfSSH@vX natively for
# known component names; the rewrite below is a defensive no-op kept only for
# older generator versions that may emit pkg:generic/wolfssh@X.
if ! CDX_OUT="$CDX_OUT" SPDX_OUT="$SPDX_OUT" \
python3 <<'PY'
import json, os, pathlib
cdx = pathlib.Path(os.environ["CDX_OUT"])
spdx = pathlib.Path(os.environ["SPDX_OUT"])
GENERIC = "pkg:generic/wolfssh@"
GITHUB = "pkg:github/wolfSSL/wolfSSH@v"
def canonicalize_purl(s):
if isinstance(s, str) and s.startswith(GENERIC):
return GITHUB + s[len(GENERIC):]
return s
if cdx.exists():
d = json.loads(cdx.read_text())
comp = d.get("metadata", {}).get("component", {})
comp["purl"] = canonicalize_purl(comp.get("purl", ""))
cdx.write_text(json.dumps(d, indent=2) + "\n")
print(f"Post-processed {cdx.name}")
if spdx.exists():
d = json.loads(spdx.read_text())
for pkg in d.get("packages", []):
for ref in pkg.get("externalRefs", []):
if ref.get("referenceType") == "purl":
ref["referenceLocator"] = canonicalize_purl(ref.get("referenceLocator", ""))
spdx.write_text(json.dumps(d, indent=2) + "\n")
print(f"Post-processed {spdx.name}")
PY
then
echo "ERROR: post-process failed (PURL canonicalization incomplete)." >&2
echo " The emitted SBOM may carry pkg:generic PURLs; not trusting it." >&2
exit 1
fi
echo "Done."

View File

@ -0,0 +1,272 @@
#!/bin/sh
# Generate wolfTPM component SBOMs (autotools make sbom, cmake sbom, or direct gen-sbom).
#
# Mode selection:
# CRA_SBOM_MODE=autotools|cmake
# autotools (default when configure+Makefile exist): runs `make sbom`
# cmake: auto-extracts sources from compile_commands.json and runs gen-sbom directly
#
# Required variables:
# WOLFSSL_DIR=path/to/wolfssl (source tree root; provides gen-sbom)
# WOLFTPM_DIR=path/to/wolftpm (source tree root)
#
# Mode-specific variables:
# WOLFTPM_BUILD_DIR=path/to/build (cmake mode: path to cmake build directory;
# triggers compile_commands.json auto-extraction)
#
# Optional variables:
# CRA_LICENSE_OVERRIDE=<SPDX-id> (e.g. LicenseRef-wolfTPM-Commercial)
# CRA_LICENSE_TEXT=<path> (required when CRA_LICENSE_OVERRIDE is a
# LicenseRef-* id: plain-text licence embedded
# in the SBOM; gen-sbom / make sbom hard-fail
# without it.)
set -eu
SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
KIT_DIR=$(dirname "$SCRIPT_DIR")
# shellcheck disable=SC2015 # `|| true` is a deliberate set -e guard, not if-then-else
WOLFTPM_DIR=${WOLFTPM_DIR:-$(cd "$KIT_DIR/../../wolftpm" 2>/dev/null && pwd || true)}
WOLFSSL_DIR=${WOLFSSL_DIR:-$(cd "$KIT_DIR/../../wolfssl" 2>/dev/null && pwd || true)}
OUT_DIR=${CRA_SBOM_OUT_DIR:-"$KIT_DIR/auditor-packet/wolftpm-component"}
if [ -z "${WOLFTPM_DIR:-}" ] || [ ! -d "$WOLFTPM_DIR" ]; then
echo "ERROR: wolfTPM source not found." >&2
echo " Set WOLFTPM_DIR to your wolftpm checkout." >&2
exit 1
fi
if [ -z "${WOLFSSL_DIR:-}" ] || [ ! -d "$WOLFSSL_DIR" ]; then
echo "ERROR: wolfSSL source not found (needed for gen-sbom)." >&2
echo " Set WOLFSSL_DIR to your wolfssl checkout." >&2
exit 1
fi
GEN="$WOLFSSL_DIR/scripts/gen-sbom"
if [ ! -f "$GEN" ]; then
echo "ERROR: $GEN not found (need wolfSSL with SBOM support)." >&2
exit 1
fi
VERSION=$(sed -n \
's/.*LIBWOLFTPM_VERSION_STRING[[:space:]]*"\([^"]*\)".*/\1/p' \
"$WOLFTPM_DIR/wolftpm/version.h" 2>/dev/null || true)
if [ -z "$VERSION" ]; then
echo "ERROR: could not extract version from $WOLFTPM_DIR/wolftpm/version.h" >&2
exit 1
fi
mkdir -p "$OUT_DIR"
CDX_OUT="$OUT_DIR/wolftpm-${VERSION}.cdx.json"
SPDX_OUT="$OUT_DIR/wolftpm-${VERSION}.spdx.json"
echo "wolfTPM tree: $WOLFTPM_DIR"
echo "wolfSSL tree: $WOLFSSL_DIR"
echo "Outputs: $CDX_OUT"
echo " $SPDX_OUT"
if [ -n "${CRA_LICENSE_OVERRIDE:-}" ]; then
echo "License override: $CRA_LICENSE_OVERRIDE"
fi
# A LicenseRef-* override requires the actual licence text to be embedded
# in the SBOM (SPDX 2.3 §10.1). Catch the omission early.
if [ -n "${CRA_LICENSE_OVERRIDE:-}" ]; then
case "$CRA_LICENSE_OVERRIDE" in
LicenseRef-*)
if [ -z "${CRA_LICENSE_TEXT:-}" ]; then
echo "ERROR: CRA_LICENSE_OVERRIDE=$CRA_LICENSE_OVERRIDE is a LicenseRef-* identifier," >&2
echo " but CRA_LICENSE_TEXT is not set. SPDX 2.3 requires the licence text to be" >&2
echo " embedded for any LicenseRef-* used in licenseConcluded/licenseDeclared." >&2
echo " Re-run with CRA_LICENSE_TEXT=/path/to/wolftpm-commercial-license.txt" >&2
exit 1
fi
if [ ! -f "$CRA_LICENSE_TEXT" ]; then
echo "ERROR: CRA_LICENSE_TEXT=$CRA_LICENSE_TEXT not found." >&2
exit 1
fi
;;
esac
fi
# Canonicalize CRA_LICENSE_TEXT to an absolute path: the autotools path runs
# `make sbom` inside a `cd "$WOLFTPM_DIR"` subshell, where a relative path would
# otherwise resolve against the wolfTPM tree rather than the caller's CWD.
if [ -n "${CRA_LICENSE_TEXT:-}" ] && [ -f "$CRA_LICENSE_TEXT" ]; then
CRA_LICENSE_TEXT=$(CDPATH='' cd -- "$(dirname -- "$CRA_LICENSE_TEXT")" && pwd)/$(basename -- "$CRA_LICENSE_TEXT")
echo "License text: $CRA_LICENSE_TEXT"
fi
# Accumulator for temp files; cleaned up on exit.
_auto_tempfiles=""
trap 'rm -f ${_auto_tempfiles:-}' EXIT
_auto_extract_srcs() {
# Extract wolftpm sources from compile_commands.json (CMake build).
if [ -n "${WOLFTPM_BUILD_DIR:-}" ] && [ -f "$WOLFTPM_BUILD_DIR/compile_commands.json" ]; then
_ccdb="$WOLFTPM_BUILD_DIR/compile_commands.json"
if ! command -v jq >/dev/null 2>&1; then
echo "ERROR: jq is required to auto-extract sources from compile_commands.json." >&2
echo " Install jq, or set CRA_SBOM_SRCS_FILE manually." >&2
exit 1
fi
_auto=$(mktemp "${TMPDIR:-/tmp}/wolftpm-auto-srcs.XXXXXX")
_auto_tempfiles="${_auto_tempfiles:-} $_auto"
jq -r '.[].file' "$_ccdb" \
| grep "^${WOLFTPM_DIR}/" \
| grep -E '/src/[^/]+\.c$' \
| sort -u > "$_auto"
if [ -s "$_auto" ]; then
_n=$(wc -l < "$_auto" | tr -d ' ')
echo " Auto-extracted $_n wolftpm sources from compile_commands.json"
CRA_SBOM_SRCS_FILE="$_auto"
return 0
fi
echo " WARNING: compile_commands.json found but yielded no wolftpm sources." >&2
fi
}
_run_autotools() {
echo "==> Autotools path: make sbom"
_tree_ver=$(sed -n \
's/.*LIBWOLFTPM_VERSION_STRING[[:space:]]*"\([^"]*\)".*/\1/p' \
"$WOLFTPM_DIR/wolftpm/version.h" 2>/dev/null || true)
if [ -n "$_tree_ver" ] && [ "$_tree_ver" != "$VERSION" ]; then
echo "ERROR: wolfTPM tree is version $_tree_ver but detected version is $VERSION." >&2
exit 1
fi
(cd "$WOLFTPM_DIR" && {
if [ ! -f Makefile ]; then
echo " Running ./configure first..."
./configure
fi
if [ -n "${CRA_LICENSE_OVERRIDE:-}" ]; then
if [ -n "${CRA_LICENSE_TEXT:-}" ]; then
make sbom WOLFSSL_DIR="$WOLFSSL_DIR" \
SBOM_LICENSE_OVERRIDE="$CRA_LICENSE_OVERRIDE" \
SBOM_LICENSE_TEXT="$CRA_LICENSE_TEXT"
else
make sbom WOLFSSL_DIR="$WOLFSSL_DIR" \
SBOM_LICENSE_OVERRIDE="$CRA_LICENSE_OVERRIDE"
fi
else
make sbom WOLFSSL_DIR="$WOLFSSL_DIR"
fi
cp -f "wolftpm-${VERSION}.cdx.json" "$CDX_OUT"
cp -f "wolftpm-${VERSION}.spdx.json" "$SPDX_OUT"
if [ -f "wolftpm-${VERSION}.spdx" ]; then
cp -f "wolftpm-${VERSION}.spdx" "$OUT_DIR/"
fi
})
}
_run_cmake() {
echo "==> cmake path: gen-sbom with compile_commands.json source extraction"
if [ -z "${WOLFTPM_BUILD_DIR:-}" ]; then
echo "ERROR: WOLFTPM_BUILD_DIR is not set." >&2
echo " Set it to your cmake out-of-source build directory." >&2
echo " Example: cmake -B build && WOLFTPM_BUILD_DIR=\$PWD/build $0" >&2
exit 1
fi
if [ ! -d "$WOLFTPM_BUILD_DIR" ]; then
echo "ERROR: WOLFTPM_BUILD_DIR=$WOLFTPM_BUILD_DIR is not a directory." >&2
exit 1
fi
CRA_SBOM_SRCS_FILE=""
_auto_extract_srcs
if [ -z "${CRA_SBOM_SRCS_FILE:-}" ]; then
echo "ERROR: could not extract wolftpm sources from compile_commands.json." >&2
echo " Reconfigure cmake with -DCMAKE_EXPORT_COMPILE_COMMANDS=ON, or" >&2
echo " switch to autotools mode (CRA_SBOM_MODE=autotools)." >&2
exit 1
fi
PYTHON3=$(command -v python3 2>/dev/null || command -v python 2>/dev/null || true)
if [ -z "$PYTHON3" ]; then
echo "ERROR: python3 not found in PATH." >&2
exit 1
fi
set -- \
--name wolftpm \
--version "$VERSION" \
--supplier "wolfSSL Inc." \
--license-file "$WOLFTPM_DIR/LICENSE" \
--srcs-file "$CRA_SBOM_SRCS_FILE" \
--cdx-out "$CDX_OUT" \
--spdx-out "$SPDX_OUT"
if [ -n "${CRA_LICENSE_OVERRIDE:-}" ]; then
set -- "$@" --license-override "$CRA_LICENSE_OVERRIDE"
if [ -n "${CRA_LICENSE_TEXT:-}" ]; then
set -- "$@" --license-text "$CRA_LICENSE_TEXT"
fi
fi
"$PYTHON3" "$GEN" "$@"
}
MODE=${CRA_SBOM_MODE:-}
case "$MODE" in
autotools) _run_autotools ;;
cmake) _run_cmake ;;
"")
if [ -n "${WOLFTPM_BUILD_DIR:-}" ] && [ -d "${WOLFTPM_BUILD_DIR}" ]; then
MODE=cmake
_run_cmake
elif [ -f "$WOLFTPM_DIR/Makefile" ] && [ -f "$WOLFTPM_DIR/configure" ]; then
MODE=autotools
_run_autotools
else
echo "ERROR: could not detect build mode." >&2
echo " Set CRA_SBOM_MODE=autotools or cmake, and ensure the build" >&2
echo " directory exists (WOLFTPM_BUILD_DIR) or configure has been run" >&2
echo " in WOLFTPM_DIR." >&2
exit 1
fi
;;
*)
echo "ERROR: CRA_SBOM_MODE must be 'autotools' or 'cmake', not '$MODE'" >&2
exit 1
;;
esac
# ---- Post-process: PURL canonicalization ----
# gen-sbom emits pkg:generic/wolftpm@X by default; rewrite to the canonical
# pkg:github/wolfSSL/wolfTPM@vX form expected in the auditor packet.
if ! CDX_OUT="$CDX_OUT" SPDX_OUT="$SPDX_OUT" \
python3 <<'PY'
import json, os, pathlib
cdx = pathlib.Path(os.environ["CDX_OUT"])
spdx = pathlib.Path(os.environ["SPDX_OUT"])
GENERIC = "pkg:generic/wolftpm@"
GITHUB = "pkg:github/wolfSSL/wolfTPM@v"
def canonicalize_purl(s):
if isinstance(s, str) and s.startswith(GENERIC):
return GITHUB + s[len(GENERIC):]
return s
if cdx.exists():
d = json.loads(cdx.read_text())
comp = d.get("metadata", {}).get("component", {})
comp["purl"] = canonicalize_purl(comp.get("purl", ""))
cdx.write_text(json.dumps(d, indent=2) + "\n")
print(f"Post-processed {cdx.name}")
if spdx.exists():
d = json.loads(spdx.read_text())
for pkg in d.get("packages", []):
for ref in pkg.get("externalRefs", []):
if ref.get("referenceType") == "purl":
ref["referenceLocator"] = canonicalize_purl(ref.get("referenceLocator", ""))
spdx.write_text(json.dumps(d, indent=2) + "\n")
print(f"Post-processed {spdx.name}")
PY
then
echo "ERROR: post-process failed (PURL canonicalization incomplete)." >&2
echo " The emitted SBOM may carry pkg:generic PURLs; not trusting it." >&2
exit 1
fi
echo "Done."