diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml new file mode 100644 index 000000000..f8bf571bb --- /dev/null +++ b/.github/workflows/sbom.yml @@ -0,0 +1,258 @@ +name: SBOM Test + +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + workflow_dispatch: + inputs: + wolfssl_ref: + description: 'wolfssl git ref that provides scripts/gen-sbom' + # TODO: switch back to 'master' once wolfSSL/wolfssl#10343 merges. + default: 'refs/pull/10343/head' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +# This workflow only reads the repo and uploads artefacts; no API writes. +permissions: + contents: read + +jobs: + sbom: + name: wolfSSH SBOM generation (linux) + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout wolfssh + uses: actions/checkout@v4 + with: + path: wolfssh + + # wolfssl is checked out once and used for two things: built + installed + # so wolfssh has a library to link, and its source tree (scripts/gen-sbom + # + wolfssl/version.h) is passed to `make sbom` via WOLFSSL_DIR. gen-sbom + # is not yet on wolfssl master, so default to the open PR head that carries + # it (wolfSSL/wolfssl#10343) so CI actually exercises `make sbom` instead of + # silently skipping. TODO: switch the fallback back to 'master' once + # #10343 merges. + - name: Checkout wolfssl (gen-sbom + library source) + uses: actions/checkout@v4 + with: + repository: wolfSSL/wolfssl + ref: ${{ github.event.inputs.wolfssl_ref || 'refs/pull/10343/head' }} + path: wolfssl + + - name: Install SBOM validator (pyspdxtools) and pcpp + run: | + # spdx-tools -> pyspdxtools (validation); pcpp -> the embedded + # (--user-settings) path's C preprocessor for walking user_settings.h. + python3 -m pip install --user 'spdx-tools==0.8.*' pcpp + echo "$HOME/.local/bin" >> "$GITHUB_PATH" + + - name: Build and install wolfssl + working-directory: wolfssl + run: | + autoreconf -ivf + ./configure --enable-all --prefix="$GITHUB_WORKSPACE/wolfssl-install" + make -j"$(nproc)" + make install + + # gen-sbom lives in wolfssl and may not be on the checked-out ref yet + # (the wolfSSL SBOM change can land separately). Gate on its presence so + # this workflow is safe to merge before that: it stays green and simply + # skips SBOM generation until a ref that carries the script is used. + - name: Detect gen-sbom availability and capabilities + id: gate + run: | + GS="$GITHUB_WORKSPACE/wolfssl/scripts/gen-sbom" + if [ ! -f "$GS" ]; then + echo "have=no" >> "$GITHUB_OUTPUT" + echo "::notice::wolfssl scripts/gen-sbom not present on this ref; skipping SBOM generation. Re-run via 'Run workflow' with wolfssl_ref set to a branch that has it until it merges to wolfssl master." + exit 0 + fi + echo "have=yes" >> "$GITHUB_OUTPUT" + if python3 "$GS" --help 2>/dev/null | grep -q -- '--dep-wolfssl'; then + echo "dep_wolfssl=yes" >> "$GITHUB_OUTPUT" + else + echo "dep_wolfssl=no" >> "$GITHUB_OUTPUT" + echo "::notice::gen-sbom on this ref has no --dep-wolfssl; the wolfssl dependency + name-derived identity assertions will be skipped (wolfSSL SBOM change not merged yet)." + fi + + - name: Configure and build wolfssh + if: steps.gate.outputs.have == 'yes' + working-directory: wolfssh + run: | + autoreconf -ivf + ./configure --with-wolfssl="$GITHUB_WORKSPACE/wolfssl-install" + make -j"$(nproc)" + + - name: Generate SBOM + if: steps.gate.outputs.have == 'yes' + working-directory: wolfssh + run: make sbom WOLFSSL_DIR="$GITHUB_WORKSPACE/wolfssl" + + - name: Outputs exist and SPDX validates + if: steps.gate.outputs.have == 'yes' + working-directory: wolfssh + run: | + ls wolfssh-*.cdx.json wolfssh-*.spdx.json wolfssh-*.spdx + pyspdxtools --infile wolfssh-*.spdx.json + + - name: CycloneDX is valid JSON with expected identity + if: steps.gate.outputs.have == 'yes' + working-directory: wolfssh + run: | + python3 - <<'PY' + import glob, json + cdx = json.load(open(glob.glob('wolfssh-*.cdx.json')[0])) + assert cdx['bomFormat'] == 'CycloneDX', cdx.get('bomFormat') + assert cdx['specVersion'] == '1.6', cdx.get('specVersion') + m = cdx['metadata']['component'] + assert m['name'] == 'wolfssh', m['name'] + assert m['purl'].startswith('pkg:github/wolfSSL/wolfssh@'), m['purl'] + props = {p['name'] for p in m.get('properties', [])} + # The AM_CPPFLAGS/config.h snapshot must capture real build config; + # PACKAGE_VERSION always lands from config.h, so its absence means + # the options snapshot regressed to empty. + assert any(n.startswith('wolfssl:build:') for n in props), \ + 'no wolfssl:build:* properties - options snapshot is empty' + print('CDX identity ok:', m['name'], m['purl']) + PY + + - name: Reproducible across two runs (SOURCE_DATE_EPOCH) + if: steps.gate.outputs.have == 'yes' + working-directory: wolfssh + run: | + rm -f wolfssh-*.cdx.json wolfssh-*.spdx.json wolfssh-*.spdx + SOURCE_DATE_EPOCH=1700000000 make sbom \ + WOLFSSL_DIR="$GITHUB_WORKSPACE/wolfssl" + sha256sum wolfssh-*.cdx.json wolfssh-*.spdx.json > /tmp/a.sums + rm -f wolfssh-*.cdx.json wolfssh-*.spdx.json wolfssh-*.spdx + SOURCE_DATE_EPOCH=1700000000 make sbom \ + WOLFSSL_DIR="$GITHUB_WORKSPACE/wolfssl" + sha256sum wolfssh-*.cdx.json wolfssh-*.spdx.json > /tmp/b.sums + diff /tmp/a.sums /tmp/b.sums + + - name: wolfssl recorded as a dependency + wolfssh identity + if: steps.gate.outputs.have == 'yes' && steps.gate.outputs.dep_wolfssl == 'yes' + working-directory: wolfssh + run: | + python3 - <<'PY' + import glob, json + d = json.load(open(glob.glob('wolfssh-*.spdx.json')[0])) + pkgs = {p['name']: p for p in d['packages']} + assert 'wolfssl' in pkgs, list(pkgs) + main = pkgs['wolfssh'] + assert main['SPDXID'] == 'SPDXRef-Package-wolfssh', main['SPDXID'] + assert 'github.com/wolfSSL/wolfssh' in main['downloadLocation'], \ + main['downloadLocation'] + rels = [(r['spdxElementId'], r['relationshipType'], + r['relatedSpdxElement']) for r in d['relationships']] + assert ('SPDXRef-Package-wolfssh', 'DEPENDS_ON', + 'SPDXRef-Package-wolfssl') in rels, rels + print('wolfssl dependency + wolfssh identity ok') + PY + + # ---- Embedded / IDE path (no autotools) ---------------------------- + # Firmware customers don't run ./configure: there's no options.h and no + # installed libwolfssh to hash. gen-sbom reads config from user_settings.h + # (via pcpp) and hashes the wolfSSH source set instead. This exercises + # that path the same way the docs tell customers to invoke it. + - name: Generate embedded SBOM (user_settings.h + source set) + if: steps.gate.outputs.have == 'yes' + working-directory: wolfssh + run: | + VER=$(sed -n 's/^AC_INIT(\[wolfssh\],\[\([^]]*\)\].*/\1/p' configure.ac) + VER=${VER:-0.0.0} + mkdir -p sbom-embedded/cfg sbom-embedded-2 + # A minimal embedded-style config; the assertions below prove these + # #defines survive pcpp and land as build properties in the SBOM. + { + echo '#ifndef USER_SETTINGS_H' + echo '#define USER_SETTINGS_H' + echo '#define WOLFSSH_TERM' + echo '#define WOLFSSH_SFTP' + echo '#define WOLFSSH_SCP' + echo '#endif' + } > sbom-embedded/cfg/user_settings.h + DEP=() + if [ "${{ steps.gate.outputs.dep_wolfssl }}" = "yes" ]; then + DEP+=(--dep-wolfssl yes) + fi + gen() { + SOURCE_DATE_EPOCH=1700000000 python3 \ + "$GITHUB_WORKSPACE/wolfssl/scripts/gen-sbom" \ + --name wolfssh --version "$VER" \ + --license-file LICENSING \ + --user-settings wolfssh/settings.h \ + --user-settings-include . \ + --user-settings-include "$GITHUB_WORKSPACE/wolfssl" \ + --user-settings-include sbom-embedded/cfg \ + --user-settings-define WOLFSSL_USER_SETTINGS \ + --srcs src/*.c \ + "${DEP[@]}" \ + --cdx-out "$1/wolfssh-embedded.cdx.json" \ + --spdx-out "$1/wolfssh-embedded.spdx.json" + } + gen sbom-embedded + gen sbom-embedded-2 + # Reproducible: identical bytes across runs (SOURCE_DATE_EPOCH fixed, + # namespace is uuid5(name,version), source-set hash is path-independent). + a=$(sha256sum < sbom-embedded/wolfssh-embedded.cdx.json) + b=$(sha256sum < sbom-embedded-2/wolfssh-embedded.cdx.json) + test "$a" = "$b" || { echo "embedded SBOM not reproducible"; exit 1; } + + - name: Embedded SBOM validates + reflects user_settings.h + source hash + if: steps.gate.outputs.have == 'yes' + working-directory: wolfssh + run: | + pyspdxtools --infile sbom-embedded/wolfssh-embedded.spdx.json + python3 - <<'PY' + import json + cdx = json.load(open('sbom-embedded/wolfssh-embedded.cdx.json')) + m = cdx['metadata']['component'] + assert m['name'] == 'wolfssh', m['name'] + assert m['purl'].startswith('pkg:github/wolfSSL/wolfssh@'), m['purl'] + # Embedded identity is the source-set hash (no library artifact exists). + algs = {h['alg'] for h in m.get('hashes', [])} + assert algs, 'no component hash - source-set (--srcs) hash missing' + # Config must come from user_settings.h through pcpp, not be empty. + props = {p['name'] for p in m.get('properties', [])} + assert any(n.endswith('WOLFSSH_SFTP') for n in props), \ + 'user_settings.h option WOLFSSH_SFTP not captured: %r' % sorted(props) + print('embedded ok:', m['name'], m['purl'], + '| user_settings props:', + sorted(n for n in props if 'WOLFSSH' in n)) + PY + + - name: Embedded SBOM records wolfssl dependency + if: steps.gate.outputs.have == 'yes' && steps.gate.outputs.dep_wolfssl == 'yes' + working-directory: wolfssh + run: | + python3 - <<'PY' + import json + d = json.load(open('sbom-embedded/wolfssh-embedded.spdx.json')) + assert 'wolfssl' in {p['name'] for p in d['packages']}, \ + [p['name'] for p in d['packages']] + rels = [(r['spdxElementId'], r['relationshipType'], + r['relatedSpdxElement']) for r in d['relationships']] + assert ('SPDXRef-Package-wolfssh', 'DEPENDS_ON', + 'SPDXRef-Package-wolfssl') in rels, rels + print('embedded wolfssl dependency ok') + PY + + - name: Upload SBOM artefacts + if: always() && steps.gate.outputs.have == 'yes' + uses: actions/upload-artifact@v4 + with: + name: wolfssh-sbom-${{ github.sha }} + path: | + wolfssh/wolfssh-*.cdx.json + wolfssh/wolfssh-*.spdx.json + wolfssh/wolfssh-*.spdx + wolfssh/sbom-embedded/wolfssh-embedded.* + if-no-files-found: warn + retention-days: 90 diff --git a/Makefile.am b/Makefile.am index d5db195d5..b04ea3555 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,6 +7,7 @@ noinst_PROGRAMS = nobase_include_HEADERS = check_PROGRAMS = dist_noinst_SCRIPTS = +CLEANFILES = #includes additional rules from aminclude.am @INC_AMINCLUDE@ @@ -79,3 +80,21 @@ merge-clean: @find ./ | $(GREP) \.OTHER | xargs rm -f @find ./ | $(GREP) \.BASE | xargs rm -f @find ./ | $(GREP) \~$$ | xargs rm -f + +# SBOM generation (CRA compliance). The recipe is shared across the wolfSSL +# stack's autotools products in scripts/sbom.am; wolfSSH just declares what it +# is (a library that links wolfSSL) and includes it. WOLFSSL_DIR must point to +# a wolfssl source tree containing scripts/gen-sbom. +SBOM_PKGNAME = wolfssh +SBOM_LICENSE_FILE = $(srcdir)/LICENSING +SBOM_DEP_WOLFSSL = yes + +# wolfSSH is GPLv3-or-later (per the per-file source headers: "either version 3 +# of the License, or (at your option) any later version") or commercial. Its +# LICENSING summary uses the "GPLv3" abbreviation, which gen-sbom's +# detect_license maps to GPL-3.0-only -- contradicting the headers -- so pin the +# header-accurate SPDX id here. Commercial licensees can still override it +# (e.g. LicenseRef-wolfSSL-Commercial). +SBOM_LICENSE_OVERRIDE ?= GPL-3.0-or-later + +include scripts/sbom.am diff --git a/README.md b/README.md index 554f1298f..c76f910a3 100644 --- a/README.md +++ b/README.md @@ -627,3 +627,48 @@ WOLFSSH APPLICATIONS wolfSSH comes with a server daemon and a command line shell tool. Check out the apps directory for more information. + +## SBOM / EU CRA Compliance + +wolfSSH generates a Software Bill of Materials (SBOM) in CycloneDX 1.6 and +SPDX 2.3 formats to support compliance with the EU Cyber Resilience Act (CRA). +The SBOM records the configured build options, hashes the built library +artifact (shared or static; ELF, Mach-O, or PE), and (with a sufficiently new +`gen-sbom`) lists wolfSSL as a dependency so vulnerability scanners can +associate wolfSSL advisories with a wolfSSH deployment. Output is reproducible: +set `SOURCE_DATE_EPOCH` (or build +from a git checkout, which uses the last commit time) and repeated runs are +byte-identical. + +```sh +make sbom WOLFSSL_DIR=/path/to/wolfssl +``` + +Requires `python3` and `pyspdxtools` (`pip install spdx-tools`). `WOLFSSL_DIR` +must point to a wolfssl source tree containing `scripts/gen-sbom` (branch +`feat/sbom-embedded`, or `master` once wolfSSL/wolfssl#10343 merges). + +Output: `wolfssh-.cdx.json`, `wolfssh-.spdx.json`, `wolfssh-.spdx` + +Optional overrides: + +- `SBOM_LICENSE_OVERRIDE` - SPDX expression to use instead of the licence + parsed from `LICENSING` (e.g. `LicenseRef-wolfSSL-Commercial` for commercial + licensees). +- `SBOM_LICENSE_TEXT` - path to the licence text for any `LicenseRef-*` used in + `SBOM_LICENSE_OVERRIDE` (required by SPDX 2.3). +- `SBOM_WOLFSSL_VERSION` - version recorded for the wolfSSL dependency; + auto-detected from `WOLFSSL_DIR/wolfssl/version.h` (or wolfSSL's `pkg-config` + entry) when unset. + +```sh +make install-sbom # installs to $(datadir)/doc/wolfssh/ +make uninstall-sbom +``` + +Note: recording wolfSSL as a dependency and emitting wolfSSH-specific project +URLs require the `gen-sbom` from wolfSSL/wolfssl#10343. Against an older +`gen-sbom`, `make sbom` still succeeds and produces a valid SBOM, but omits the +wolfSSL dependency entry and inherits wolfSSL's project URLs. + +For further CRA guidance see [wolfssl/doc/CRA.md](https://github.com/wolfSSL/wolfssl/blob/master/doc/CRA.md). diff --git a/configure.ac b/configure.ac index 4aab10756..5a2342220 100644 --- a/configure.ac +++ b/configure.ac @@ -309,6 +309,13 @@ AC_SUBST([AM_CPPFLAGS]) AC_SUBST([AM_CFLAGS]) AC_SUBST([AM_LDFLAGS]) +# Tools used by the SBOM targets (see Makefile.am `make sbom`). GIT is used +# only to derive SOURCE_DATE_EPOCH for reproducible SBOM output; all three are +# optional and the target reports a clear error when a required one is missing. +AC_PATH_PROG([PYTHON3], [python3]) +AC_PATH_PROG([PYSPDXTOOLS], [pyspdxtools]) +AC_PATH_PROG([GIT], [git]) + # FINAL AC_CONFIG_FILES([Makefile wolfssh/version.h]) diff --git a/scripts/sbom.am b/scripts/sbom.am new file mode 100644 index 000000000..c3844fd23 --- /dev/null +++ b/scripts/sbom.am @@ -0,0 +1,196 @@ +# scripts/sbom.am - shared Automake recipe for CRA-compliant SBOM generation. +# +# One generator (gen-sbom) does the work; each product just describes itself and +# includes this fragment. It is deliberately product-agnostic: a Makefile.am +# sets a few variables (below) and does `include scripts/sbom.am` to get the +# `sbom`, `install-sbom` and `uninstall-sbom` targets. +# +# The canonical copy lives in the wolfSSL repository (scripts/sbom.am); keep +# product copies in sync. gen-sbom is taken from a vendored scripts/gen-sbom +# if a product ships one (used automatically), otherwise from a wolfSSL source +# tree via WOLFSSL_DIR. wolfSSH uses the WOLFSSL_DIR route; vendoring gen-sbom +# for fully offline tarball builds can be added later with no change here. +# +# --------------------------------------------------------------------------- +# The including Makefile.am MUST set, before `include scripts/sbom.am`: +# SBOM_PKGNAME Product name recorded in the SBOM (e.g. wolfssh). Drives +# the output filenames and gen-sbom --name. +# SBOM_LICENSE_FILE Path to the product's LICENSING file +# (e.g. $(srcdir)/LICENSING). +# +# Optional (defaults shown): +# SBOM_ARTIFACT lib | bin - which build output to hash. Default: lib. +# SBOM_LIB_STEM Library basename w/o extension. Default: lib$(SBOM_PKGNAME). +# SBOM_BIN_NAME Program name when SBOM_ARTIFACT = bin. Default: $(SBOM_PKGNAME). +# SBOM_DEP_WOLFSSL yes | no - record wolfSSL as a dependency. Default: no. +# SBOM_DEP_OPENSSL yes | no - record OpenSSL as a dependency (wolfProvider / +# wolfEngine). Default: no. +# SBOM_LICENSE_OVERRIDE SPDX expression to record instead of the licence +# detected from SBOM_LICENSE_FILE. +# SBOM_LICENSE_TEXT Path to licence text for any LicenseRef-* used in +# SBOM_LICENSE_OVERRIDE (required by SPDX 2.3). +# SBOM_WOLFSSL_VERSION Version recorded for the wolfSSL dependency; +# auto-detected from WOLFSSL_DIR/wolfssl/version.h when unset. +# SBOM_OPENSSL_VERSION Version recorded for the OpenSSL dependency; +# gen-sbom resolves it via pkg-config when unset. +# +# The wolfSSL/OpenSSL dependency flags are feature-detected against gen-sbom +# --help, so a product wired for them still produces a valid SBOM (with a NOTE) +# against a gen-sbom that predates the flag. +# +# gen-sbom is located at $(srcdir)/scripts/gen-sbom if vendored, else at +# $(WOLFSSL_DIR)/scripts/gen-sbom. python3, pyspdxtools and git come from +# configure (AC_PATH_PROG); git is used only to derive SOURCE_DATE_EPOCH. +# --------------------------------------------------------------------------- + +SBOM_ARTIFACT ?= lib +SBOM_LIB_STEM ?= lib$(SBOM_PKGNAME) +SBOM_BIN_NAME ?= $(SBOM_PKGNAME) +SBOM_DEP_WOLFSSL ?= no +SBOM_DEP_OPENSSL ?= no + +SBOM_CDX = $(SBOM_PKGNAME)-$(PACKAGE_VERSION).cdx.json +SBOM_SPDX = $(SBOM_PKGNAME)-$(PACKAGE_VERSION).spdx.json +SBOM_SPDX_TV = $(SBOM_PKGNAME)-$(PACKAGE_VERSION).spdx +sbomdir = $(datadir)/doc/$(PACKAGE) + +# Prefer a vendored gen-sbom; fall back to an external wolfSSL source tree. +# The fallback is $(wildcard)-guarded and only consulted when WOLFSSL_DIR is +# set, so an unset WOLFSSL_DIR leaves SBOM_GEN empty (and the sbom recipe's +# `test -f` prints the "set WOLFSSL_DIR" error) rather than resolving to an +# absolute /scripts/gen-sbom that could run an unrelated host script. +SBOM_GEN = $(firstword $(wildcard $(srcdir)/scripts/gen-sbom) \ + $(if $(WOLFSSL_DIR),$(wildcard $(WOLFSSL_DIR)/scripts/gen-sbom))) + +# Library artifact search order (versioned first) covering ELF, Mach-O and PE. +# Windows import libs (.lib) come with and without the "lib" prefix. +SBOM_LIB_GLOBS = \ + $(SBOM_LIB_STEM).so.[0-9]* \ + $(SBOM_LIB_STEM).so \ + $(SBOM_LIB_STEM).[0-9]*.dylib \ + $(SBOM_LIB_STEM).dylib \ + $(SBOM_LIB_STEM).dll \ + $(SBOM_LIB_STEM).dll.a \ + $(SBOM_LIB_STEM).lib \ + $(SBOM_PKGNAME).lib \ + $(SBOM_LIB_STEM).a + +# Automake requires CLEANFILES to be initialised with `=` before `+=`; the +# including Makefile.am must declare `CLEANFILES =` (typically in its primaries +# init block) before `include scripts/sbom.am`. +CLEANFILES += $(SBOM_CDX) $(SBOM_SPDX) $(SBOM_SPDX_TV) + +.PHONY: sbom install-sbom uninstall-sbom + +# Stage a `make install` into a private tree, discover the installed artifact +# (shared/static library or program; ELF/Mach-O/PE), hash it, capture the +# configured build macros (AM_CPPFLAGS + config.h), generate SPDX+CDX, validate +# the SPDX, then convert to tag-value. The staging tree and temp defines file +# are removed unconditionally via `trap`, even on failure. SOURCE_DATE_EPOCH is +# honoured for reproducible output (defaults to the last git commit time). +sbom: + @test -n "$(PYTHON3)" || { \ + echo "ERROR: 'python3' not found in PATH. Cannot generate SBOM."; \ + exit 1; } + @test -n "$(PYSPDXTOOLS)" || { \ + echo "ERROR: 'pyspdxtools' not found (pip install spdx-tools)."; \ + exit 1; } + @test -f "$(SBOM_GEN)" || { \ + echo "ERROR: gen-sbom not found. Vendor scripts/gen-sbom, or re-run:"; \ + echo " make sbom WOLFSSL_DIR=/path/to/wolfssl"; \ + exit 1; } + @rm -rf $(abs_builddir)/_sbom_staging + @set -e; \ + _defines=`mktemp $(abs_builddir)/_sbom_defines.XXXXXX`; \ + trap 'rm -rf $(abs_builddir)/_sbom_staging "$$_defines"' EXIT INT TERM HUP; \ + $(MAKE) install DESTDIR=$(abs_builddir)/_sbom_staging; \ + sbom_art=""; \ + if test "$(SBOM_ARTIFACT)" = bin; then \ + for art in \ + "$(abs_builddir)/_sbom_staging$(bindir)/$(SBOM_BIN_NAME)" \ + "$(abs_builddir)/_sbom_staging$(bindir)/$(SBOM_BIN_NAME)".exe; do \ + if test -f "$$art"; then sbom_art="$$art"; break; fi; \ + done; \ + else \ + for art in \ + $(addprefix "$(abs_builddir)/_sbom_staging$(libdir)"/,$(SBOM_LIB_GLOBS)) \ + $(addprefix "$(abs_builddir)/_sbom_staging$(bindir)"/,$(SBOM_LIB_STEM).dll $(SBOM_PKGNAME).dll); do \ + if test -f "$$art"; then sbom_art="$$art"; break; fi; \ + done; \ + fi; \ + if test -z "$$sbom_art"; then \ + echo ""; \ + echo "ERROR: no installed $(SBOM_PKGNAME) artifact found for SBOM."; \ + echo " (configure with --enable-shared or --enable-static)"; \ + echo ""; \ + exit 1; \ + fi; \ + echo "SBOM: hashing $$sbom_art"; \ + $(CC) -dM -E $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(if $(wildcard $(abs_builddir)/config.h),-include $(abs_builddir)/config.h) \ + -x c /dev/null > "$$_defines"; \ + if test -z "$${SOURCE_DATE_EPOCH:-}" && test -n "$(GIT)" && \ + $(GIT) -C "$(srcdir)" rev-parse --git-dir >/dev/null 2>&1; then \ + sde=`$(GIT) -C "$(srcdir)" log -1 --format=%ct 2>/dev/null`; \ + if test -n "$$sde"; then SOURCE_DATE_EPOCH="$$sde"; export SOURCE_DATE_EPOCH; fi; \ + fi; \ + dep_args=""; \ + if test "$(SBOM_DEP_WOLFSSL)" = yes; then \ + if $(PYTHON3) "$(SBOM_GEN)" --help 2>/dev/null \ + | $(GREP) -q -- '--dep-wolfssl'; then \ + dep_args="$$dep_args --dep-wolfssl yes"; \ + wv="$(SBOM_WOLFSSL_VERSION)"; \ + if test -z "$$wv" && test -f "$(WOLFSSL_DIR)/wolfssl/version.h"; then \ + wv=`sed -n 's/.*LIBWOLFSSL_VERSION_STRING[ \t]*"\([^"]*\)".*/\1/p' \ + "$(WOLFSSL_DIR)/wolfssl/version.h"`; \ + fi; \ + if test -n "$$wv"; then \ + dep_args="$$dep_args --dep-version wolfssl=$$wv"; \ + fi; \ + else \ + echo "NOTE: this gen-sbom has no --dep-wolfssl support, so the SBOM"; \ + echo " will not list wolfssl as a dependency component. That"; \ + echo " support is added by wolfSSL/wolfssl#10343; until it merges"; \ + echo " to wolfssl master, point WOLFSSL_DIR at that PR's branch"; \ + echo " to enable it. The generated SBOM is valid either way."; \ + fi; \ + fi; \ + if test "$(SBOM_DEP_OPENSSL)" = yes; then \ + if $(PYTHON3) "$(SBOM_GEN)" --help 2>/dev/null \ + | $(GREP) -q -- '--dep-openssl'; then \ + dep_args="$$dep_args --dep-openssl yes"; \ + if test -n "$(SBOM_OPENSSL_VERSION)"; then \ + dep_args="$$dep_args --dep-version openssl=$(SBOM_OPENSSL_VERSION)"; \ + fi; \ + else \ + echo "NOTE: this gen-sbom has no --dep-openssl support; openssl will"; \ + echo " not be listed as a dependency component."; \ + fi; \ + fi; \ + $(PYTHON3) "$(SBOM_GEN)" \ + --name $(SBOM_PKGNAME) \ + --version $(PACKAGE_VERSION) \ + --supplier "wolfSSL Inc." \ + --license-file $(SBOM_LICENSE_FILE) \ + --options-h "$$_defines" \ + --lib "$$sbom_art" \ + $$dep_args \ + $(if $(SBOM_LICENSE_OVERRIDE),--license-override '$(SBOM_LICENSE_OVERRIDE)') \ + $(if $(SBOM_LICENSE_TEXT),--license-text '$(SBOM_LICENSE_TEXT)') \ + --cdx-out $(abs_builddir)/$(SBOM_CDX) \ + --spdx-out $(abs_builddir)/$(SBOM_SPDX); \ + $(PYSPDXTOOLS) --infile $(abs_builddir)/$(SBOM_SPDX) \ + --outfile $(abs_builddir)/$(SBOM_SPDX_TV) + +install-sbom: sbom + $(MKDIR_P) $(DESTDIR)$(sbomdir) + $(INSTALL_DATA) $(SBOM_CDX) $(DESTDIR)$(sbomdir)/ + $(INSTALL_DATA) $(SBOM_SPDX) $(DESTDIR)$(sbomdir)/ + $(INSTALL_DATA) $(SBOM_SPDX_TV) $(DESTDIR)$(sbomdir)/ + +uninstall-sbom: + -rm -f $(DESTDIR)$(sbomdir)/$(SBOM_CDX) + -rm -f $(DESTDIR)$(sbomdir)/$(SBOM_SPDX) + -rm -f $(DESTDIR)$(sbomdir)/$(SBOM_SPDX_TV) + +uninstall-hook: uninstall-sbom