Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions INSTALL
Original file line number Diff line number Diff line change
Expand Up @@ -322,3 +322,39 @@ We also have vcpkg ports for wolftpm, wolfmqtt and curl.

Deprecated. wolfSSL now has its own XMMS/XMSS^MT implementation in
wolfCrypt.

21. Generating an SBOM (Software Bill of Materials)

wolfSSL can generate a Software Bill of Materials for EU Cyber Resilience
Act (CRA) compliance after a normal build and install.

Prerequisites:
- python3 (detected automatically by configure)
- pyspdxtools (pip install spdx-tools)

Usage:

$ ./configure
$ make
$ make sbom

This produces three files in the build directory:

wolfssl-<version>.cdx.json CycloneDX 1.6 JSON
wolfssl-<version>.spdx.json SPDX 2.3 JSON
wolfssl-<version>.spdx SPDX 2.3 tag-value (validated by pyspdxtools)

The SPDX JSON is validated by pyspdxtools before the tag-value file is
written; make sbom fails if validation fails.

To install the SBOM files to $(datadir)/doc/wolfssl/:

$ make install-sbom

To remove installed SBOM files:

$ make uninstall-sbom

The generated files are removed by make clean.

For details on the SBOM contents and CRA context, see doc/SBOM.md.
56 changes: 56 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -350,3 +350,59 @@ merge-clean:

.cu.lo:
$(LIBTOOL) --tag=CC --mode=compile $(COMPILE) --compile -o $@ $< -static

# SBOM generation (CRA compliance)
SBOM_CDX = wolfssl-$(PACKAGE_VERSION).cdx.json
SBOM_SPDX = wolfssl-$(PACKAGE_VERSION).spdx.json
SBOM_SPDX_TV = wolfssl-$(PACKAGE_VERSION).spdx
sbomdir = $(datadir)/doc/$(PACKAGE)

.PHONY: sbom install-sbom uninstall-sbom

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
rm -rf $(abs_builddir)/_sbom_staging
$(MAKE) install DESTDIR=$(abs_builddir)/_sbom_staging
$(PYTHON3) $(srcdir)/scripts/gen-sbom \
Comment on lines +376 to +378
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The staging directory is only removed on the success path. If make install, gen-sbom, or pyspdxtools fails, _sbom_staging can be left behind, which is messy and can affect subsequent runs (especially in CI). Consider making cleanup unconditional (e.g., using a shell trap or a single shell block that guarantees rm -rf ... executes on exit/failure).

Copilot uses AI. Check for mistakes.
--name $(PACKAGE) \
--version $(PACKAGE_VERSION) \
--license-file $(srcdir)/LICENSING \
--options-h $(abs_builddir)/wolfssl/options.h \
--lib $(abs_builddir)/_sbom_staging$(libdir)/libwolfssl.so.$(WOLFSSL_LIBRARY_VERSION_FIRST).$(WOLFSSL_LIBRARY_VERSION_SECOND).$(WOLFSSL_LIBRARY_VERSION_THIRD) \
--dep-liboqs $(ENABLED_LIBOQS) \
--dep-libxmss $(ENABLED_LIBXMSS) \
--dep-libxmss-root '$(XMSS_ROOT)' \
--dep-liblms $(ENABLED_LIBLMS) \
--dep-liblms-root '$(LIBLMS_ROOT)' \
--dep-libz $(ENABLED_LIBZ) \
--git '$(GIT)' \
--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)
Comment on lines +393 to +395
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The staging directory is only removed on the success path. If make install, gen-sbom, or pyspdxtools fails, _sbom_staging can be left behind, which is messy and can affect subsequent runs (especially in CI). Consider making cleanup unconditional (e.g., using a shell trap or a single shell block that guarantees rm -rf ... executes on exit/failure).

Copilot uses AI. Check for mistakes.

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)

CLEANFILES += $(SBOM_CDX) $(SBOM_SPDX) $(SBOM_SPDX_TV)
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ applications which have previously used the OpenSSL package. For a complete
feature list, see [Chapter 4](https://www.wolfssl.com/docs/wolfssl-manual/ch4/)
of the wolfSSL manual.

## SBOM / CRA Compliance

wolfSSL provides a Software Bill of Materials (SBOM) for EU Cyber Resilience
Act (CRA) compliance via `make sbom`. See `doc/SBOM.md` for details.

## Notes, Please Read

### Note 1
Expand Down
12 changes: 12 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1989,6 +1989,7 @@ done
# liblms
# Get the path to the hash-sigs LMS HSS lib.
ENABLED_LIBLMS="no"
LIBLMS_ROOT=""
tryliblmsdir=""
AC_ARG_WITH([liblms],
[AS_HELP_STRING([--with-liblms=PATH],[PATH to hash-sigs LMS/HSS install (default /usr/local) (requires --enable-experimental)!])],
Expand Down Expand Up @@ -2051,6 +2052,7 @@ AC_ARG_WITH([liblms],

AM_CFLAGS="$AM_CFLAGS -DHAVE_LIBLMS"
ENABLED_LIBLMS="yes"
LIBLMS_ROOT=$tryliblmsdir
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LIBLMS_ROOT is assigned without quoting, so paths containing whitespace will be split by the shell during configure and the value exported into the Makefile will be incorrect. Quote the assignment (and any similar path-valued assignments) so --with-liblms="/path with spaces" works reliably.

Suggested change
LIBLMS_ROOT=$tryliblmsdir
LIBLMS_ROOT="$tryliblmsdir"

Copilot uses AI. Check for mistakes.
]
)

Expand Down Expand Up @@ -11756,6 +11758,16 @@ AC_SUBST([WOLFSSL_PREFIX_ABS])
AC_SUBST([WOLFSSL_LIBDIR_ABS])
AC_SUBST([WOLFSSL_INCLUDEDIR_ABS])

# SBOM generation
AC_PATH_PROG([PYTHON3], [python3])
AC_PATH_PROG([PYSPDXTOOLS], [pyspdxtools])
AC_PATH_PROG([GIT], [git])
AC_SUBST([ENABLED_LIBOQS])
AC_SUBST([ENABLED_LIBXMSS])
AC_SUBST([ENABLED_LIBLMS])
AC_SUBST([ENABLED_LIBZ])
AC_SUBST([LIBLMS_ROOT])

# FINAL
AC_CONFIG_FILES([stamp-h], [echo timestamp > stamp-h])
AC_CONFIG_FILES([Makefile
Expand Down
107 changes: 107 additions & 0 deletions doc/SBOM.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# wolfSSL SBOM Generation

wolfSSL generates a Software Bill of Materials (SBOM) to support compliance
with the EU Cyber Resilience Act (CRA), which requires software products
placed on the EU market to provide a machine-readable SBOM identifying all
software components.

## Quick Start

```sh
./configure
make
make sbom
```

This requires `python3` and `pyspdxtools` (`pip install spdx-tools`).
Both are detected by `configure`; `make sbom` fails with a clear error
message if either is missing.

## 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.

## Installing the SBOM

```sh
make install-sbom # installs to $(datadir)/doc/wolfssl/
make uninstall-sbom # removes the installed files
```

The generated files are removed by `make clean`.

## 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:generic/wolfssl@<version>` |
| Download location | `https://github.com/wolfSSL/wolfssl` |
| Third-party deps | none (wolfssl has no runtime dependencies in a default build) |

### 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 SBOM reflects the
open-source license. Commercial licensees should update the `licenseConcluded`
field to `LicenseRef-wolfSSL-Commercial` or their applicable SPDX expression
when distributing under a commercial agreement.

## Validating the SBOM Manually

```sh
# 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
```

### External dependency version detection

For dependencies with pkg-config support (`liboqs`, `libz`), the version is
queried via `pkg-config --modversion` at generation time.

For dependencies without pkg-config (`libxmss`, `liblms`), wolfSSL is typically
built against a source checkout rather than an installed package. The generator
falls back to `git describe --tags --always` on the source tree root (passed via
`configure` as `XMSS_ROOT` / `LIBLMS_ROOT`). If the source tree has no tags,
`git describe` returns the short commit hash, which is recorded as-is. If the
source tree is unavailable or `git` is not found, version is recorded as
`NOASSERTION`.
Comment on lines +97 to +98
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This statement doesn’t match the implementation for CycloneDX: when a dependency version is unknown, CycloneDX output omits version and purl (while SPDX uses NOASSERTION for versionInfo). Update this section to reflect the format-specific behavior to avoid confusing users comparing outputs.

Suggested change
source tree is unavailable or `git` is not found, version is recorded as
`NOASSERTION`.
source tree is unavailable or `git` is not found, SPDX records `NOASSERTION`
for `versionInfo`, while CycloneDX omits `version` and `purl`.

Copilot uses AI. Check for mistakes.

## Implementation Notes

SBOM generation is implemented in `scripts/gen-sbom` (Python 3, stdlib only)
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.
Loading
Loading