diff --git a/common.go b/common.go index b57015d..6dfc7f6 100644 --- a/common.go +++ b/common.go @@ -298,6 +298,9 @@ type ConnectionState struct { // ekm is a closure exposed via ExportKeyingMaterial. 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 diff --git a/conn.go b/conn.go index 561de72..17a4046 100644 --- a/conn.go +++ b/conn.go @@ -52,6 +52,7 @@ type Conn struct { handshakes int extMasterSecret bool didResume bool // whether this connection was a session resumption + didHRR bool // whether a HelloRetryRequest was sent/received cipherSuite uint16 ocspResponse []byte // stapled OCSP response scts [][]byte // signed certificate timestamps from server @@ -1669,6 +1670,7 @@ func (c *Conn) connectionStateLocked() ConnectionState { state.Version = c.vers state.NegotiatedProtocol = c.clientProtocol state.DidResume = c.didResume + state.testingOnlyDidHRR = c.didHRR state.NegotiatedProtocolIsMutual = true state.ServerName = c.serverName state.CipherSuite = c.cipherSuite diff --git a/handshake_client_tls13.go b/handshake_client_tls13.go index 484924d..7b09281 100644 --- a/handshake_client_tls13.go +++ b/handshake_client_tls13.go @@ -307,6 +307,7 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { return err } + c.didHRR = true return nil } diff --git a/handshake_server_tls13.go b/handshake_server_tls13.go index ab39d06..5ccf13b 100644 --- a/handshake_server_tls13.go +++ b/handshake_server_tls13.go @@ -19,6 +19,7 @@ import ( "hash" "io" "math/big" + "slices" "time" ) @@ -233,21 +234,25 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error { // groups with a key share, to avoid a HelloRetryRequest round-trip. var selectedGroup CurveID var clientKeyShare *keyShare -GroupSelection: - for _, preferredGroup := range c.config.curvePreferences() { - for _, ks := range hs.clientHello.keyShares { - if ks.group == preferredGroup { - selectedGroup = ks.group - clientKeyShare = &ks - break GroupSelection + preferredGroups := c.config.curvePreferences() + for _, preferredGroup := range preferredGroups { + ki := slices.IndexFunc(hs.clientHello.keyShares, func(ks keyShare) bool { + return ks.group == preferredGroup + }) + if ki != -1 { + 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 - } - for _, group := range hs.clientHello.supportedCurves { - if group == preferredGroup { - selectedGroup = group + } + if selectedGroup == 0 { + for _, preferredGroup := range preferredGroups { + if slices.Contains(hs.clientHello.supportedCurves, preferredGroup) { + selectedGroup = preferredGroup break } } @@ -584,6 +589,7 @@ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) return errors.New("tls: client illegally modified second ClientHello") } + c.didHRR = true hs.clientHello = clientHello return nil }