2009-11-05 23:44:32 +00:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package tls
|
|
|
|
|
|
|
|
import (
|
2011-02-01 16:02:48 +00:00
|
|
|
"crypto"
|
2009-12-15 23:33:31 +00:00
|
|
|
"crypto/rsa"
|
|
|
|
"crypto/subtle"
|
2010-08-16 16:22:22 +01:00
|
|
|
"crypto/x509"
|
2011-11-02 02:04:37 +00:00
|
|
|
"errors"
|
2009-12-15 23:33:31 +00:00
|
|
|
"io"
|
2009-11-05 23:44:32 +00:00
|
|
|
)
|
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
// serverHandshakeState contains details of a server handshake in progress.
|
|
|
|
// It's discarded once the handshake has completed.
|
|
|
|
type serverHandshakeState struct {
|
|
|
|
c *Conn
|
|
|
|
clientHello *clientHelloMsg
|
|
|
|
hello *serverHelloMsg
|
|
|
|
suite *cipherSuite
|
|
|
|
ellipticOk bool
|
|
|
|
sessionState *sessionState
|
|
|
|
finishedHash finishedHash
|
|
|
|
masterSecret []byte
|
|
|
|
certsFromClient [][]byte
|
|
|
|
}
|
|
|
|
|
|
|
|
// serverHandshake performs a TLS handshake as a server.
|
2011-11-02 02:04:37 +00:00
|
|
|
func (c *Conn) serverHandshake() error {
|
2010-04-27 06:19:04 +01:00
|
|
|
config := c.config
|
2012-09-24 21:52:43 +01:00
|
|
|
|
|
|
|
// If this is the first server handshake, we generate a random key to
|
|
|
|
// encrypt the tickets with.
|
2013-03-21 03:53:38 +00:00
|
|
|
config.serverInitOnce.Do(config.serverInit)
|
2012-09-24 21:52:43 +01:00
|
|
|
|
|
|
|
hs := serverHandshakeState{
|
|
|
|
c: c,
|
|
|
|
}
|
|
|
|
isResume, err := hs.readClientHello()
|
2010-04-27 06:19:04 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2012-09-24 21:52:43 +01:00
|
|
|
|
|
|
|
// For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3
|
|
|
|
if isResume {
|
|
|
|
// The client has included a session ticket and so we do an abbreviated handshake.
|
|
|
|
if err := hs.doResumeHandshake(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := hs.establishKeys(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := hs.sendFinished(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := hs.readFinished(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
c.didResume = true
|
|
|
|
} else {
|
|
|
|
// The client didn't include a session ticket, or it wasn't
|
|
|
|
// valid so we do a full handshake.
|
|
|
|
if err := hs.doFullHandshake(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := hs.establishKeys(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := hs.readFinished(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := hs.sendSessionTicket(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := hs.sendFinished(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c.handshakeComplete = true
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// readClientHello reads a ClientHello message from the client and decides
|
|
|
|
// whether we will perform session resumption.
|
|
|
|
func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
|
|
|
|
config := hs.c.config
|
|
|
|
c := hs.c
|
|
|
|
|
|
|
|
msg, err := c.readHandshake()
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
var ok bool
|
|
|
|
hs.clientHello, ok = msg.(*clientHelloMsg)
|
2009-11-05 23:44:32 +00:00
|
|
|
if !ok {
|
2012-09-24 21:52:43 +01:00
|
|
|
return false, c.sendAlert(alertUnexpectedMessage)
|
2009-11-05 23:44:32 +00:00
|
|
|
}
|
2013-06-05 01:02:22 +01:00
|
|
|
c.vers, ok = config.mutualVersion(hs.clientHello.vers)
|
2009-11-05 23:44:32 +00:00
|
|
|
if !ok {
|
2012-09-24 21:52:43 +01:00
|
|
|
return false, c.sendAlert(alertProtocolVersion)
|
2009-11-05 23:44:32 +00:00
|
|
|
}
|
2010-04-27 06:19:04 +01:00
|
|
|
c.haveVers = true
|
2009-11-05 23:44:32 +00:00
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.finishedHash = newFinishedHash(c.vers)
|
|
|
|
hs.finishedHash.Write(hs.clientHello.marshal())
|
2009-11-05 23:44:32 +00:00
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.hello = new(serverHelloMsg)
|
2009-11-05 23:44:32 +00:00
|
|
|
|
2010-12-16 22:10:50 +00:00
|
|
|
supportedCurve := false
|
|
|
|
Curves:
|
2012-09-24 21:52:43 +01:00
|
|
|
for _, curve := range hs.clientHello.supportedCurves {
|
2010-12-16 22:10:50 +00:00
|
|
|
switch curve {
|
|
|
|
case curveP256, curveP384, curveP521:
|
|
|
|
supportedCurve = true
|
|
|
|
break Curves
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
supportedPointFormat := false
|
2012-09-24 21:52:43 +01:00
|
|
|
for _, pointFormat := range hs.clientHello.supportedPoints {
|
2010-12-16 22:10:50 +00:00
|
|
|
if pointFormat == pointFormatUncompressed {
|
|
|
|
supportedPointFormat = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.ellipticOk = supportedCurve && supportedPointFormat
|
2009-11-05 23:44:32 +00:00
|
|
|
|
2009-12-15 23:33:31 +00:00
|
|
|
foundCompression := false
|
2009-11-05 23:44:32 +00:00
|
|
|
// We only support null compression, so check that the client offered it.
|
2012-09-24 21:52:43 +01:00
|
|
|
for _, compression := range hs.clientHello.compressionMethods {
|
2009-11-05 23:44:32 +00:00
|
|
|
if compression == compressionNone {
|
2009-12-15 23:33:31 +00:00
|
|
|
foundCompression = true
|
|
|
|
break
|
2009-11-05 23:44:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
if !foundCompression {
|
|
|
|
return false, c.sendAlert(alertHandshakeFailure)
|
2009-12-15 23:33:31 +00:00
|
|
|
}
|
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.hello.vers = c.vers
|
2011-11-30 17:01:46 +00:00
|
|
|
t := uint32(config.time().Unix())
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.hello.random = make([]byte, 32)
|
|
|
|
hs.hello.random[0] = byte(t >> 24)
|
|
|
|
hs.hello.random[1] = byte(t >> 16)
|
|
|
|
hs.hello.random[2] = byte(t >> 8)
|
|
|
|
hs.hello.random[3] = byte(t)
|
|
|
|
_, err = io.ReadFull(config.rand(), hs.hello.random[4:])
|
2009-11-05 23:44:32 +00:00
|
|
|
if err != nil {
|
2012-09-24 21:52:43 +01:00
|
|
|
return false, c.sendAlert(alertInternalError)
|
|
|
|
}
|
|
|
|
hs.hello.compressionMethod = compressionNone
|
|
|
|
if len(hs.clientHello.serverName) > 0 {
|
|
|
|
c.serverName = hs.clientHello.serverName
|
|
|
|
}
|
2013-05-21 15:47:31 +01:00
|
|
|
// Although sending an empty NPN extension is reasonable, Firefox has
|
|
|
|
// had a bug around this. Best to send nothing at all if
|
|
|
|
// config.NextProtos is empty. See
|
|
|
|
// https://code.google.com/p/go/issues/detail?id=5445.
|
|
|
|
if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.hello.nextProtoNeg = true
|
|
|
|
hs.hello.nextProtos = config.NextProtos
|
|
|
|
}
|
|
|
|
|
|
|
|
if hs.checkForResumption() {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
2013-01-22 15:10:38 +00:00
|
|
|
var preferenceList, supportedList []uint16
|
|
|
|
if c.config.PreferServerCipherSuites {
|
|
|
|
preferenceList = c.config.cipherSuites()
|
|
|
|
supportedList = hs.clientHello.cipherSuites
|
|
|
|
} else {
|
|
|
|
preferenceList = hs.clientHello.cipherSuites
|
|
|
|
supportedList = c.config.cipherSuites()
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, id := range preferenceList {
|
|
|
|
if hs.suite = c.tryCipherSuite(id, supportedList, hs.ellipticOk); hs.suite != nil {
|
2012-09-24 21:52:43 +01:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if hs.suite == nil {
|
|
|
|
return false, c.sendAlert(alertHandshakeFailure)
|
|
|
|
}
|
|
|
|
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// checkForResumption returns true if we should perform resumption on this connection.
|
|
|
|
func (hs *serverHandshakeState) checkForResumption() bool {
|
|
|
|
c := hs.c
|
|
|
|
|
|
|
|
var ok bool
|
|
|
|
if hs.sessionState, ok = c.decryptTicket(hs.clientHello.sessionTicket); !ok {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if hs.sessionState.vers > hs.clientHello.vers {
|
|
|
|
return false
|
|
|
|
}
|
2013-06-05 01:02:22 +01:00
|
|
|
if vers, ok := c.config.mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers {
|
2012-09-24 21:52:43 +01:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
cipherSuiteOk := false
|
|
|
|
// Check that the client is still offering the ciphersuite in the session.
|
|
|
|
for _, id := range hs.clientHello.cipherSuites {
|
|
|
|
if id == hs.sessionState.cipherSuite {
|
|
|
|
cipherSuiteOk = true
|
|
|
|
break
|
|
|
|
}
|
2009-11-05 23:44:32 +00:00
|
|
|
}
|
2012-09-24 21:52:43 +01:00
|
|
|
if !cipherSuiteOk {
|
|
|
|
return false
|
2009-12-23 19:13:09 +00:00
|
|
|
}
|
2009-11-05 23:44:32 +00:00
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
// Check that we also support the ciphersuite from the session.
|
2013-01-22 15:10:38 +00:00
|
|
|
hs.suite = c.tryCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.ellipticOk)
|
2012-09-24 21:52:43 +01:00
|
|
|
if hs.suite == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
sessionHasClientCerts := len(hs.sessionState.certificates) != 0
|
|
|
|
needClientCerts := c.config.ClientAuth == RequireAnyClientCert || c.config.ClientAuth == RequireAndVerifyClientCert
|
|
|
|
if needClientCerts && !sessionHasClientCerts {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if sessionHasClientCerts && c.config.ClientAuth == NoClientCert {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (hs *serverHandshakeState) doResumeHandshake() error {
|
|
|
|
c := hs.c
|
|
|
|
|
|
|
|
hs.hello.cipherSuite = hs.suite.id
|
|
|
|
// We echo the client's session ID in the ServerHello to let it know
|
|
|
|
// that we're doing a resumption.
|
|
|
|
hs.hello.sessionId = hs.clientHello.sessionId
|
|
|
|
hs.finishedHash.Write(hs.hello.marshal())
|
|
|
|
c.writeRecord(recordTypeHandshake, hs.hello.marshal())
|
|
|
|
|
|
|
|
if len(hs.sessionState.certificates) > 0 {
|
|
|
|
if _, err := hs.processCertsFromClient(hs.sessionState.certificates); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
hs.masterSecret = hs.sessionState.masterSecret
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (hs *serverHandshakeState) doFullHandshake() error {
|
|
|
|
config := hs.c.config
|
|
|
|
c := hs.c
|
|
|
|
|
2009-11-05 23:44:32 +00:00
|
|
|
if len(config.Certificates) == 0 {
|
2010-04-27 06:19:04 +01:00
|
|
|
return c.sendAlert(alertInternalError)
|
2009-11-05 23:44:32 +00:00
|
|
|
}
|
2012-04-12 17:35:21 +01:00
|
|
|
cert := &config.Certificates[0]
|
2012-09-24 21:52:43 +01:00
|
|
|
if len(hs.clientHello.serverName) > 0 {
|
|
|
|
cert = config.getCertificateForName(hs.clientHello.serverName)
|
2011-10-08 15:06:53 +01:00
|
|
|
}
|
2012-04-12 17:35:21 +01:00
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
if hs.clientHello.ocspStapling && len(cert.OCSPStaple) > 0 {
|
|
|
|
hs.hello.ocspStapling = true
|
2012-04-12 17:35:21 +01:00
|
|
|
}
|
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled
|
|
|
|
hs.hello.cipherSuite = hs.suite.id
|
|
|
|
hs.finishedHash.Write(hs.hello.marshal())
|
|
|
|
c.writeRecord(recordTypeHandshake, hs.hello.marshal())
|
2012-04-12 17:35:21 +01:00
|
|
|
|
|
|
|
certMsg := new(certificateMsg)
|
|
|
|
certMsg.certificates = cert.Certificate
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.finishedHash.Write(certMsg.marshal())
|
2010-04-27 06:19:04 +01:00
|
|
|
c.writeRecord(recordTypeHandshake, certMsg.marshal())
|
2009-11-05 23:44:32 +00:00
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
if hs.hello.ocspStapling {
|
2011-04-14 19:47:28 +01:00
|
|
|
certStatus := new(certificateStatusMsg)
|
|
|
|
certStatus.statusType = statusTypeOCSP
|
2012-04-12 17:35:21 +01:00
|
|
|
certStatus.response = cert.OCSPStaple
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.finishedHash.Write(certStatus.marshal())
|
2011-04-14 19:47:28 +01:00
|
|
|
c.writeRecord(recordTypeHandshake, certStatus.marshal())
|
|
|
|
}
|
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
keyAgreement := hs.suite.ka()
|
|
|
|
skx, err := keyAgreement.generateServerKeyExchange(config, cert, hs.clientHello, hs.hello)
|
2010-12-16 22:10:50 +00:00
|
|
|
if err != nil {
|
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if skx != nil {
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.finishedHash.Write(skx.marshal())
|
2010-12-16 22:10:50 +00:00
|
|
|
c.writeRecord(recordTypeHandshake, skx.marshal())
|
|
|
|
}
|
|
|
|
|
2012-01-05 17:05:38 +00:00
|
|
|
if config.ClientAuth >= RequestClientCert {
|
2010-08-16 16:22:22 +01:00
|
|
|
// Request a client certificate
|
|
|
|
certReq := new(certificateRequestMsg)
|
|
|
|
certReq.certificateTypes = []byte{certTypeRSASign}
|
2012-01-05 17:05:38 +00:00
|
|
|
|
2010-08-16 16:22:22 +01:00
|
|
|
// An empty list of certificateAuthorities signals to
|
|
|
|
// the client that it may send any certificate in response
|
2012-01-05 17:05:38 +00:00
|
|
|
// to our request. When we know the CAs we trust, then
|
|
|
|
// we can send them down, so that the client can choose
|
|
|
|
// an appropriate certificate to give to us.
|
|
|
|
if config.ClientCAs != nil {
|
|
|
|
certReq.certificateAuthorities = config.ClientCAs.Subjects()
|
|
|
|
}
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.finishedHash.Write(certReq.marshal())
|
2010-08-16 16:22:22 +01:00
|
|
|
c.writeRecord(recordTypeHandshake, certReq.marshal())
|
|
|
|
}
|
|
|
|
|
2009-12-15 23:33:31 +00:00
|
|
|
helloDone := new(serverHelloDoneMsg)
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.finishedHash.Write(helloDone.marshal())
|
2010-04-27 06:19:04 +01:00
|
|
|
c.writeRecord(recordTypeHandshake, helloDone.marshal())
|
2009-11-05 23:44:32 +00:00
|
|
|
|
2012-01-05 17:05:38 +00:00
|
|
|
var pub *rsa.PublicKey // public key for client auth, if any
|
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
msg, err := c.readHandshake()
|
2012-01-05 17:05:38 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
var ok bool
|
2012-01-05 17:05:38 +00:00
|
|
|
// If we requested a client certificate, then the client must send a
|
|
|
|
// certificate message, even if it's empty.
|
|
|
|
if config.ClientAuth >= RequestClientCert {
|
|
|
|
if certMsg, ok = msg.(*certificateMsg); !ok {
|
|
|
|
return c.sendAlert(alertHandshakeFailure)
|
2010-08-16 16:22:22 +01:00
|
|
|
}
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.finishedHash.Write(certMsg.marshal())
|
2010-08-16 16:22:22 +01:00
|
|
|
|
2012-01-05 17:05:38 +00:00
|
|
|
if len(certMsg.certificates) == 0 {
|
|
|
|
// The client didn't actually send a certificate
|
|
|
|
switch config.ClientAuth {
|
|
|
|
case RequireAnyClientCert, RequireAndVerifyClientCert:
|
|
|
|
c.sendAlert(alertBadCertificate)
|
|
|
|
return errors.New("tls: client didn't provide a certificate")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
pub, err = hs.processCertsFromClient(certMsg.certificates)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2010-08-16 16:22:22 +01:00
|
|
|
}
|
2012-01-05 17:05:38 +00:00
|
|
|
|
|
|
|
msg, err = c.readHandshake()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2010-08-16 16:22:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get client key exchange
|
2010-04-27 06:19:04 +01:00
|
|
|
ckx, ok := msg.(*clientKeyExchangeMsg)
|
2009-11-05 23:44:32 +00:00
|
|
|
if !ok {
|
2010-04-27 06:19:04 +01:00
|
|
|
return c.sendAlert(alertUnexpectedMessage)
|
2009-11-05 23:44:32 +00:00
|
|
|
}
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.finishedHash.Write(ckx.marshal())
|
2009-11-05 23:44:32 +00:00
|
|
|
|
2010-08-16 16:22:22 +01:00
|
|
|
// If we received a client cert in response to our certificate request message,
|
|
|
|
// the client will send us a certificateVerifyMsg immediately after the
|
2011-05-18 18:14:56 +01:00
|
|
|
// clientKeyExchangeMsg. This message is a MD5SHA1 digest of all preceding
|
2010-08-16 16:22:22 +01:00
|
|
|
// handshake-layer messages that is signed using the private key corresponding
|
|
|
|
// to the client's certificate. This allows us to verify that the client is in
|
2011-05-18 18:14:56 +01:00
|
|
|
// possession of the private key of the certificate.
|
2010-08-16 16:22:22 +01:00
|
|
|
if len(c.peerCertificates) > 0 {
|
|
|
|
msg, err = c.readHandshake()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
certVerify, ok := msg.(*certificateVerifyMsg)
|
|
|
|
if !ok {
|
|
|
|
return c.sendAlert(alertUnexpectedMessage)
|
|
|
|
}
|
|
|
|
|
2011-12-06 23:25:14 +00:00
|
|
|
digest := make([]byte, 0, 36)
|
2012-09-24 21:52:43 +01:00
|
|
|
digest = hs.finishedHash.serverMD5.Sum(digest)
|
|
|
|
digest = hs.finishedHash.serverSHA1.Sum(digest)
|
2011-02-01 16:02:48 +00:00
|
|
|
err = rsa.VerifyPKCS1v15(pub, crypto.MD5SHA1, digest, certVerify.signature)
|
2010-08-16 16:22:22 +01:00
|
|
|
if err != nil {
|
2010-10-11 15:39:56 +01:00
|
|
|
c.sendAlert(alertBadCertificate)
|
2011-11-02 02:04:37 +00:00
|
|
|
return errors.New("could not validate signature of connection nonces: " + err.Error())
|
2010-08-16 16:22:22 +01:00
|
|
|
}
|
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.finishedHash.Write(certVerify.marshal())
|
2010-08-16 16:22:22 +01:00
|
|
|
}
|
|
|
|
|
2012-04-12 17:35:21 +01:00
|
|
|
preMasterSecret, err := keyAgreement.processClientKeyExchange(config, cert, ckx, c.vers)
|
2009-11-05 23:44:32 +00:00
|
|
|
if err != nil {
|
2010-12-16 22:10:50 +00:00
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
return err
|
2009-11-05 23:44:32 +00:00
|
|
|
}
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.masterSecret = masterFromPreMasterSecret(c.vers, preMasterSecret, hs.clientHello.random, hs.hello.random)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (hs *serverHandshakeState) establishKeys() error {
|
|
|
|
c := hs.c
|
2009-11-05 23:44:32 +00:00
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
|
|
|
|
keysFromMasterSecret(c.vers, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
|
2009-11-05 23:44:32 +00:00
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
clientCipher := hs.suite.cipher(clientKey, clientIV, true /* for reading */)
|
|
|
|
clientHash := hs.suite.mac(c.vers, clientMAC)
|
2011-09-14 20:32:19 +01:00
|
|
|
c.in.prepareCipherSpec(c.vers, clientCipher, clientHash)
|
2012-09-24 21:52:43 +01:00
|
|
|
|
|
|
|
serverCipher := hs.suite.cipher(serverKey, serverIV, false /* not for reading */)
|
|
|
|
serverHash := hs.suite.mac(c.vers, serverMAC)
|
|
|
|
c.out.prepareCipherSpec(c.vers, serverCipher, serverHash)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (hs *serverHandshakeState) readFinished() error {
|
|
|
|
c := hs.c
|
|
|
|
|
2010-04-27 06:19:04 +01:00
|
|
|
c.readRecord(recordTypeChangeCipherSpec)
|
|
|
|
if err := c.error(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2009-11-05 23:44:32 +00:00
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
if hs.hello.nextProtoNeg {
|
|
|
|
msg, err := c.readHandshake()
|
2010-04-27 06:19:04 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
nextProto, ok := msg.(*nextProtoMsg)
|
2009-12-23 19:13:09 +00:00
|
|
|
if !ok {
|
2010-04-27 06:19:04 +01:00
|
|
|
return c.sendAlert(alertUnexpectedMessage)
|
2009-12-23 19:13:09 +00:00
|
|
|
}
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.finishedHash.Write(nextProto.marshal())
|
2010-04-27 06:19:04 +01:00
|
|
|
c.clientProtocol = nextProto.proto
|
2009-12-23 19:13:09 +00:00
|
|
|
}
|
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
msg, err := c.readHandshake()
|
2010-04-27 06:19:04 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
clientFinished, ok := msg.(*finishedMsg)
|
2009-11-05 23:44:32 +00:00
|
|
|
if !ok {
|
2010-04-27 06:19:04 +01:00
|
|
|
return c.sendAlert(alertUnexpectedMessage)
|
2009-11-05 23:44:32 +00:00
|
|
|
}
|
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
verify := hs.finishedHash.clientSum(hs.masterSecret)
|
2009-11-05 23:44:32 +00:00
|
|
|
if len(verify) != len(clientFinished.verifyData) ||
|
|
|
|
subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
|
2010-04-27 06:19:04 +01:00
|
|
|
return c.sendAlert(alertHandshakeFailure)
|
2009-11-05 23:44:32 +00:00
|
|
|
}
|
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
hs.finishedHash.Write(clientFinished.marshal())
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (hs *serverHandshakeState) sendSessionTicket() error {
|
|
|
|
if !hs.hello.ticketSupported {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
c := hs.c
|
|
|
|
m := new(newSessionTicketMsg)
|
|
|
|
|
|
|
|
var err error
|
|
|
|
state := sessionState{
|
|
|
|
vers: c.vers,
|
|
|
|
cipherSuite: hs.suite.id,
|
|
|
|
masterSecret: hs.masterSecret,
|
|
|
|
certificates: hs.certsFromClient,
|
|
|
|
}
|
|
|
|
m.ticket, err = c.encryptTicket(&state)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
hs.finishedHash.Write(m.marshal())
|
|
|
|
c.writeRecord(recordTypeHandshake, m.marshal())
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (hs *serverHandshakeState) sendFinished() error {
|
|
|
|
c := hs.c
|
2009-11-05 23:44:32 +00:00
|
|
|
|
2010-04-27 06:19:04 +01:00
|
|
|
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
|
2009-11-05 23:44:32 +00:00
|
|
|
|
2009-12-15 23:33:31 +00:00
|
|
|
finished := new(finishedMsg)
|
2012-09-24 21:52:43 +01:00
|
|
|
finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
|
|
|
|
hs.finishedHash.Write(finished.marshal())
|
2010-04-27 06:19:04 +01:00
|
|
|
c.writeRecord(recordTypeHandshake, finished.marshal())
|
2009-11-05 23:44:32 +00:00
|
|
|
|
2012-09-24 21:52:43 +01:00
|
|
|
c.cipherSuite = hs.suite.id
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// processCertsFromClient takes a chain of client certificates either from a
|
|
|
|
// Certificates message or from a sessionState and verifies them. It returns
|
|
|
|
// the public key of the leaf certificate.
|
|
|
|
func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (*rsa.PublicKey, error) {
|
|
|
|
c := hs.c
|
|
|
|
|
|
|
|
hs.certsFromClient = certificates
|
|
|
|
certs := make([]*x509.Certificate, len(certificates))
|
|
|
|
var err error
|
|
|
|
for i, asn1Data := range certificates {
|
|
|
|
if certs[i], err = x509.ParseCertificate(asn1Data); err != nil {
|
|
|
|
c.sendAlert(alertBadCertificate)
|
|
|
|
return nil, errors.New("tls: failed to parse client certificate: " + err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 {
|
|
|
|
opts := x509.VerifyOptions{
|
|
|
|
Roots: c.config.ClientCAs,
|
|
|
|
CurrentTime: c.config.time(),
|
|
|
|
Intermediates: x509.NewCertPool(),
|
|
|
|
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, cert := range certs[1:] {
|
|
|
|
opts.Intermediates.AddCert(cert)
|
|
|
|
}
|
|
|
|
|
|
|
|
chains, err := certs[0].Verify(opts)
|
|
|
|
if err != nil {
|
|
|
|
c.sendAlert(alertBadCertificate)
|
|
|
|
return nil, errors.New("tls: failed to verify client's certificate: " + err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
ok := false
|
|
|
|
for _, ku := range certs[0].ExtKeyUsage {
|
|
|
|
if ku == x509.ExtKeyUsageClientAuth {
|
|
|
|
ok = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !ok {
|
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
return nil, errors.New("tls: client's certificate's extended key usage doesn't permit it to be used for client authentication")
|
|
|
|
}
|
|
|
|
|
|
|
|
c.verifiedChains = chains
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(certs) > 0 {
|
|
|
|
pub, ok := certs[0].PublicKey.(*rsa.PublicKey)
|
|
|
|
if !ok {
|
|
|
|
return nil, c.sendAlert(alertUnsupportedCertificate)
|
|
|
|
}
|
|
|
|
c.peerCertificates = certs
|
|
|
|
return pub, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// tryCipherSuite returns a cipherSuite with the given id if that cipher suite
|
|
|
|
// is acceptable to use.
|
2013-01-22 15:10:38 +00:00
|
|
|
func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, ellipticOk bool) *cipherSuite {
|
|
|
|
for _, supported := range supportedCipherSuites {
|
2012-09-24 21:52:43 +01:00
|
|
|
if id == supported {
|
|
|
|
var candidate *cipherSuite
|
|
|
|
|
|
|
|
for _, s := range cipherSuites {
|
|
|
|
if s.id == id {
|
|
|
|
candidate = s
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if candidate == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
// Don't select a ciphersuite which we can't
|
|
|
|
// support for this client.
|
|
|
|
if candidate.elliptic && !ellipticOk {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return candidate
|
|
|
|
}
|
|
|
|
}
|
2009-11-05 23:44:32 +00:00
|
|
|
|
2010-04-27 06:19:04 +01:00
|
|
|
return nil
|
2009-11-05 23:44:32 +00:00
|
|
|
}
|