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
parent
c77b4a5ac7
commit
8b558f3d5a
|
|
@ -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"
|
||||
|
|
@ -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."
|
||||
|
|
@ -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."
|
||||
|
|
@ -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."
|
||||
|
|
@ -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."
|
||||
|
|
@ -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."
|
||||
Loading…
Reference in New Issue