Fenrir 2026-06-02: TLS/DTLS correctness, resumption & renegotiation safety fixes#10582
Open
julek-wolfssl wants to merge 10 commits into
Open
Fenrir 2026-06-02: TLS/DTLS correctness, resumption & renegotiation safety fixes#10582julek-wolfssl wants to merge 10 commits into
julek-wolfssl wants to merge 10 commits into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR addresses multiple Fenrir-tracked TLS/DTLS correctness and safety findings across parsing strictness, renegotiation handling, resumption validation, record-sequence hygiene, session cache invalidation on fatal alerts, key zeroization, and adds regression tests to prevent reintroduction.
Changes:
- Tighten TLS 1.3 message parsing to reject trailing bytes after extension blocks (EncryptedExtensions, CertificateRequest).
- Harden TLS 1.2 renegotiation and resumption behavior (NO_RENEGOTIATION option behavior, SCR renegotiation_info enforcement, EMS + cipher-suite consistency on resumption, refuse sequence-number wrap).
- Add/extend regression tests (memio renegotiation refusal tests; RSA verify/PSS negative tamper tests) and improve DTLS 1.3 key hygiene (zeroization before free).
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| wolfssl/internal.h | Extends secure renegotiation state with a new per-handshake renegInfoSeen flag and repacks SCR flags into bitfields. |
| wolfssl/error-ssl.h | Introduces SEQUENCE_NUMBER_E for TLS record sequence-number wrap prevention. |
| tests/api/test_tls_ext.h | Exposes new memio regression test prototypes for NO_RENEGOTIATION behavior. |
| tests/api/test_tls_ext.c | Adds client/server memio tests ensuring NO_RENEGOTIATION refuses renegotiation via warning alert while keeping the connection usable. |
| tests/api/test_ossl_rsa.c | Adds negative tamper tests for RSA v1.5 verify and RSA-PSS verification paths. |
| tests/api.c | Registers the new TLS extension regression tests in the main test list. |
| src/tls13.c | Enforces strict length equality for TLS 1.3 EncryptedExtensions and rejects trailing bytes in CertificateRequest. |
| src/tls.c | Tracks presence of renegotiation_info when parsing SCR extension in ClientHello. |
| src/internal.c | Implements NO_RENEGOTIATION warning behavior, SCR renegotiation checks, session invalidation on fatal alerts, TLS 1.2 record sequence wrap refusal, DTLS 1.3 ChaCha key zeroization, and resumption EMS/suite consistency checks. |
| src/dtls13.c | Zeroizes DTLS 1.3 record-number ChaCha context on wc_Chacha_SetKey failure before freeing. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
9c5a037 to
a31b83b
Compare
|
retest this please |
|
a31b83b to
e1b916c
Compare
Extend test_wolfSSL_RSA_verify and test_wolfSSL_RSA_padding_add_PKCS1_PSS with negative cases that flip a byte in the signature/encoding and in the hash, asserting verification fails. This guards the XMEMCMP-based signature acceptance decision in wolfSSL_RSA_verify_mgf against regressions that would let any decryption result of matching length pass as valid.
DoTls13EncryptedExtensions only bounds-checked the extensions length against the message size, silently ignoring any trailing bytes. RFC 8446 Section 4.3.1 defines the message as solely the extensions block, so enforce length equality and return BUFFER_ERROR (decode_error) on a mismatch.
DoTls13CertificateRequest advanced past the certificate_request_context and extensions blocks but never verified the whole message body was consumed, silently ignoring trailing bytes. RFC 8446 Section 4.3.2 fixes the wire format; enforce that the consumed length equals the message size and return BUFFER_ERROR (decode_error) otherwise.
FreeCiphers released the DTLS 1.3 record-number protection ChaCha contexts with XFREE only, leaving key material in freed heap memory. ForceZero both contexts before freeing, matching the regular TLS ChaCha path in FreeCiphersSide, and also zeroize a partially-set key in Dtls13InitChaChaCipher when wc_Chacha_SetKey fails.
CompleteServerHello's resumption branch derived keys from the cached master secret without checking the resumed session's extended_master_secret state against the abbreviated ServerHello, letting a MITM strip EMS on resumption. Per RFC 7627 Section 5.3, abort with a fatal handshake_failure when the cached session's EMS flag does not match the ServerHello EMS state.
On session-ID resumption the client only checked that the server's selected suite was in its offered list, not that it equaled the resumed session's suite, so a server could resume the session ID under a different cipher suite. Per RFC 5246 Section 7.4.1.2 / F.1.4 a resumed session reuses its negotiated suite; abort with a fatal illegal_parameter on mismatch.
GetSEQIncrement silently rolled the 64-bit write sequence counter from 2^64-1 back to 0, reusing sequence number 0 with the same keys. Per RFC 5246 Section 6.1 sequence numbers MUST NOT wrap. BuildMessage now refuses to emit a TLS 1.2 record once the write sequence number has reached its maximum, returning the new SEQUENCE_NUMBER_E error so the caller renegotiates or closes instead.
DoAlert marked a connection closed on a received fatal alert but left the established session in the resumption cache, and the send path did the same, so a session whose connection ended in a fatal alert remained resumable. Per RFC 5246 Section 7.2.2 the session identifier MUST be invalidated; evict the established session from the cache on both receipt and transmission of a fatal alert via the new InvalidateSessionOnFatalAlert helper.
e1b916c to
94d1bb7
Compare
Member
Author
|
Retest this please. |
The documented 'reject peer-initiated renegotiation' option was accepted and stored but never consulted. Now DoHelloRequest replies with a no_renegotiation warning instead of starting SCR when the bit is set (client side), and the server refuses a renegotiation ClientHello with a no_renegotiation warning instead of resetting handshake state.
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).
94d1bb7 to
fa6ab55
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Addresses ten Fenrir-tracked findings (TLS/DTLS correctness, session-resumption safety, renegotiation safety, and key hygiene). Each fix is its own commit, tagged with its
F-<NUMBER>.Fixes
test_wolfSSL_RSA_verifyandtest_wolfSSL_RSA_padding_add_PKCS1_PSS(PKCS#1 v1.5 and PSS), guarding theXMEMCMPsignature-acceptance check.DoTls13EncryptedExtensionsnow rejects trailing bytes after the extensions block (length equality, RFC 8446 §4.3.1).DoTls13CertificateRequestnow rejects trailing bytes after the extensions block (RFC 8446 §4.3.2).FreeCiphers, plus thewc_Chacha_SetKeyfailure path).renegotiation_infoon a renegotiation ClientHello and aborts if absent; also rejects an SCSV received during renegotiation (RFC 5746 §3.5/§3.7).BuildMessagerefuses to emit a TLS 1.2 record once the write sequence number reaches its maximum, instead of silently wrapping (newSEQUENCE_NUMBER_E, RFC 5246 §6.1).WOLFSSL_OP_NO_RENEGOTIATION: refuse peer-initiated renegotiation with ano_renegotiationwarning while keeping the connection established, on both the client (HelloRequest) and server (renegotiation ClientHello) paths.Tests
New memio regression tests in
tests/api/test_tls_ext.c:test_scr_no_renegotiation_option— server refuses renegotiation, stays established, and still passes application data.test_helloRequest_no_renegotiation_option— client refuses a server HelloRequest, stays established, and still passes application data.Both directions of post-refusal application data exchange are asserted.
Verification
./commit-tests.sh(current /--disable-fastmath/ full configs) — all pass, 0 failures../configure --enable-all && make check— pass, 0 failures.make checkon a secure-renegotiation config (exercising the new SCR tests) — pass, 0 failures.