Skip to content

Fenrir 2026-06-02: TLS/DTLS correctness, resumption & renegotiation safety fixes#10582

Open
julek-wolfssl wants to merge 10 commits into
wolfSSL:masterfrom
julek-wolfssl:fenrir-20260602
Open

Fenrir 2026-06-02: TLS/DTLS correctness, resumption & renegotiation safety fixes#10582
julek-wolfssl wants to merge 10 commits into
wolfSSL:masterfrom
julek-wolfssl:fenrir-20260602

Conversation

@julek-wolfssl
Copy link
Copy Markdown
Member

@julek-wolfssl julek-wolfssl commented Jun 3, 2026

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

  • F-3888 — Add negative tests for tampered RSA signatures/hashes in test_wolfSSL_RSA_verify and test_wolfSSL_RSA_padding_add_PKCS1_PSS (PKCS#1 v1.5 and PSS), guarding the XMEMCMP signature-acceptance check.
  • F-4867DoTls13EncryptedExtensions now rejects trailing bytes after the extensions block (length equality, RFC 8446 §4.3.1).
  • F-4868DoTls13CertificateRequest now rejects trailing bytes after the extensions block (RFC 8446 §4.3.2).
  • F-5633 — Zeroize DTLS 1.3 ChaCha record-number protection keys before freeing (FreeCiphers, plus the wc_Chacha_SetKey failure path).
  • F-5807 — Client enforces extended_master_secret consistency on resumption; abort on mismatch (RFC 7627 §5.3).
  • F-5810 — Server requires renegotiation_info on a renegotiation ClientHello and aborts if absent; also rejects an SCSV received during renegotiation (RFC 5746 §3.5/§3.7).
  • F-5811 — Client verifies the resumed cipher suite matches the cached session and aborts on mismatch (RFC 5246 §7.4.1.3).
  • F-5813BuildMessage refuses to emit a TLS 1.2 record once the write sequence number reaches its maximum, instead of silently wrapping (new SEQUENCE_NUMBER_E, RFC 5246 §6.1).
  • F-5818 — Invalidate the cached session on a fatal alert (receipt and transmission) so it cannot be resumed (RFC 5246 §7.2.2).
  • F-4144 — Honor WOLFSSL_OP_NO_RENEGOTIATION: refuse peer-initiated renegotiation with a no_renegotiation warning 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 check on a secure-renegotiation config (exercising the new SCR tests) — pass, 0 failures.

Copilot AI review requested due to automatic review settings June 3, 2026 10:56
@julek-wolfssl julek-wolfssl self-assigned this Jun 3, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread src/internal.c
@julek-wolfssl julek-wolfssl marked this pull request as ready for review June 3, 2026 13:22
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

retest this please

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

MemBrowse Memory Report

gcc-arm-cortex-m3

  • FLASH: .text +108 B (+0.1%, 120,681 B / 262,144 B, total: 46% used)

gcc-arm-cortex-m4

  • FLASH: .rodata.wolfSSL_ERR_reason_error_string.str1.1 +34 B, .text +128 B (+0.1%, 198,096 B / 262,144 B, total: 76% used)

gcc-arm-cortex-m4-dtls13

  • FLASH: .text +64 B (+0.0%, 178,648 B / 1,048,576 B, total: 17% used)

gcc-arm-cortex-m4-openssl-compat

  • FLASH: .rodata +40 B, .text +384 B (+0.1%, 765,116 B / 1,048,576 B, total: 73% used)

gcc-arm-cortex-m4-pq

  • FLASH: .rodata +32 B, .text +128 B (+0.1%, 276,280 B / 1,048,576 B, total: 26% used)

gcc-arm-cortex-m4-rsa-only

  • FLASH: .rodata +32 B, .text +384 B (+0.1%, 322,008 B / 1,048,576 B, total: 31% used)

gcc-arm-cortex-m4-tls12

  • FLASH: .text +128 B (+0.1%, 121,421 B / 262,144 B, total: 46% used)

gcc-arm-cortex-m4-tls13

  • FLASH: .rodata.wolfSSL_ERR_reason_error_string.str1.1 +34 B, .text +64 B (+0.0%, 233,538 B / 262,144 B, total: 89% used)

gcc-arm-cortex-m7

  • FLASH: .rodata.wolfSSL_ERR_reason_error_string.str1.1 +34 B, .text +128 B (+0.1%, 198,096 B / 262,144 B, total: 76% used)

gcc-arm-cortex-m7-pq

  • FLASH: .rodata +32 B, .text +128 B (+0.1%, 276,856 B / 1,048,576 B, total: 26% used)

gcc-arm-cortex-m7-tls13

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.
@julek-wolfssl
Copy link
Copy Markdown
Member Author

julek-wolfssl commented Jun 4, 2026

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).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants