fix(handshake): enforce HandshakeTimeoutSec read deadline (pre-auth slowloris)

HandshakeTimeoutSec was defined but referenced nowhere and no SetReadDeadline existed, so a peer could stall the pre-auth handshake indefinitely (goroutine/FD exhaustion). Initiator.Run and Responder.Run now set a read deadline of HandshakeTimeoutSec when conn is a net.Conn, cleared on return; bare io.ReadWriter callers remain responsible for their own timeout.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
This commit is contained in:
Antje Worring
2026-06-06 18:05:41 -07:00
co-authored by Hanzo Dev
parent 048b6c91f5
commit 9b69731086
2 changed files with 20 additions and 0 deletions
+10
View File
@@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"io"
"net"
"runtime"
"time"
@@ -61,6 +62,15 @@ func (i *Initiator) Run(conn io.ReadWriter) (*Session, error) {
return nil, errors.New("zap-pq: initiator requires Local with private key")
}
// Bound the whole handshake by HandshakeTimeoutSec so a peer that
// connects and then stalls (or dribbles bytes) cannot pin this goroutine
// and FD indefinitely. Applies only when conn is a net.Conn; callers
// passing a bare io.ReadWriter remain responsible for their own timeout.
if nc, ok := conn.(net.Conn); ok {
_ = nc.SetReadDeadline(time.Now().Add(HandshakeTimeoutSec * time.Second))
defer func() { _ = nc.SetReadDeadline(time.Time{}) }()
}
suite := i.Suite
if suite == 0 {
suite = SuiteX25519MLKEM
+10
View File
@@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"io"
"net"
"runtime"
"time"
@@ -62,6 +63,15 @@ func (rs *Responder) Run(conn io.ReadWriter) (*Session, error) {
return nil, errors.New("zap-pq: ReplayCache is required under StrictPQ/FIPS profile")
}
// Bound the whole handshake by HandshakeTimeoutSec so an unauthenticated
// peer that connects and then stalls cannot pin this goroutine and FD
// indefinitely (pre-auth slowloris). Applies only when conn is a net.Conn;
// bare io.ReadWriter callers own their own timeout.
if nc, ok := conn.(net.Conn); ok {
_ = nc.SetReadDeadline(time.Now().Add(HandshakeTimeoutSec * time.Second))
defer func() { _ = nc.SetReadDeadline(time.Time{}) }()
}
r := rs.Rand
if r == nil {
r = rand.Reader