```
==485951== Uninitialised value was created by a stack allocation
==485951== at 0x207D47: des3_key_wrap_test (test.c:12773)
```
and
```
==485951== Uninitialised value was created by a stack allocation
==485951== at 0x3A075E: test_wc_AesGcmArgMcdc (test_aes.c:8968)
```
The RISC-V ASM build provides its own AES-GCM implementation
(wolfcrypt/src/port/riscv/riscv-64-aes.c) rather than AES_GCM_decrypt_C, so
it does not clear the output buffer on authentication failure. Exclude it
from the zero-check, matching the other non-C decrypt paths. Fixes the
riscv64 multi-arch testwolfcrypt failure.
Skoll review of the auth-fail zero-check test in aesgcm_test:
- The guard listed WOLFSSL_ARMASM_NO_HW_CRYPTO and __aarch64__, which are
defined on default x86-64 builds, so the zero-check block was compiled out
and the assertion never actually ran there. They are subsumed by
WOLFSSL_ARMASM (the condition under which AES_GCM_decrypt_C is not the
decrypt path), so use that instead and the check runs on the C path.
- Exclude WC_AES_GCM_DEC_AUTH_EARLY (out is not written on an early-auth
failure) and WOLFSSL_ASYNC_CRYPT (a real async device may offload the
decrypt and not clear the output).
Verified: default make check passes with the zero-check now executing;
testwolfcrypt AES-GCM passes with --enable-aesni and with
-DWC_AES_GCM_DEC_AUTH_EARLY.
Review follow-ups for the constant-time AES-GCM decrypt output clear:
- Guard the output-masking pass with #ifndef WC_AES_GCM_DEC_AUTH_EARLY. In
that configuration the tag is verified before decryption and a mismatch
returns before any output is written, so the masking pass is a guaranteed
no-op; skipping it avoids a wasted O(sz) pass.
- Add a test in aesgcm_test: decrypt with a corrupted tag into a pre-filled
buffer and assert wc_AesGcmDecrypt returns AES_GCM_AUTH_E and, on the
software C path, that the output buffer is cleared to zero. The AES-NI/asm
decrypt paths and the FIPS module do not clear the output on auth failure,
so the zero check forces the C path (use_aesni = 0) and is limited to it
(and skipped under HAVE_FIPS). The AES_GCM_AUTH_E comparison uses
WC_NO_ERR_TRACE().
Verified (gcc 15.2): make check passes on the default (C path) build;
testwolfcrypt AES-GCM passes with --enable-aesni and with
-DWC_AES_GCM_DEC_AUTH_EARLY; ct-valgrind aes_gcm reports 0 errors.
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.
Server-side PKCS#7 encode improvements that let downstream EST/SCEP enrollment
code (wolfCert) drive the existing encoder through the public API rather than
hand-rolling DER. Everything is gated under the existing HAVE_PKCS7 — no new
build options and no new public functions; the convenience wrappers live
caller-side.
Allow degenerate (certs-only) SignedData encode
Relax the hashOID != 0 requirement in PKCS7_EncodeSigned() when
sidType == DEGENERATE_SID, so a caller can produce a certs-only bundle (no
signer, attributes, or eContent — the form used by EST /cacerts and SCEP
GetCACert) by selecting DEGENERATE_SID via wc_PKCS7_SetSignerIdentifierType()
and calling wc_PKCS7_EncodeSignedData(). The output round-trips through
wc_PKCS7_VerifySignedData().
Size the signed-attribute array to the actual count
The SignerInfo attribute working array is now sized to the real attribute
count instead of a fixed [7] array. An inline buffer (sized
MAX_SIGNED_ATTRIBS_SZ, the historical footprint) covers the common
allocation-free case; a heap buffer is used only when the count exceeds it.
The default-attribute count comes from a single helper
(wc_PKCS7_GetDefaultSignedAttribCount) so the sizing matches the emission
logic exactly, and the canned-attribute write is bound-checked against the
array capacity. This also fixes a latent overflow where the backing array was
hardcoded [7] while the bound check used MAX_SIGNED_ATTRIBS_SZ. The macro is
retained for source compatibility but no longer caps the count.
Document the decoded-attribute value shape
Documented the stable shape of PKCS7DecodedAttrib.value (the contents of the
SET OF AttributeValue, outer SET tag stripped) so callers can rely on it. No
behavior change.
Fix multi-certificate decode in non-streaming builds
Bound the additional-certificate loop in wc_PKCS7_VerifySignedData against the
absolute end of the certificate set (idx + length) rather than the relative
length. In NO_PKCS7_STREAM builds the old bound dropped trailing certificates
(all but the first when a large eContent preceded the set), failing
verification when the signer cert was among those dropped. Streaming builds
were unaffected.
Tests
Added coverage in pkcs7signed_test: degenerate certs-only encode via the
public API, nine-attribute encode (beyond the inline capacity), decoded
attribute value shape for PrintableString and OCTET STRING, and a
multi-certificate decode regression with large content that triggers the
bound bug under NO_PKCS7_STREAM. Added a signed-attribute selection
round-trip covering a messageDigest-only subset and the no-attributes case
via wc_PKCS7_SetDefaultSignedAttribs/wc_PKCS7_NoDefaultSignedAttribs, a
WOLFSSL_NO_MALLOC over-capacity case that must return BUFFER_E instead of
overrunning the inline buffer, and a malformed certificate-set length that
exercises the certSetEnd clamp in the verifier. Config-sensitive cases are
guarded.
* remove FIPS 186-5 sign-mode restrictions from WC_HASH_CUSTOM_MIN_DIGEST_SIZE.
* set up WC_MIN_DIGEST_SIZE_FOR_SIGN and WC_MIN_DIGEST_SIZE_FOR_VERIFY, derived from WC_HASH_CUSTOM_MIN_DIGEST_SIZE, but enforcing FIPS 186-5 sign-mode restrictions only for WC_MIN_DIGEST_SIZE_FOR_SIGN.
* replace all uses of WC_MIN_DIGEST_SIZE with WC_MIN_DIGEST_SIZE_FOR_SIGN or WC_MIN_DIGEST_SIZE_FOR_VERIFY as appropriate.
wolfcrypt/test/test.c: in cryptocb_test(), don't expect callback execution in FIPS builds.
wolfssl/wolfcrypt/settings.h: in WOLFSSL_LINUXKM section, if defined(NO_SHA) while registering ECDSA handlers, force WC_MIN_DIGEST_SIZE_FOR_VERIFY to 20 for SHA-1 verify support.
Allow encoding and verifying a CMS SignedData whose encapContentInfo
carries no eContent, that is, a signed-attributes-only signature over
empty content (RFC 5652 makes eContent OPTIONAL). This is required for
SCEP CertRep PENDING and FAILURE messages (RFC 8894 section 3.2.2),
which must omit the pkcsPKIEnvelope entirely.
Encode: wc_PKCS7_EncodeSignedData computes the messageDigest over the
empty content when detached is set and contentSz is 0, since there is no
eContent to drive the normal content-hashing pass.
Verify: PKCS7_VerifySignedData no longer rejects an absent eContent when
no external content or hash was supplied. It is processed as a detached
signature over empty content, and wc_PKCS7_VerifyContentMessageDigest
computes the digest of zero-length content using the parsed digest
algorithm. The messageDigest comparison still rejects a stripped
non-empty eContent.
Add pkcs7_signed_no_content_test, a round-trip over a CMS SignedData
whose encapContentInfo carries no eContent (a detached signature over
empty content, signed-attributes-only), as produced by SCEP CertRep
PENDING/FAILURE messages. The encode omits the eContent and the verify
accepts it without any caller-supplied content or hash, checking the
messageDigest against the hash of empty content. Run for RSA/SHA-256.
wolfcrypt/src/coding.c: in Base64_Decode() and Base64_Decode_nonCT(), check for non-whitespace characters past the end and return ASN_INPUT_E if found;
wolfcrypt/test/test.c: in base64_test(), remove ';' from goodChar[], and add trailing*[] test strings and N_BYTE_TRAILING_TEST(), for positive and negative testing of new checks.
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.
* in slhdsa_keygen_kat() and slhdsa_id_label_test(), pass devId to wc_SlhDsaKey_Init*()
* in cryptocb_test(), inhibit the callback verification check for SLHDSA if FIPS (no crypto callbacks in FIPS-wrapped calls).
* implement wc_local_AesGcmCheckTagSz() with pedantic checks for valid authtag size. SP 800-38D restrictions are now uniformly imposed, unless WC_AES_GCM_ALLOW_NONSTANDARD_TAG_LENGTH is defined (not allow with FIPS).
* refactor tag size checks in wc_AesGcmEncrypt(), wc_AesGcmDecrypt(), wc_AesGcmEncryptFinal(), wc_AesGcmDecryptFinal(), and wc_PKCS7_DecodeAuthEnvelopedData().
* in test.c, update aesgcm_non12iv_test() to skip tag sizes expected to fail.
ARM64/ARM32/Thumb2:
- Inline-asm use param names not registers.
- Return value through first parameter and not first register
- 32-bit values zero extended when loaded off stack
aes.c: Aligned-accedd GHASH for 32-bit CPUs.
test.c: #ifdef protection update.
sha3.h: make digest and block size constants defines for use in hash.h
sha512.h: internal Transform_Sha512* functions declared when only SHA-384.
sp_int.h: include WOLFSSL_SP_MATH_ALL in SP_INT_BITS selection
memory.c: fix printf format to be compatible with more platforms