Make every --enable-tinytls13 spelling build and pass locally, and grow the
CI matrix to cover them. These are fixes found while testing the configs the
CI workflow had not actually exercised.
- internal.h, internal.c, ssl_load.c: include ML-DSA and Falcon in the
pkCurveOID member and producer guards so the PSK plus ML-DSA build compiles.
- tls13.c: gate the DoTls13CertificateVerify definition on NO_CERTS to match
its call site.
- settings.h: let the AES-256 adder survive the floor, default the
user_settings path to the SHA-256 floor, make WOLFSSL_NO_MALLOC opt-in so
the test suite still runs, and keep ML-DSA ASN.1 for the cert profile.
- configure.ac: drive ENABLED_ASM and emit WOLFSSL_NO_ASM for the small C
floor, restrict SP math to P-256, strip ML-DSA ASN.1 only on the PSK floor,
and print a notice for the reduced security cert verify.
- examples: guard the cert loading paths for NO_CERTS and treat NO_CERTS as
PSK mode in echoserver and echoclient.
- Add examples/configs/tinytls13_smoke.c, an in memory TLS 1.3 handshake test
that drives PSK, ECDSA, ML-DSA-65 and RSA-PSS chain verify, plus forced
cipher suites, for builds with no example or unit test harness.
- certs: add ECDSA leaves signed by the ML-DSA-65 and RSA-PSS CAs so the cert
profiles drive a real PQC and PSS chain verify in CI.
- .github/workflows/tinytls13.yml: cover every profile and adder, run the
smoke handshake on the build verified configs, and least privilege the
workflow token.
ParseCipherList() only cleared the InitSuites mask for "!aNULL"/"!eNULL",
which governs generated defaults, so an explicitly listed ADH or NULL-cipher
suite survived (e.g. "ADH-AES128-SHA:!aNULL" still offered an unauthenticated
suite). Scrub the explicit suites after parsing; exclusions are order-
independent and sticky (a later "ALL" cannot re-enable them).
Add test_wolfSSL_set_cipher_list_exclusions.
Only exempt the missing-certificate check during the initial handshake; once a
post-handshake CertificateRequest is outstanding the server again requires the
client certificate (and its CertificateVerify). Adds a post-handshake auth
test.
Ensure a peer's certificate form (X.509 vs raw public key) matches the
negotiated certificate type, defaulting to X.509 when none was negotiated,
on both the client and server. Adds RPK regression tests covering both
directions.
Require the keyCertSign key usage on non-root intermediate CAs added during
path building when a KeyUsage extension is present, per RFC 5280. Adds a
regression test.
Robustness fixes in the OpenSSL-compatibility certificate verifier, independent
of the depth-exhaustion fix:
- Fail closed on allocation failure. When the failedCerts working stack could
not be allocated, the function fell through to exit with ret still set to
WOLFSSL_SUCCESS and reported the chain as verified without checking anything
(a fail-open regression from the leak fix that turned the early return into a
goto exit). Also check the ctx->chain allocation. Both now set an error.
- Remove caller-supplied intermediates from the correct stack. The intermediates
appended to the working cert list during chain building were popped from
ctx->store->certs by count, but they are appended to whichever stack is in use
- which may be the caller's setTrustedSk (X509_STORE_CTX_set0_trusted_stack).
Remove them by pointer identity from that same stack, recomputed from
ctxIntermediates. Identity removal also survives the chain-building retries
that reorder the stack, where a positional pop could drop a legitimate trusted
entry and leave an injected intermediate behind - which a later verification
reusing the store/ctx would then snapshot as a trust anchor. The removal helper
walks the list once (O(n)) rather than indexing per position.
- NULL-guard ctx->store->param before dereferencing its flags in the
partial-chain check.
Add regression tests covering: the trusted stack being restored after
verification, and the retry path (tampered plus genuine same-subject
intermediates, both orderings) leaving the store clean for later use.
Fail compatibility-layer verification when the path-building loop runs
out of its depth budget before reaching a configured trust anchor,
instead of accepting the last verified link. Add a regression test.
Ensure caller-supplied intermediate certificates cannot terminate the
chain during compatibility-layer verification; a path must reach a
configured trust anchor. Add a regression test and supporting certs.
The sequence number 2^64-1 is itself RFC 5246 6.1-legal; only the wrap to 0
is forbidden. GetSEQIncrement reads the current counter then post-increments
it, so the check refuses the final legal sequence number to avoid the
wrapping post-increment. Document that this last value is deliberately
sacrificed rather than implying 2^64-1 is itself unusable.
DoAlert evicted the cached session from the fatal-alert handling that runs
before the plaintext-under-encryption validation, so a forged TLS 1.3
plaintext alert injected on an established connection evicted the session
(forcing a full handshake on reconnect) even though the alert is then
rejected as PARSE_ERROR. The unexpected_message teardown sent in response
also evicted through the SendAlert hook.
Move the receive-side eviction past the validation, into the branch that
processes a genuine alert, and have InvalidateSessionOnFatalAlert refuse to
evict for a TLS 1.3 plaintext alert received while encryption is on (the
current record was not decrypted) - covering both the receive path and the
unexpected_message teardown sent in response. RFC 8446 6.2 does not require
TLS 1.3 invalidation, so this loses nothing; TLS 1.2 (RFC 5246 7.2.2) is
unaffected.
The client's resumed-session EMS (F-5807) and cipher-suite (F-5811) checks
were enforced in CompleteServerHello at ServerHello-parse time. For stateless
ticket resumption the client sends an empty session ID and cannot yet tell
whether the server accepted the ticket (RFC 5077 3.4): a server that declines
the ticket falls back to a full handshake under a freshly negotiated
suite/EMS state, which these checks wrongly aborted with MATCH_SUITE_ERROR,
breaking the RFC 5077 ticket-decline fallback to a full handshake.
Move both checks into CheckResumptionConsistency and run it only once
resumption is confirmed - from whichever the server sends first in the
abbreviated flight: a renewed NewSessionTicket (before SetupSession refreshes
the cached suite/EMS to the current values) or its ChangeCipherSpec. By then
the "Not resuming as thought" path has cleared 'resuming' for any ticket
decline, so the full-handshake fallback proceeds.
Add test_tls12_resume_ticket_decline_fallback (ticket declined by a fresh
server CTX, full handshake under a different suite must succeed) and gate
test_tls12_resume_ticket_wrong_suite on WOLFSSL_NO_DEF_TICKET_ENC_CB so it
skips rather than fails in builds without the default ticket encryption
callback.
crl.c, internal.h: leak of sigParams requiring reorder the struct fields to that it is above memcpy part.
dtl13.c: free the DRLS fragments buffer in Dtls13FreeFsmResources in case fragment is never sent.
ocsp.c: only free cid if locally allocated.
tls.c: make sure ecc_kse is zeroized and can be freed.
tls13.c: set hsHashesEch after init so isn't lost on failure.
evp_pk.c: free key on the BIO error path
Fixed various tests to not leak or crash on memory allocation failure.
Address review on PR #10582:
- The client-side extended_master_secret consistency check skipped all
session-ticket resumptions, leaving a generic ticket resumption open to
an undetected EMS downgrade by a malicious server or MITM. The client
retains the EMS state for ticket sessions too (SetupSession), so the
check now applies to ticket resumption as well, mirroring the adjacent
cipher-suite check. Only EAP-FAST style resumption - where the
session-secret callback supplies the master secret for an opaque PAC
ticket - is exempt, matched precisely via ssl->sessionSecretCb just as
the callback invocation in DoServerHello does.
- Add test_tls_ems_resumption_server_downgrade, exercising the
client-direction downgrade (server resumes but omits EMS from its
ServerHello) for both session-ID and session-ticket resumption. This
client-side branch previously had no test coverage.
MAX_ENCODED_SIG_SZ grows to ~50KB once SLH-DSA is enabled, yet it was
used to size PKCS#1/signature scratch and output buffers across the
library, wasting stack and heap even for classic RSA/ECC operations.
- Add MAX_ENCODED_CLASSIC_SIG_SZ for RSA/DSA/ECC DigestInfo buffers that
can never hold a PQC signature.
- Size the certificate/CSR signing output buffer from the signing key at
runtime instead of the worst-case macro.
- Add overridable WOLFSSL_MAX_SIG_SZ for the WOLFSSL_NO_MALLOC buffer.
- Reject a signature type that does not match the signing key.
Extend wc_MakeCert_ex/wc_SignCert_ex/wc_MakeCertReq_ex to issue HSS/LMS and
XMSS/XMSS^MT certificates and PKCS#10 requests, building on the existing
RFC 9802 verification support. New LMS_TYPE/XMSS_TYPE/XMSSMT_TYPE selectors,
wc_{Lms,Xmss}Key_PublicKeyToDer SPKI encoders, runtime signature-buffer
sizing, and sigType/key consistency checks. Generation is ASN.1-template
only, matching where the verification path lives.
Tests generate self-signed roots, CSRs and a CA->ECC-leaf chain in-process
and verify them, replacing the patched Bouncy Castle fixtures (only the stock
RFC 9802-aligned LMS interop anchor is kept).
RFC 9147 Section 8's 2^48-1 epoch ceiling is a sender-only rule; the same
paragraph says receiving implementations MUST NOT enforce it. The KeyUpdate
receive path was rejecting a peer epoch that crossed 2^48-1, violating that.
Guard only the genuine wrap-to-zero (Section 4.2.1) and let the receiving
epoch advance past 2^48-1. The sender-side gates are unchanged.
The TLS 1.2 client only compared the ServerHello suite against the
cached session suite for session-ID resumption; ticket resumption was
skipped on the assumption the suite is bound in the ticket. But the
ticket is opaque to the client, so it must enforce the match itself -
otherwise a server could resume a ticket under a different (weaker)
suite the client offered and the downgrade would go undetected
(RFC 5246 7.4.1.3).
The check is skipped only when the client retained no suite for the
session (cipherSuite0/cipherSuite both zero), so there is nothing to
compare against - as for EAP-FAST, whose PAC is a TLS ticket whose keys
come from the session-secret callback and which never populates the
cached suite. (0,0) is TLS_NULL_WITH_NULL_NULL, never negotiated, so it
unambiguously means "no retained suite". The EMS check remains
ticket-gated.
Add memio regression tests: a ticket resumption under a different
(retained) suite is rejected with MATCH_SUITE_ERROR, and a resumption
whose cached suite was not retained still succeeds.
Add count < 0 validation to wolfSSL_CTX_set_groups and wolfSSL_set_groups
(src/tls.c) to prevent negative count from bypassing the upper-bound check
and corrupting numGroups via byte truncation.
Widen count == 0 to count <= 0 and add NULL groups check in
wolfSSL_CTX_set1_groups and wolfSSL_set1_groups (src/ssl.c).
Add NULL buf and NULL cipher checks in wolfSSL_get_shared_ciphers to
prevent NULL pointer dereference.
In the WOLFSSL_OP_NO_RENEGOTIATION refusal path, WOLFSSL_LEAVE logged a
hard-coded 0 while the function actually returned SendAlert()'s result.
Capture the return value first so the trace reflects reality (e.g. when
SendAlert fails due to write backpressure) and return it.
The cipher property helpers (SSL_CIPHER_get_kx_nid / get_auth_nid /
get_cipher_nid / get_digest_nid / is_aead) parse the cipher name looked
up via cipher->offset in GetCipherSegment(). That offset is only
populated when the cipher is obtained through wolfSSL_get_ciphers_compat()
(SSL_get_ciphers()). When the cipher comes from SSL_get_current_cipher(),
offset is left at 0, so these helpers parsed cipher_names[0] (a TLS 1.3
suite) instead of the negotiated cipher - e.g. returning NID_kx_any for a
plain PSK suite while SSL_CIPHER_get_name() (which uses the suite bytes)
reported the correct name.
Resolve the cipher_names entry from the always-populated suite bytes in
GetCipherSegment(), falling back to cipher->offset when no match is found.
Also add the missing plain "PSK" -> NID_kx_psk entry to the kx lookup
table so PSK suites report NID_kx_psk instead of NID_undef.
Add a regression test that drives the SSL_get_current_cipher() path for
TLS_PSK_WITH_AES_128_GCM_SHA256 and checks all five property helpers.
The TLS 1.2 server derived the single advertised ClientCertificateType
and the signature_algorithms list in its CertificateRequest from the
negotiated cipher suite's own signature algorithm. On an ECDHE-ECDSA
suite only ecdsa_sign was offered (and only ECDSA sig algs), so RSA
clients could not authenticate even though the server could happily
verify an RSA certificate. The same was true in reverse for an RSA
server: the CertificateRequest only advertised rsa_sign.
Refactor SendCertificateRequest to advertise certificate_types and
signature_algorithms covering both sig families when both are compiled
in. Three static helpers in internal.c keep the logic in one place
without mutating ssl->suites:
GetServerCertReqCertTypes - certificate_types to emit
GetServerCertReqHashSigAlgo - signature_algorithms to emit
InServerCertReqHashSigAlgo - membership check used for verification
The advertised lists are written to stack buffers in the caller. To
keep DoCertificateVerify in agreement with what we actually sent, the
SupportedHashSigAlgo call site there is replaced with
InServerCertReqHashSigAlgo, which rebuilds the same list locally and
looks up the client's chosen algo.
Replace the magic certTypes buffer size with a new
MAX_CERT_REQ_CERT_TYPE_CNT constant declared next to
ClientCertificateType.
Add two end-to-end mutual-auth tests covering both directions:
test_tls12_ecdhe_ecdsa_rsa_client_cert - ECDSA server, RSA client
test_tls12_ecdhe_rsa_ecdsa_client_cert - RSA server, ECDSA client
Update test_certreq_sighash_algos to permit RSA / RSA-PSS sig algs in
the ECDHE-ECDSA CertificateRequest; the previous assertion locked in
the ECDSA-only behaviour that this change corrects.
TLS 1.3 is unaffected: RFC 8446 removed certificate_types from
CertificateRequest, and TLS 1.3 cipher suites do not bind a signature
algorithm, so the server's hashSigAlgo already covers both sig
families when either has been compiled in.
The server validated client_verify_data only inside
TLSX_SecureRenegotiation_Parse, which never runs when the renegotiation_info
extension is absent, so a renegotiation ClientHello that omitted it was never
checked. Track a per-handshake renegInfoSeen flag and, after parsing the
renegotiation ClientHello extensions, abort with handshake_failure if the
extension was absent (RFC 5746 3.7). Also reject an SCSV received during
renegotiation (RFC 5746 3.5).