@@ -134,7 +134,7 @@ func (c *Conn) makeClientHello(minVersion uint16) (*clientHelloMsg, clientKeySha
134134 hello .supportedSignatureAlgorithms = testingOnlyForceClientHelloSignatureAlgorithms
135135 }
136136
137- var secret clientKeySharePrivate
137+ secret := make ( clientKeySharePrivate )
138138 if hello .supportedVersions [0 ] == VersionTLS13 {
139139 // Reset the list of ciphers when the client only supports TLS 1.3.
140140 if len (hello .supportedVersions ) == 1 {
@@ -146,30 +146,74 @@ func (c *Conn) makeClientHello(minVersion uint16) (*clientHelloMsg, clientKeySha
146146 hello .cipherSuites = append (hello .cipherSuites , defaultCipherSuitesTLS13NoAES ... )
147147 }
148148
149- curveID := config .curvePreferences ()[0 ]
150- if scheme := curveIdToCirclScheme (curveID ); scheme != nil {
151- pk , sk , err := generateKemKeyPair (scheme , curveID , config .rand ())
152- if err != nil {
153- return nil , nil , fmt .Errorf ("generateKemKeyPair %s: %w" ,
154- scheme .Name (), err )
155- }
156- packedPk , err := pk .MarshalBinary ()
157- if err != nil {
158- return nil , nil , fmt .Errorf ("pack circl public key %s: %w" ,
159- scheme .Name (), err )
149+ curveIDs := []CurveID {config .curvePreferences ()[0 ]}
150+
151+ if config .ClientCurveGuess != nil {
152+ curveIDs = config .ClientCurveGuess
153+ }
154+
155+ hello .keyShares = make ([]keyShare , 0 , len (curveIDs ))
156+
157+ // Check whether ClientCurveGuess is a subsequence of CurvePreferences
158+ // as is required by RFC8446 §4.2.8
159+ offset := 0
160+ curvePreferences := config .curvePreferences ()
161+ found := 0
162+ CurveGuessCheck:
163+ for _ , curveID := range curveIDs {
164+ for {
165+ if offset == len (curvePreferences ) {
166+ break CurveGuessCheck
167+ }
168+
169+ if curvePreferences [offset ] == curveID {
170+ found ++
171+ break
172+ }
173+
174+ offset ++
160175 }
161- hello .keyShares = []keyShare {{group : curveID , data : packedPk }}
162- secret = sk
163- } else {
164- if _ , ok := curveForCurveID (curveID ); ! ok {
165- return nil , nil , errors .New ("tls: CurvePreferences includes unsupported curve" )
176+ }
177+ if found != len (curveIDs ) {
178+ return nil , nil , errors .New ("tls: ClientCurveGuess not a subsequence of CurvePreferences" )
179+ }
180+
181+ for _ , curveID := range curveIDs {
182+ var (
183+ singleSecret interface {}
184+ singleShare []byte
185+ )
186+
187+ if _ , ok := secret [curveID ]; ok {
188+ return nil , nil , errors .New ("tls: ClientCurveGuess contains duplicate" )
166189 }
167- key , err := generateECDHEKey (config .rand (), curveID )
168- if err != nil {
169- return nil , nil , err
190+
191+ if scheme := curveIdToCirclScheme (curveID ); scheme != nil {
192+ pk , sk , err := generateKemKeyPair (scheme , curveID , config .rand ())
193+ if err != nil {
194+ return nil , nil , fmt .Errorf ("generateKemKeyPair %s: %w" ,
195+ scheme .Name (), err )
196+ }
197+ packedPk , err := pk .MarshalBinary ()
198+ if err != nil {
199+ return nil , nil , fmt .Errorf ("pack circl public key %s: %w" ,
200+ scheme .Name (), err )
201+ }
202+ singleShare = packedPk
203+ singleSecret = sk
204+ } else {
205+ if _ , ok := curveForCurveID (curveID ); ! ok {
206+ return nil , nil , errors .New ("tls: CurvePreferences includes unsupported curve" )
207+ }
208+ key , err := generateECDHEKey (config .rand (), curveID )
209+ if err != nil {
210+ return nil , nil , err
211+ }
212+ singleShare = key .PublicKey ().Bytes ()
213+ singleSecret = key
170214 }
171- hello .keyShares = [] keyShare {{ group : curveID , data : key . PublicKey (). Bytes ()}}
172- secret = key
215+ hello .keyShares = append ( hello . keyShares , keyShare {group : curveID , data : singleShare })
216+ secret [ curveID ] = singleSecret
173217 }
174218
175219 hello .delegatedCredentialSupported = config .SupportDelegatedCredential
0 commit comments