blob: 32b90e2b3c80faf430751b4d22f69e62c04bf493 [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
42 hello := &clientHelloMsg{
43 vers: c.config.maxVersion(),
44 compressionMethods: []uint8{compressionNone},
45 random: make([]byte, 32),
46 ocspStapling: true,
47 serverName: c.config.ServerName,
48 supportedCurves: c.config.curvePreferences(),
49 supportedPoints: []uint8{pointFormatUncompressed},
50 nextProtoNeg: len(c.config.NextProtos) > 0,
51 secureRenegotiation: true,
David Benjamin35a7a442014-07-05 00:23:20 -040052 duplicateExtension: c.config.Bugs.DuplicateExtension,
Adam Langley95c29f32014-06-20 12:00:00 -070053 }
54
55 possibleCipherSuites := c.config.cipherSuites()
56 hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites))
57
58NextCipherSuite:
59 for _, suiteId := range possibleCipherSuites {
60 for _, suite := range cipherSuites {
61 if suite.id != suiteId {
62 continue
63 }
64 // Don't advertise TLS 1.2-only cipher suites unless
65 // we're attempting TLS 1.2.
66 if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
67 continue
68 }
69 hello.cipherSuites = append(hello.cipherSuites, suiteId)
70 continue NextCipherSuite
71 }
72 }
73
74 _, err := io.ReadFull(c.config.rand(), hello.random)
75 if err != nil {
76 c.sendAlert(alertInternalError)
77 return errors.New("tls: short read from Rand: " + err.Error())
78 }
79
80 if hello.vers >= VersionTLS12 {
81 hello.signatureAndHashes = supportedSKXSignatureAlgorithms
82 }
83
84 var session *ClientSessionState
85 var cacheKey string
86 sessionCache := c.config.ClientSessionCache
87 if c.config.SessionTicketsDisabled {
88 sessionCache = nil
89 }
90
91 if sessionCache != nil {
92 hello.ticketSupported = true
93
94 // Try to resume a previously negotiated TLS session, if
95 // available.
96 cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
97 candidateSession, ok := sessionCache.Get(cacheKey)
98 if ok {
99 // Check that the ciphersuite/version used for the
100 // previous session are still valid.
101 cipherSuiteOk := false
102 for _, id := range hello.cipherSuites {
103 if id == candidateSession.cipherSuite {
104 cipherSuiteOk = true
105 break
106 }
107 }
108
109 versOk := candidateSession.vers >= c.config.minVersion() &&
110 candidateSession.vers <= c.config.maxVersion()
111 if versOk && cipherSuiteOk {
112 session = candidateSession
113 }
114 }
115 }
116
117 if session != nil {
118 hello.sessionTicket = session.sessionTicket
119 // A random session ID is used to detect when the
120 // server accepted the ticket and is resuming a session
121 // (see RFC 5077).
122 hello.sessionId = make([]byte, 16)
123 if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil {
124 c.sendAlert(alertInternalError)
125 return errors.New("tls: short read from Rand: " + err.Error())
126 }
127 }
128
129 c.writeRecord(recordTypeHandshake, hello.marshal())
130
131 msg, err := c.readHandshake()
132 if err != nil {
133 return err
134 }
135 serverHello, ok := msg.(*serverHelloMsg)
136 if !ok {
137 c.sendAlert(alertUnexpectedMessage)
138 return unexpectedMessageError(serverHello, msg)
139 }
140
141 vers, ok := c.config.mutualVersion(serverHello.vers)
142 if !ok || vers < VersionTLS10 {
143 // TLS 1.0 is the minimum version supported as a client.
144 c.sendAlert(alertProtocolVersion)
145 return fmt.Errorf("tls: server selected unsupported protocol version %x", serverHello.vers)
146 }
147 c.vers = vers
148 c.haveVers = true
149
150 suite := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
151 if suite == nil {
152 c.sendAlert(alertHandshakeFailure)
153 return fmt.Errorf("tls: server selected an unsupported cipher suite")
154 }
155
156 hs := &clientHandshakeState{
157 c: c,
158 serverHello: serverHello,
159 hello: hello,
160 suite: suite,
161 finishedHash: newFinishedHash(c.vers, suite),
162 session: session,
163 }
164
165 hs.finishedHash.Write(hs.hello.marshal())
166 hs.finishedHash.Write(hs.serverHello.marshal())
167
David Benjaminf3ec83d2014-07-21 22:42:34 -0400168 if c.config.Bugs.EarlyChangeCipherSpec > 0 {
169 hs.establishKeys()
170 c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
171 }
172
Adam Langley95c29f32014-06-20 12:00:00 -0700173 isResume, err := hs.processServerHello()
174 if err != nil {
175 return err
176 }
177
178 if isResume {
David Benjaminf3ec83d2014-07-21 22:42:34 -0400179 if c.config.Bugs.EarlyChangeCipherSpec == 0 {
180 if err := hs.establishKeys(); err != nil {
181 return err
182 }
Adam Langley95c29f32014-06-20 12:00:00 -0700183 }
184 if err := hs.readSessionTicket(); err != nil {
185 return err
186 }
187 if err := hs.readFinished(); err != nil {
188 return err
189 }
190 if err := hs.sendFinished(); err != nil {
191 return err
192 }
193 } else {
194 if err := hs.doFullHandshake(); err != nil {
195 return err
196 }
197 if err := hs.establishKeys(); err != nil {
198 return err
199 }
200 if err := hs.sendFinished(); err != nil {
201 return err
202 }
203 if err := hs.readSessionTicket(); err != nil {
204 return err
205 }
206 if err := hs.readFinished(); err != nil {
207 return err
208 }
209 }
210
211 if sessionCache != nil && hs.session != nil && session != hs.session {
212 sessionCache.Put(cacheKey, hs.session)
213 }
214
215 c.didResume = isResume
216 c.handshakeComplete = true
217 c.cipherSuite = suite.id
218 return nil
219}
220
221func (hs *clientHandshakeState) doFullHandshake() error {
222 c := hs.c
223
224 msg, err := c.readHandshake()
225 if err != nil {
226 return err
227 }
228 certMsg, ok := msg.(*certificateMsg)
229 if !ok || len(certMsg.certificates) == 0 {
230 c.sendAlert(alertUnexpectedMessage)
231 return unexpectedMessageError(certMsg, msg)
232 }
233 hs.finishedHash.Write(certMsg.marshal())
234
235 certs := make([]*x509.Certificate, len(certMsg.certificates))
236 for i, asn1Data := range certMsg.certificates {
237 cert, err := x509.ParseCertificate(asn1Data)
238 if err != nil {
239 c.sendAlert(alertBadCertificate)
240 return errors.New("tls: failed to parse certificate from server: " + err.Error())
241 }
242 certs[i] = cert
243 }
244
245 if !c.config.InsecureSkipVerify {
246 opts := x509.VerifyOptions{
247 Roots: c.config.RootCAs,
248 CurrentTime: c.config.time(),
249 DNSName: c.config.ServerName,
250 Intermediates: x509.NewCertPool(),
251 }
252
253 for i, cert := range certs {
254 if i == 0 {
255 continue
256 }
257 opts.Intermediates.AddCert(cert)
258 }
259 c.verifiedChains, err = certs[0].Verify(opts)
260 if err != nil {
261 c.sendAlert(alertBadCertificate)
262 return err
263 }
264 }
265
266 switch certs[0].PublicKey.(type) {
267 case *rsa.PublicKey, *ecdsa.PublicKey:
268 break
269 default:
270 c.sendAlert(alertUnsupportedCertificate)
271 return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
272 }
273
274 c.peerCertificates = certs
275
276 if hs.serverHello.ocspStapling {
277 msg, err = c.readHandshake()
278 if err != nil {
279 return err
280 }
281 cs, ok := msg.(*certificateStatusMsg)
282 if !ok {
283 c.sendAlert(alertUnexpectedMessage)
284 return unexpectedMessageError(cs, msg)
285 }
286 hs.finishedHash.Write(cs.marshal())
287
288 if cs.statusType == statusTypeOCSP {
289 c.ocspResponse = cs.response
290 }
291 }
292
293 msg, err = c.readHandshake()
294 if err != nil {
295 return err
296 }
297
298 keyAgreement := hs.suite.ka(c.vers)
299
300 skx, ok := msg.(*serverKeyExchangeMsg)
301 if ok {
302 hs.finishedHash.Write(skx.marshal())
303 err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, certs[0], skx)
304 if err != nil {
305 c.sendAlert(alertUnexpectedMessage)
306 return err
307 }
308
309 msg, err = c.readHandshake()
310 if err != nil {
311 return err
312 }
313 }
314
315 var chainToSend *Certificate
316 var certRequested bool
317 certReq, ok := msg.(*certificateRequestMsg)
318 if ok {
319 certRequested = true
320
321 // RFC 4346 on the certificateAuthorities field:
322 // A list of the distinguished names of acceptable certificate
323 // authorities. These distinguished names may specify a desired
324 // distinguished name for a root CA or for a subordinate CA;
325 // thus, this message can be used to describe both known roots
326 // and a desired authorization space. If the
327 // certificate_authorities list is empty then the client MAY
328 // send any certificate of the appropriate
329 // ClientCertificateType, unless there is some external
330 // arrangement to the contrary.
331
332 hs.finishedHash.Write(certReq.marshal())
333
334 var rsaAvail, ecdsaAvail bool
335 for _, certType := range certReq.certificateTypes {
336 switch certType {
David Benjamin7b030512014-07-08 17:30:11 -0400337 case CertTypeRSASign:
Adam Langley95c29f32014-06-20 12:00:00 -0700338 rsaAvail = true
David Benjamin7b030512014-07-08 17:30:11 -0400339 case CertTypeECDSASign:
Adam Langley95c29f32014-06-20 12:00:00 -0700340 ecdsaAvail = true
341 }
342 }
343
344 // We need to search our list of client certs for one
345 // where SignatureAlgorithm is RSA and the Issuer is in
346 // certReq.certificateAuthorities
347 findCert:
348 for i, chain := range c.config.Certificates {
349 if !rsaAvail && !ecdsaAvail {
350 continue
351 }
352
353 for j, cert := range chain.Certificate {
354 x509Cert := chain.Leaf
355 // parse the certificate if this isn't the leaf
356 // node, or if chain.Leaf was nil
357 if j != 0 || x509Cert == nil {
358 if x509Cert, err = x509.ParseCertificate(cert); err != nil {
359 c.sendAlert(alertInternalError)
360 return errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error())
361 }
362 }
363
364 switch {
365 case rsaAvail && x509Cert.PublicKeyAlgorithm == x509.RSA:
366 case ecdsaAvail && x509Cert.PublicKeyAlgorithm == x509.ECDSA:
367 default:
368 continue findCert
369 }
370
371 if len(certReq.certificateAuthorities) == 0 {
372 // they gave us an empty list, so just take the
373 // first RSA cert from c.config.Certificates
374 chainToSend = &chain
375 break findCert
376 }
377
378 for _, ca := range certReq.certificateAuthorities {
379 if bytes.Equal(x509Cert.RawIssuer, ca) {
380 chainToSend = &chain
381 break findCert
382 }
383 }
384 }
385 }
386
387 msg, err = c.readHandshake()
388 if err != nil {
389 return err
390 }
391 }
392
393 shd, ok := msg.(*serverHelloDoneMsg)
394 if !ok {
395 c.sendAlert(alertUnexpectedMessage)
396 return unexpectedMessageError(shd, msg)
397 }
398 hs.finishedHash.Write(shd.marshal())
399
400 // If the server requested a certificate then we have to send a
401 // Certificate message, even if it's empty because we don't have a
402 // certificate to send.
403 if certRequested {
404 certMsg = new(certificateMsg)
405 if chainToSend != nil {
406 certMsg.certificates = chainToSend.Certificate
407 }
408 hs.finishedHash.Write(certMsg.marshal())
409 c.writeRecord(recordTypeHandshake, certMsg.marshal())
410 }
411
412 preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, certs[0])
413 if err != nil {
414 c.sendAlert(alertInternalError)
415 return err
416 }
417 if ckx != nil {
David Benjaminf3ec83d2014-07-21 22:42:34 -0400418 if c.config.Bugs.EarlyChangeCipherSpec < 2 {
419 hs.finishedHash.Write(ckx.marshal())
420 }
Adam Langley95c29f32014-06-20 12:00:00 -0700421 c.writeRecord(recordTypeHandshake, ckx.marshal())
422 }
423
424 if chainToSend != nil {
425 var signed []byte
426 certVerify := &certificateVerifyMsg{
427 hasSignatureAndHash: c.vers >= VersionTLS12,
428 }
429
430 switch key := c.config.Certificates[0].PrivateKey.(type) {
431 case *ecdsa.PrivateKey:
David Benjaminde620d92014-07-18 15:03:41 -0400432 certVerify.signatureAndHash, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.signatureAndHashes, signatureECDSA)
433 if err != nil {
434 break
435 }
436 var digest []byte
437 digest, _, err = hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash)
438 if err != nil {
439 break
440 }
441 var r, s *big.Int
442 r, s, err = ecdsa.Sign(c.config.rand(), key, digest)
Adam Langley95c29f32014-06-20 12:00:00 -0700443 if err == nil {
444 signed, err = asn1.Marshal(ecdsaSignature{r, s})
445 }
Adam Langley95c29f32014-06-20 12:00:00 -0700446 case *rsa.PrivateKey:
David Benjaminde620d92014-07-18 15:03:41 -0400447 certVerify.signatureAndHash, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.signatureAndHashes, signatureRSA)
448 if err != nil {
449 break
450 }
451 var digest []byte
452 var hashFunc crypto.Hash
453 digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash)
454 if err != nil {
455 break
456 }
Adam Langley95c29f32014-06-20 12:00:00 -0700457 signed, err = rsa.SignPKCS1v15(c.config.rand(), key, hashFunc, digest)
Adam Langley95c29f32014-06-20 12:00:00 -0700458 default:
459 err = errors.New("unknown private key type")
460 }
461 if err != nil {
462 c.sendAlert(alertInternalError)
463 return errors.New("tls: failed to sign handshake with client certificate: " + err.Error())
464 }
465 certVerify.signature = signed
466
467 hs.finishedHash.Write(certVerify.marshal())
468 c.writeRecord(recordTypeHandshake, certVerify.marshal())
469 }
470
471 hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
472 return nil
473}
474
475func (hs *clientHandshakeState) establishKeys() error {
476 c := hs.c
477
478 clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
479 keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
480 var clientCipher, serverCipher interface{}
481 var clientHash, serverHash macFunction
482 if hs.suite.cipher != nil {
483 clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
484 clientHash = hs.suite.mac(c.vers, clientMAC)
485 serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */)
486 serverHash = hs.suite.mac(c.vers, serverMAC)
487 } else {
488 clientCipher = hs.suite.aead(clientKey, clientIV)
489 serverCipher = hs.suite.aead(serverKey, serverIV)
490 }
491
492 c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
493 c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
494 return nil
495}
496
497func (hs *clientHandshakeState) serverResumedSession() bool {
498 // If the server responded with the same sessionId then it means the
499 // sessionTicket is being used to resume a TLS session.
500 return hs.session != nil && hs.hello.sessionId != nil &&
501 bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId)
502}
503
504func (hs *clientHandshakeState) processServerHello() (bool, error) {
505 c := hs.c
506
507 if hs.serverHello.compressionMethod != compressionNone {
508 c.sendAlert(alertUnexpectedMessage)
509 return false, errors.New("tls: server selected unsupported compression format")
510 }
511
512 if !hs.hello.nextProtoNeg && hs.serverHello.nextProtoNeg {
513 c.sendAlert(alertHandshakeFailure)
514 return false, errors.New("server advertised unrequested NPN extension")
515 }
516
517 if hs.serverResumedSession() {
518 // Restore masterSecret and peerCerts from previous state
519 hs.masterSecret = hs.session.masterSecret
520 c.peerCertificates = hs.session.serverCertificates
521 return true, nil
522 }
523 return false, nil
524}
525
526func (hs *clientHandshakeState) readFinished() error {
527 c := hs.c
528
529 c.readRecord(recordTypeChangeCipherSpec)
530 if err := c.in.error(); err != nil {
531 return err
532 }
533
534 msg, err := c.readHandshake()
535 if err != nil {
536 return err
537 }
538 serverFinished, ok := msg.(*finishedMsg)
539 if !ok {
540 c.sendAlert(alertUnexpectedMessage)
541 return unexpectedMessageError(serverFinished, msg)
542 }
543
David Benjaminf3ec83d2014-07-21 22:42:34 -0400544 if c.config.Bugs.EarlyChangeCipherSpec == 0 {
545 verify := hs.finishedHash.serverSum(hs.masterSecret)
546 if len(verify) != len(serverFinished.verifyData) ||
547 subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
548 c.sendAlert(alertHandshakeFailure)
549 return errors.New("tls: server's Finished message was incorrect")
550 }
Adam Langley95c29f32014-06-20 12:00:00 -0700551 }
552 hs.finishedHash.Write(serverFinished.marshal())
553 return nil
554}
555
556func (hs *clientHandshakeState) readSessionTicket() error {
557 if !hs.serverHello.ticketSupported {
558 return nil
559 }
560
561 c := hs.c
562 msg, err := c.readHandshake()
563 if err != nil {
564 return err
565 }
566 sessionTicketMsg, ok := msg.(*newSessionTicketMsg)
567 if !ok {
568 c.sendAlert(alertUnexpectedMessage)
569 return unexpectedMessageError(sessionTicketMsg, msg)
570 }
571 hs.finishedHash.Write(sessionTicketMsg.marshal())
572
573 hs.session = &ClientSessionState{
574 sessionTicket: sessionTicketMsg.ticket,
575 vers: c.vers,
576 cipherSuite: hs.suite.id,
577 masterSecret: hs.masterSecret,
578 serverCertificates: c.peerCertificates,
579 }
580
581 return nil
582}
583
584func (hs *clientHandshakeState) sendFinished() error {
585 c := hs.c
586
David Benjaminf3ec83d2014-07-21 22:42:34 -0400587 if !c.config.Bugs.SkipChangeCipherSpec &&
588 c.config.Bugs.EarlyChangeCipherSpec == 0 {
David Benjamina0e52232014-07-19 17:39:58 -0400589 c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
590 }
Adam Langley95c29f32014-06-20 12:00:00 -0700591 if hs.serverHello.nextProtoNeg {
592 nextProto := new(nextProtoMsg)
593 proto, fallback := mutualProtocol(c.config.NextProtos, hs.serverHello.nextProtos)
594 nextProto.proto = proto
595 c.clientProtocol = proto
596 c.clientProtocolFallback = fallback
597
598 hs.finishedHash.Write(nextProto.marshal())
599 c.writeRecord(recordTypeHandshake, nextProto.marshal())
600 }
601
602 finished := new(finishedMsg)
David Benjaminf3ec83d2014-07-21 22:42:34 -0400603 if c.config.Bugs.EarlyChangeCipherSpec == 2 {
604 finished.verifyData = hs.finishedHash.clientSum(nil)
605 } else {
606 finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
607 }
Adam Langley95c29f32014-06-20 12:00:00 -0700608 hs.finishedHash.Write(finished.marshal())
609 c.writeRecord(recordTypeHandshake, finished.marshal())
610 return nil
611}
612
613// clientSessionCacheKey returns a key used to cache sessionTickets that could
614// be used to resume previously negotiated TLS sessions with a server.
615func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
616 if len(config.ServerName) > 0 {
617 return config.ServerName
618 }
619 return serverAddr.String()
620}
621
622// mutualProtocol finds the mutual Next Protocol Negotiation protocol given the
623// set of client and server supported protocols. The set of client supported
624// protocols must not be empty. It returns the resulting protocol and flag
625// indicating if the fallback case was reached.
626func mutualProtocol(clientProtos, serverProtos []string) (string, bool) {
627 for _, s := range serverProtos {
628 for _, c := range clientProtos {
629 if s == c {
630 return s, false
631 }
632 }
633 }
634
635 return clientProtos[0], true
636}