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.
Scrub the temporary "FN-DSA" name and the "FIPS 206" designation from all
in-tree comments, build text, and message strings, leaving the algorithm
named only as "Falcon". The eventual standardized name is not announced.
The differential known-answer test message ("wolfSSL FN-DSA differential
KAT") is a signed input, so the Falcon-512/1024 public keys and signatures
in wolfcrypt/test/test.c (and the mirrored Falcon-512 vector in
IDE/m33mu-falcon-verify/kat.h) were regenerated with liboqs over the new
message "wolfSSL Falcon differential KAT", preserving the differential
property (liboqs-produced signatures verified by the native verifier).
Verified: testwolfcrypt Falcon test passes; the m33mu verify-only harness
passes (BKPT 0x7f) with the regenerated vector.
Wire Falcon into the crypto callback framework like the other algorithms:
- wc_falcon_make_key now dispatches to wc_CryptoCb_MakePqcSignatureKey
(WC_PQC_SIG_TYPE_FALCON); wc_falcon_sign_msg / wc_falcon_verify_msg already
dispatched to wc_CryptoCb_PqcSign / PqcVerify. All three fall through to the
software implementation when the callback is unavailable.
- Add WOLF_CRYPTO_CB_ONLY_FALCON (mirrors WOLF_CRYPTO_CB_ONLY_RSA/ECC): the
callback becomes authoritative (no software fallback; returns NO_VALID_DEVID
when no device is registered) and the native core (wc_falcon*.c) is compiled
out entirely. WC_FALCON_HAVE_NATIVE_SIGN and the falcon_native_* prototypes
are gated off in that build.
Tests (test.c):
- myCryptoDevCb gains a Falcon branch for PQC keygen/sign/verify.
- falcon_test / falcon_verify_kat now use the global test devId, so
cryptocb_test drives every Falcon operation through the callback and asserts
(via the exampleVar hit counter) that the cb path was actually taken.
- Under WOLF_CRYPTO_CB_ONLY_FALCON, falcon_test instead confirms the API
returns NO_VALID_DEVID with no device registered, and the KAT data/verifier
(software-only) are compiled out.
Verified: default (no cryptocb), --enable-cryptocb, and
-DWOLF_CRYPTO_CB_ONLY_FALCON all build and pass testwolfcrypt (falcon_test +
crypto callback test); the CB_ONLY library contains no falcon_native_* symbols.
Add a complete native Falcon post-quantum lattice signature implementation to
wolfCrypt, replacing the liboqs wrapper. Full key generation, signing and
verification for Falcon-512 (level 1) and Falcon-1024 (level 5).
- Public API wc_falcon_* / falcon_key in falcon.c wraps the native core
(falcon_native_* in wc_falcon.c) plus wc_falcon_{fpr,fft,poly,sampler,
codec,keygen,sign,bigint}.c. No liboqs dependency.
- Portable, constant-time integer-emulated floating-point (fpr) backend is
the default; opt-in per-architecture acceleration:
--enable-falcon-double inline native double
--enable-falcon-asm x86-64 SSE2 out-of-line fpr asm
--enable-falcon-avx2 x86-64 AVX2 (4-wide) FFT
- Division-free (Barrett) integer NTT on the verify path, so no hardware
divide is required on Cortex-M / embedded targets.
- Verify uses a cached twiddle-factor NTT; signing uses the FFT / ffLDL tree
and discrete Gaussian sampler over the abstract fpr seam.
- test.c falcon_test (KAT verify + native keygen/sign/verify roundtrip);
scripts/falcon-interop.c and a CI workflow cross-check native<->liboqs in
both directions.
wolfssl/wolfcrypt/aes.h: if HAVE_FIPS && !WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED, make wc_AesGcmEncrypt() a WOLFSSL_LOCAL, and if !_WC_BUILDING_AES_C, add a WC_DEPRECATED() attribute to it.
wolfssl/wolfcrypt/wc_compat.h, wolfssl/wolfcrypt/include.am, .wolfssl_known_macro_extras: add wc_compat.h: when HAVE_FIPS and !WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED, shim wc_AesGcmEncrypt() to remap it to FIPS-allowed APIs.
wolfssl/wolfcrypt/types.h: at the end, #ifndef BUILDING_WOLFSSL, #include <wolfssl/wolfcrypt/wc_compat.h>, to assure transparent shimming of wc_AesGcmEncrypt() for all outside callers.
wolfcrypt/src/evp.c, wolfcrypt/src/hpke.c, wolfcrypt/src/pkcs7.c, wolfcrypt/benchmark/benchmark.c, wolfcrypt/test/test.c, wolfssl/ssl.h: #include <wolfssl/wolfcrypt/wc_compat.h> to shim in-library/in-module calls to wc_AesGcmEncrypt().
src/internal.c: in TicketEncDec(), add const attributes to constable input args, and fix swapped out/in in calls to wc_AesGcmEncrypt().
tests/api/test_aes.c: in test_wc_AesGcmEncryptDecrypt(), skip longIV test if WC_TEST_AES_GCM_ENCRYPT_NO_NONSTD_IV (defined by wc_compat.h when needed).
wolfssl/wolfcrypt/error-crypt.h, wolfssl/error-ssl.h, wolfcrypt/src/error.c, src/internal.c:
* add FIPS_WRONG_API_E;
* put several error codes back into sequence in wc_GetErrorString() switch().
* move wc_static_assert()s from headers to corresponding .c files, to eliminate dependency on wolfcrypt/types.h;
* remove unneeded #include <wolfssl/wolfcrypt/types.h> from error-crypt.h.
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.
```
==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.