@@ -61,12 +61,17 @@ clean:
6161CC ?= cc
6262WOLFSSL_DIR ?= ../wolfssl
6363WOLFHSM_CFG_DIR ?= test/config
64+ PREFIX ?= /usr/local
65+ SBOM_INSTALL_DIR ?= $(PREFIX ) /share/doc/wolfhsm
66+ SBOM_VALIDATE ?= yes
67+ SBOM_DEP_WOLFSSL ?= yes
6468VERSION = $(shell sed -n 's/^. wolfHSM Release v//p' ChangeLog.md | head -1 | cut -d' ' -f1)
6569SRCS := $(sort $(wildcard src/* .c) )
6670SBOM_CDX = wolfhsm-$(VERSION ) .cdx.json
6771SBOM_SPDX = wolfhsm-$(VERSION ) .spdx.json
72+ SBOM_SPDX_TV = wolfhsm-$(VERSION ) .spdx
6873
69- .PHONY : sbom
74+ .PHONY : sbom install-sbom uninstall-sbom
7075
7176sbom :
7277 @if [ -z " $( VERSION) " ]; then \
9196 echo " wolfhsm_cfg.h (and user_settings.h) your build uses." >&2 ; \
9297 exit 1; \
9398 fi
99+ @if [ " $( SBOM_VALIDATE) " != " no" ] && \
100+ ! command -v pyspdxtools > /dev/null 2>&1 ; then \
101+ echo " ERROR: 'pyspdxtools' not found (pip install spdx-tools)." >&2 ; \
102+ echo " It validates the SPDX output and converts it to" >&2 ; \
103+ echo " tag-value. Set SBOM_VALIDATE=no to skip both." >&2 ; \
104+ exit 1; \
105+ fi
94106 @echo " wolfHSM version: $( VERSION) "
95107 @echo " Sources: $( words $( SRCS) ) .c files in src/"
96108 @echo " Config: $( WOLFHSM_CFG_DIR) /wolfhsm_cfg.h"
@@ -124,13 +136,59 @@ sbom:
124136 if ! command -v python3 >/dev/null 2>&1; then \
125137 echo "ERROR: python3 not found." >&2; exit 1; \
126138 fi && \
139+ if [ -z "$${SOURCE_DATE_EPOCH:-}" ] && \
140+ command -v git >/dev/null 2>&1 && \
141+ git rev-parse --git-dir >/dev/null 2>&1; then \
142+ sde=$$(git log -1 --format=%ct 2>/dev/null); \
143+ if [ -n "$$sde" ]; then \
144+ SOURCE_DATE_EPOCH="$$sde"; export SOURCE_DATE_EPOCH; \
145+ fi; \
146+ fi && \
147+ dep_args=""; \
148+ if [ "$(SBOM_DEP_WOLFSSL)" != "no" ]; then \
149+ if python3 $(WOLFSSL_DIR)/scripts/gen-sbom --help 2>/dev/null \
150+ | grep -q -- '--dep-wolfssl'; then \
151+ dep_args="--dep-wolfssl yes"; \
152+ wv=$$(sed -n 's/.*LIBWOLFSSL_VERSION_STRING[[:space:]]*"\([^"]*\)".*/\1/p' \
153+ "$(WOLFSSL_DIR)/wolfssl/version.h" 2>/dev/null); \
154+ if [ -n "$$wv" ]; then \
155+ dep_args="$$dep_args --dep-version wolfssl=$$wv"; \
156+ fi; \
157+ else \
158+ echo "NOTE: this gen-sbom lacks --dep-wolfssl; wolfssl will not"; \
159+ echo " be listed as a dependency component in the SBOM."; \
160+ fi; \
161+ fi && \
127162 python3 $(WOLFSSL_DIR)/scripts/gen-sbom \
128163 --name wolfhsm \
129164 --version $(VERSION) \
130165 --supplier "wolfSSL Inc." \
131166 --license-file LICENSING \
132167 --options-h "$$_defines" \
133168 --srcs $(SRCS) \
169+ $$dep_args \
134170 --cdx-out $(SBOM_CDX) \
135- --spdx-out $(SBOM_SPDX)
136- @echo "Done: $(SBOM_CDX) $(SBOM_SPDX)"
171+ --spdx-out $(SBOM_SPDX) && \
172+ if [ "$(SBOM_VALIDATE)" != "no" ]; then \
173+ pyspdxtools --infile $(SBOM_SPDX) --outfile $(SBOM_SPDX_TV) && \
174+ echo "Done: $(SBOM_CDX) $(SBOM_SPDX) $(SBOM_SPDX_TV)"; \
175+ else \
176+ echo "Done: $(SBOM_CDX) $(SBOM_SPDX)"; \
177+ fi
178+
179+ # SBOM install is opt-in (`make install-sbom`), matching the family
180+ # convention in wolfssl's scripts/sbom.am: plain `make` never installs
181+ # SBOM files. wolfHSM's root Makefile has no install/uninstall targets
182+ # to hook, so uninstall-sbom is standalone rather than chained.
183+ install-sbom : sbom
184+ @mkdir -p $(DESTDIR )$(SBOM_INSTALL_DIR )
185+ install -m 0644 $(SBOM_CDX ) $(DESTDIR )$(SBOM_INSTALL_DIR ) /
186+ install -m 0644 $(SBOM_SPDX ) $(DESTDIR )$(SBOM_INSTALL_DIR ) /
187+ @if [ -f " $( SBOM_SPDX_TV) " ]; then \
188+ install -m 0644 $(SBOM_SPDX_TV ) $(DESTDIR )$(SBOM_INSTALL_DIR ) /; \
189+ fi
190+
191+ uninstall-sbom :
192+ -rm -f $(DESTDIR )$(SBOM_INSTALL_DIR ) /$(SBOM_CDX ) \
193+ $(DESTDIR )$(SBOM_INSTALL_DIR ) /$(SBOM_SPDX ) \
194+ $(DESTDIR )$(SBOM_INSTALL_DIR ) /$(SBOM_SPDX_TV )
0 commit comments