mirror of https://github.com/wolfSSL/wolfTPM.git
SBOM: adopt shared sbom.am fragment; bring CMake target to parity
Autotools: replace the inline make sbom recipe with the shared
scripts/sbom.am fragment (declare wolftpm identity, LICENSE, wolfSSL
dependency, and wolftpm/options.h as the feature-macro source). Add GIT
discovery + AC_SUBST for reproducible SOURCE_DATE_EPOCH, and revert the
WOLFTPM_LIBRARY_VERSION_{FIRST,SECOND,THIRD} split that only fed the old
hardcoded --lib path (the fragment discovers the artifact by glob).
CMake: pin the SBOM licence to GPL-3.0-or-later (header-accurate; matches
autotools SBOM_LICENSE_OVERRIDE) and record wolfSSL as a dependency via
--dep-wolfssl, capability-gated on gen-sbom --help so older gen-sbom
versions still produce a valid (dependency-less) SBOM.
Pin the license default to GPL-3.0-or-later to match the source headers
("or (at your option) any later version"), fixing the SBOM licence field.
Add a CI workflow that builds wolfSSL + wolfTPM and asserts SBOM identity,
licence, options capture, reproducibility, and the wolfSSL dependency.
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
pull/536/head
parent
6f86a048dd
commit
fc511714d3
|
|
@ -0,0 +1,175 @@
|
|||
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: wolfTPM SBOM generation (linux)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Checkout wolftpm
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: wolftpm
|
||||
|
||||
# wolfTPM links wolfSSL/wolfCrypt (RNG, parameter encryption, PK
|
||||
# callbacks), so its SBOM records wolfSSL as a dependency. wolfSSL is
|
||||
# built + installed here so wolfTPM has a library to link, and the same
|
||||
# source tree (scripts/gen-sbom + wolfssl/version.h) is passed to
|
||||
# `make sbom` via WOLFSSL_DIR -- so the recorded wolfSSL dependency
|
||||
# version matches the linked one. 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 build tooling and SBOM validator (pyspdxtools)
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential autoconf automake libtool \
|
||||
pkg-config
|
||||
python3 -m pip install --user 'spdx-tools==0.8.*'
|
||||
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Build and install wolfssl
|
||||
working-directory: wolfssl
|
||||
run: |
|
||||
autoreconf -ivf
|
||||
./configure --enable-wolftpm --enable-pkcallbacks \
|
||||
--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 and on
|
||||
# --dep-wolfssl so this workflow is safe against a gen-sbom that predates
|
||||
# it.
|
||||
- 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."
|
||||
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."
|
||||
fi
|
||||
|
||||
- name: Configure and build wolftpm
|
||||
if: steps.gate.outputs.have == 'yes'
|
||||
working-directory: wolftpm
|
||||
run: |
|
||||
autoreconf -ivf
|
||||
./configure --enable-swtpm --disable-fwtpm --disable-examples \
|
||||
--with-wolfcrypt="$GITHUB_WORKSPACE/wolfssl-install"
|
||||
make -j"$(nproc)"
|
||||
|
||||
- name: Generate SBOM
|
||||
if: steps.gate.outputs.have == 'yes'
|
||||
working-directory: wolftpm
|
||||
run: make sbom WOLFSSL_DIR="$GITHUB_WORKSPACE/wolfssl"
|
||||
|
||||
- name: Outputs exist and SPDX validates
|
||||
if: steps.gate.outputs.have == 'yes'
|
||||
working-directory: wolftpm
|
||||
run: |
|
||||
ls wolftpm-*.cdx.json wolftpm-*.spdx.json wolftpm-*.spdx
|
||||
pyspdxtools --infile wolftpm-*.spdx.json
|
||||
|
||||
- name: CycloneDX identity, licence, and captured options
|
||||
if: steps.gate.outputs.have == 'yes'
|
||||
working-directory: wolftpm
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import glob, json
|
||||
cdx = json.load(open(glob.glob('wolftpm-*.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'] == 'wolftpm', m['name']
|
||||
assert m['purl'].startswith('pkg:github/wolfSSL/wolftpm@'), m['purl']
|
||||
# Default override must land as GPL-3.0-or-later (matches source headers).
|
||||
ids = [l.get('license', {}).get('id') for l in m.get('licenses', [])]
|
||||
assert 'GPL-3.0-or-later' in ids, ids
|
||||
# Identity is the hashed library artifact.
|
||||
assert {h['alg'] for h in m.get('hashes', [])}, 'no component hash'
|
||||
# SBOM_OPTIONS_H must have been parsed: wolfTPM records its feature
|
||||
# macros in wolftpm/options.h, so the SBOM's build properties must be
|
||||
# populated.
|
||||
props = [p for p in m.get('properties', [])
|
||||
if p.get('name', '').startswith('wolfssl:build:')]
|
||||
assert props, 'no wolfssl:build:* properties captured from options.h'
|
||||
print('CDX ok:', m['name'], m['purl'], ids, f'{len(props)} build props')
|
||||
PY
|
||||
|
||||
- name: Reproducible across two runs (SOURCE_DATE_EPOCH)
|
||||
if: steps.gate.outputs.have == 'yes'
|
||||
working-directory: wolftpm
|
||||
run: |
|
||||
rm -f wolftpm-*.cdx.json wolftpm-*.spdx.json wolftpm-*.spdx
|
||||
SOURCE_DATE_EPOCH=1700000000 make sbom \
|
||||
WOLFSSL_DIR="$GITHUB_WORKSPACE/wolfssl"
|
||||
sha256sum wolftpm-*.cdx.json wolftpm-*.spdx.json > /tmp/a.sums
|
||||
rm -f wolftpm-*.cdx.json wolftpm-*.spdx.json wolftpm-*.spdx
|
||||
SOURCE_DATE_EPOCH=1700000000 make sbom \
|
||||
WOLFSSL_DIR="$GITHUB_WORKSPACE/wolfssl"
|
||||
sha256sum wolftpm-*.cdx.json wolftpm-*.spdx.json > /tmp/b.sums
|
||||
diff /tmp/a.sums /tmp/b.sums
|
||||
|
||||
- name: wolfssl recorded as a dependency
|
||||
if: steps.gate.outputs.have == 'yes' && steps.gate.outputs.dep_wolfssl == 'yes'
|
||||
working-directory: wolftpm
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import glob, json
|
||||
d = json.load(open(glob.glob('wolftpm-*.spdx.json')[0]))
|
||||
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-wolftpm', 'DEPENDS_ON',
|
||||
'SPDXRef-Package-wolfssl') in rels, rels
|
||||
print('wolfssl dependency ok')
|
||||
PY
|
||||
|
||||
- name: Upload SBOM artefacts
|
||||
if: always() && steps.gate.outputs.have == 'yes'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: wolftpm-sbom-${{ github.sha }}
|
||||
path: |
|
||||
wolftpm/wolftpm-*.cdx.json
|
||||
wolftpm/wolftpm-*.spdx.json
|
||||
wolftpm/wolftpm-*.spdx
|
||||
if-no-files-found: warn
|
||||
retention-days: 90
|
||||
|
|
@ -793,6 +793,15 @@ if(BUILD_WOLFTPM_LIB)
|
|||
set(WOLFSSL_DIR "" CACHE PATH
|
||||
"Path to wolfssl source tree with scripts/gen-sbom")
|
||||
|
||||
# wolfTPM 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. Pin the header-accurate SPDX id so the SBOM is correct
|
||||
# regardless of the gen-sbom version's licence detection; commercial
|
||||
# licensees can override it (e.g. LicenseRef-wolfSSL-Commercial). This
|
||||
# mirrors SBOM_LICENSE_OVERRIDE in the autotools build.
|
||||
set(SBOM_LICENSE_OVERRIDE "GPL-3.0-or-later" CACHE STRING
|
||||
"SPDX licence expression recorded in the SBOM")
|
||||
|
||||
# Derive the version from wolftpm/version.h, NOT from PROJECT_VERSION.
|
||||
# autotools `make sbom` uses PACKAGE_VERSION, which is sourced from
|
||||
# version.h. Reading the same header here keeps the cmake and autotools
|
||||
|
|
@ -863,6 +872,25 @@ if(BUILD_WOLFTPM_LIB)
|
|||
set(SBOM_LIB
|
||||
"${SBOM_STAGING}/lib/libwolftpm${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||
|
||||
# wolfTPM links wolfSSL/wolfCrypt, so record wolfSSL as a dependency in the
|
||||
# SBOM (matches the autotools SBOM_DEP_WOLFSSL=yes). Recording it needs the
|
||||
# gen-sbom from wolfSSL/wolfssl#10343; older gen-sbom rejects unknown flags,
|
||||
# so probe --help and only pass --dep-wolfssl when supported. Against an
|
||||
# older gen-sbom the SBOM is still valid but omits the wolfSSL entry.
|
||||
set(_sbom_dep_wolfssl "")
|
||||
execute_process(
|
||||
COMMAND ${PYTHON3_CMD} ${WOLFSSL_DIR}/scripts/gen-sbom --help
|
||||
OUTPUT_VARIABLE _sbom_help
|
||||
ERROR_QUIET)
|
||||
if(_sbom_help MATCHES "--dep-wolfssl")
|
||||
set(_sbom_dep_wolfssl --dep-wolfssl yes)
|
||||
else()
|
||||
message(WARNING
|
||||
"sbom: ${WOLFSSL_DIR}/scripts/gen-sbom has no --dep-wolfssl; "
|
||||
"the SBOM will omit the wolfSSL dependency entry. Use the gen-sbom "
|
||||
"from wolfSSL/wolfssl#10343 (or master once merged) to record it.")
|
||||
endif()
|
||||
|
||||
# ${OPTION_FILE} is the generated wolftpm/options.h, the same compile-time
|
||||
# option fingerprint autotools `make sbom` feeds to gen-sbom via
|
||||
# --options-h. Using it (rather than a raw `cc -dM` dump, which would only
|
||||
|
|
@ -881,6 +909,8 @@ if(BUILD_WOLFTPM_LIB)
|
|||
--license-file ${CMAKE_SOURCE_DIR}/LICENSE
|
||||
--options-h ${OPTION_FILE}
|
||||
--lib ${SBOM_LIB}
|
||||
--license-override ${SBOM_LICENSE_OVERRIDE}
|
||||
${_sbom_dep_wolfssl}
|
||||
--cdx-out ${SBOM_CDX}
|
||||
--spdx-out ${SBOM_SPDX}
|
||||
# Validate the SPDX JSON and emit the tag-value rendering as a side
|
||||
|
|
|
|||
80
Makefile.am
80
Makefile.am
|
|
@ -133,69 +133,25 @@ cppcheck:
|
|||
--error-exitcode=89 --std=c89 \
|
||||
-I wolftpm src/ hal/ examples
|
||||
|
||||
# SBOM generation (CRA compliance)
|
||||
SBOM_CDX = wolftpm-$(PACKAGE_VERSION).cdx.json
|
||||
SBOM_SPDX = wolftpm-$(PACKAGE_VERSION).spdx.json
|
||||
SBOM_SPDX_TV = wolftpm-$(PACKAGE_VERSION).spdx
|
||||
sbomdir = $(datadir)/doc/$(PACKAGE)
|
||||
# SBOM generation (CRA compliance). The recipe is shared across the wolfSSL
|
||||
# stack's autotools products in scripts/sbom.am; wolfTPM just declares what it
|
||||
# is (a libwolftpm library that links wolfSSL/wolfCrypt) and includes it.
|
||||
# WOLFSSL_DIR must point to a wolfssl source tree containing scripts/gen-sbom.
|
||||
SBOM_PKGNAME = wolftpm
|
||||
SBOM_LICENSE_FILE = $(srcdir)/LICENSE
|
||||
SBOM_DEP_WOLFSSL = yes
|
||||
|
||||
.PHONY: sbom install-sbom uninstall-sbom
|
||||
# wolfTPM records its feature macros in its own generated options header, so
|
||||
# point gen-sbom at that header rather than at the compiler-derived defaults.
|
||||
SBOM_OPTIONS_H = $(abs_builddir)/wolftpm/options.h
|
||||
|
||||
sbom:
|
||||
@if test -z "$(PYTHON3)"; then \
|
||||
echo ""; \
|
||||
echo "ERROR: 'python3' not found in PATH. Cannot generate SBOM."; \
|
||||
echo ""; \
|
||||
exit 1; \
|
||||
fi
|
||||
@if test -z "$(PYSPDXTOOLS)"; then \
|
||||
echo ""; \
|
||||
echo "ERROR: 'pyspdxtools' not found in PATH. Cannot validate SBOM."; \
|
||||
echo " Install: pip install spdx-tools"; \
|
||||
echo ""; \
|
||||
exit 1; \
|
||||
fi
|
||||
@if test -z "$(WOLFSSL_DIR)"; then \
|
||||
echo ""; \
|
||||
echo "ERROR: WOLFSSL_DIR is not set. Cannot locate gen-sbom."; \
|
||||
echo " Set WOLFSSL_DIR to your wolfSSL source tree, e.g.:"; \
|
||||
echo " make sbom WOLFSSL_DIR=/path/to/wolfssl"; \
|
||||
echo ""; \
|
||||
exit 1; \
|
||||
fi
|
||||
@if test ! -f "$(WOLFSSL_DIR)/scripts/gen-sbom"; then \
|
||||
echo ""; \
|
||||
echo "ERROR: $(WOLFSSL_DIR)/scripts/gen-sbom not found."; \
|
||||
echo " Check that WOLFSSL_DIR points to a wolfSSL tree with SBOM support."; \
|
||||
echo ""; \
|
||||
exit 1; \
|
||||
fi
|
||||
rm -rf $(abs_builddir)/_sbom_staging
|
||||
$(MAKE) install DESTDIR=$(abs_builddir)/_sbom_staging
|
||||
$(PYTHON3) $(WOLFSSL_DIR)/scripts/gen-sbom \
|
||||
--name wolftpm \
|
||||
--version $(PACKAGE_VERSION) \
|
||||
--supplier "wolfSSL Inc." \
|
||||
--license-file $(srcdir)/LICENSE \
|
||||
--options-h $(abs_builddir)/wolftpm/options.h \
|
||||
--lib $(abs_builddir)/_sbom_staging$(libdir)/libwolftpm.so.@WOLFTPM_LIBRARY_VERSION_FIRST@.@WOLFTPM_LIBRARY_VERSION_SECOND@.@WOLFTPM_LIBRARY_VERSION_THIRD@ \
|
||||
$(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)
|
||||
rm -rf $(abs_builddir)/_sbom_staging
|
||||
$(PYSPDXTOOLS) --infile $(abs_builddir)/$(SBOM_SPDX) \
|
||||
--outfile $(abs_builddir)/$(SBOM_SPDX_TV)
|
||||
# wolfTPM 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. Pin
|
||||
# the header-accurate SPDX id here so the SBOM is correct regardless of the
|
||||
# gen-sbom version's licence detection; commercial licensees can override it
|
||||
# (e.g. LicenseRef-wolfSSL-Commercial).
|
||||
SBOM_LICENSE_OVERRIDE ?= GPL-3.0-or-later
|
||||
|
||||
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)/
|
||||
EXTRA_DIST += scripts/sbom.am
|
||||
|
||||
uninstall-sbom:
|
||||
-rm -f $(DESTDIR)$(sbomdir)/$(SBOM_CDX)
|
||||
-rm -f $(DESTDIR)$(sbomdir)/$(SBOM_SPDX)
|
||||
-rm -f $(DESTDIR)$(sbomdir)/$(SBOM_SPDX_TV)
|
||||
|
||||
CLEANFILES += $(SBOM_CDX) $(SBOM_SPDX) $(SBOM_SPDX_TV)
|
||||
include scripts/sbom.am
|
||||
|
|
|
|||
28
README.md
28
README.md
|
|
@ -1126,6 +1126,12 @@ See `./examples/endorsement/get_ek_certs`.
|
|||
|
||||
wolfTPM 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 (from `wolftpm/options.h`),
|
||||
hashes the built `libwolftpm` 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 wolfTPM
|
||||
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
|
||||
|
|
@ -1135,19 +1141,29 @@ 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 files in the build directory:
|
||||
Output: `wolftpm-<version>.cdx.json`, `wolftpm-<version>.spdx.json`, `wolftpm-<version>.spdx`
|
||||
|
||||
| File | Format |
|
||||
|------|--------|
|
||||
| `wolftpm-<version>.cdx.json` | CycloneDX 1.6 |
|
||||
| `wolftpm-<version>.spdx.json` | SPDX 2.3 JSON |
|
||||
| `wolftpm-<version>.spdx` | SPDX 2.3 tag-value |
|
||||
Optional overrides:
|
||||
|
||||
- `SBOM_LICENSE_OVERRIDE` - SPDX expression to use instead of the licence
|
||||
parsed from `LICENSE` (e.g. `LicenseRef-wolfSSL-Commercial` for commercial
|
||||
licensees). Defaults to `GPL-3.0-or-later` (the per-file header licence).
|
||||
- `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/wolftpm/
|
||||
make uninstall-sbom
|
||||
```
|
||||
|
||||
Note: recording wolfSSL as a dependency and emitting wolfTPM-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).
|
||||
|
||||
## Support
|
||||
|
|
|
|||
29
configure.ac
29
configure.ac
|
|
@ -29,16 +29,17 @@ AC_ARG_PROGRAM
|
|||
|
||||
AC_CONFIG_HEADERS([src/config.h])
|
||||
|
||||
WOLFTPM_LIBRARY_VERSION_FIRST=17
|
||||
# ^--- current (installed so name: current-age)
|
||||
WOLFTPM_LIBRARY_VERSION_SECOND=0
|
||||
# ^-- revision
|
||||
WOLFTPM_LIBRARY_VERSION_THIRD=0
|
||||
# ^--- age
|
||||
WOLFTPM_LIBRARY_VERSION=${WOLFTPM_LIBRARY_VERSION_FIRST}:${WOLFTPM_LIBRARY_VERSION_SECOND}:${WOLFTPM_LIBRARY_VERSION_THIRD}
|
||||
AC_SUBST([WOLFTPM_LIBRARY_VERSION_FIRST])
|
||||
AC_SUBST([WOLFTPM_LIBRARY_VERSION_SECOND])
|
||||
AC_SUBST([WOLFTPM_LIBRARY_VERSION_THIRD])
|
||||
WOLFTPM_LIBRARY_VERSION=17:0:0
|
||||
# | | |
|
||||
# +------+ | +---+
|
||||
# | | |
|
||||
# current:revision:age
|
||||
# | | |
|
||||
# | | +- increment if source code has changed
|
||||
# | | set to zero if [current] or [revision] is incremented
|
||||
# | +- increment if interfaces have been added
|
||||
# | set to zero if [current] is incremented
|
||||
# +- increment if interfaces have been removed or changed
|
||||
AC_SUBST([WOLFTPM_LIBRARY_VERSION])
|
||||
|
||||
|
||||
|
|
@ -990,9 +991,15 @@ AC_SUBST([AM_CFLAGS])
|
|||
AC_SUBST([AM_LDFLAGS])
|
||||
AC_SUBST([CPPCHECK])
|
||||
|
||||
# SBOM generation
|
||||
# Tools used by the SBOM targets (see scripts/sbom.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])
|
||||
AC_SUBST([PYTHON3])
|
||||
AC_SUBST([PYSPDXTOOLS])
|
||||
AC_SUBST([GIT])
|
||||
|
||||
# FINAL
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
|
|
|
|||
|
|
@ -0,0 +1,206 @@
|
|||
# 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_OPTIONS_H Path to a product-generated options header (e.g.
|
||||
# wolfMQTT's $(builddir)/wolfmqtt/options.h) that records
|
||||
# the enabled build macros. Set this for products whose
|
||||
# feature flags are NOT in config.h (no AC_DEFINE); when
|
||||
# unset the recipe derives the macros from the compiler +
|
||||
# config.h. Default: unset.
|
||||
# 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"; \
|
||||
opts_h="$(SBOM_OPTIONS_H)"; \
|
||||
if test -z "$$opts_h"; then \
|
||||
opts_h="$$_defines"; \
|
||||
$(CC) -dM -E $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
|
||||
$(if $(wildcard $(abs_builddir)/config.h),-include $(abs_builddir)/config.h) \
|
||||
-x c /dev/null > "$$_defines"; \
|
||||
fi; \
|
||||
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 "$$opts_h" \
|
||||
--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
|
||||
Loading…
Reference in New Issue