Re: [PATCH net-next v6 0/6] tls: perform TLS 1.3 KeyUpdate in the kernel

From: Sabrina Dubroca

Date: Fri Nov 06 2026 - 16:40:44 EST


Hi Martin,

I'm on a medical break so I won't be able to give this a proper review
for another week or two, but since it keeps landing in my inbox, I
want to make a comment.

Note: I haven't been following the discussions, and I can't give this
the attention it deserves for now (the cover letter is already a bit
much). So this is kind of a "can we slow down until we agree that we
really want that?"


2026-11-05, 11:30:36 -0500, Martin Belanger via B4 Relay wrote:
> kTLS does not currently handle TLS 1.3 KeyUpdate. It never sends a
> KeyUpdate.

Because it isn't meant to handle any part of the handshake at all,
just the record layer. The user gives us data, we stuff that into
records and send the records down the TCP socket. That's it.

So what you're proposing is a very fundamental change to how kTLS
works, I'm not convinced we want to go this way.

> And when it receives one, it blocks the socket until the
> application installs the next key. kTLS also does not enforce the key
> usage limit on transmit.
>
> This applies to TLS libraries in user space as well as kernel users such
> as NVMe/TCP or sunrpc:
>
> - GnuTLS sends a KeyUpdate after 2^24 records when it runs its own
> record layer. With kTLS, the record layer is handled in the kernel and
> GnuTLS therefore never runs the check. OpenSSL never sends a KeyUpdate
> on its own.

If userspace libraries don't do the right thing, we can fix the
libraries. They will anyway have to be fixed to behave correctly with
only the "old" uAPI, since they can't rely on this new stuff being
present in the running kernel. Or they'd have to completely disable
ktls if the kernel doesn't support this new uAPI, which would suck.

> - NVMe/TCP and sunrpc don't have a mechanism to install a new key. A

And that can't be handled with the existing handshake subsystem? (I'm
not that familiar with it, nor with QUIC or NVMe/TCP and sunrpc)

> conforming peer that sends a KeyUpdate ends or stalls their
> connection.
>
> RFC 9846 (July 2026), which obsoletes RFC 8446, makes the limit
> mandatory (section 5.5): "Implementations MUST either close the
> connection or do a key update as described in Section 4.7.3 prior to
> reaching these limits." Long-lived connections with small records reach
> the limit quickly. One NVMe/TCP queue sends at least one record per
> command, and more with large I/O. Depending on the load and link speed,
> the 2^24 limit can be reached in less than 10 minutes in many cases.

My math says that's 28k records/second, it's a lot.


> Why the record layer
> ====================
>
> KeyUpdate must be handled where the records are built.
>
> The 2^24 limit is a record count, and only the record layer can see the
> count precisely as it changes. A user sitting above kTLS can only read
> the count with getsockopt(TLS_TX) after each write. A kTLS user writes
> bytes, and the kernel splits and merges those bytes into records. I
> counted send calls in an NVMe/TCP prototype trying to guesstimate the
> 2^24 limit. The count was correct with 4 KB I/O, but was 21 times too
> low with 1 MB I/O. Each send call translates into a different number of
> records. It's simply not possible to precisely guess the number of
> records based on the number of send calls.
>
> The KeyUpdate must also go at a precise place in the record stream
> (section 4.7.3). It is encrypted with the old key, and every record
> after it with the new key. When the peer sets update_requested, our
> KeyUpdate must go out before the next Application Data record. The key
> can only change between two records. Only net/tls has control over that.
> Fixing this in one driver or library would leave other drivers or
> libraries to re-implement their own (imperfect) solution.

I'm not yet convinced this is a strong enough argument to justify
changing the model under which ktls operates with a change of this
size and that also requires 500L of new selftests.


> What the series does
> ====================
>
> - Two new socket options, TLS_TX_TRAFFIC_SECRET and
> TLS_RX_TRAFFIC_SECRET, are used to register the application traffic
> secrets. The secret is passed as raw bytes. The kernel derives the
> hash (SHA-256 or SHA-384) from the cipher installed with TLS_TX or
> TLS_RX. The TX secret must be set first because the RX secret needs
> the TX secret in case a received KeyUpdate asks for a reply.
> - A third socket option, TLS_TX_KEY_UPDATE, can be used to send a
> KeyUpdate now. It can also optionally ask the peer to update too.

Why does this need to be a socket option? It feels wrong to use a
socket option to trigger sending data, why not hook on sendmsg()?

--
Sabrina