1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
19 // serverHandshakeState contains details of a server handshake in progress.
20 // It's discarded once the handshake has completed.
21 type serverHandshakeState
struct {
23 clientHello
*clientHelloMsg
30 sessionState
*sessionState
31 finishedHash finishedHash
33 certsFromClient
[][]byte
35 cachedClientHelloInfo
*ClientHelloInfo
38 // serverHandshake performs a TLS handshake as a server.
39 // c.out.Mutex <= L; c.handshakeMutex <= L.
40 func (c
*Conn
) serverHandshake() error
{
41 // If this is the first server handshake, we generate a random key to
42 // encrypt the tickets with.
43 c
.config
.serverInitOnce
.Do(func() { c
.config
.serverInit(nil) })
45 hs
:= serverHandshakeState
{
48 isResume
, err
:= hs
.readClientHello()
53 // For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3
56 // The client has included a session ticket and so we do an abbreviated handshake.
57 if err
:= hs
.doResumeHandshake(); err
!= nil {
60 if err
:= hs
.establishKeys(); err
!= nil {
63 // ticketSupported is set in a resumption handshake if the
64 // ticket from the client was encrypted with an old session
65 // ticket key and thus a refreshed ticket should be sent.
66 if hs
.hello
.ticketSupported
{
67 if err
:= hs
.sendSessionTicket(); err
!= nil {
71 if err
:= hs
.sendFinished(c
.serverFinished
[:]); err
!= nil {
74 if _
, err
:= c
.flush(); err
!= nil {
77 c
.clientFinishedIsFirst
= false
78 if err
:= hs
.readFinished(nil); err
!= nil {
83 // The client didn't include a session ticket, or it wasn't
84 // valid so we do a full handshake.
85 if err
:= hs
.doFullHandshake(); err
!= nil {
88 if err
:= hs
.establishKeys(); err
!= nil {
91 if err
:= hs
.readFinished(c
.clientFinished
[:]); err
!= nil {
94 c
.clientFinishedIsFirst
= true
96 if err
:= hs
.sendSessionTicket(); err
!= nil {
99 if err
:= hs
.sendFinished(nil); err
!= nil {
102 if _
, err
:= c
.flush(); err
!= nil {
106 c
.handshakeComplete
= true
111 // readClientHello reads a ClientHello message from the client and decides
112 // whether we will perform session resumption.
113 func (hs
*serverHandshakeState
) readClientHello() (isResume
bool, err error
) {
116 msg
, err
:= c
.readHandshake()
121 hs
.clientHello
, ok
= msg
.(*clientHelloMsg
)
123 c
.sendAlert(alertUnexpectedMessage
)
124 return false, unexpectedMessageError(hs
.clientHello
, msg
)
127 if c
.config
.GetConfigForClient
!= nil {
128 if newConfig
, err
:= c
.config
.GetConfigForClient(hs
.clientHelloInfo()); err
!= nil {
129 c
.sendAlert(alertInternalError
)
131 } else if newConfig
!= nil {
132 newConfig
.serverInitOnce
.Do(func() { newConfig
.serverInit(c
.config
) })
137 c
.vers
, ok
= c
.config
.mutualVersion(hs
.clientHello
.vers
)
139 c
.sendAlert(alertProtocolVersion
)
140 return false, fmt
.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs
.clientHello
.vers
)
144 hs
.hello
= new(serverHelloMsg
)
146 supportedCurve
:= false
147 preferredCurves
:= c
.config
.curvePreferences()
149 for _
, curve
:= range hs
.clientHello
.supportedCurves
{
150 for _
, supported
:= range preferredCurves
{
151 if supported
== curve
{
152 supportedCurve
= true
158 supportedPointFormat
:= false
159 for _
, pointFormat
:= range hs
.clientHello
.supportedPoints
{
160 if pointFormat
== pointFormatUncompressed
{
161 supportedPointFormat
= true
165 hs
.ellipticOk
= supportedCurve
&& supportedPointFormat
167 foundCompression
:= false
168 // We only support null compression, so check that the client offered it.
169 for _
, compression
:= range hs
.clientHello
.compressionMethods
{
170 if compression
== compressionNone
{
171 foundCompression
= true
176 if !foundCompression
{
177 c
.sendAlert(alertHandshakeFailure
)
178 return false, errors
.New("tls: client does not support uncompressed connections")
181 hs
.hello
.vers
= c
.vers
182 hs
.hello
.random
= make([]byte, 32)
183 _
, err
= io
.ReadFull(c
.config
.rand(), hs
.hello
.random
)
185 c
.sendAlert(alertInternalError
)
189 if len(hs
.clientHello
.secureRenegotiation
) != 0 {
190 c
.sendAlert(alertHandshakeFailure
)
191 return false, errors
.New("tls: initial handshake had non-empty renegotiation extension")
194 hs
.hello
.secureRenegotiationSupported
= hs
.clientHello
.secureRenegotiationSupported
195 hs
.hello
.compressionMethod
= compressionNone
196 if len(hs
.clientHello
.serverName
) > 0 {
197 c
.serverName
= hs
.clientHello
.serverName
200 if len(hs
.clientHello
.alpnProtocols
) > 0 {
201 if selectedProto
, fallback
:= mutualProtocol(hs
.clientHello
.alpnProtocols
, c
.config
.NextProtos
); !fallback
{
202 hs
.hello
.alpnProtocol
= selectedProto
203 c
.clientProtocol
= selectedProto
206 // Although sending an empty NPN extension is reasonable, Firefox has
207 // had a bug around this. Best to send nothing at all if
208 // c.config.NextProtos is empty. See
209 // https://golang.org/issue/5445.
210 if hs
.clientHello
.nextProtoNeg
&& len(c
.config
.NextProtos
) > 0 {
211 hs
.hello
.nextProtoNeg
= true
212 hs
.hello
.nextProtos
= c
.config
.NextProtos
216 hs
.cert
, err
= c
.config
.getCertificate(hs
.clientHelloInfo())
218 c
.sendAlert(alertInternalError
)
221 if hs
.clientHello
.scts
{
222 hs
.hello
.scts
= hs
.cert
.SignedCertificateTimestamps
225 if priv
, ok
:= hs
.cert
.PrivateKey
.(crypto
.Signer
); ok
{
226 switch priv
.Public().(type) {
227 case *ecdsa
.PublicKey
:
232 c
.sendAlert(alertInternalError
)
233 return false, fmt
.Errorf("tls: unsupported signing key type (%T)", priv
.Public())
236 if priv
, ok
:= hs
.cert
.PrivateKey
.(crypto
.Decrypter
); ok
{
237 switch priv
.Public().(type) {
239 hs
.rsaDecryptOk
= true
241 c
.sendAlert(alertInternalError
)
242 return false, fmt
.Errorf("tls: unsupported decryption key type (%T)", priv
.Public())
246 if hs
.checkForResumption() {
250 var preferenceList
, supportedList
[]uint16
251 if c
.config
.PreferServerCipherSuites
{
252 preferenceList
= c
.config
.cipherSuites()
253 supportedList
= hs
.clientHello
.cipherSuites
255 preferenceList
= hs
.clientHello
.cipherSuites
256 supportedList
= c
.config
.cipherSuites()
259 for _
, id
:= range preferenceList
{
260 if hs
.setCipherSuite(id
, supportedList
, c
.vers
) {
266 c
.sendAlert(alertHandshakeFailure
)
267 return false, errors
.New("tls: no cipher suite supported by both client and server")
270 // See https://tools.ietf.org/html/rfc7507.
271 for _
, id
:= range hs
.clientHello
.cipherSuites
{
272 if id
== TLS_FALLBACK_SCSV
{
273 // The client is doing a fallback connection.
274 if hs
.clientHello
.vers
< c
.config
.maxVersion() {
275 c
.sendAlert(alertInappropriateFallback
)
276 return false, errors
.New("tls: client using inappropriate protocol fallback")
285 // checkForResumption reports whether we should perform resumption on this connection.
286 func (hs
*serverHandshakeState
) checkForResumption() bool {
289 if c
.config
.SessionTicketsDisabled
{
294 var sessionTicket
= append([]uint8{}, hs
.clientHello
.sessionTicket
...)
295 if hs
.sessionState
, ok
= c
.decryptTicket(sessionTicket
); !ok
{
299 // Never resume a session for a different TLS version.
300 if c
.vers
!= hs
.sessionState
.vers
{
304 cipherSuiteOk
:= false
305 // Check that the client is still offering the ciphersuite in the session.
306 for _
, id
:= range hs
.clientHello
.cipherSuites
{
307 if id
== hs
.sessionState
.cipherSuite
{
316 // Check that we also support the ciphersuite from the session.
317 if !hs
.setCipherSuite(hs
.sessionState
.cipherSuite
, c
.config
.cipherSuites(), hs
.sessionState
.vers
) {
321 sessionHasClientCerts
:= len(hs
.sessionState
.certificates
) != 0
322 needClientCerts
:= c
.config
.ClientAuth
== RequireAnyClientCert || c
.config
.ClientAuth
== RequireAndVerifyClientCert
323 if needClientCerts
&& !sessionHasClientCerts
{
326 if sessionHasClientCerts
&& c
.config
.ClientAuth
== NoClientCert
{
333 func (hs
*serverHandshakeState
) doResumeHandshake() error
{
336 hs
.hello
.cipherSuite
= hs
.suite
.id
337 // We echo the client's session ID in the ServerHello to let it know
338 // that we're doing a resumption.
339 hs
.hello
.sessionId
= hs
.clientHello
.sessionId
340 hs
.hello
.ticketSupported
= hs
.sessionState
.usedOldKey
341 hs
.finishedHash
= newFinishedHash(c
.vers
, hs
.suite
)
342 hs
.finishedHash
.discardHandshakeBuffer()
343 hs
.finishedHash
.Write(hs
.clientHello
.marshal())
344 hs
.finishedHash
.Write(hs
.hello
.marshal())
345 if _
, err
:= c
.writeRecord(recordTypeHandshake
, hs
.hello
.marshal()); err
!= nil {
349 if len(hs
.sessionState
.certificates
) > 0 {
350 if _
, err
:= hs
.processCertsFromClient(hs
.sessionState
.certificates
); err
!= nil {
355 hs
.masterSecret
= hs
.sessionState
.masterSecret
360 func (hs
*serverHandshakeState
) doFullHandshake() error
{
363 if hs
.clientHello
.ocspStapling
&& len(hs
.cert
.OCSPStaple
) > 0 {
364 hs
.hello
.ocspStapling
= true
367 hs
.hello
.ticketSupported
= hs
.clientHello
.ticketSupported
&& !c
.config
.SessionTicketsDisabled
368 hs
.hello
.cipherSuite
= hs
.suite
.id
370 hs
.finishedHash
= newFinishedHash(hs
.c
.vers
, hs
.suite
)
371 if c
.config
.ClientAuth
== NoClientCert
{
372 // No need to keep a full record of the handshake if client
373 // certificates won't be used.
374 hs
.finishedHash
.discardHandshakeBuffer()
376 hs
.finishedHash
.Write(hs
.clientHello
.marshal())
377 hs
.finishedHash
.Write(hs
.hello
.marshal())
378 if _
, err
:= c
.writeRecord(recordTypeHandshake
, hs
.hello
.marshal()); err
!= nil {
382 certMsg
:= new(certificateMsg
)
383 certMsg
.certificates
= hs
.cert
.Certificate
384 hs
.finishedHash
.Write(certMsg
.marshal())
385 if _
, err
:= c
.writeRecord(recordTypeHandshake
, certMsg
.marshal()); err
!= nil {
389 if hs
.hello
.ocspStapling
{
390 certStatus
:= new(certificateStatusMsg
)
391 certStatus
.statusType
= statusTypeOCSP
392 certStatus
.response
= hs
.cert
.OCSPStaple
393 hs
.finishedHash
.Write(certStatus
.marshal())
394 if _
, err
:= c
.writeRecord(recordTypeHandshake
, certStatus
.marshal()); err
!= nil {
399 keyAgreement
:= hs
.suite
.ka(c
.vers
)
400 skx
, err
:= keyAgreement
.generateServerKeyExchange(c
.config
, hs
.cert
, hs
.clientHello
, hs
.hello
)
402 c
.sendAlert(alertHandshakeFailure
)
406 hs
.finishedHash
.Write(skx
.marshal())
407 if _
, err
:= c
.writeRecord(recordTypeHandshake
, skx
.marshal()); err
!= nil {
412 if c
.config
.ClientAuth
>= RequestClientCert
{
413 // Request a client certificate
414 certReq
:= new(certificateRequestMsg
)
415 certReq
.certificateTypes
= []byte{
416 byte(certTypeRSASign
),
417 byte(certTypeECDSASign
),
419 if c
.vers
>= VersionTLS12
{
420 certReq
.hasSignatureAndHash
= true
421 certReq
.signatureAndHashes
= supportedSignatureAlgorithms
424 // An empty list of certificateAuthorities signals to
425 // the client that it may send any certificate in response
426 // to our request. When we know the CAs we trust, then
427 // we can send them down, so that the client can choose
428 // an appropriate certificate to give to us.
429 if c
.config
.ClientCAs
!= nil {
430 certReq
.certificateAuthorities
= c
.config
.ClientCAs
.Subjects()
432 hs
.finishedHash
.Write(certReq
.marshal())
433 if _
, err
:= c
.writeRecord(recordTypeHandshake
, certReq
.marshal()); err
!= nil {
438 helloDone
:= new(serverHelloDoneMsg
)
439 hs
.finishedHash
.Write(helloDone
.marshal())
440 if _
, err
:= c
.writeRecord(recordTypeHandshake
, helloDone
.marshal()); err
!= nil {
444 if _
, err
:= c
.flush(); err
!= nil {
448 var pub crypto
.PublicKey
// public key for client auth, if any
450 msg
, err
:= c
.readHandshake()
456 // If we requested a client certificate, then the client must send a
457 // certificate message, even if it's empty.
458 if c
.config
.ClientAuth
>= RequestClientCert
{
459 if certMsg
, ok
= msg
.(*certificateMsg
); !ok
{
460 c
.sendAlert(alertUnexpectedMessage
)
461 return unexpectedMessageError(certMsg
, msg
)
463 hs
.finishedHash
.Write(certMsg
.marshal())
465 if len(certMsg
.certificates
) == 0 {
466 // The client didn't actually send a certificate
467 switch c
.config
.ClientAuth
{
468 case RequireAnyClientCert
, RequireAndVerifyClientCert
:
469 c
.sendAlert(alertBadCertificate
)
470 return errors
.New("tls: client didn't provide a certificate")
474 pub
, err
= hs
.processCertsFromClient(certMsg
.certificates
)
479 msg
, err
= c
.readHandshake()
485 // Get client key exchange
486 ckx
, ok
:= msg
.(*clientKeyExchangeMsg
)
488 c
.sendAlert(alertUnexpectedMessage
)
489 return unexpectedMessageError(ckx
, msg
)
491 hs
.finishedHash
.Write(ckx
.marshal())
493 preMasterSecret
, err
:= keyAgreement
.processClientKeyExchange(c
.config
, hs
.cert
, ckx
, c
.vers
)
495 c
.sendAlert(alertHandshakeFailure
)
498 hs
.masterSecret
= masterFromPreMasterSecret(c
.vers
, hs
.suite
, preMasterSecret
, hs
.clientHello
.random
, hs
.hello
.random
)
499 if err
:= c
.config
.writeKeyLog(hs
.clientHello
.random
, hs
.masterSecret
); err
!= nil {
500 c
.sendAlert(alertInternalError
)
504 // If we received a client cert in response to our certificate request message,
505 // the client will send us a certificateVerifyMsg immediately after the
506 // clientKeyExchangeMsg. This message is a digest of all preceding
507 // handshake-layer messages that is signed using the private key corresponding
508 // to the client's certificate. This allows us to verify that the client is in
509 // possession of the private key of the certificate.
510 if len(c
.peerCertificates
) > 0 {
511 msg
, err
= c
.readHandshake()
515 certVerify
, ok
:= msg
.(*certificateVerifyMsg
)
517 c
.sendAlert(alertUnexpectedMessage
)
518 return unexpectedMessageError(certVerify
, msg
)
521 // Determine the signature type.
522 var signatureAndHash signatureAndHash
523 if certVerify
.hasSignatureAndHash
{
524 signatureAndHash
= certVerify
.signatureAndHash
525 if !isSupportedSignatureAndHash(signatureAndHash
, supportedSignatureAlgorithms
) {
526 return errors
.New("tls: unsupported hash function for client certificate")
529 // Before TLS 1.2 the signature algorithm was implicit
530 // from the key type, and only one hash per signature
531 // algorithm was possible. Leave the hash as zero.
533 case *ecdsa
.PublicKey
:
534 signatureAndHash
.signature
= signatureECDSA
536 signatureAndHash
.signature
= signatureRSA
540 switch key
:= pub
.(type) {
541 case *ecdsa
.PublicKey
:
542 if signatureAndHash
.signature
!= signatureECDSA
{
543 err
= errors
.New("tls: bad signature type for client's ECDSA certificate")
546 ecdsaSig
:= new(ecdsaSignature
)
547 if _
, err
= asn1
.Unmarshal(certVerify
.signature
, ecdsaSig
); err
!= nil {
550 if ecdsaSig
.R
.Sign() <= 0 || ecdsaSig
.S
.Sign() <= 0 {
551 err
= errors
.New("tls: ECDSA signature contained zero or negative values")
555 if digest
, _
, err
= hs
.finishedHash
.hashForClientCertificate(signatureAndHash
, hs
.masterSecret
); err
!= nil {
558 if !ecdsa
.Verify(key
, digest
, ecdsaSig
.R
, ecdsaSig
.S
) {
559 err
= errors
.New("tls: ECDSA verification failure")
562 if signatureAndHash
.signature
!= signatureRSA
{
563 err
= errors
.New("tls: bad signature type for client's RSA certificate")
567 var hashFunc crypto
.Hash
568 if digest
, hashFunc
, err
= hs
.finishedHash
.hashForClientCertificate(signatureAndHash
, hs
.masterSecret
); err
!= nil {
571 err
= rsa
.VerifyPKCS1v15(key
, hashFunc
, digest
, certVerify
.signature
)
574 c
.sendAlert(alertBadCertificate
)
575 return errors
.New("tls: could not validate signature of connection nonces: " + err
.Error())
578 hs
.finishedHash
.Write(certVerify
.marshal())
581 hs
.finishedHash
.discardHandshakeBuffer()
586 func (hs
*serverHandshakeState
) establishKeys() error
{
589 clientMAC
, serverMAC
, clientKey
, serverKey
, clientIV
, serverIV
:=
590 keysFromMasterSecret(c
.vers
, hs
.suite
, hs
.masterSecret
, hs
.clientHello
.random
, hs
.hello
.random
, hs
.suite
.macLen
, hs
.suite
.keyLen
, hs
.suite
.ivLen
)
592 var clientCipher
, serverCipher
interface{}
593 var clientHash
, serverHash macFunction
595 if hs
.suite
.aead
== nil {
596 clientCipher
= hs
.suite
.cipher(clientKey
, clientIV
, true /* for reading */)
597 clientHash
= hs
.suite
.mac(c
.vers
, clientMAC
)
598 serverCipher
= hs
.suite
.cipher(serverKey
, serverIV
, false /* not for reading */)
599 serverHash
= hs
.suite
.mac(c
.vers
, serverMAC
)
601 clientCipher
= hs
.suite
.aead(clientKey
, clientIV
)
602 serverCipher
= hs
.suite
.aead(serverKey
, serverIV
)
605 c
.in
.prepareCipherSpec(c
.vers
, clientCipher
, clientHash
)
606 c
.out
.prepareCipherSpec(c
.vers
, serverCipher
, serverHash
)
611 func (hs
*serverHandshakeState
) readFinished(out
[]byte) error
{
614 c
.readRecord(recordTypeChangeCipherSpec
)
619 if hs
.hello
.nextProtoNeg
{
620 msg
, err
:= c
.readHandshake()
624 nextProto
, ok
:= msg
.(*nextProtoMsg
)
626 c
.sendAlert(alertUnexpectedMessage
)
627 return unexpectedMessageError(nextProto
, msg
)
629 hs
.finishedHash
.Write(nextProto
.marshal())
630 c
.clientProtocol
= nextProto
.proto
633 msg
, err
:= c
.readHandshake()
637 clientFinished
, ok
:= msg
.(*finishedMsg
)
639 c
.sendAlert(alertUnexpectedMessage
)
640 return unexpectedMessageError(clientFinished
, msg
)
643 verify
:= hs
.finishedHash
.clientSum(hs
.masterSecret
)
644 if len(verify
) != len(clientFinished
.verifyData
) ||
645 subtle
.ConstantTimeCompare(verify
, clientFinished
.verifyData
) != 1 {
646 c
.sendAlert(alertHandshakeFailure
)
647 return errors
.New("tls: client's Finished message is incorrect")
650 hs
.finishedHash
.Write(clientFinished
.marshal())
655 func (hs
*serverHandshakeState
) sendSessionTicket() error
{
656 if !hs
.hello
.ticketSupported
{
661 m
:= new(newSessionTicketMsg
)
664 state
:= sessionState
{
666 cipherSuite
: hs
.suite
.id
,
667 masterSecret
: hs
.masterSecret
,
668 certificates
: hs
.certsFromClient
,
670 m
.ticket
, err
= c
.encryptTicket(&state
)
675 hs
.finishedHash
.Write(m
.marshal())
676 if _
, err
:= c
.writeRecord(recordTypeHandshake
, m
.marshal()); err
!= nil {
683 func (hs
*serverHandshakeState
) sendFinished(out
[]byte) error
{
686 if _
, err
:= c
.writeRecord(recordTypeChangeCipherSpec
, []byte{1}); err
!= nil {
690 finished
:= new(finishedMsg
)
691 finished
.verifyData
= hs
.finishedHash
.serverSum(hs
.masterSecret
)
692 hs
.finishedHash
.Write(finished
.marshal())
693 if _
, err
:= c
.writeRecord(recordTypeHandshake
, finished
.marshal()); err
!= nil {
697 c
.cipherSuite
= hs
.suite
.id
698 copy(out
, finished
.verifyData
)
703 // processCertsFromClient takes a chain of client certificates either from a
704 // Certificates message or from a sessionState and verifies them. It returns
705 // the public key of the leaf certificate.
706 func (hs
*serverHandshakeState
) processCertsFromClient(certificates
[][]byte) (crypto
.PublicKey
, error
) {
709 hs
.certsFromClient
= certificates
710 certs
:= make([]*x509
.Certificate
, len(certificates
))
712 for i
, asn1Data
:= range certificates
{
713 if certs
[i
], err
= x509
.ParseCertificate(asn1Data
); err
!= nil {
714 c
.sendAlert(alertBadCertificate
)
715 return nil, errors
.New("tls: failed to parse client certificate: " + err
.Error())
719 if c
.config
.ClientAuth
>= VerifyClientCertIfGiven
&& len(certs
) > 0 {
720 opts
:= x509
.VerifyOptions
{
721 Roots
: c
.config
.ClientCAs
,
722 CurrentTime
: c
.config
.time(),
723 Intermediates
: x509
.NewCertPool(),
724 KeyUsages
: []x509
.ExtKeyUsage
{x509
.ExtKeyUsageClientAuth
},
727 for _
, cert
:= range certs
[1:] {
728 opts
.Intermediates
.AddCert(cert
)
731 chains
, err
:= certs
[0].Verify(opts
)
733 c
.sendAlert(alertBadCertificate
)
734 return nil, errors
.New("tls: failed to verify client's certificate: " + err
.Error())
737 c
.verifiedChains
= chains
740 if c
.config
.VerifyPeerCertificate
!= nil {
741 if err
:= c
.config
.VerifyPeerCertificate(certificates
, c
.verifiedChains
); err
!= nil {
742 c
.sendAlert(alertBadCertificate
)
751 var pub crypto
.PublicKey
752 switch key
:= certs
[0].PublicKey
.(type) {
753 case *ecdsa
.PublicKey
, *rsa
.PublicKey
:
756 c
.sendAlert(alertUnsupportedCertificate
)
757 return nil, fmt
.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs
[0].PublicKey
)
759 c
.peerCertificates
= certs
763 // setCipherSuite sets a cipherSuite with the given id as the serverHandshakeState
764 // suite if that cipher suite is acceptable to use.
765 // It returns a bool indicating if the suite was set.
766 func (hs
*serverHandshakeState
) setCipherSuite(id
uint16, supportedCipherSuites
[]uint16, version
uint16) bool {
767 for _
, supported
:= range supportedCipherSuites
{
769 var candidate
*cipherSuite
771 for _
, s
:= range cipherSuites
{
777 if candidate
== nil {
780 // Don't select a ciphersuite which we can't
781 // support for this client.
782 if candidate
.flags
&suiteECDHE
!= 0 {
786 if candidate
.flags
&suiteECDSA
!= 0 {
790 } else if !hs
.rsaSignOk
{
793 } else if !hs
.rsaDecryptOk
{
796 if version
< VersionTLS12
&& candidate
.flags
&suiteTLS12
!= 0 {
806 // suppVersArray is the backing array of ClientHelloInfo.SupportedVersions
807 var suppVersArray
= [...]uint16{VersionTLS12
, VersionTLS11
, VersionTLS10
, VersionSSL30
}
809 func (hs
*serverHandshakeState
) clientHelloInfo() *ClientHelloInfo
{
810 if hs
.cachedClientHelloInfo
!= nil {
811 return hs
.cachedClientHelloInfo
814 var supportedVersions
[]uint16
815 if hs
.clientHello
.vers
> VersionTLS12
{
816 supportedVersions
= suppVersArray
[:]
817 } else if hs
.clientHello
.vers
>= VersionSSL30
{
818 supportedVersions
= suppVersArray
[VersionTLS12
-hs
.clientHello
.vers
:]
821 signatureSchemes
:= make([]SignatureScheme
, 0, len(hs
.clientHello
.signatureAndHashes
))
822 for _
, sah
:= range hs
.clientHello
.signatureAndHashes
{
823 signatureSchemes
= append(signatureSchemes
, SignatureScheme(sah
.hash
)<<8+SignatureScheme(sah
.signature
))
826 hs
.cachedClientHelloInfo
= &ClientHelloInfo
{
827 CipherSuites
: hs
.clientHello
.cipherSuites
,
828 ServerName
: hs
.clientHello
.serverName
,
829 SupportedCurves
: hs
.clientHello
.supportedCurves
,
830 SupportedPoints
: hs
.clientHello
.supportedPoints
,
831 SignatureSchemes
: signatureSchemes
,
832 SupportedProtos
: hs
.clientHello
.alpnProtocols
,
833 SupportedVersions
: supportedVersions
,
837 return hs
.cachedClientHelloInfo