golang/go · error
tls: received malformed key_share extension
Error message
tls: received malformed key_share extension
What it means
Thrown during HelloRetryRequest processing when the server's key_share extension includes a server_share with a non-zero group. In a HelloRetryRequest, the server should use the selected_group field to request a different key share from the client — including an actual server share is malformed.
Source
Thrown at src/crypto/tls/handshake_client_tls13.go:306
c.sendAlert(alertUnsupportedExtension)
return errors.New("tls: unexpected encrypted client hello extension in serverHello")
}
// The only HelloRetryRequest extensions we support are key_share and
// cookie, and clients must abort the handshake if the HRR would not result
// in any change in the ClientHello.
if hs.serverHello.selectedGroup == 0 && hs.serverHello.cookie == nil {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: server sent an unnecessary HelloRetryRequest message")
}
if hs.serverHello.cookie != nil {
hello.cookie = hs.serverHello.cookie
}
if hs.serverHello.serverShare.group != 0 {
c.sendAlert(alertDecodeError)
return errors.New("tls: received malformed key_share extension")
}
// If the server sent a key_share extension selecting a group, ensure it's
// a group we advertised but did not send a key share for, and send a key
// share for it this time.
if curveID := hs.serverHello.selectedGroup; curveID != 0 {
if !slices.Contains(hello.supportedCurves, curveID) {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: server selected unsupported group")
}
if slices.ContainsFunc(hs.hello.keyShares, func(ks keyShare) bool {
return ks.group == curveID
}) {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share")
}
ke, err := keyExchangeForCurveID(curveID)
if err != nil {View on GitHub (pinned to b6b368adc5)
Solutions
- Server should use the key_share selected_group field in HelloRetryRequest, not the server_share entry.
- Report as a server-side TLS 1.3 implementation bug.
- If the server cannot be fixed, restrict client to TLS 1.2.
- Verify with an alternative TLS client (e.g. openssl) to confirm it is a server issue.
Defensive patterns
Strategy: try-catch
Try / catch
conn, err := tls.Dial("tcp", addr, config)
if err != nil {
if strings.Contains(err.Error(), "malformed key_share extension") {
// Server bug in HRR key_share — fall back to TLS 1.2
config.MaxVersion = tls.VersionTLS12
conn, err = tls.Dial("tcp", addr, config)
}
} Prevention
- Capture HRR messages with Wireshark to verify key_share format.
- Report malformed HRR key_share bugs to server vendors.
- Test HRR by offering only key shares the server doesn't initially accept.
When it happens
Trigger: Triggered when hs.serverHello.serverShare.group != 0 during HRR processing. The client sends alertDecodeError. The server incorrectly included a key share (its own public key) in the HRR instead of just selecting a group.
Common situations: Server bug: including a server key share in the HelloRetryRequest extension instead of using the selected_group field. Non-compliant TLS 1.3 server implementation that confuses the HRR key_share format with the regular ServerHello format.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- tls: malformed encrypted client hello extension
- tls: server selected unsupported group
- tls: server changed cipher suite after a HelloRetryRequest
- tls: server sent an unnecessary HelloRetryRequest message
- tls: malformed key_share extension
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/35d69b40b3692f4d.
Report an issue: GitHub.