Enable all-zero shared secret check for Curve448/25519 by default. Ensure post_handshake_auth extension was sent before accepting post-handshake CertificateRequest message.
Follow up to PR #10450 with some minor fixes:
* FIPS 205 numbering: slh_sign is §10.2.1 Alg 22; slh_verify is Alg 24;
hash_slh_verify is Alg 25 (impl comments and doxygen).
* Widen wc_SlhDsaKey_SignHashWithRandom's addRnd to const byte* to
match wc_SlhDsaKey_SignWithRandom.
* Make the SLHDSA_PHMSG_MAX_LEN invariant explicit with a named
SLHDSA_LARGEST_APPROVED_PHM_LEN constant and a wc_static_assert.
* SHAKE128/SHAKE256 round-trip and length-rejection coverage for both
SignHash and VerifyHash.
* Doxygen: briefs for the five DER encode/decode APIs; accurate
decoder failure-rollback wording; tighter return-code lists for
Verify and VerifyMsg.
* ChangeLog: silent-failure caveat for raw messages whose length
happens to equal the digest size of the chosen hashType.
wc_SlhDsaKey_{Sign,Verify}Hash* previously accepted the raw message and
performed the pre-hash internally. They now require the caller to hash the
message first and pass the resulting digest -- the functions no longer call
wc_*Hash() themselves and feed the supplied digest directly into the M'
construction. Parameters are renamed from msg/msgSz to hash/hashSz to reflect
this, and hashSz is validated against wc_HashGetDigestSize(hashType) per
FIPS 205 Section 10.2.2 (32 for SHAKE128, 64 for SHAKE256), returning
BAD_LENGTH_E on mismatch.
This matches ML-DSA's wc_dilithium_{sign,verify}_ctx_hash, NIST ACVP
signatureInterface=external / preHash=preHash vectors, and other libraries
(OpenSSL HASH-ML-DSA, leancrypto, mldsa-native). It also enables distributed
signers and HSM-style flows where the digest is computed separately from the
signing operation.
Migration: callers must now hash the message before invoking these APIs;
passing the raw message will either fail length validation or produce
signatures over the wrong input. The M'-supplied wc_SlhDsaKey_SignMsg* /
VerifyMsg family (FIPS 205 internal interface, Algorithms 19/20) is
unchanged but gains stricter input validation and doxygen coverage.
Replace the liboqs-based pre-standardization SPHINCS+ implementation
with the native FIPS 205 SLH-DSA implementation across the
certificate / ASN.1 / X.509 layers, and add SLH-DSA-rooted test
certificates plus TLS 1.3 .conf scenarios that exercise the new
verification path. All liboqs SPHINCS+ code is removed.
This enables SLH-DSA for certificate chain authentication: CA
certificates signed with SLH-DSA, certificate signature verification
against an SLH-DSA root. TLS 1.3 entity authentication via
CertificateVerify with SLH-DSA will be added in a follow-up PR.
Follows RFC 9909 (X.509 Algorithm Identifiers for SLH-DSA) and
NIST FIPS 205. Supports both SHAKE and SHA-2 parameter families
across all twelve standardized variants.
DER codec:
- New PrivateKeyDecode, PublicKeyDecode, KeyToDer, PrivateKeyToDer,
PublicKeyToDer with RFC 9909 encoding (bare OCTET STRING containing
4*n raw bytes = SK.seed || SK.prf || PK.seed || PK.root, no nested
wrapper). OID auto-detection across all twelve SHAKE / SHA-2 variants.
- PublicKeyDecode raw-bytes fast path mirrors wc_Falcon_PublicKeyDecode
and wc_Dilithium_PublicKeyDecode so callers (notably
wolfssl_x509_make_der and ConfirmSignature, which pass the raw
BIT STRING contents stashed by StoreKey) decode correctly. Honours
the caller's *inOutIdx start offset.
- Error paths in Private/PublicKeyDecode preserve params/flags/
inOutIdx and only ForceZero the buffer half each helper actually
writes; skip the wipe entirely on BAD_LENGTH_E (no bytes touched).
- ImportPublic uses |= on flags so a Private-then-Public import
sequence retains FLAG_PRIVATE.
OID dispatch:
- 12 standardized NIST OIDs (6 SHAKE + 6 SHA-2) per RFC 9909. The
pre-standardization OID-collision mechanism is removed since NIST
OIDs do not collide.
- wc_SlhDsaOidToParam / wc_SlhDsaOidToCertType return NOT_COMPILED_IN
(rather than -1) for recognised SLH-DSA OIDs whose parameter set
isn't built; wc_IsSlhDsaOid recognises both. The x509 dispatch
surfaces this as a precise diagnostic instead of the generic
"No public key found".
- wc_GetKeyOID picks a placeholder parameter from whatever variant is
compiled in and #errors at compile time if none is.
- asn_orig.c EncodeCert / EncodeCertReq accept SHA-2 SLH-DSA keyTypes
alongside SHAKE.
Tests and fixtures:
- Test cert chain in certs/slhdsa/: SLH-DSA-SHAKE-128s and
SLH-DSA-SHA2-128s self-signed roots that sign reused ML-DSA-44
entity keys (server + client), plus the gen script
(gen-slhdsa-mldsa-certs.sh, OpenSSL >= 3.5).
- New TLS 1.3 .conf scenarios under tests/suites.c dispatch:
test-tls13-slhdsa-shake.conf, test-tls13-slhdsa-sha2.conf, and a
wrong-CA negative test test-tls13-slhdsa-fail.conf.
- DER round-trip and on-disk decode tests; bench_slhdsa_*_key.der
fixtures regenerated with wolfSSL's own encoder so the codec is
pinned to RFC 9909.
- New unit test test_wc_slhdsa_x509_i2d_roundtrip exercises the raw
PublicKeyDecode entry point that wolfssl_x509_make_der relies on.
- test_wc_slhdsa_check_key now tests both Public-then-Private and
Private-then-Public import orderings.
Build / ABI:
- DYNAMIC_TYPE_SPHINCS = 98 kept as RESERVED with a tombstone comment
for ABI stability; new code should use DYNAMIC_TYPE_SLHDSA (107).
- All build system / IDE project files updated; SPHINCS+ sources,
headers, and test data removed.
- Dead bench_slhdsa_*_key arrays removed from gencertbuf.pl and
certs_test.h; the .der files on disk drive the decode tests.
RFC 8446 section 8 requires any server instance to accept 0-RTT for a
given ClientHello at most once. Prior to this change wolfSSL's behaviour
diverged from that requirement in several ways:
* ctx->maxEarlyDataSz defaulted to MAX_EARLY_DATA_SZ whenever the
library was built with WOLFSSL_EARLY_DATA, so servers auto-
advertised 0-RTT in NewSessionTicket without the application
asking. RFC 8446 E.5 says 0-RTT MUST NOT be enabled unless
specifically requested.
* The post-accept eviction is compiled out under NO_SESSION_CACHE,
so builds without the cache accepted 0-RTT with no replay defence.
* Stateless self-encrypted tickets do not carry a session ID on the
stateless DoClientTicket decrypt path, so wolfSSL_SSL_CTX_remove_
session could not locate them to evict.
* wolfSSL_SSL_CTX_remove_session always returned 0 on success
regardless of whether the session was actually in the cache,
diverging from OpenSSL's SSL_CTX_remove_session (1 on success,
0 on not-found).
Changes:
* src/internal.c: ctx->maxEarlyDataSz defaults to 0; applications
must opt in with wolfSSL_CTX_set_max_early_data.
* src/tls13.c: #error when WOLFSSL_EARLY_DATA is built with
HAVE_SESSION_TICKET and NO_SESSION_CACHE. Escape hatch
WOLFSSL_EARLY_DATA_NO_ANTI_REPLAY for deployments that take
application-layer responsibility.
* wolfssl/internal.h: imply WOLFSSL_TICKET_HAVE_ID from
WOLFSSL_EARLY_DATA so stateless-ticket issuance populates the
cache under an ID that eviction can find.
* src/ssl_sess.c: wolfSSL_SSL_CTX_remove_session returns 1 when the
session was found (internal-cache hit, or ctx->rem_sess_cb fired
for an external cache), 0 otherwise. Matches OpenSSL semantics.
* src/tls13.c: the 0-RTT acceptance condition in CheckPreSharedKeys
now calls wolfSSL_SSL_CTX_remove_session and checks its return:
the eviction is the check. If the session was in the cache, 0-RTT
is accepted and the single-use requirement is satisfied. If not,
the early_data extension is rejected through the normal path so
the record layer correctly skips in-flight 0-RTT records.
WOLFSSL_MSG at each rejection site.
* doc/dox_comments/header_files/ssl.h: document runtime opt-in.
* tests: four new tests —
test_tls13_0rtt_default_off (fails without default-to-0 fix),
test_tls13_0rtt_stateless_replay (fails without TICKET_HAVE_ID
implication and remove_session gate),
test_tls13_remove_session_return (fails without return-value fix),
test_tls13_0rtt_ext_cache_eviction (fails without ext-cache
counts-as-found fix).
test_tls13_early_data explicitly opts in via
wolfSSL_CTX_set_max_early_data.
tests/api.c: two SSL_CTX_remove_session == 0 assertions updated
to == 1.
Add SRAM PUF (Physically Unclonable Function) support to wolfCrypt. Derives device-unique cryptographic keys from the power-on state of SRAM memory using a BCH(127,64,t=10) fuzzy extractor with HKDF key derivation.
- **wolfCrypt PUF API** (`wolfcrypt/src/puf.c`, `wolfssl/wolfcrypt/puf.h`)
- `wc_PufInit`, `wc_PufReadSram`, `wc_PufEnroll`, `wc_PufReconstruct`
- `wc_PufDeriveKey` (HKDF-SHA256), `wc_PufGetIdentity` (SHA-256 device fingerprint)
- `wc_PufZeroize` (secure context cleanup)
- `wc_PufSetTestData` (synthetic SRAM for testing without hardware)
- **BCH(127,64,t=10) error-correcting codec** - corrects up to 10 bit flips per 127-bit codeword across 16 codewords
- **`WC_PUF_SHA3` build option** - select SHA3-256 instead of SHA-256 for identity hash and HKDF (default: SHA-256)
- **Precomputed GF(2^7) tables** - `const` arrays in `.rodata` (no runtime init, thread-safe, flash-resident on embedded)
- `./configure --enable-puf` (auto-enables HKDF dependency)
- CMake: `WOLFSSL_PUF=yes`
- `WOLFSSL_USER_SETTINGS`: define `WOLFSSL_PUF` and `WOLFSSL_PUF_SRAM`
- See wolfssl-examples/puf for example implementation on STM32 NUCLEO-H563ZI (Cortex-M33, STM32H563ZI)
- Supports test mode (synthetic SRAM)
- Builds to ~13KB `.elf`
- Tested on NUCLEO-H563ZI: enrollment, noisy reconstruction, key derivation all pass
- `.github/workflows/puf.yml`: host build + test workflow for PUF feature
- Doxygen API docs for all 8 public functions
- PUF group added to `doxygen_groups.h`
Implement RFC8773bis (draft-ietf-tls-8773bis-13)
cert_with_extern_psk for TLS 1.3, including protocol checks
and API support.
Includes unit tests for API and handshake behavior as well
as tests in the testsuite using extended examples.
.github/workflows/wolfCrypt-Wconversion.yml: Add -Wcast-qual to all scenarios.
wolfssl/wolfcrypt/signature.h, wolfcrypt/src/signature.c, doc/dox_comments/header_files/signature.h:
Remove incorrect const qualifier on the key argument in
* wc_SignatureVerifyHash()
* wc_SignatureVerify()
* wc_SignatureGenerateHash()
* wc_SignatureGenerateHash_ex()
* wc_SignatureGenerate()
* wc_SignatureGenerate_ex()
This fixes UB code patterns throughout signature.c. key is inherently
accessed readwrite by the underlying low level crypto. Fortunately, wolfCrypt
has no APIs/methods to allow actual const MPI key objects, therefore these
seeming breaking API changes can't actually break any users.
globally:
* Add const qualifiers to all struct pointer members that are assigned values
computed from const pointers.
* Add const qualifiers to intermediate casts for accessors and read-only
dereference constructs, as needed for -Wcast-qual hygiene, e.g. for a macro
GET_U16(a), use (*(const word16*)(a)) rather than (*(word16*)(a)).
* Add const qualifiers to internal declarations, and remove illegal casts, as
needed for -Wcast-qual hygiene.
* Add missing const qualifiers to all casts for argument, operand, and
assignment type agreement, as needed for -Wcast-qual hygiene, e.g.
"*data = (const byte*)dataASN->data.ref.data" rather than
"*data = (byte*)dataASN->data.ref.data".
wolfssl/wolfcrypt/asn.h, wolfssl/wolfcrypt/asn_public.h, wolfcrypt/src/asn.c, wolfcrypt/src/asn_orig.c:
* Add additional lifecycle management for object members that are only sometimes locally allocated:
DNS_entry.nameStored
DNS_entry.ipStringStored
DNS_entry.ridStringStored
wolfssl/wolfcrypt/types.h: add WC_BARRIER() macro -- a portable construct that
prevents compiler optimizers from reordering operations across the barrier.
wolfssl/wolfcrypt/blake2-impl.h, wolfcrypt/src/blake2s.c, wolfcrypt/src/blake2b.c:
* In blake2b_init(), blake2b_init_key(), blake2s_init(), and
blake2s_init_key(), refactor blake2b_param initialization using WC_BARRIER()
(fixes volatile abuse that triggered -Wcast-qual).
* Remove the residual and unused WOLFSSL_BLAKE2[BS]_INIT_EACH_FIELD code.
wolfcrypt/src/ecc.c and wolfssl/wolfcrypt/ecc.h:
Remove incorrect const qualifier on curve arg to wc_ecc_free_curve() (internal function).
Add full RSA-PSS (RSASSA-PSS) support to PKCS#7 SignedData
encoding and verification.
This change enables SignerInfo.signatureAlgorithm to use
id-RSASSA-PSS with explicit RSASSA-PSS-params (hash, MGF1,
salt length), as required by RFC 4055 and CMS profiles.
Key changes:
- Add RSA-PSS encode and verify paths for PKCS7 SignedData
- Encode full RSASSA-PSS AlgorithmIdentifier parameters
- Decode RSA-PSS parameters from SignerInfo for verification
- Treat RSA-PSS like ECDSA (sign raw digest, not DigestInfo)
- Fix certificate signatureAlgorithm parameter length handling
- Add API test coverage for RSA-PSS SignedData
This resolves failures when using RSA-PSS signer certificates
(e.g. -173 invalid signature algorithm) and maintains backward
compatibility with RSA PKCS#1 v1.5 and ECDSA.
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
Add CryptoCB-based AES key import support to enable Secure Element
offload without exposing raw AES key material to wolfCrypt.
When WOLF_CRYPTO_CB_AES_SETKEY is defined, wolfCrypt invokes a CryptoCB
callback during AES key setup. Behavior is determined by the callback
return value:
- If callback returns 0: Key is imported to the device (aes->devCtx).
Key is NOT copied to wolfCrypt RAM; GCM H/M tables are NOT generated.
Full hardware offload is assumed.
- If callback returns CRYPTOCB_UNAVAILABLE: Device does not support
SetKey. Normal software path is used; key is copied to devKey for
optional encrypt/decrypt acceleration.
- Any other error: Propagated to the caller.
Key points:
- Add wc_CryptoCb_AesSetKey() callback for AES key import
- Update AES SetKey paths to call CryptoCB and branch on return value
- Skip GCM H/M table generation when callback succeeded (devCtx set)
- Preserve existing behavior when devId is INVALID_DEVID or
WOLF_CRYPTO_CB_AES_SETKEY is not defined
Testing:
- Add unit test for CryptoCB AES SetKey (verifies key isolation when
callback succeeds)
- Add end-to-end AES-GCM offload test (SetKey, Encrypt, Decrypt, Free
via CryptoCB)
- Tests use a mock SE with software AES to validate routing
Enable with: CPPFLAGS="-DWOLF_CRYPTO_CB_AES_SETKEY -DWOLF_CRYPTO_CB_FREE"
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>