0
0
mirror of https://github.com/XTLS/REALITY.git synced 2025-08-22 14:38:35 +00:00

crypto/tls: clarify group selection logic

I initially thought the logic was broken, but writing the test I
realized it was actually very clever (derogative). It was relying on the
outer loop continuing after a supported match without a key share,
allowing a later key share to override it (but not a later supported
match because of the "if selectedGroup != 0 { continue }").

Replaced the clever loop with two hopefully more understandable loops,
and added a test (which was already passing).

We were however not checking that the selected group is in the supported
list if we found it in key shares first. (This was only a MAY.) Fixed.

Fixes #65686

Change-Id: I09ea44f90167ffa36809deb78255ed039a217b6d
Reviewed-on: https://go-review.googlesource.com/c/go/+/586655
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
This commit is contained in:
yuhan6665 2024-08-18 21:04:28 -04:00
parent 194e5a43dc
commit 8be2b3051b
4 changed files with 25 additions and 13 deletions

View File

@ -298,6 +298,9 @@ type ConnectionState struct {
// ekm is a closure exposed via ExportKeyingMaterial. // ekm is a closure exposed via ExportKeyingMaterial.
ekm func(label string, context []byte, length int) ([]byte, error) ekm func(label string, context []byte, length int) ([]byte, error)
// testingOnlyDidHRR is true if a HelloRetryRequest was sent/received.
testingOnlyDidHRR bool
} }
// ExportKeyingMaterial returns length bytes of exported key material in a new // ExportKeyingMaterial returns length bytes of exported key material in a new

View File

@ -52,6 +52,7 @@ type Conn struct {
handshakes int handshakes int
extMasterSecret bool extMasterSecret bool
didResume bool // whether this connection was a session resumption didResume bool // whether this connection was a session resumption
didHRR bool // whether a HelloRetryRequest was sent/received
cipherSuite uint16 cipherSuite uint16
ocspResponse []byte // stapled OCSP response ocspResponse []byte // stapled OCSP response
scts [][]byte // signed certificate timestamps from server scts [][]byte // signed certificate timestamps from server
@ -1669,6 +1670,7 @@ func (c *Conn) connectionStateLocked() ConnectionState {
state.Version = c.vers state.Version = c.vers
state.NegotiatedProtocol = c.clientProtocol state.NegotiatedProtocol = c.clientProtocol
state.DidResume = c.didResume state.DidResume = c.didResume
state.testingOnlyDidHRR = c.didHRR
state.NegotiatedProtocolIsMutual = true state.NegotiatedProtocolIsMutual = true
state.ServerName = c.serverName state.ServerName = c.serverName
state.CipherSuite = c.cipherSuite state.CipherSuite = c.cipherSuite

View File

@ -307,6 +307,7 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
return err return err
} }
c.didHRR = true
return nil return nil
} }

View File

@ -19,6 +19,7 @@ import (
"hash" "hash"
"io" "io"
"math/big" "math/big"
"slices"
"time" "time"
) )
@ -233,21 +234,25 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error {
// groups with a key share, to avoid a HelloRetryRequest round-trip. // groups with a key share, to avoid a HelloRetryRequest round-trip.
var selectedGroup CurveID var selectedGroup CurveID
var clientKeyShare *keyShare var clientKeyShare *keyShare
GroupSelection: preferredGroups := c.config.curvePreferences()
for _, preferredGroup := range c.config.curvePreferences() { for _, preferredGroup := range preferredGroups {
for _, ks := range hs.clientHello.keyShares { ki := slices.IndexFunc(hs.clientHello.keyShares, func(ks keyShare) bool {
if ks.group == preferredGroup { return ks.group == preferredGroup
selectedGroup = ks.group })
clientKeyShare = &ks if ki != -1 {
break GroupSelection clientKeyShare = &hs.clientHello.keyShares[ki]
selectedGroup = clientKeyShare.group
if !slices.Contains(hs.clientHello.supportedCurves, selectedGroup) {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: client sent key share for group it does not support")
} }
break
} }
if selectedGroup != 0 { }
continue if selectedGroup == 0 {
} for _, preferredGroup := range preferredGroups {
for _, group := range hs.clientHello.supportedCurves { if slices.Contains(hs.clientHello.supportedCurves, preferredGroup) {
if group == preferredGroup { selectedGroup = preferredGroup
selectedGroup = group
break break
} }
} }
@ -584,6 +589,7 @@ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID)
return errors.New("tls: client illegally modified second ClientHello") return errors.New("tls: client illegally modified second ClientHello")
} }
c.didHRR = true
hs.clientHello = clientHello hs.clientHello = clientHello
return nil return nil
} }