wc_DhSetKey_ex loads DH parameters as untrusted and validates that the
modulus is prime, but it passed no RNG, so the check fell back to a
Miller-Rabin test using the fixed small-prime bases 2 through 19. That
test is defeatable: a composite crafted as a strong pseudoprime to those
known bases passes as prime, letting an attacker supply a composite
modulus with a smooth factorization for small-subgroup recovery of the
private exponent and shared secret.
When no RNG is supplied on the untrusted path, create a temporary RNG so
mp_prime_is_prime_ex runs with random witnesses, which such crafted
composites cannot reliably pass. Named FFDHE primes still short-circuit
the check, and builds without an RNG keep the deterministic test.
Fixes F-6776.
wc_ecc_shared_secret_gen_sync ran the scalar multiplication and then
copied the x-coordinate to the output without checking whether the
result was the point at infinity. Both math backends report success for
the identity: ecc_map_ex sets x, y to zero and z to one and returns
success, and the single precision generators serialize the identity as
an all-zero x-coordinate. Either way a shared secret that computed to
infinity was handed back as an all-zero secret with a success code,
where SP 800-56Ar3 5.7.1.2 requires an error and stop.
Check the mapped point on the software path, and detect the all-zero
output after the single precision generators, returning ECC_INF_E in
both cases. The scan accumulates over the whole buffer so it does not
branch on the secret.
A key whose private value is resident in an SE050 carries no software
scalar, so the software multiply legitimately yields the identity for
it. Skip the check for those keys specifically, rather than for a zero
scalar: on a prime-order curve a zero scalar is the one way the identity
can arise, so exempting it would disable the check for the case it
exists to catch.
Fixes F-6770.
wc_Chacha_Process validated only its pointer arguments and then produced
keystream directly from the context state. A zero-initialized ChaCha
context, common for static or global storage, that received a nonce via
wc_Chacha_SetIV but never had wc_Chacha_SetKey called would encrypt with
an all-zero, attacker-predictable key and still return success. This is
the same fail-open class already guarded against in wc_Arc4Process.
Add a keySet flag to the ChaCha struct, set it in wc_Chacha_SetKey, and
return MISSING_KEY from wc_Chacha_Process when the key was never set.
Fixes F-6893.
Add AES-GCM (128/256) as an ECIES DEM next to the AES-CBC/CTR+HMAC modes. Only the encryption key comes from the KDF; the mac salt is bound as GCM AAD and the 16-byte tag replaces the HMAC. The GCM DEM honors all three IV build modes, and default fixed-nonce GCM is gated behind the new WOLFSSL_ECIES_STATIC_GCM_NONCE opt-in. Adds ECIES CryptoCb encrypt/decrypt, the WOLF_CRYPTO_CB ctx getters, devId/heap threading into the DEM primitives, and test/benchmark/CI coverage.
Add WOLFSSL_TLS_READ_AHEAD (--enable-readahead), toggled at runtime via
wolfSSL_set_read_ahead(). When enabled, the record-header read pulls a
full record in one recv() so the body arrives without a second syscall.
The receive window is configurable with
wolfSSL_CTX/SSL_set_default_read_buffer_len() (OpenSSL-compatible):
0 keeps the one-record default, a larger value coalesces several records
per recv(), a smaller value caps the per-connection buffer footprint.
Records exceeding the window are still received correctly, the buffer
grows on demand and is reallocated back down to the window afterwards so
the retained footprint stays bounded.
Includes docs, API tests, and a benchmark toggle.
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.
- gen-advisory: honour explicit per-version status when defaultStatus is
"affected", so unaffected/fixed releases are no longer marked vulnerable
- gen-advisory: fail loudly when a CVE record has no non-empty English
description (CSAF/CycloneDX note text is required, minLength 1)
- gen-advisory: note that --cve-id fetches from the CVE Services API
- bomsh_verify: scope the object-store shape check to sha1, matching the
sha1 gitoid hashing (drop the unreachable sha256-length branch)
- Makefile.am: fail `make bomsh` early when python3/pyspdxtools are absent;
quote $(ENABLED_LIBZ)/$(ENABLED_LIBOQS); consolidate clean-local so the
omnibor/ and advisories/out/ build dirs are removed on clean
- tests: cover the defaultStatus fix, the _bucket_for unknown-state
hard-fail, and a csaf_validate.mjs runner self-test wired into CI
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
Add tooling to produce Software Bills of Materials and build provenance
for wolfSSL, supporting EU Cyber Resilience Act (CRA) obligations.
SBOM generation:
- New `make sbom` target producing SPDX 2.3 output with NTIA minimum
elements, urn:uuid document namespaces, and SPDX LicenseRef compliance.
- Reproducible library discovery across autotools and CMake builds, with
liboqs recorded as a linked artefact.
- Standalone `scripts/gen-sbom` for embedded / RTOS / custom-builder
flows that do not use the main build system, plus --srcs-file,
--no-artifact-hash, and hash-source options.
Build provenance (OmniBOR / bomsh):
- End-to-end bomsh tracing of the built binaries with ArtifactID
insertion, snapshotting the traced library before libtool relink and
hashing the bomsh-traced binary.
- `scripts/bomsh_verify.py` to validate provenance against the traced
gitoid.
Security advisories:
- `scripts/gen-advisory` generating CSAF 2.0 and CycloneDX VEX, with a
`make` target, VEX overlay schema/example, and CWE name data.
Docs, tests, and CI:
- doc/SBOM.md and doc/CRA.md, plus README/INSTALL updates.
- Unit and regression tests for gen-sbom and gen-advisory.
- New sbom.yml and advisory.yml workflows: SPDX validation via
pyspdxtools, CSAF validation, bomsh provenance verification, SBOM
artifact archiving, macOS coverage, and actions pinned to SHAs.
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
Remaining fixes from the second review round:
- keygen: falcon_compute_public's scratch buffer holds NTT(f) (private-key
material) in its tail; wc_ForceZero it before both frees (the
f-not-invertible reject path and the success path). Also zeroize the
internally allocated hwork for consistency with the tmpbuf hardening.
- sampler: falcon_sampler_z's rejection loop never consulted the sticky
PRNG error flag, so a mid-signature SHAKE256 squeeze failure could make
berexp deterministically reject and the loop spin forever. Check p.err
each iteration and bail out; the returned value is discarded since
falcon_sign_core rejects the whole signature once p.err is set.
falcon_prng_init now frees the SHAKE256 context when a later init step
fails (plugs a device-context leak in WOLFSSL_ASYNC_CRYPT builds), and
falcon_prng_refill early-returns once the error is latched instead of
re-issuing failing squeezes.
- codec: guard the bits-dependent shifts in falcon_trim_i8_encode/decode
against out-of-range widths (defense in depth; callers only pass 5..8).
- check_key: implement the cryptographic private/public cross-check that
91ebd89d7 documented as a follow-up. New falcon_native_check_key decodes
(f, g) from the private key and h from the public key and verifies the
defining relation h*f == g (mod q, mod X^n + 1) slot-wise in the NTT
domain (falcon_ntt keeps values canonical in [0, q)); a slot with
NTT(f) == 0 is rejected too, as keygen only emits invertible f.
wc_falcon_check_key dispatches to it whenever the native signing core is
compiled in, and falls back to the presence check in verify-only /
callback-only builds. Doxygen updated to the actual contract, and a unit
test added: a mismatched pair (public half from a different key) must
fail with PUBLIC_KEY_E. This also strengthens the keypair validation
done via wc_falcon_check_key in asn.c.
- wc_falcon.c: replace the lazily-initialised, mutable NTT twiddle-table
cache with precomputed read-only const tables (falcon_zetas/izetas_l1/l5).
This removes the data race on the shared cache (a reader could see the
init flag set before all table entries were visible) and also drops the
now-unused falcon_brv / falcon_build_tables helpers. Verify stays fast
(const reads, no per-call rebuild); KAT confirms the values.
- falcon.c: correct the wc_falcon_sign_msg doc comment (signing needs the
*private* key; required buffer size is the active level's signature size,
not always FALCON_LEVEL1_SIG_SIZE) and validate rng != NULL in the
software path so the error is reported at the API boundary.
- wc_falcon_sign.c / wc_falcon_sign.h: route key->heap into
falcon_complete_private and falcon_expand_privkey (their large fpr scratch
allocations previously used a NULL heap hint, bypassing custom heap
routing); and fail fast in falcon_do_sign_tree on the sampler's sticky
PRNG error (passed in as samplerErr) instead of running to the restart
bound.
- wc_falcon_codec.h: use the project-standard WOLF_CRYPT_WC_FALCON_CODEC_H
include guard instead of the collision-prone generic FALCON_CODEC_H.
- doc/dox_comments (ssl.h + -ja): drop the stale "or HAVE_LIBOQS" from the
ML-KEM hybrid group requirements; liboqs is no longer supported.
Add doc/dox_comments/header_files/falcon.h covering every public wc_falcon_* /
wc_Falcon_* function (init/init_ex/init_id/init_label, set/get level, make_key,
sign/verify, import/export public+private, check_key, sizes, and the DER
encode/decode helpers), plus a Falcon \defgroup in doxygen_groups.h. List
Falcon in the INSTALL algorithm summary.
Docs refer to the algorithm only as "Falcon" (it is not standardized yet); the
temporary-name note and the configure --help / summary text are reworded to not
name a specific future standard.
Added support for encoding and decoding keys in ASN.1.
Added support for X.509 certificates and CSRs.
Generated certificates and CSRs. Not fo FrodoKEM-640 as is not in the specs.
RFC 9973 "TLS 1.3 Extension for Using Certificates with an External
Pre-Shared Key" is now published and obsoletes RFC 8773. The
cert_with_extern_psk implementation was written against the 8773bis
draft that became RFC 9973, so it is already compliant.
Update the textual references in comments, the configure help comment,
the extension codepoint comment, a test comment, and the Doxygen docs.
This is a documentation only change. The WOLFSSL_CERT_WITH_EXTERN_PSK
macro, the --enable-cert-with-extern-psk option, the public API names,
and the extension codepoint 33 (0x0021) are all unchanged, and no logic
is affected. Historical ChangeLog and README entries are left as they
shipped.
Add a new option to require that an external Pre-Shared Key is negotiated
for a handshake to succeed, configured via the new APIs
wolfSSL_CTX_require_psk()/wolfSSL_require_psk(). When set, a handshake
that completes without negotiating an external PSK is aborted with
PSK_MISSING_ERROR instead of falling back to a certificate handshake, so
the PSK acts as an additional security factor.
This is a TLS 1.3 / DTLS 1.3 feature. In (D)TLS 1.2 the use of a PSK is
determined by the negotiated cipher suite, so a mandatory PSK is instead
configured there by restricting the cipher suite list to PSK suites; the
new APIs therefore reject non-TLS-1.3 contexts with BAD_FUNC_ARG.
To keep the requirement fail-closed, the APIs also disable version
downgrade on the object so a downgrade-capable context (e.g. one created
from a v23 method) cannot silently fall back to (D)TLS 1.2 and complete
without a PSK; a peer that does not support (D)TLS 1.3 fails to connect.
The requirement applies to external PSKs only (not session tickets):
session-ticket resumption is exempt. To preserve forward secrecy a
mandatory external PSK must also use an (EC)DHE key exchange; a pure
psk_ke handshake is rejected with PSK_KEY_ERROR. When used with
WOLFSSL_CERT_WITH_EXTERN_PSK, it also ensures that peers are properly
authenticated with both the PSK and via certificates.
The new APIs live alongside the existing wolfSSL_[CTX_]no_dhe_psk()/
only_dhe_psk() PSK options and do not depend on certificate support, so
the feature is usable in NO_CERTS (PSK-only) builds.
Added unit tests for the new APIs and enforcement.
Expose the internal SAN-list helpers as public wc_ APIs so callers can build a
DNS_entry list, encode it into a DER GeneralNames SEQUENCE, and populate a Cert
directly:
- wc_SetDNSEntry() - append a typed alt-name entry to a list
- wc_FlattenAltNames() - encode a list into a buffer (thin wrapper)
- wc_SetAltNamesFromList() - encode a list straight into cert->altNames/Sz
Declarations live in asn.h (they use the DNS_entry type) and are gated by the
existing WOLFSSL_ASN_API export macro; doxygen notes the WOLFSSL_PUBLIC_ASN/
OPENSSL_EXTRA export requirement. Adds a wolfCrypt test covering the success,
NULL-list, NULL-output, BUFFER_E, and Cert paths.
Add a crypto-callback operation for validating an ECC key.
Under WOLF_CRYPTO_CB_ONLY_ECC validation now fails closed with
NO_VALID_DEVID when no device handles the operation; previously such
keys were accepted unvalidated. This is a deliberate compatibility
break, documented at the dispatch site.
Under WOLF_CRYPTO_CB_ONLY_ECC, HAVE_ECC_MAKE_PUB is now enabled and
backed by the dispatch alone, failing closed with NO_VALID_DEVID when
no device handles the operation (previously NOT_COMPILED_IN).
Return PUBLIC_KEY_E for wc_ed25519_export_key if public key is not
present.
Return PUBLIC_KEY_E for wc_ed448_export_key if public key is not
present.
Rename several inLen parameters to outLen for consistency.
Fix F-4427
- Replace public wc_CryptoCb_GetDevice() with
wc_CryptoCb_IsDeviceRegistered() returns 1 or 0. keep the CryptoCb
struct and GetDevice private.
- Reject RegisterDevice(INVALID_DEVID) with BAD_FUNC_ARG instead of ALREADY_E.
- Document the new API and the ALREADY_E/BAD_FUNC_ARG returns.
- Fix table-full test to not leak when MAX_CRYPTO_DEVID_CALLBACKS >= 256.