- *_wire_sni test is now more efficient
- openssl-ech workflow now does interop with ECH rejection
extra improvements:
- tested TLSX_EchSwapExtensions
- added ctx level SNI to padding calculation
- Improvement of SNI handling for ECH
- Changed EchSwapExtensions to append instead of prepend
- Reworked ECH testing
wc_MakeRsaKey()'s non-small-stack path declares p/q/tmp1..3 as stack
mp_ints and only mp_init's them after the argument and size checks. An
early 'goto out' from those checks reaches the WOLFSSL_CHECK_MEM_ZERO
cleanup, which calls mp_memzero_check() on the still-uninitialized structs;
the garbage size field makes the check scan an arbitrary stack range and
can false-abort on unrelated registered memory. Zero the temporaries up
front (under WOLFSSL_CHECK_MEM_ZERO) so the early-out cleanup is safe.
ELF V1 headers are need for cross-compiles.
PPC64 is big or little endian so assembly code modified to be able to be built for both.
Fix wiring of vector AES implementations in aes.c.
wc_DhImportKeyPair() registers key->priv for zero-on-free tracking via
mp_memzero_add() under WOLFSSL_CHECK_MEM_ZERO, but wc_FreeDhKey() cleared
priv with mp_forcezero(), which zeroes the data without removing the
registration. Unlike wc_FreeRsaKey(), wc_FreeDhKey() had no
wc_MemZero_Check() to remove the entry, so the registration leaked past
the DhKey's lifetime and a later, unrelated wc_MemZero_Check() over reused
stack could false-abort on it. Add wc_MemZero_Check(key, sizeof(*key)) at
the end of wc_FreeDhKey(), mirroring wc_FreeRsaKey().
The small (reduced-C) curve25519/ed25519 code and the Intel x64 assembly
both define the same fe_/sc_/curve25519 symbols. A user_settings.h that
keeps CURVE25519_SMALL/ED25519_SMALL while USE_INTEL_SPEEDUP selects the
x64 assembly (as happens with --enable-usersettings, which does not run
configure's implementation selection) links with duplicate symbols that
are hard to diagnose. Detect the incompatible combination at compile time
via a clear #error keyed on CURVED25519_X64 (the single source of truth
for 'x64 25519 asm active'), so it fails fast instead. NO_CURVED25519_X64
remains the escape hatch to keep the small implementation.
wc_GenerateSeed only checked os for NULL, so a NULL output passed straight
into the entropy backend. glibc's vDSO getrandom() dereferences the buffer
without validating it and segfaults instead of returning an error. Add the
output NULL check (matching wc_RNG_GenerateBlock's convention) so the public
seed API fails cleanly with BAD_FUNC_ARG.
PollAndReSeed was compiled under #ifdef HAVE_HASHDRBG alone, but its only
callers (in wc_RNG_GenerateBlock) sit in the #else of CUSTOM_RAND_GENERATE_
BLOCK, and it references wc_GenerateSeed which is not provided when a custom
block generator replaces the seed layer. Defining HAVE_HASHDRBG together
with CUSTOM_RAND_GENERATE_BLOCK therefore produced an undefined-symbol link
error. Match _InitRng's guard so the function is compiled exactly when it
can be called.
curve25519.c calls curve25519_base() on the CURVED25519_X64 / aarch64
ARMASM path, but the function is only defined in assembly and had no C
prototype in any header, so a strict C compiler (implicit-declaration as
error) failed to build that configuration. Declare it alongside the
sibling curve25519() prototype under the same guard.
The (L,N) size check ran unconditionally, so after an earlier failure it
overwrote the specific error (e.g. DH_CHECK_PUB_E from the p primality
check) with BAD_FUNC_ARG, and computed qSz from a q that was never read
(the q read is itself gated on err==MP_OKAY). Gate the size check the same
way as the surrounding steps so the first, most specific error is returned.
wc_curve25519_check_public's BIG_ENDIAN branch checked pub[i] != 0 in its
top-order boundary loop where the mirrored LITTLE_ENDIAN branch checks
pub[i] != 0xff. The field prime p = 2^255 - 19 has 0xff middle bytes, so
the != 0 test broke out on the first non-0xff byte and the near-prime
rejection was effectively non-functional for big-endian inputs. Match the
little-endian branch so out-of-range big-endian public keys are rejected.
Address review feedback (dgarske):
- Restore SECURITY-POLICY.md instead of deleting it. The full policy
(severity rubric, scope, coordinated disclosure, credit) stays in-repo;
the canonical website URL is now presented as a mirror of it, not a
replacement, so other repos can still reference one copy.
- SECURITY.md: prefer support@wolfssl.com, offer secure@wolfssl.com with
the PGP key as an option, and drop the phone number.
- Restore the mandatory report-template requirement and the "keep the
vulnerability private until a fix is released" guidance, resolving the
contradiction between the intro and the template section.
Add ML-DSA signing and verification for CMS/PKCS#7 SignedData, following
RFC 9882. ML-DSA is used in CMS "pure" mode: the signature is computed
over the complete message (the DER SET OF signed attributes, or the
eContent when none are present) with an empty context string and absent
signatureAlgorithm parameters, rather than over a pre-computed DigestInfo
as with RSA/ECDSA.
wolfcrypt/src/pkcs7.c:
- New ML-DSA helpers: wc_PKCS7_MlDsaLevelFromOID, wc_PKCS7_BuildPureSigMessage,
wc_PKCS7_MlDsaSign and wc_PKCS7_MlDsaVerify, wired into the per-algorithm
switch sites (GetSignSize, SignedDataGetEncAlgoId, SetPublicKeyOID,
CheckPublicKeyDer) and the sign/verify dispatchers. Only the final FIPS 204
ML-DSA OIDs are accepted; pre-standard draft Dilithium OIDs are not.
- GetSignSize derives the ML-DSA signature length from the parameter set.
- InitWithCert copies the signer public key into the RSA-sized publicKey buffer
only for RSA/ECC certs (the raw-sign callback consumers); large PQC keys such
as ML-DSA would overflow it and are never read back, so publicKeySz stays 0.
- wc_MlDsaKey is always heap allocated (it embeds multi-KB key buffers); the
accompanying DecodedCert uses the WC_DECLARE_VAR/WC_ALLOC_VAR_EX macros for
stack-vs-heap handling under WOLFSSL_SMALL_STACK.
- wc_PKCS7_SignedDataBuildSignature skips building the DigestInfo for ML-DSA,
which signs the full message in pure mode and never consumes it.
- wc_PKCS7_MlDsaSign wraps the ML-DSA private-key decode in
PRIVATE_KEY_UNLOCK/PRIVATE_KEY_LOCK. Unlike RSA/ECC, the FIPS module gates
wc_MlDsaKey_PrivateKeyDecode behind the private-key read lock, so signing
would otherwise fail with FIPS_PRIVATE_KEY_LOCKED_E under --enable-fips. The
macros are no-ops in non-FIPS builds.
wolfssl/wolfcrypt/pkcs7.h:
- Document that the fixed-size signer public key buffer (publicKey/publicKeySz)
holds only RSA/ECC keys; it stays RSA-sized.
wolfcrypt/src/hash.c:
- Map the SHAKE128/SHAKE256 OIDs to their hash types in wc_OidGetHash().
certs/mldsa:
- Add expanded-only PKCS#8 DER private keys (mldsa44/65/87-key.der) matching
the self-signed ML-DSA certificates, with README and include.am updates.
The expanded-only shape (no seed) decodes via wc_MlDsaKey_ImportPrivRaw
without keygen-from-seed or the ASN template, so pkcs7signed_mldsa_test also
passes in WOLFSSL_MLDSA_NO_MAKE_KEY and non-WOLFSSL_ASN_TEMPLATE builds.
certs/renewcerts.sh:
- Generate the mldsa<N>-key.der files from the matching mldsa<N>-key.pem in the
expanded-only shape (openssl pkey -provparam ml-dsa.output_formats=priv), so
a regeneration keeps the DER key in step with the cert. The OpenSSL detection
probe now requires both ML-DSA keygen and that conversion across all three
levels, so the block runs fully (matched cert+key) or is skipped entirely
rather than aborting mid-way.
wolfcrypt/test/test.c:
- Add pkcs7signed_mldsa_test(): round-trip encode/verify of SignedData across
ML-DSA-44/65/87, with and without signed attributes, including a check that
the digest algorithm parameters are encoded as expected. The message-digest
OID is selected from the enabled hash set (SHA-512, else SHA-256, else SHA-1)
so the test builds when SHA-512 is disabled. A negative case confirms ML-DSA
rejects a caller-supplied pre-computed content hash with BAD_FUNC_ARG.
test_wc_falcon_sign_verify aborted (SIGABRT) when run as part of the
full unit suite in liboqs configs. The direct OQS_SIG_keypair() call
draws from liboqs' randombytes callback, which wolfSSL points at its
default liboqs RNG; wolfSSL_liboqsClose() (run by wolfCrypt_Cleanup)
frees that RNG without resetting liboqs_init, so after any earlier
Init/Cleanup cycle in the suite the re-Init never re-creates it and
the callback abort()s on the freed RNG. Running the test alone passed,
which is why this only surfaced in make check.
Drop the direct liboqs usage entirely: decode the embedded
bench_falcon_level1_key (certs_test.h) with wc_Falcon_PrivateKeyDecode
and exercise sign/verify through the wolfSSL API only, which hands the
test's own RNG to liboqs and does not depend on the default-RNG
lifecycle. Also removes the oqs/oqs.h include and the OQS_STATUS
handling; with no liboqs symbols left in the body, only the guard
still references HAVE_LIBOQS, easing the planned liboqs removal.
Validated in --with-liboqs --enable-experimental --enable-falcon (the
failing PRB-liboqs config): the full unit suite now completes with the
test passing at the position that aborted; also passes under
opensslall+falcon and compiles clean with -Werror=bad-function-cast.
ExpectIntEQ casts both arguments to int (tests/unit.h ExpectInt), and
casting a function call that returns the liboqs OQS_STATUS enum trips
-Werror=bad-function-cast, which is part of the test warning set. Store
the status in a local first; casting a variable does not trigger the
warning. Broke falcon-enabled configs once the HAVE_PQC guard fix made
this test compile.
Verified: the TU reproduces the exact CI error before this change and
compiles clean after, and test_wc_falcon_sign_verify still passes in a
--disable-md5 --enable-opensslextra --enable-falcon --with-liboqs
build.