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.
21 type clientHandshakeState
struct {
23 serverHello
*serverHelloMsg
26 finishedHash finishedHash
28 session
*ClientSessionState
31 func (c
*Conn
) clientHandshake() error
{
33 c
.config
= defaultConfig()
36 hello
:= &clientHelloMsg
{
37 vers
: c
.config
.maxVersion(),
38 compressionMethods
: []uint8{compressionNone
},
39 random
: make([]byte, 32),
41 serverName
: c
.config
.ServerName
,
42 supportedCurves
: []uint16{curveP256
, curveP384
, curveP521
},
43 supportedPoints
: []uint8{pointFormatUncompressed
},
44 nextProtoNeg
: len(c
.config
.NextProtos
) > 0,
45 secureRenegotiation
: true,
48 possibleCipherSuites
:= c
.config
.cipherSuites()
49 hello
.cipherSuites
= make([]uint16, 0, len(possibleCipherSuites
))
52 for _
, suiteId
:= range possibleCipherSuites
{
53 for _
, suite
:= range cipherSuites
{
54 if suite
.id
!= suiteId
{
57 // Don't advertise TLS 1.2-only cipher suites unless
58 // we're attempting TLS 1.2.
59 if hello
.vers
< VersionTLS12
&& suite
.flags
&suiteTLS12
!= 0 {
62 hello
.cipherSuites
= append(hello
.cipherSuites
, suiteId
)
63 continue NextCipherSuite
67 _
, err
:= io
.ReadFull(c
.config
.rand(), hello
.random
)
69 c
.sendAlert(alertInternalError
)
70 return errors
.New("tls: short read from Rand: " + err
.Error())
73 if hello
.vers
>= VersionTLS12
{
74 hello
.signatureAndHashes
= supportedSKXSignatureAlgorithms
77 var session
*ClientSessionState
79 sessionCache
:= c
.config
.ClientSessionCache
80 if c
.config
.SessionTicketsDisabled
{
84 if sessionCache
!= nil {
85 hello
.ticketSupported
= true
87 // Try to resume a previously negotiated TLS session, if
89 cacheKey
= clientSessionCacheKey(c
.conn
.RemoteAddr(), c
.config
)
90 candidateSession
, ok
:= sessionCache
.Get(cacheKey
)
92 // Check that the ciphersuite/version used for the
93 // previous session are still valid.
94 cipherSuiteOk
:= false
95 for _
, id
:= range hello
.cipherSuites
{
96 if id
== candidateSession
.cipherSuite
{
102 versOk
:= candidateSession
.vers
>= c
.config
.minVersion() &&
103 candidateSession
.vers
<= c
.config
.maxVersion()
104 if versOk
&& cipherSuiteOk
{
105 session
= candidateSession
111 hello
.sessionTicket
= session
.sessionTicket
112 // A random session ID is used to detect when the
113 // server accepted the ticket and is resuming a session
115 hello
.sessionId
= make([]byte, 16)
116 if _
, err
:= io
.ReadFull(c
.config
.rand(), hello
.sessionId
); err
!= nil {
117 c
.sendAlert(alertInternalError
)
118 return errors
.New("tls: short read from Rand: " + err
.Error())
122 c
.writeRecord(recordTypeHandshake
, hello
.marshal())
124 msg
, err
:= c
.readHandshake()
128 serverHello
, ok
:= msg
.(*serverHelloMsg
)
130 c
.sendAlert(alertUnexpectedMessage
)
131 return unexpectedMessageError(serverHello
, msg
)
134 vers
, ok
:= c
.config
.mutualVersion(serverHello
.vers
)
135 if !ok || vers
< VersionTLS10
{
136 // TLS 1.0 is the minimum version supported as a client.
137 c
.sendAlert(alertProtocolVersion
)
138 return fmt
.Errorf("tls: server selected unsupported protocol version %x", serverHello
.vers
)
143 suite
:= mutualCipherSuite(c
.config
.cipherSuites(), serverHello
.cipherSuite
)
145 c
.sendAlert(alertHandshakeFailure
)
146 return fmt
.Errorf("tls: server selected an unsupported cipher suite")
149 hs
:= &clientHandshakeState
{
151 serverHello
: serverHello
,
154 finishedHash
: newFinishedHash(c
.vers
),
158 hs
.finishedHash
.Write(hs
.hello
.marshal())
159 hs
.finishedHash
.Write(hs
.serverHello
.marshal())
161 isResume
, err
:= hs
.processServerHello()
167 if err
:= hs
.establishKeys(); err
!= nil {
170 if err
:= hs
.readSessionTicket(); err
!= nil {
173 if err
:= hs
.readFinished(); err
!= nil {
176 if err
:= hs
.sendFinished(); err
!= nil {
180 if err
:= hs
.doFullHandshake(); err
!= nil {
183 if err
:= hs
.establishKeys(); err
!= nil {
186 if err
:= hs
.sendFinished(); err
!= nil {
189 if err
:= hs
.readSessionTicket(); err
!= nil {
192 if err
:= hs
.readFinished(); err
!= nil {
197 if sessionCache
!= nil && hs
.session
!= nil && session
!= hs
.session
{
198 sessionCache
.Put(cacheKey
, hs
.session
)
201 c
.didResume
= isResume
202 c
.handshakeComplete
= true
203 c
.cipherSuite
= suite
.id
207 func (hs
*clientHandshakeState
) doFullHandshake() error
{
210 msg
, err
:= c
.readHandshake()
214 certMsg
, ok
:= msg
.(*certificateMsg
)
215 if !ok ||
len(certMsg
.certificates
) == 0 {
216 c
.sendAlert(alertUnexpectedMessage
)
217 return unexpectedMessageError(certMsg
, msg
)
219 hs
.finishedHash
.Write(certMsg
.marshal())
221 certs
:= make([]*x509
.Certificate
, len(certMsg
.certificates
))
222 for i
, asn1Data
:= range certMsg
.certificates
{
223 cert
, err
:= x509
.ParseCertificate(asn1Data
)
225 c
.sendAlert(alertBadCertificate
)
226 return errors
.New("tls: failed to parse certificate from server: " + err
.Error())
231 if !c
.config
.InsecureSkipVerify
{
232 opts
:= x509
.VerifyOptions
{
233 Roots
: c
.config
.RootCAs
,
234 CurrentTime
: c
.config
.time(),
235 DNSName
: c
.config
.ServerName
,
236 Intermediates
: x509
.NewCertPool(),
239 for i
, cert
:= range certs
{
243 opts
.Intermediates
.AddCert(cert
)
245 c
.verifiedChains
, err
= certs
[0].Verify(opts
)
247 c
.sendAlert(alertBadCertificate
)
252 switch certs
[0].PublicKey
.(type) {
253 case *rsa
.PublicKey
, *ecdsa
.PublicKey
:
256 c
.sendAlert(alertUnsupportedCertificate
)
257 return fmt
.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs
[0].PublicKey
)
260 c
.peerCertificates
= certs
262 if hs
.serverHello
.ocspStapling
{
263 msg
, err
= c
.readHandshake()
267 cs
, ok
:= msg
.(*certificateStatusMsg
)
269 c
.sendAlert(alertUnexpectedMessage
)
270 return unexpectedMessageError(cs
, msg
)
272 hs
.finishedHash
.Write(cs
.marshal())
274 if cs
.statusType
== statusTypeOCSP
{
275 c
.ocspResponse
= cs
.response
279 msg
, err
= c
.readHandshake()
284 keyAgreement
:= hs
.suite
.ka(c
.vers
)
286 skx
, ok
:= msg
.(*serverKeyExchangeMsg
)
288 hs
.finishedHash
.Write(skx
.marshal())
289 err
= keyAgreement
.processServerKeyExchange(c
.config
, hs
.hello
, hs
.serverHello
, certs
[0], skx
)
291 c
.sendAlert(alertUnexpectedMessage
)
295 msg
, err
= c
.readHandshake()
301 var chainToSend
*Certificate
302 var certRequested
bool
303 certReq
, ok
:= msg
.(*certificateRequestMsg
)
307 // RFC 4346 on the certificateAuthorities field:
308 // A list of the distinguished names of acceptable certificate
309 // authorities. These distinguished names may specify a desired
310 // distinguished name for a root CA or for a subordinate CA;
311 // thus, this message can be used to describe both known roots
312 // and a desired authorization space. If the
313 // certificate_authorities list is empty then the client MAY
314 // send any certificate of the appropriate
315 // ClientCertificateType, unless there is some external
316 // arrangement to the contrary.
318 hs
.finishedHash
.Write(certReq
.marshal())
320 var rsaAvail
, ecdsaAvail
bool
321 for _
, certType
:= range certReq
.certificateTypes
{
323 case certTypeRSASign
:
325 case certTypeECDSASign
:
330 // We need to search our list of client certs for one
331 // where SignatureAlgorithm is RSA and the Issuer is in
332 // certReq.certificateAuthorities
334 for i
, chain
:= range c
.config
.Certificates
{
335 if !rsaAvail
&& !ecdsaAvail
{
339 for j
, cert
:= range chain
.Certificate
{
340 x509Cert
:= chain
.Leaf
341 // parse the certificate if this isn't the leaf
342 // node, or if chain.Leaf was nil
343 if j
!= 0 || x509Cert
== nil {
344 if x509Cert
, err
= x509
.ParseCertificate(cert
); err
!= nil {
345 c
.sendAlert(alertInternalError
)
346 return errors
.New("tls: failed to parse client certificate #" + strconv
.Itoa(i
) + ": " + err
.Error())
351 case rsaAvail
&& x509Cert
.PublicKeyAlgorithm
== x509
.RSA
:
352 case ecdsaAvail
&& x509Cert
.PublicKeyAlgorithm
== x509
.ECDSA
:
357 if len(certReq
.certificateAuthorities
) == 0 {
358 // they gave us an empty list, so just take the
359 // first RSA cert from c.config.Certificates
364 for _
, ca
:= range certReq
.certificateAuthorities
{
365 if bytes
.Equal(x509Cert
.RawIssuer
, ca
) {
373 msg
, err
= c
.readHandshake()
379 shd
, ok
:= msg
.(*serverHelloDoneMsg
)
381 c
.sendAlert(alertUnexpectedMessage
)
382 return unexpectedMessageError(shd
, msg
)
384 hs
.finishedHash
.Write(shd
.marshal())
386 // If the server requested a certificate then we have to send a
387 // Certificate message, even if it's empty because we don't have a
388 // certificate to send.
390 certMsg
= new(certificateMsg
)
391 if chainToSend
!= nil {
392 certMsg
.certificates
= chainToSend
.Certificate
394 hs
.finishedHash
.Write(certMsg
.marshal())
395 c
.writeRecord(recordTypeHandshake
, certMsg
.marshal())
398 preMasterSecret
, ckx
, err
:= keyAgreement
.generateClientKeyExchange(c
.config
, hs
.hello
, certs
[0])
400 c
.sendAlert(alertInternalError
)
404 hs
.finishedHash
.Write(ckx
.marshal())
405 c
.writeRecord(recordTypeHandshake
, ckx
.marshal())
408 if chainToSend
!= nil {
410 certVerify
:= &certificateVerifyMsg
{
411 hasSignatureAndHash
: c
.vers
>= VersionTLS12
,
414 switch key
:= c
.config
.Certificates
[0].PrivateKey
.(type) {
415 case *ecdsa
.PrivateKey
:
416 digest
, _
, hashId
:= hs
.finishedHash
.hashForClientCertificate(signatureECDSA
)
417 r
, s
, err
:= ecdsa
.Sign(c
.config
.rand(), key
, digest
)
419 signed
, err
= asn1
.Marshal(ecdsaSignature
{r
, s
})
421 certVerify
.signatureAndHash
.signature
= signatureECDSA
422 certVerify
.signatureAndHash
.hash
= hashId
423 case *rsa
.PrivateKey
:
424 digest
, hashFunc
, hashId
:= hs
.finishedHash
.hashForClientCertificate(signatureRSA
)
425 signed
, err
= rsa
.SignPKCS1v15(c
.config
.rand(), key
, hashFunc
, digest
)
426 certVerify
.signatureAndHash
.signature
= signatureRSA
427 certVerify
.signatureAndHash
.hash
= hashId
429 err
= errors
.New("unknown private key type")
432 c
.sendAlert(alertInternalError
)
433 return errors
.New("tls: failed to sign handshake with client certificate: " + err
.Error())
435 certVerify
.signature
= signed
437 hs
.finishedHash
.Write(certVerify
.marshal())
438 c
.writeRecord(recordTypeHandshake
, certVerify
.marshal())
441 hs
.masterSecret
= masterFromPreMasterSecret(c
.vers
, preMasterSecret
, hs
.hello
.random
, hs
.serverHello
.random
)
445 func (hs
*clientHandshakeState
) establishKeys() error
{
448 clientMAC
, serverMAC
, clientKey
, serverKey
, clientIV
, serverIV
:=
449 keysFromMasterSecret(c
.vers
, hs
.masterSecret
, hs
.hello
.random
, hs
.serverHello
.random
, hs
.suite
.macLen
, hs
.suite
.keyLen
, hs
.suite
.ivLen
)
450 var clientCipher
, serverCipher
interface{}
451 var clientHash
, serverHash macFunction
452 if hs
.suite
.cipher
!= nil {
453 clientCipher
= hs
.suite
.cipher(clientKey
, clientIV
, false /* not for reading */)
454 clientHash
= hs
.suite
.mac(c
.vers
, clientMAC
)
455 serverCipher
= hs
.suite
.cipher(serverKey
, serverIV
, true /* for reading */)
456 serverHash
= hs
.suite
.mac(c
.vers
, serverMAC
)
458 clientCipher
= hs
.suite
.aead(clientKey
, clientIV
)
459 serverCipher
= hs
.suite
.aead(serverKey
, serverIV
)
462 c
.in
.prepareCipherSpec(c
.vers
, serverCipher
, serverHash
)
463 c
.out
.prepareCipherSpec(c
.vers
, clientCipher
, clientHash
)
467 func (hs
*clientHandshakeState
) serverResumedSession() bool {
468 // If the server responded with the same sessionId then it means the
469 // sessionTicket is being used to resume a TLS session.
470 return hs
.session
!= nil && hs
.hello
.sessionId
!= nil &&
471 bytes
.Equal(hs
.serverHello
.sessionId
, hs
.hello
.sessionId
)
474 func (hs
*clientHandshakeState
) processServerHello() (bool, error
) {
477 if hs
.serverHello
.compressionMethod
!= compressionNone
{
478 c
.sendAlert(alertUnexpectedMessage
)
479 return false, errors
.New("tls: server selected unsupported compression format")
482 if !hs
.hello
.nextProtoNeg
&& hs
.serverHello
.nextProtoNeg
{
483 c
.sendAlert(alertHandshakeFailure
)
484 return false, errors
.New("server advertised unrequested NPN extension")
487 if hs
.serverResumedSession() {
488 // Restore masterSecret and peerCerts from previous state
489 hs
.masterSecret
= hs
.session
.masterSecret
490 c
.peerCertificates
= hs
.session
.serverCertificates
496 func (hs
*clientHandshakeState
) readFinished() error
{
499 c
.readRecord(recordTypeChangeCipherSpec
)
500 if err
:= c
.error(); err
!= nil {
504 msg
, err
:= c
.readHandshake()
508 serverFinished
, ok
:= msg
.(*finishedMsg
)
510 c
.sendAlert(alertUnexpectedMessage
)
511 return unexpectedMessageError(serverFinished
, msg
)
514 verify
:= hs
.finishedHash
.serverSum(hs
.masterSecret
)
515 if len(verify
) != len(serverFinished
.verifyData
) ||
516 subtle
.ConstantTimeCompare(verify
, serverFinished
.verifyData
) != 1 {
517 c
.sendAlert(alertHandshakeFailure
)
518 return errors
.New("tls: server's Finished message was incorrect")
520 hs
.finishedHash
.Write(serverFinished
.marshal())
524 func (hs
*clientHandshakeState
) readSessionTicket() error
{
525 if !hs
.serverHello
.ticketSupported
{
530 msg
, err
:= c
.readHandshake()
534 sessionTicketMsg
, ok
:= msg
.(*newSessionTicketMsg
)
536 c
.sendAlert(alertUnexpectedMessage
)
537 return unexpectedMessageError(sessionTicketMsg
, msg
)
539 hs
.finishedHash
.Write(sessionTicketMsg
.marshal())
541 hs
.session
= &ClientSessionState
{
542 sessionTicket
: sessionTicketMsg
.ticket
,
544 cipherSuite
: hs
.suite
.id
,
545 masterSecret
: hs
.masterSecret
,
546 serverCertificates
: c
.peerCertificates
,
552 func (hs
*clientHandshakeState
) sendFinished() error
{
555 c
.writeRecord(recordTypeChangeCipherSpec
, []byte{1})
556 if hs
.serverHello
.nextProtoNeg
{
557 nextProto
:= new(nextProtoMsg
)
558 proto
, fallback
:= mutualProtocol(c
.config
.NextProtos
, hs
.serverHello
.nextProtos
)
559 nextProto
.proto
= proto
560 c
.clientProtocol
= proto
561 c
.clientProtocolFallback
= fallback
563 hs
.finishedHash
.Write(nextProto
.marshal())
564 c
.writeRecord(recordTypeHandshake
, nextProto
.marshal())
567 finished
:= new(finishedMsg
)
568 finished
.verifyData
= hs
.finishedHash
.clientSum(hs
.masterSecret
)
569 hs
.finishedHash
.Write(finished
.marshal())
570 c
.writeRecord(recordTypeHandshake
, finished
.marshal())
574 // clientSessionCacheKey returns a key used to cache sessionTickets that could
575 // be used to resume previously negotiated TLS sessions with a server.
576 func clientSessionCacheKey(serverAddr net
.Addr
, config
*Config
) string {
577 if len(config
.ServerName
) > 0 {
578 return config
.ServerName
580 return serverAddr
.String()
583 // mutualProtocol finds the mutual Next Protocol Negotiation protocol given the
584 // set of client and server supported protocols. The set of client supported
585 // protocols must not be empty. It returns the resulting protocol and flag
586 // indicating if the fallback case was reached.
587 func mutualProtocol(clientProtos
, serverProtos
[]string) (string, bool) {
588 for _
, s
:= range serverProtos
{
589 for _
, c
:= range clientProtos
{
596 return clientProtos
[0], true