blob: f2cbbe48559a87e3d89914ce70f3254e1f89e0f3 [file] [log] [blame]
Adam Langley95c29f32014-06-20 12:00:00 -07001// 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.
4
5package main
6
7import (
8 "bytes"
David Benjaminde620d92014-07-18 15:03:41 -04009 "crypto"
Adam Langley95c29f32014-06-20 12:00:00 -070010 "crypto/ecdsa"
11 "crypto/rsa"
12 "crypto/subtle"
13 "crypto/x509"
14 "encoding/asn1"
15 "errors"
16 "fmt"
17 "io"
David Benjaminde620d92014-07-18 15:03:41 -040018 "math/big"
Adam Langley95c29f32014-06-20 12:00:00 -070019 "net"
20 "strconv"
21)
22
23type clientHandshakeState struct {
24 c *Conn
25 serverHello *serverHelloMsg
26 hello *clientHelloMsg
27 suite *cipherSuite
28 finishedHash finishedHash
29 masterSecret []byte
30 session *ClientSessionState
31}
32
33func (c *Conn) clientHandshake() error {
34 if c.config == nil {
35 c.config = defaultConfig()
36 }
37
38 if len(c.config.ServerName) == 0 && !c.config.InsecureSkipVerify {
39 return errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
40 }
41
David Benjamin83c0bc92014-08-04 01:23:53 -040042 c.sendHandshakeSeq = 0
43 c.recvHandshakeSeq = 0
44
Adam Langley95c29f32014-06-20 12:00:00 -070045 hello := &clientHelloMsg{
David Benjamin83c0bc92014-08-04 01:23:53 -040046 isDTLS: c.isDTLS,
Adam Langley95c29f32014-06-20 12:00:00 -070047 vers: c.config.maxVersion(),
48 compressionMethods: []uint8{compressionNone},
49 random: make([]byte, 32),
50 ocspStapling: true,
51 serverName: c.config.ServerName,
52 supportedCurves: c.config.curvePreferences(),
53 supportedPoints: []uint8{pointFormatUncompressed},
54 nextProtoNeg: len(c.config.NextProtos) > 0,
55 secureRenegotiation: true,
David Benjamin35a7a442014-07-05 00:23:20 -040056 duplicateExtension: c.config.Bugs.DuplicateExtension,
Adam Langley95c29f32014-06-20 12:00:00 -070057 }
58
David Benjamin98e882e2014-08-08 13:24:34 -040059 if c.config.Bugs.SendClientVersion != 0 {
60 hello.vers = c.config.Bugs.SendClientVersion
61 }
62
Adam Langley95c29f32014-06-20 12:00:00 -070063 possibleCipherSuites := c.config.cipherSuites()
64 hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites))
65
66NextCipherSuite:
67 for _, suiteId := range possibleCipherSuites {
68 for _, suite := range cipherSuites {
69 if suite.id != suiteId {
70 continue
71 }
72 // Don't advertise TLS 1.2-only cipher suites unless
73 // we're attempting TLS 1.2.
74 if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
75 continue
76 }
David Benjamin83c0bc92014-08-04 01:23:53 -040077 // Don't advertise non-DTLS cipher suites on DTLS.
78 if c.isDTLS && suite.flags&suiteNoDTLS != 0 {
79 continue
80 }
Adam Langley95c29f32014-06-20 12:00:00 -070081 hello.cipherSuites = append(hello.cipherSuites, suiteId)
82 continue NextCipherSuite
83 }
84 }
85
David Benjaminbef270a2014-08-02 04:22:02 -040086 if c.config.Bugs.SendFallbackSCSV {
87 hello.cipherSuites = append(hello.cipherSuites, fallbackSCSV)
88 }
89
Adam Langley95c29f32014-06-20 12:00:00 -070090 _, err := io.ReadFull(c.config.rand(), hello.random)
91 if err != nil {
92 c.sendAlert(alertInternalError)
93 return errors.New("tls: short read from Rand: " + err.Error())
94 }
95
96 if hello.vers >= VersionTLS12 {
97 hello.signatureAndHashes = supportedSKXSignatureAlgorithms
98 }
99
100 var session *ClientSessionState
101 var cacheKey string
102 sessionCache := c.config.ClientSessionCache
103 if c.config.SessionTicketsDisabled {
104 sessionCache = nil
105 }
106
107 if sessionCache != nil {
108 hello.ticketSupported = true
109
110 // Try to resume a previously negotiated TLS session, if
111 // available.
112 cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
113 candidateSession, ok := sessionCache.Get(cacheKey)
114 if ok {
115 // Check that the ciphersuite/version used for the
116 // previous session are still valid.
117 cipherSuiteOk := false
118 for _, id := range hello.cipherSuites {
119 if id == candidateSession.cipherSuite {
120 cipherSuiteOk = true
121 break
122 }
123 }
124
125 versOk := candidateSession.vers >= c.config.minVersion() &&
126 candidateSession.vers <= c.config.maxVersion()
127 if versOk && cipherSuiteOk {
128 session = candidateSession
129 }
130 }
131 }
132
133 if session != nil {
134 hello.sessionTicket = session.sessionTicket
135 // A random session ID is used to detect when the
136 // server accepted the ticket and is resuming a session
137 // (see RFC 5077).
138 hello.sessionId = make([]byte, 16)
139 if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil {
140 c.sendAlert(alertInternalError)
141 return errors.New("tls: short read from Rand: " + err.Error())
142 }
143 }
144
David Benjamind86c7672014-08-02 04:07:12 -0400145 var helloBytes []byte
146 if c.config.Bugs.SendV2ClientHello {
147 v2Hello := &v2ClientHelloMsg{
148 vers: hello.vers,
149 cipherSuites: hello.cipherSuites,
150 // No session resumption for V2ClientHello.
151 sessionId: nil,
152 challenge: hello.random,
153 }
154 helloBytes = v2Hello.marshal()
155 c.writeV2Record(helloBytes)
156 } else {
157 helloBytes = hello.marshal()
158 c.writeRecord(recordTypeHandshake, helloBytes)
159 }
Adam Langley95c29f32014-06-20 12:00:00 -0700160
161 msg, err := c.readHandshake()
162 if err != nil {
163 return err
164 }
David Benjamin83c0bc92014-08-04 01:23:53 -0400165
166 if c.isDTLS {
167 helloVerifyRequest, ok := msg.(*helloVerifyRequestMsg)
168 if ok {
169 hello.raw = nil
170 hello.cookie = helloVerifyRequest.cookie
171 helloBytes = hello.marshal()
172 c.writeRecord(recordTypeHandshake, helloBytes)
173
174 msg, err = c.readHandshake()
175 if err != nil {
176 return err
177 }
178 }
179 }
180
Adam Langley95c29f32014-06-20 12:00:00 -0700181 serverHello, ok := msg.(*serverHelloMsg)
182 if !ok {
183 c.sendAlert(alertUnexpectedMessage)
184 return unexpectedMessageError(serverHello, msg)
185 }
186
187 vers, ok := c.config.mutualVersion(serverHello.vers)
188 if !ok || vers < VersionTLS10 {
189 // TLS 1.0 is the minimum version supported as a client.
190 c.sendAlert(alertProtocolVersion)
191 return fmt.Errorf("tls: server selected unsupported protocol version %x", serverHello.vers)
192 }
193 c.vers = vers
194 c.haveVers = true
195
196 suite := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
197 if suite == nil {
198 c.sendAlert(alertHandshakeFailure)
199 return fmt.Errorf("tls: server selected an unsupported cipher suite")
200 }
201
202 hs := &clientHandshakeState{
203 c: c,
204 serverHello: serverHello,
205 hello: hello,
206 suite: suite,
207 finishedHash: newFinishedHash(c.vers, suite),
208 session: session,
209 }
210
David Benjamin83c0bc92014-08-04 01:23:53 -0400211 hs.writeHash(helloBytes, hs.c.sendHandshakeSeq-1)
212 hs.writeServerHash(hs.serverHello.marshal())
Adam Langley95c29f32014-06-20 12:00:00 -0700213
David Benjaminf3ec83d2014-07-21 22:42:34 -0400214 if c.config.Bugs.EarlyChangeCipherSpec > 0 {
215 hs.establishKeys()
216 c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
217 }
218
Adam Langley95c29f32014-06-20 12:00:00 -0700219 isResume, err := hs.processServerHello()
220 if err != nil {
221 return err
222 }
223
224 if isResume {
David Benjaminf3ec83d2014-07-21 22:42:34 -0400225 if c.config.Bugs.EarlyChangeCipherSpec == 0 {
226 if err := hs.establishKeys(); err != nil {
227 return err
228 }
Adam Langley95c29f32014-06-20 12:00:00 -0700229 }
230 if err := hs.readSessionTicket(); err != nil {
231 return err
232 }
233 if err := hs.readFinished(); err != nil {
234 return err
235 }
236 if err := hs.sendFinished(); err != nil {
237 return err
238 }
239 } else {
240 if err := hs.doFullHandshake(); err != nil {
241 return err
242 }
243 if err := hs.establishKeys(); err != nil {
244 return err
245 }
246 if err := hs.sendFinished(); err != nil {
247 return err
248 }
249 if err := hs.readSessionTicket(); err != nil {
250 return err
251 }
252 if err := hs.readFinished(); err != nil {
253 return err
254 }
255 }
256
257 if sessionCache != nil && hs.session != nil && session != hs.session {
258 sessionCache.Put(cacheKey, hs.session)
259 }
260
261 c.didResume = isResume
262 c.handshakeComplete = true
263 c.cipherSuite = suite.id
264 return nil
265}
266
267func (hs *clientHandshakeState) doFullHandshake() error {
268 c := hs.c
269
270 msg, err := c.readHandshake()
271 if err != nil {
272 return err
273 }
274 certMsg, ok := msg.(*certificateMsg)
275 if !ok || len(certMsg.certificates) == 0 {
276 c.sendAlert(alertUnexpectedMessage)
277 return unexpectedMessageError(certMsg, msg)
278 }
David Benjamin83c0bc92014-08-04 01:23:53 -0400279 hs.writeServerHash(certMsg.marshal())
Adam Langley95c29f32014-06-20 12:00:00 -0700280
281 certs := make([]*x509.Certificate, len(certMsg.certificates))
282 for i, asn1Data := range certMsg.certificates {
283 cert, err := x509.ParseCertificate(asn1Data)
284 if err != nil {
285 c.sendAlert(alertBadCertificate)
286 return errors.New("tls: failed to parse certificate from server: " + err.Error())
287 }
288 certs[i] = cert
289 }
290
291 if !c.config.InsecureSkipVerify {
292 opts := x509.VerifyOptions{
293 Roots: c.config.RootCAs,
294 CurrentTime: c.config.time(),
295 DNSName: c.config.ServerName,
296 Intermediates: x509.NewCertPool(),
297 }
298
299 for i, cert := range certs {
300 if i == 0 {
301 continue
302 }
303 opts.Intermediates.AddCert(cert)
304 }
305 c.verifiedChains, err = certs[0].Verify(opts)
306 if err != nil {
307 c.sendAlert(alertBadCertificate)
308 return err
309 }
310 }
311
312 switch certs[0].PublicKey.(type) {
313 case *rsa.PublicKey, *ecdsa.PublicKey:
314 break
315 default:
316 c.sendAlert(alertUnsupportedCertificate)
317 return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
318 }
319
320 c.peerCertificates = certs
321
322 if hs.serverHello.ocspStapling {
323 msg, err = c.readHandshake()
324 if err != nil {
325 return err
326 }
327 cs, ok := msg.(*certificateStatusMsg)
328 if !ok {
329 c.sendAlert(alertUnexpectedMessage)
330 return unexpectedMessageError(cs, msg)
331 }
David Benjamin83c0bc92014-08-04 01:23:53 -0400332 hs.writeServerHash(cs.marshal())
Adam Langley95c29f32014-06-20 12:00:00 -0700333
334 if cs.statusType == statusTypeOCSP {
335 c.ocspResponse = cs.response
336 }
337 }
338
339 msg, err = c.readHandshake()
340 if err != nil {
341 return err
342 }
343
344 keyAgreement := hs.suite.ka(c.vers)
345
346 skx, ok := msg.(*serverKeyExchangeMsg)
347 if ok {
David Benjamin83c0bc92014-08-04 01:23:53 -0400348 hs.writeServerHash(skx.marshal())
Adam Langley95c29f32014-06-20 12:00:00 -0700349 err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, certs[0], skx)
350 if err != nil {
351 c.sendAlert(alertUnexpectedMessage)
352 return err
353 }
354
355 msg, err = c.readHandshake()
356 if err != nil {
357 return err
358 }
359 }
360
361 var chainToSend *Certificate
362 var certRequested bool
363 certReq, ok := msg.(*certificateRequestMsg)
364 if ok {
365 certRequested = true
366
367 // RFC 4346 on the certificateAuthorities field:
368 // A list of the distinguished names of acceptable certificate
369 // authorities. These distinguished names may specify a desired
370 // distinguished name for a root CA or for a subordinate CA;
371 // thus, this message can be used to describe both known roots
372 // and a desired authorization space. If the
373 // certificate_authorities list is empty then the client MAY
374 // send any certificate of the appropriate
375 // ClientCertificateType, unless there is some external
376 // arrangement to the contrary.
377
David Benjamin83c0bc92014-08-04 01:23:53 -0400378 hs.writeServerHash(certReq.marshal())
Adam Langley95c29f32014-06-20 12:00:00 -0700379
380 var rsaAvail, ecdsaAvail bool
381 for _, certType := range certReq.certificateTypes {
382 switch certType {
David Benjamin7b030512014-07-08 17:30:11 -0400383 case CertTypeRSASign:
Adam Langley95c29f32014-06-20 12:00:00 -0700384 rsaAvail = true
David Benjamin7b030512014-07-08 17:30:11 -0400385 case CertTypeECDSASign:
Adam Langley95c29f32014-06-20 12:00:00 -0700386 ecdsaAvail = true
387 }
388 }
389
390 // We need to search our list of client certs for one
391 // where SignatureAlgorithm is RSA and the Issuer is in
392 // certReq.certificateAuthorities
393 findCert:
394 for i, chain := range c.config.Certificates {
395 if !rsaAvail && !ecdsaAvail {
396 continue
397 }
398
399 for j, cert := range chain.Certificate {
400 x509Cert := chain.Leaf
401 // parse the certificate if this isn't the leaf
402 // node, or if chain.Leaf was nil
403 if j != 0 || x509Cert == nil {
404 if x509Cert, err = x509.ParseCertificate(cert); err != nil {
405 c.sendAlert(alertInternalError)
406 return errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error())
407 }
408 }
409
410 switch {
411 case rsaAvail && x509Cert.PublicKeyAlgorithm == x509.RSA:
412 case ecdsaAvail && x509Cert.PublicKeyAlgorithm == x509.ECDSA:
413 default:
414 continue findCert
415 }
416
417 if len(certReq.certificateAuthorities) == 0 {
418 // they gave us an empty list, so just take the
419 // first RSA cert from c.config.Certificates
420 chainToSend = &chain
421 break findCert
422 }
423
424 for _, ca := range certReq.certificateAuthorities {
425 if bytes.Equal(x509Cert.RawIssuer, ca) {
426 chainToSend = &chain
427 break findCert
428 }
429 }
430 }
431 }
432
433 msg, err = c.readHandshake()
434 if err != nil {
435 return err
436 }
437 }
438
439 shd, ok := msg.(*serverHelloDoneMsg)
440 if !ok {
441 c.sendAlert(alertUnexpectedMessage)
442 return unexpectedMessageError(shd, msg)
443 }
David Benjamin83c0bc92014-08-04 01:23:53 -0400444 hs.writeServerHash(shd.marshal())
Adam Langley95c29f32014-06-20 12:00:00 -0700445
446 // If the server requested a certificate then we have to send a
447 // Certificate message, even if it's empty because we don't have a
448 // certificate to send.
449 if certRequested {
450 certMsg = new(certificateMsg)
451 if chainToSend != nil {
452 certMsg.certificates = chainToSend.Certificate
453 }
David Benjamin83c0bc92014-08-04 01:23:53 -0400454 hs.writeClientHash(certMsg.marshal())
Adam Langley95c29f32014-06-20 12:00:00 -0700455 c.writeRecord(recordTypeHandshake, certMsg.marshal())
456 }
457
458 preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, certs[0])
459 if err != nil {
460 c.sendAlert(alertInternalError)
461 return err
462 }
463 if ckx != nil {
David Benjaminf3ec83d2014-07-21 22:42:34 -0400464 if c.config.Bugs.EarlyChangeCipherSpec < 2 {
David Benjamin83c0bc92014-08-04 01:23:53 -0400465 hs.writeClientHash(ckx.marshal())
David Benjaminf3ec83d2014-07-21 22:42:34 -0400466 }
Adam Langley95c29f32014-06-20 12:00:00 -0700467 c.writeRecord(recordTypeHandshake, ckx.marshal())
468 }
469
470 if chainToSend != nil {
471 var signed []byte
472 certVerify := &certificateVerifyMsg{
473 hasSignatureAndHash: c.vers >= VersionTLS12,
474 }
475
476 switch key := c.config.Certificates[0].PrivateKey.(type) {
477 case *ecdsa.PrivateKey:
David Benjaminde620d92014-07-18 15:03:41 -0400478 certVerify.signatureAndHash, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.signatureAndHashes, signatureECDSA)
479 if err != nil {
480 break
481 }
482 var digest []byte
483 digest, _, err = hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash)
484 if err != nil {
485 break
486 }
487 var r, s *big.Int
488 r, s, err = ecdsa.Sign(c.config.rand(), key, digest)
Adam Langley95c29f32014-06-20 12:00:00 -0700489 if err == nil {
490 signed, err = asn1.Marshal(ecdsaSignature{r, s})
491 }
Adam Langley95c29f32014-06-20 12:00:00 -0700492 case *rsa.PrivateKey:
David Benjaminde620d92014-07-18 15:03:41 -0400493 certVerify.signatureAndHash, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.signatureAndHashes, signatureRSA)
494 if err != nil {
495 break
496 }
497 var digest []byte
498 var hashFunc crypto.Hash
499 digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash)
500 if err != nil {
501 break
502 }
Adam Langley95c29f32014-06-20 12:00:00 -0700503 signed, err = rsa.SignPKCS1v15(c.config.rand(), key, hashFunc, digest)
Adam Langley95c29f32014-06-20 12:00:00 -0700504 default:
505 err = errors.New("unknown private key type")
506 }
507 if err != nil {
508 c.sendAlert(alertInternalError)
509 return errors.New("tls: failed to sign handshake with client certificate: " + err.Error())
510 }
511 certVerify.signature = signed
512
David Benjamin83c0bc92014-08-04 01:23:53 -0400513 hs.writeClientHash(certVerify.marshal())
Adam Langley95c29f32014-06-20 12:00:00 -0700514 c.writeRecord(recordTypeHandshake, certVerify.marshal())
515 }
516
517 hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
518 return nil
519}
520
521func (hs *clientHandshakeState) establishKeys() error {
522 c := hs.c
523
524 clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
525 keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
526 var clientCipher, serverCipher interface{}
527 var clientHash, serverHash macFunction
528 if hs.suite.cipher != nil {
529 clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
530 clientHash = hs.suite.mac(c.vers, clientMAC)
531 serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */)
532 serverHash = hs.suite.mac(c.vers, serverMAC)
533 } else {
534 clientCipher = hs.suite.aead(clientKey, clientIV)
535 serverCipher = hs.suite.aead(serverKey, serverIV)
536 }
537
538 c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
539 c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
540 return nil
541}
542
543func (hs *clientHandshakeState) serverResumedSession() bool {
544 // If the server responded with the same sessionId then it means the
545 // sessionTicket is being used to resume a TLS session.
546 return hs.session != nil && hs.hello.sessionId != nil &&
547 bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId)
548}
549
550func (hs *clientHandshakeState) processServerHello() (bool, error) {
551 c := hs.c
552
553 if hs.serverHello.compressionMethod != compressionNone {
554 c.sendAlert(alertUnexpectedMessage)
555 return false, errors.New("tls: server selected unsupported compression format")
556 }
557
558 if !hs.hello.nextProtoNeg && hs.serverHello.nextProtoNeg {
559 c.sendAlert(alertHandshakeFailure)
560 return false, errors.New("server advertised unrequested NPN extension")
561 }
562
563 if hs.serverResumedSession() {
564 // Restore masterSecret and peerCerts from previous state
565 hs.masterSecret = hs.session.masterSecret
566 c.peerCertificates = hs.session.serverCertificates
567 return true, nil
568 }
569 return false, nil
570}
571
572func (hs *clientHandshakeState) readFinished() error {
573 c := hs.c
574
575 c.readRecord(recordTypeChangeCipherSpec)
576 if err := c.in.error(); err != nil {
577 return err
578 }
579
580 msg, err := c.readHandshake()
581 if err != nil {
582 return err
583 }
584 serverFinished, ok := msg.(*finishedMsg)
585 if !ok {
586 c.sendAlert(alertUnexpectedMessage)
587 return unexpectedMessageError(serverFinished, msg)
588 }
589
David Benjaminf3ec83d2014-07-21 22:42:34 -0400590 if c.config.Bugs.EarlyChangeCipherSpec == 0 {
591 verify := hs.finishedHash.serverSum(hs.masterSecret)
592 if len(verify) != len(serverFinished.verifyData) ||
593 subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
594 c.sendAlert(alertHandshakeFailure)
595 return errors.New("tls: server's Finished message was incorrect")
596 }
Adam Langley95c29f32014-06-20 12:00:00 -0700597 }
David Benjamin83c0bc92014-08-04 01:23:53 -0400598 hs.writeServerHash(serverFinished.marshal())
Adam Langley95c29f32014-06-20 12:00:00 -0700599 return nil
600}
601
602func (hs *clientHandshakeState) readSessionTicket() error {
603 if !hs.serverHello.ticketSupported {
604 return nil
605 }
606
607 c := hs.c
608 msg, err := c.readHandshake()
609 if err != nil {
610 return err
611 }
612 sessionTicketMsg, ok := msg.(*newSessionTicketMsg)
613 if !ok {
614 c.sendAlert(alertUnexpectedMessage)
615 return unexpectedMessageError(sessionTicketMsg, msg)
616 }
David Benjamin83c0bc92014-08-04 01:23:53 -0400617 hs.writeServerHash(sessionTicketMsg.marshal())
Adam Langley95c29f32014-06-20 12:00:00 -0700618
619 hs.session = &ClientSessionState{
620 sessionTicket: sessionTicketMsg.ticket,
621 vers: c.vers,
622 cipherSuite: hs.suite.id,
623 masterSecret: hs.masterSecret,
624 serverCertificates: c.peerCertificates,
625 }
626
627 return nil
628}
629
630func (hs *clientHandshakeState) sendFinished() error {
631 c := hs.c
632
David Benjamin86271ee2014-07-21 16:14:03 -0400633 var postCCSBytes []byte
David Benjamin83c0bc92014-08-04 01:23:53 -0400634 seqno := hs.c.sendHandshakeSeq
Adam Langley95c29f32014-06-20 12:00:00 -0700635 if hs.serverHello.nextProtoNeg {
636 nextProto := new(nextProtoMsg)
637 proto, fallback := mutualProtocol(c.config.NextProtos, hs.serverHello.nextProtos)
638 nextProto.proto = proto
639 c.clientProtocol = proto
640 c.clientProtocolFallback = fallback
641
David Benjamin86271ee2014-07-21 16:14:03 -0400642 nextProtoBytes := nextProto.marshal()
David Benjamin83c0bc92014-08-04 01:23:53 -0400643 hs.writeHash(nextProtoBytes, seqno)
644 seqno++
David Benjamin86271ee2014-07-21 16:14:03 -0400645 postCCSBytes = append(postCCSBytes, nextProtoBytes...)
Adam Langley95c29f32014-06-20 12:00:00 -0700646 }
647
648 finished := new(finishedMsg)
David Benjaminf3ec83d2014-07-21 22:42:34 -0400649 if c.config.Bugs.EarlyChangeCipherSpec == 2 {
650 finished.verifyData = hs.finishedHash.clientSum(nil)
651 } else {
652 finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
653 }
David Benjamin86271ee2014-07-21 16:14:03 -0400654 finishedBytes := finished.marshal()
David Benjamin83c0bc92014-08-04 01:23:53 -0400655 hs.writeHash(finishedBytes, seqno)
David Benjamin86271ee2014-07-21 16:14:03 -0400656 postCCSBytes = append(postCCSBytes, finishedBytes...)
657
658 if c.config.Bugs.FragmentAcrossChangeCipherSpec {
659 c.writeRecord(recordTypeHandshake, postCCSBytes[:5])
660 postCCSBytes = postCCSBytes[5:]
661 }
662
663 if !c.config.Bugs.SkipChangeCipherSpec &&
664 c.config.Bugs.EarlyChangeCipherSpec == 0 {
665 c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
666 }
667
668 c.writeRecord(recordTypeHandshake, postCCSBytes)
Adam Langley95c29f32014-06-20 12:00:00 -0700669 return nil
670}
671
David Benjamin83c0bc92014-08-04 01:23:53 -0400672func (hs *clientHandshakeState) writeClientHash(msg []byte) {
673 // writeClientHash is called before writeRecord.
674 hs.writeHash(msg, hs.c.sendHandshakeSeq)
675}
676
677func (hs *clientHandshakeState) writeServerHash(msg []byte) {
678 // writeServerHash is called after readHandshake.
679 hs.writeHash(msg, hs.c.recvHandshakeSeq-1)
680}
681
682func (hs *clientHandshakeState) writeHash(msg []byte, seqno uint16) {
683 if hs.c.isDTLS {
684 // This is somewhat hacky. DTLS hashes a slightly different format.
685 // First, the TLS header.
686 hs.finishedHash.Write(msg[:4])
687 // Then the sequence number and reassembled fragment offset (always 0).
688 hs.finishedHash.Write([]byte{byte(seqno >> 8), byte(seqno), 0, 0, 0})
689 // Then the reassembled fragment (always equal to the message length).
690 hs.finishedHash.Write(msg[1:4])
691 // And then the message body.
692 hs.finishedHash.Write(msg[4:])
693 } else {
694 hs.finishedHash.Write(msg)
695 }
696}
697
Adam Langley95c29f32014-06-20 12:00:00 -0700698// clientSessionCacheKey returns a key used to cache sessionTickets that could
699// be used to resume previously negotiated TLS sessions with a server.
700func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
701 if len(config.ServerName) > 0 {
702 return config.ServerName
703 }
704 return serverAddr.String()
705}
706
707// mutualProtocol finds the mutual Next Protocol Negotiation protocol given the
708// set of client and server supported protocols. The set of client supported
709// protocols must not be empty. It returns the resulting protocol and flag
710// indicating if the fallback case was reached.
711func mutualProtocol(clientProtos, serverProtos []string) (string, bool) {
712 for _, s := range serverProtos {
713 for _, c := range clientProtos {
714 if s == c {
715 return s, false
716 }
717 }
718 }
719
720 return clientProtos[0], true
721}