Closed Bug 2052288 Opened 2 months ago Closed 2 months ago

Stale ECH GREASE buffer corrupts HRR transcript

Categories

(NSS :: Libraries, defect, P2)

Tracking

(nss 3.126)

RESOLVED FIXED
Tracking Status
nss --- 3.126

People

(Reporter: jschanck, Assigned: jschanck)

Details

(Whiteboard: [nss-nofx])

Attachments

(1 file)

I encountered this while trying to write tests for mlkem1024 support in Firefox. Here's Claude's summary.

Affected component

lib/ssl/ — TLS 1.3 server, ECH HRR GREASE / stateless HRR cookie path.

Steps to reproduce

  1. Configure an NSS TLS 1.3 server that supports only a key-exchange group the client does not place first, so the server must send an HRR (e.g. a P-256-only or ML-KEM-1024-only server against a client that prefers X25519).
  2. Have the client offer an ECH extension — including default ECH GREASE, which is enabled by default in Firefox and other modern clients (SSL_EnableTls13GreaseEch).
  3. Complete the handshake on a single server socket (i.e. the normal stateless-cookie HRR recovery path; no fresh socket between CH1 and CH2).

Expected

Handshake completes: HRR requesting the server's group, client resends with the correct key share, connection established.

Actual

  • Debug builds: assertion failure
Assertion failure: !ss->ssl3.hs.greaseEchBuf.len, at tls13con.c:2761
#04: tls13_ConstructHelloRetryRequest (tls13con.c:2762)
  • Release builds: no crash and no memory unsafety, but the handshake fails (transcript-hash mismatch → bad Finished MAC / decrypt-error alert). The connection never completes.

Root cause

tls13_SendHelloRetryRequest (lib/ssl/tls13con.c) sets ss->ssl3.hs.greaseEchBuf to the 8-byte ECH HRR GREASE signal whenever ss->xtnData.ech is set, then constructs and sends the HRR. It never clears the buffer afterward.

The signal is preserved in the HRR cookie. On the second ClientHello, tls13_RecoverHashState (lib/ssl/tls13hashstate.c:303) calls tls13_ConstructHelloRetryRequest with the cookie's signal to rebuild the transcript:

if (cookieGreaseEchSignal) {
    PORT_Assert(!ss->ssl3.hs.greaseEchBuf.len);   /* tls13con.c:2761 */
    rv = sslBuffer_Append(&ss->ssl3.hs.greaseEchBuf,
                          cookieGreaseEchSignal, TLS13_ECH_SIGNAL_LEN);
    ...
}

Pushed by jschanck@mozilla.com:
https://hg.mozilla.org/projects/nss/rev/a9224ff7ae27
clear greaseEchBuf after constructing HRR. r=djackson

Status: ASSIGNED → RESOLVED
Closed: 2 months ago
Resolution: --- → FIXED
status-nss: --- → 3.126
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: