wolfSSL removed liboqs: Falcon is now provided natively by wolfCrypt, and --with-liboqs is a deprecated no-op (configure.ac). A build therefore no longer links liboqs, so recording it as an SBOM dependency is dead code and the SBOM integration CI (which asserted a liboqs dep package) failed. Remove the liboqs dependency throughout: - scripts/gen-sbom: drop DEP_META['liboqs'] and the --dep-liboqs flag. - Makefile.am / configure.ac: drop --dep-liboqs "$(ENABLED_LIBOQS)" and the now-unused AC_SUBST([ENABLED_LIBOQS]). - .github/workflows/sbom.yml: drop the liboqs install / --with-liboqs steps and the liboqs dep assertion; keep the native-Falcon build so the HAVE_FALCON build-property capture is still exercised. - scripts/test_gen_sbom.py: drop the liboqs-specific tests, guard against the key reappearing, and use openssl as the example dep elsewhere. - doc/SBOM.md: drop the --dep-liboqs / liboqs dependency references.
32 KiB
wolfSSL SBOM and Build Provenance
wolfSSL provides two complementary artefacts for software supply chain transparency:
| Artefact | Target | Answers |
|---|---|---|
| SBOM (SPDX 2.3 + CycloneDX 1.6) | scripts/gen-sbom / make sbom |
What wolfSSL is: component identity, license, checksums, CPE, PURL |
| OmniBOR artifact graph | make bomsh |
How wolfSSL was built: cryptographic source-to-binary traceability |
Together they provide full coverage for the EU Cyber Resilience Act (CRA)
and similar supply chain transparency requirements. Each target is
independently useful; running both produces an enriched SPDX document that
bridges the two artefacts with a single PERSISTENT-ID gitoid reference.
The SBOM generator has two entry points so both customer segments are covered:
| Entry point | Who it is for | Build system |
|---|---|---|
python3 scripts/gen-sbom … (standalone) |
Embedded / RTOS customers building with their own Makefile, Keil, IAR, STM32CubeIDE, ESP-IDF, Zephyr, plain CMake, etc. | Any |
make sbom (autotools wrapper) |
Linux server / Debian / RPM / Yocto / FIPS-Ready customers running ./configure && make |
Autotools |
Both call the same Python core and produce SBOMs that pass SPDX 2.3
(pyspdxtools) and CycloneDX 1.6 (cyclonedx-bom strict JSON validator)
schema validation. The autotools make sbom integration job
additionally runs ntia-conformance-checker against NTIA Minimum
Elements 2021; see .github/workflows/sbom.yml for the exact set of
validators run on every PR. Pick whichever matches your build flow.
1. Standalone Python tool (recommended for embedded / IDE builds)
scripts/gen-sbom is pure Python 3 stdlib (plus an optional pcpp dep,
see below). Customers who configure wolfSSL via a hand-edited
user_settings.h and link wolfSSL source files directly into firmware
invoke it directly, without running ./configure or producing a
standalone libwolfssl.a.
1.1 Quick start
python3 scripts/gen-sbom \
--name wolfssl --version 5.9.1 \
--license-file LICENSING \
--user-settings wolfssl/wolfcrypt/settings.h \
--user-settings-include . \
--user-settings-include path/to/your/user_settings_dir \
--user-settings-define WOLFSSL_USER_SETTINGS \
--srcs wolfcrypt/src/aes.c wolfcrypt/src/sha.c \
wolfcrypt/src/sha256.c wolfcrypt/src/dh.c \
wolfcrypt/src/random.c \
--cdx-out wolfssl-5.9.1.cdx.json \
--spdx-out wolfssl-5.9.1.spdx.json
That command produces the same two SBOM JSON files (CycloneDX 1.6 and SPDX
2.3) that make sbom produces, with no autotools involvement.
1.2 What you provide
| Flag | What | Where it comes from |
|---|---|---|
--name wolfssl |
Component name | Hard-coded; always wolfssl |
--version 5.9.1 |
Component version | Whatever wolfSSL release you pulled |
--license-file LICENSING |
wolfSSL's LICENSING file |
Already in your wolfSSL source tree |
--user-settings wolfssl/wolfcrypt/settings.h |
wolfSSL's master settings header | Already in your wolfSSL source tree |
--user-settings-include DIR (repeatable) |
Include path containing your user_settings.h and the wolfSSL tree |
Same as the -I flags in your build |
--user-settings-define NAME[=VALUE] (repeatable) |
Macros to predefine for preprocessing | Same as the -D flags in your build (at minimum: -D WOLFSSL_USER_SETTINGS) |
--srcs PATH … |
wolfSSL source files compiled into your firmware | The same source list you pass to your compiler |
--srcs-file PATH |
A file listing the wolfSSL source files, one per line (# comments and blank lines ignored) |
Emitted mechanically by your IDE / build (link map, project export) when the list is too long for the command line |
--cdx-out / --spdx-out |
Output paths for the SBOM JSON files | Anywhere you want |
Exactly one component-checksum source is required: --lib, --srcs /
--srcs-file, or --no-artifact-hash (see § 1.4).
Optional flags:
| Flag | When to use it |
|---|---|
--supplier "Acme Inc." |
Override the default wolfSSL Inc. (rare) |
--dep-libz yes |
If your build links libz |
--dep-version libz=1.3.1 |
Explicit dep version when pkg-config is unavailable (typical cross-compile) |
--license-override LicenseRef-wolfSSL-Commercial |
If you are a commercial licensee, not GPL |
--license-text /path/to/commercial-license.txt |
Required when --license-override is a LicenseRef-* |
--no-artifact-hash |
Record a placeholder checksum when no hashable artefact exists (ROM image, HSM firmware, binary-only redistribution). Mutually exclusive with --lib / --srcs / --srcs-file (see § 1.4) |
--document-namespace https://example.com/sbom/wolfssl-5.9.1.spdx.json |
Override the SPDX documentNamespace. Default is a deterministic urn:uuid: derived from --name/--version (SPDX 2.3 §6.5 requires only uniqueness, not resolvability). Set this when your distribution re-hosts the SBOM under a stable URL. |
1.3 Dependencies
- Python 3. Required. Stdlib only when using
--options-h. pcpp(pip install pcpp). Required only when using--user-settings. pcpp is a pure-Python C preprocessor that walkssettings.hand youruser_settings.hthe same way the C compiler does, so the SBOM build properties reflect the actual compiled configuration rather than just the literal text ofuser_settings.h. If pcpp is not available you can pre-process externally with the compiler and pass the result via--options-h(see § 1.5).pyspdxtools(pip install spdx-tools). Optional. Needed only if you want to validate the produced SPDX or convert it to tag-value form.
1.4 What the SBOM checksum represents
In a make sbom build the hashes / checksums field in the SBOM is
the SHA-256 of libwolfssl.so / libwolfssl.a / libwolfssl.dylib.
In an embedded build there is typically no separate library archive —
wolfSSL .c files are compiled directly into your firmware. Asking the
customer to synthesize a .a purely for SBOM purposes would be artificial
and would make the build harder. Instead, the standalone path computes
an OmniBOR-compatible Merkle hash over the wolfSSL source files you list
in --srcs:
- For each source file, compute its OmniBOR
gitoid(SHA-256 over"blob <size>\0" + filecontents, byte-identical togit hash-object --object-format=sha256). - Sort by basename.
- Hash the concatenated
(basename, gitoid)pairs.
The resulting hash:
- represents "the wolfSSL source code that is in this firmware", which is what an auditor actually wants to see;
- is independent of the order you pass
--srcs, the absolute paths on the build host, or the build host's filesystem; - changes if any compiled-in source byte changes (catches tampering and back-ported patches);
- interoperates with bomsh / OmniBOR tooling, which key off the same gitoid format.
Each standalone SBOM is annotated with extra properties so the checksum's semantics are unambiguous to downstream consumers:
{ "name": "wolfssl:sbom:hash-kind", "value": "source-merkle-omnibor" },
{ "name": "wolfssl:sbom:hash-source", "value": "srcs" },
{ "name": "wolfssl:sbom:source-set", "value": "aes.c,dh.c,sha.c,sha256.c,..." }
wolfssl:sbom:hash-source is the coarse, stable provenance tag that
downstream tooling filters on — which input the checksum came from:
hash-source |
Meaning |
|---|---|
lib |
SHA-256 of a built library archive (--lib) |
srcs |
OmniBOR gitoid Merkle hash of the compiled source set (--srcs / --srcs-file) |
none |
Placeholder; no hashable artefact was available (--no-artifact-hash) |
wolfssl:sbom:hash-kind carries the finer implementation detail
(library-binary vs source-merkle-omnibor vs none); hash-source
is what an integrator keys on without needing to know the hashing
internals.
No hashable artefact (--no-artifact-hash)
For ROM images, HSM firmware, or binary-only redistributions where
neither a library archive nor the compiled source files are accessible,
pass --no-artifact-hash. The checksum field is then a synthetic
64-zero placeholder (0000…0000), and the SBOM carries:
{ "name": "wolfssl:sbom:hash-source", "value": "none" },
{ "name": "wolfssl:sbom:no-artifact-hash-note", "value": "No artefact hash was available …" }
The placeholder can never collide with a real SHA-256, and the note
directs integrators to contact wolfSSL for an integrity-verification
approach appropriate to their build. Use this only as a last resort:
a srcs-based hash is strongly preferred because it is independently
verifiable against the public wolfSSL source tree.
The autotools make sbom path keeps wolfssl:sbom:hash-kind implicit
(equal to library-binary) so its output stays byte-identical to
previous releases.
1.5 Pre-processed defines (no pcpp needed)
If pcpp is unavailable on your build host or you prefer to use the
compiler that actually builds wolfSSL, dump its post-preprocessor #define
table and pass that to --options-h:
$CC $CFLAGS -dM -E \
-DWOLFSSL_USER_SETTINGS \
-include wolfssl/wolfcrypt/settings.h \
-x c /dev/null > build/wolfssl-defines.h
python3 scripts/gen-sbom \
--name wolfssl --version 5.9.1 \
--license-file LICENSING \
--options-h build/wolfssl-defines.h \
--srcs wolfcrypt/src/aes.c wolfcrypt/src/sha.c ... \
--cdx-out wolfssl-5.9.1.cdx.json \
--spdx-out wolfssl-5.9.1.spdx.json
--options-h reads any flat C header containing #define NAME VALUE
lines, so the GCC / Clang / armclang -dM -E output drops in directly.
For IAR (--predef_macros) or legacy Keil armcc (--list_macros) the
output may need a one-line sed to match the #define NAME VALUE
shape.
Noise filtering. A raw $CC -dM -E dump contains hundreds of
compiler / preprocessor reserved identifiers (__VERSION__, __SSE2__,
__INT_FAST32_MAX__, _LP64, …) and on macOS also Apple's entire
<TargetConditionals.h> family (TARGET_OS_MAC=1, TARGET_IPHONE_*,
…) which leak in via system header inclusion. These describe the
build host, not wolfSSL, and would otherwise drown out the wolfSSL
configuration in the SBOM and break reproducibility across hosts.
gen-sbom filters them automatically; the SBOM ends up with only the
HAVE_* / WOLFSSL_* / NO_* / etc. macros that actually describe
the wolfSSL build. See _is_noise_macro in scripts/gen-sbom for the
exact policy and the test cases in scripts/test_gen_sbom.py
(TestIsNoiseMacro) for the pinned coverage.
Header-suffix carve-out: the filter also drops include-guard names
(*_H like WOLF_CRYPT_SETTINGS_H, WOLFSSL_OPTIONS_H) but
preserves real wolfSSL configuration that happens to end in _H.
The carve-out tokens are HAVE_, NO_, and USE_, which between
them cover every _H-suffixed configuration flag in the wolfSSL
tree:
- autoconf header probes —
HAVE_STDINT_H,WOLFSSL_HAVE_ATOMIC_H,WOLFSSL_HAVE_ASSERT_H, … - stdlib disablement (NETOS / Telit / similar RTOS profiles) —
NO_STDINT_H,NO_STDLIB_H,NO_LIMITS_H,NO_CTYPE_H,NO_STRING_H,NO_STDDEF_H,WOLFSSL_NO_ASSERT_H - build-mode toggles —
USE_FLAT_TEST_H,USE_FLAT_BENCHMARK_H
Customers using a _H-suffixed feature flag that does not carry
one of these tokens (e.g. a debug-only opt-in) should rename it
to drop the _H suffix, or open an issue to extend the carve-out.
The --user-settings (pcpp) path applies the same filter, so both
entry points produce semantically equivalent build-property sets for
the same effective configuration.
Hard-fail on preprocessing errors. When the --user-settings
path encounters an #error directive, an unbalanced #if, or a
missing #include while walking settings.h, gen-sbom exits
non-zero rather than emitting a partial SBOM. pcpp would otherwise
print a diagnostic and continue, producing an artefact that silently
omits whatever configuration came after the failure — exactly the
kind of silent drift a CRA reviewer cannot detect. Fix the upstream
issue (or supply the missing --user-settings-include /
--user-settings-define arguments) and rerun.
1.6 Per-IDE / per-toolchain recipes
1.6.1 Custom Makefile (most embedded projects)
Drop these rules into your project Makefile. The WOLFCRYPT_OBJS /
WOLFCRYPT_SRCS variables almost certainly already exist in your build
since they list the wolfSSL files you compile.
WOLFSSL_DIR ?= ../wolfssl
build/libwolfssl-sbom.a: $(WOLFCRYPT_OBJS)
$(AR) rcs $@ $^
sbom: build/libwolfssl-sbom.a
python3 $(WOLFSSL_DIR)/scripts/gen-sbom \
--name wolfssl --version 5.9.1 \
--license-file $(WOLFSSL_DIR)/LICENSING \
--user-settings $(WOLFSSL_DIR)/wolfssl/wolfcrypt/settings.h \
--user-settings-include $(WOLFSSL_DIR) \
--user-settings-include $(USER_SETTINGS_DIR) \
--user-settings-define WOLFSSL_USER_SETTINGS \
--srcs $(WOLFCRYPT_SRCS) \
--cdx-out wolfssl-5.9.1.cdx.json \
--spdx-out wolfssl-5.9.1.spdx.json
Note: the .a here is optional. If you prefer to skip it and rely on
--srcs for the checksum (the recommended embedded mode), drop the
build/libwolfssl-sbom.a rule and remove its dependency from sbom:.
1.6.2 ESP-IDF (Espressif)
ESP-IDF builds with CMake/Ninja and exposes a CMakeLists.txt per
component. Add a custom target to components/wolfssl/CMakeLists.txt:
add_custom_target(wolfssl-sbom
COMMAND python3 ${CMAKE_CURRENT_SOURCE_DIR}/scripts/gen-sbom
--name wolfssl --version 5.9.1
--license-file ${CMAKE_CURRENT_SOURCE_DIR}/LICENSING
--user-settings ${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/wolfcrypt/settings.h
--user-settings-include ${CMAKE_CURRENT_SOURCE_DIR}
--user-settings-include ${WOLFSSL_USER_SETTINGS_DIR}
--user-settings-define WOLFSSL_USER_SETTINGS
--srcs ${WOLFSSL_SRCS}
--cdx-out ${CMAKE_BINARY_DIR}/wolfssl-5.9.1.cdx.json
--spdx-out ${CMAKE_BINARY_DIR}/wolfssl-5.9.1.spdx.json
VERBATIM)
Then idf.py wolfssl-sbom produces both SBOM files in the build
directory.
1.6.3 Zephyr
# In your application CMakeLists.txt or a Zephyr module CMake file:
add_custom_target(wolfssl-sbom
COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_WOLFSSL_MODULE_DIR}/scripts/gen-sbom
--name wolfssl --version 5.9.1
--license-file ${ZEPHYR_WOLFSSL_MODULE_DIR}/LICENSING
--user-settings ${ZEPHYR_WOLFSSL_MODULE_DIR}/wolfssl/wolfcrypt/settings.h
--user-settings-include ${ZEPHYR_WOLFSSL_MODULE_DIR}
--user-settings-define WOLFSSL_USER_SETTINGS
--srcs ${WOLFSSL_SOURCES}
--cdx-out ${CMAKE_BINARY_DIR}/wolfssl.cdx.json
--spdx-out ${CMAKE_BINARY_DIR}/wolfssl.spdx.json)
Run with west build -t wolfssl-sbom.
1.6.4 STM32CubeIDE
STM32CubeIDE generates Eclipse CDT-managed Makefiles. Add the SBOM recipe as a post-build step: Project → Properties → C/C++ Build → Settings → Build Steps → Post-build steps:
python3 ${ProjDirPath}/Drivers/wolfssl/scripts/gen-sbom \
--name wolfssl --version 5.9.1 \
--license-file ${ProjDirPath}/Drivers/wolfssl/LICENSING \
--user-settings ${ProjDirPath}/Drivers/wolfssl/wolfssl/wolfcrypt/settings.h \
--user-settings-include ${ProjDirPath}/Drivers/wolfssl \
--user-settings-include ${ProjDirPath}/Core/Inc \
--user-settings-define WOLFSSL_USER_SETTINGS \
--srcs ${ProjDirPath}/Drivers/wolfssl/wolfcrypt/src/aes.c [...] \
--cdx-out ${ProjDirPath}/wolfssl.cdx.json \
--spdx-out ${ProjDirPath}/wolfssl.spdx.json
1.6.5 Keil μVision (MDK-ARM)
Use Options for Target → User → Run #1 (After Build):
python3 .\Drivers\wolfssl\scripts\gen-sbom --name wolfssl --version 5.9.1 ^
--license-file .\Drivers\wolfssl\LICENSING ^
--user-settings .\Drivers\wolfssl\wolfssl\wolfcrypt\settings.h ^
--user-settings-include .\Drivers\wolfssl ^
--user-settings-define WOLFSSL_USER_SETTINGS ^
--srcs .\Drivers\wolfssl\wolfcrypt\src\aes.c [...] ^
--cdx-out .\wolfssl.cdx.json --spdx-out .\wolfssl.spdx.json
For legacy armcc 5.x toolchains where -dM -E is not available, use
the modern armclang (Keil v6) which is GCC-flag-compatible.
1.6.6 IAR EWARM
Use Project → Options → Build Actions → Post-build command line (one line, all on one logical line in EWARM):
python3 $PROJ_DIR$\..\wolfssl\scripts\gen-sbom --name wolfssl --version 5.9.1
--license-file $PROJ_DIR$\..\wolfssl\LICENSING
--user-settings $PROJ_DIR$\..\wolfssl\wolfssl\wolfcrypt\settings.h
--user-settings-include $PROJ_DIR$\..\wolfssl
--user-settings-define WOLFSSL_USER_SETTINGS
--srcs $PROJ_DIR$\..\wolfssl\wolfcrypt\src\aes.c [...]
--cdx-out $PROJ_DIR$\wolfssl.cdx.json
--spdx-out $PROJ_DIR$\wolfssl.spdx.json
1.6.7 Plain CMake (any project)
add_custom_target(wolfssl-sbom
COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/wolfssl/scripts/gen-sbom
--name wolfssl --version 5.9.1
--license-file ${CMAKE_SOURCE_DIR}/wolfssl/LICENSING
--user-settings ${CMAKE_SOURCE_DIR}/wolfssl/wolfssl/wolfcrypt/settings.h
--user-settings-include ${CMAKE_SOURCE_DIR}/wolfssl
--user-settings-include ${WOLFSSL_USER_SETTINGS_DIR}
--user-settings-define WOLFSSL_USER_SETTINGS
--srcs ${WOLFSSL_C_SOURCES}
--cdx-out ${CMAKE_BINARY_DIR}/wolfssl-${WOLFSSL_VERSION}.cdx.json
--spdx-out ${CMAKE_BINARY_DIR}/wolfssl-${WOLFSSL_VERSION}.spdx.json)
1.7 Reproducibility
The standalone path honors SOURCE_DATE_EPOCH exactly the same way
make sbom does. Two runs against the same source tree, settings, and
source set with the same SOURCE_DATE_EPOCH produce byte-identical
.spdx.json and .cdx.json files. This is regression-tested in CI.
2. Autotools convenience wrapper (make sbom)
For Linux server / Debian / RPM / Yocto / FIPS-Ready customers who
already run ./configure && make, make sbom is a one-line shortcut
that wraps scripts/gen-sbom with all paths resolved automatically.
2.1 Quick start
./configure
make
make sbom
Requires python3 and pyspdxtools (pip install spdx-tools).
2.2 Full coverage: component identity + build provenance
./configure
make
make sbom
make bomsh
Additionally requires bomtrace3 and bomsh_create_bom.py in PATH.
See Prerequisites for make bomsh below.
All tools are detected by configure; either target fails with a clear
error message if a required tool is missing.
2.3 Output files
make sbom produces three files in the build directory:
| File | Format | Standard | Primary use |
|---|---|---|---|
wolfssl-<version>.cdx.json |
JSON | CycloneDX 1.6 | Supply-chain tooling, VEX |
wolfssl-<version>.spdx.json |
JSON | SPDX 2.3 | Machine processing |
wolfssl-<version>.spdx |
Tag-value | SPDX 2.3 | Human review, archival |
The .spdx tag-value file is produced by pyspdxtools converting the
.spdx.json. If the JSON fails SPDX validation, make sbom stops with
a non-zero exit and the tag-value file is not written.
2.4 SBOM contents
Both formats contain the same information:
| Field | Value |
|---|---|
| Name | wolfssl |
| Version | from configure.ac (PACKAGE_VERSION) |
| Type | library |
| Supplier | wolfSSL Inc. |
| License | detected from LICENSING file (currently GPL-3.0-only) |
| Copyright | Copyright (C) 2006-<year> wolfSSL Inc. |
| SHA-256 | hash of the installed libwolfssl.so.X.Y.Z |
| CPE | cpe:2.3:a:wolfssl:wolfssl:<version>:*:*:*:*:*:*:* |
| PURL | pkg:github/wolfSSL/wolfssl@v<version> (resolves directly in OSV / GHSA / Snyk / Trivy without per-vendor mapping) |
| Download location | https://github.com/wolfSSL/wolfssl |
| Third-party deps | none in a default build; --with-libz adds zlib (recorded as a DEPENDS_ON package with its own purl/CPE/supplier). All builds depend transitively on the host C runtime; this is not enumerated as an SBOM component since it is system-supplied and varies per runtime target. |
License detection
The license SPDX identifier is parsed from the LICENSING file at SBOM
generation time, not hardcoded. If the LICENSING file cannot be parsed,
make sbom warns and uses NOASSERTION rather than silently emitting a
wrong value.
Dual licensing
wolfSSL is available under GPL-3.0-only for open-source use, with a
commercial license for proprietary products. The default SBOM reflects the
open-source license. Commercial licensees should regenerate the SBOM with
--license-override set to their applicable SPDX expression — the generator
exposes this directly:
python3 scripts/gen-sbom \
--license-override LicenseRef-wolfSSL-Commercial \
--license-text /path/to/wolfssl-commercial-license.txt \
... other flags ...
--license-text is required whenever --license-override is a custom
LicenseRef-*: SPDX 2.3 mandates that any LicenseRef in licenseConcluded
or licenseDeclared be backed by a hasExtractedLicensingInfos entry that
embeds the actual licence text. Running without it is a configuration
error and the generator exits non-zero rather than emit a misleading SBOM
that auditors might then circulate.
For an SPDX-listed override (Apache-2.0, MIT, etc.), --license-text
is unnecessary because validators already know the canonical text.
make sbom plumbs both knobs through the matching make variables:
make sbom \
SBOM_LICENSE_OVERRIDE=LicenseRef-wolfSSL-Commercial \
SBOM_LICENSE_TEXT=/path/to/wolfssl-commercial-license.txt
Overriding the SPDX documentNamespace
By default the SPDX document's documentNamespace is a deterministic
urn:uuid:<uuid5-derived> value. SPDX 2.3 §6.5 only requires that this
field be a unique URI; it does not have to resolve to anything. The
default avoids asserting a hosted URL the wolfSSL project does not serve.
If your distribution re-publishes the SBOM under a stable URL you control,
set SBOM_DOCUMENT_NAMESPACE (or --document-namespace in the standalone
entry point) so downstream consumers can externalDocumentRef your
hosted copy:
make sbom \
SBOM_DOCUMENT_NAMESPACE=https://example.com/sbom/wolfssl-5.9.1.spdx.json
External dependency version detection
The optional external dependency wolfSSL can link against (libz) is an
installed package and is queried via pkg-config --modversion at SBOM
generation time. The SBOM records the linked library by its package name
(zlib) so that downstream vulnerability scanners (OSV, Grype, Trivy,
Dependency-Track) match CVEs against the right component. Algorithm
enablement (e.g. Falcon, now provided natively by wolfCrypt) is captured
separately as build properties (wolfssl:build:HAVE_FALCON etc.) parsed
from wolfssl/options.h.
If pkg-config does not report a version (the package is not installed, or
its .pc file is missing):
- SPDX records
versionInfo: NOASSERTIONand emits nopurlexternal ref. - CycloneDX omits the
versionandpurlfields entirely and the generator prints a warning to stderr.
For embedded / cross-compile builds without pkg-config, the standalone
entry point exposes a --dep-version libz=1.3.1 override (see § 1.2). The
autotools path exposes the same override through the SBOM_DEP_VERSIONS
make variable (space-separated KEY=VERSION pairs), so a packaging host
that lacks the dependency's .pc file can still record the version instead
of NOASSERTION:
make sbom SBOM_DEP_VERSIONS='libz=1.3.1'
2.5 Validating the SBOM manually
# Validate SPDX JSON
pyspdxtools --infile wolfssl-<version>.spdx.json
# Convert to another format (e.g. RDF)
pyspdxtools --infile wolfssl-<version>.spdx.json \
--outfile wolfssl-<version>.spdx.rdf
2.6 Installing the SBOM
make install-sbom # installs to $(datadir)/doc/wolfssl/
make uninstall-sbom # removes the installed files
The generated files are removed by make clean.
2.7 Implementation notes
SBOM generation is implemented in scripts/gen-sbom (Python 3, stdlib
only for the autotools path) and hooked into the autotools build via
Makefile.am and configure.ac. The script stages a make install
into a temporary directory, hashes the installed library, generates both
SBOM formats, then removes the staging directory. The pyspdxtools
validation and conversion step runs after generation and gates the build
on SPDX conformance.
The standalone embedded entry point (§ 1) calls the same script with
different flags; the autotools target is essentially a path-resolver
wrapper that finds the installed library, the autotools-generated
options.h, and the pkg-config versions of any linked deps.
3. make bomsh
make bomsh uses the Bomsh project to
trace the wolfSSL build under bomtrace3 (a patched strace) and produce
an OmniBOR artifact dependency graph: a content-addressed Merkle DAG mapping
every built binary back to the exact set of source files that produced it.
3.1 Prerequisites for make bomsh
| Tool | Required | Where to get it |
|---|---|---|
bomtrace3 |
yes | Build from source: omnibor/bomsh |
bomsh_create_bom.py |
yes | scripts/ directory of the bomsh repo, placed in PATH |
bomsh_sbom.py |
no | Same; needed only for SPDX enrichment step |
bomtrace3 is a patched strace — it is a userspace binary and requires no
kernel modifications. It uses the standard ptrace() syscall available on
any stock Linux kernel. The only environments where it may be unavailable
are containers running with a hardened seccomp profile or systems with
kernel.yama.ptrace_scope=3.
make bomsh is Linux-host-only by design. For non-Linux build hosts
(macOS, Windows), use a Linux CI runner / WSL2 / a Linux container. The
target running the produced wolfSSL binary can be anything — bomsh traces
the cross-compiler invocation on Linux regardless of what platform the
binary will eventually run on.
Building bomtrace3
git clone https://github.com/omnibor/bomsh
git clone https://github.com/strace/strace strace3
cd strace3
patch -p1 < ../bomsh/.devcontainer/patches/bomtrace3.patch
cp ../bomsh/.devcontainer/src/*.[hc] src/
./bootstrap && ./configure && make
cp src/strace ~/.local/bin/bomtrace3
Place bomsh_create_bom.py (and optionally bomsh_sbom.py) from the bomsh
scripts/ directory somewhere in PATH.
3.2 What make bomsh does
- Runs
make cleanto ensure a full rebuild. This is necessary becausebomtrace3intercepts syscalls live during compilation and cannot post-process an already-built tree. This step also removes any priorwolfssl-<version>.{cdx,spdx}.jsonfrom a stand-alonemake sbom, which is intentional: the documentmake bomshenriches must come from the traced rebuild, not from a stale pre-trace one. - Writes a build-local
_bomsh.confredirecting the raw logfile out of/tmp/to the build directory (avoids collisions between concurrent builds). - Runs
bomtrace3 -c _bomsh.conf make— rebuilds wolfSSL under strace tracing, recording every compiler invocation with its inputs and outputs. - Runs
bomsh_create_bom.pyto process the raw logfile and produce the OmniBOR artifact graph inomnibor/. - Discovers the bomsh-traced library under
src/.libs/and runsmake sbom SBOM_LIB_OVERRIDE=<traced-library>so the regenerated SPDX hashes the same binary that bomsh traced (see § 3.5). - If
bomsh_sbom.pyis available, annotates the regenerated SPDX document with OmniBORExternalRefidentifiers, producingomnibor.wolfssl-<version>.spdx.json.
3.3 Output files
| Path | Description |
|---|---|
omnibor/objects/ |
OmniBOR artifact objects (SHA-1 content-addressed dependency graph) |
omnibor/metadata/bomsh/ |
Bomsh build metadata |
omnibor.wolfssl-<ver>.spdx.json |
SPDX 2.3 JSON enriched with OmniBOR ExternalRef (produced only when both bomsh_sbom.py and wolfssl-<ver>.spdx.json are present) |
The PERSISTENT-ID gitoid entry added to the enriched SPDX looks like:
{
"referenceCategory": "PERSISTENT-ID",
"referenceType": "gitoid",
"referenceLocator": "gitoid:blob:sha1:<hash>"
}
This sits alongside the existing CPE and PURL externalRefs on the wolfSSL
package entry and is the key into the OmniBOR Merkle DAG in omnibor/.
3.4 Installing
make install-bomsh # installs omnibor/ and enriched SPDX to $(datadir)/doc/wolfssl/
make uninstall-bomsh # removes installed files
The generated files are removed by make clean.
3.5 Implementation notes
make bomsh runs a full clean rebuild under bomtrace3 on every invocation.
The ~20% runtime overhead of bomtrace3 means the rebuild takes roughly
1.2× the normal build time.
The raw logfile (bomsh_raw_logfile.sha1) and conf file (_bomsh.conf)
are written to the build directory and removed by make clean. The
omnibor/ tree is also removed by make clean.
Identity of the SHA-256 in the enriched SPDX
make bomsh discovers the bomsh-traced library under
$(abs_builddir)/src/.libs/ and passes it to the nested make sbom
invocation as SBOM_LIB_OVERRIDE, so the SHA-256 in the SPDX
checksums[] is the SHA-256 of the exact binary that bomtrace3
traced. Without that override make sbom would re-link via make install DESTDIR=... and hash a libtool-relinked artefact whose
SHA-256 differs from the traced library, leaving the SHA-256 in
checksums[] and the OmniBOR externalRefs describing two different
files in the same SPDX document.
CI verifiability gates
The bomsh CI job enforces two independent self-consistency properties
on every PR, in addition to schema validation of the enriched SPDX
through pyspdxtools:
- Resolvability — every
gitoidlisted in the SPDXexternalRefsresolves to a blob present atomnibor/objects/<aa>/<rest>. - Object-store integrity — every blob in
omnibor/objects/round-trips throughsha1(b"blob <len>\0" + content), so a corrupt or truncated object store is caught at PR time, not by a downstream verifier weeks later.
If either fails, the PR fails — the bomsh provenance bundle that a CRA reviewer would download is never published with a broken bridge.
A third gate is not implemented: the gitoid that bomsh_sbom.py
attaches to the SPDX is the bom_id of the OmniBOR Input Manifest for
the traced artefact, not the git-blob hash of the binary itself. The
two are different by design (the bom_id summarises the build inputs,
not the linked output bytes), so a "gitoid == sha1 of the binary"
check would always fail. What ties the SBOM to the binary today is
the SHA-256 in checksums[], which the SBOM_LIB_OVERRIDE plumbing
described above guarantees is the SHA-256 of the bomsh-traced library.
The verifier itself lives at scripts/bomsh_verify.py (importable, with
synthetic-fixture unit tests in scripts/test_gen_sbom.py). Run it
against any local make bomsh output with:
python3 scripts/bomsh_verify.py
4. Combined workflow
Running both targets produces the complete set of supply chain transparency
artefacts. make bomsh automatically enriches the SPDX document from
make sbom if it is present; there is no need to pass any extra flags.
./configure
make
make sbom # component identity
make bomsh # build provenance + enriched SPDX
All output files:
| File | From | Description |
|---|---|---|
wolfssl-<ver>.cdx.json |
make sbom |
CycloneDX 1.6 component SBOM |
wolfssl-<ver>.spdx.json |
make sbom |
SPDX 2.3 JSON component SBOM |
wolfssl-<ver>.spdx |
make sbom |
SPDX 2.3 tag-value, validated |
omnibor/ |
make bomsh |
OmniBOR artifact dependency graph |
omnibor.wolfssl-<ver>.spdx.json |
make bomsh |
SPDX 2.3 JSON enriched with OmniBOR gitoid |
The enriched SPDX is the document to hand to a CRA auditor or downstream consumer when you want both component identity and build traceability in one file.
5. Using wolfSSL's artefacts in a product
If you are shipping a product that includes wolfSSL and need to satisfy CRA
obligations, see doc/CRA.md for guidance on integrating these artefacts
into your product SBOM and what to provide to a conformity assessor.
If a vulnerability is found in wolfSSL itself or in any dependency listed
in the SBOM, see SECURITY-POLICY.md at the
repository root for wolfSSL's disclosure process, severity rubric, and
coordinated-disclosure practice. Reports use
SECURITY-REPORT-TEMPLATE.md and go to
support@wolfssl.com; published advisories are at
https://www.wolfssl.com/docs/security-vulnerabilities/.