"fmt"
"io"
"sync/atomic"
+ "time"
)
// serverHandshakeState contains details of a server handshake in progress.
// serverHandshake performs a TLS handshake as a server.
func (c *Conn) serverHandshake() error {
- // If this is the first server handshake, we generate a random key to
- // encrypt the tickets with.
- c.config.serverInitOnce.Do(func() { c.config.serverInit(nil) })
-
clientHello, err := c.readClientHello()
if err != nil {
return err
c.buffering = true
if hs.checkForResumption() {
// The client has included a session ticket and so we do an abbreviated handshake.
+ c.didResume = true
if err := hs.doResumeHandshake(); err != nil {
return err
}
if err := hs.establishKeys(); err != nil {
return err
}
- // ticketSupported is set in a resumption handshake if the
- // ticket from the client was encrypted with an old session
- // ticket key and thus a refreshed ticket should be sent.
- if hs.hello.ticketSupported {
- if err := hs.sendSessionTicket(); err != nil {
- return err
- }
+ if err := hs.sendSessionTicket(); err != nil {
+ return err
}
if err := hs.sendFinished(c.serverFinished[:]); err != nil {
return err
if err := hs.readFinished(nil); 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.
return nil, unexpectedMessageError(clientHello, msg)
}
+ var configForClient *Config
+ originalConfig := c.config
if c.config.GetConfigForClient != nil {
chi := clientHelloInfo(c, clientHello)
- if newConfig, err := c.config.GetConfigForClient(chi); err != nil {
+ if configForClient, err = c.config.GetConfigForClient(chi); err != nil {
c.sendAlert(alertInternalError)
return nil, err
- } else if newConfig != nil {
- newConfig.serverInitOnce.Do(func() { newConfig.serverInit(c.config) })
- c.config = newConfig
+ } else if configForClient != nil {
+ c.config = configForClient
}
}
+ c.ticketKeys = originalConfig.ticketKeys(configForClient)
clientVersions := clientHello.supportedVersions
if len(clientHello.supportedVersions) == 0 {
c.sendAlert(alertHandshakeFailure)
return errors.New("tls: no cipher suite supported by both client and server")
}
+ c.cipherSuite = hs.suite.id
for _, id := range hs.clientHello.cipherSuites {
if id == TLS_FALLBACK_SCSV {
return false
}
+ createdAt := time.Unix(int64(hs.sessionState.createdAt), 0)
+ if c.config.time().Sub(createdAt) > maxSessionTicketLifetime {
+ return false
+ }
+
// Never resume a session for a different TLS version.
if c.vers != hs.sessionState.vers {
return false
c := hs.c
hs.hello.cipherSuite = hs.suite.id
+ c.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
return err
}
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
hs.masterSecret = hs.sessionState.masterSecret
return nil
return err
}
}
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
// Get client key exchange
ckx, ok := msg.(*clientKeyExchangeMsg)
}
func (hs *serverHandshakeState) sendSessionTicket() error {
+ // ticketSupported is set in a resumption handshake if the
+ // ticket from the client was encrypted with an old session
+ // ticket key and thus a refreshed ticket should be sent.
if !hs.hello.ticketSupported {
return nil
}
c := hs.c
m := new(newSessionTicketMsg)
+ createdAt := uint64(c.config.time().Unix())
+ if hs.sessionState != nil {
+ // If this is re-wrapping an old key, then keep
+ // the original time it was created.
+ createdAt = hs.sessionState.createdAt
+ }
+
var certsFromClient [][]byte
for _, cert := range c.peerCertificates {
certsFromClient = append(certsFromClient, cert.Raw)
state := sessionState{
vers: c.vers,
cipherSuite: hs.suite.id,
+ createdAt: createdAt,
masterSecret: hs.masterSecret,
certificates: certsFromClient,
}
return err
}
- c.cipherSuite = hs.suite.id
copy(out, finished.verifyData)
return nil
c.verifiedChains = chains
}
+ c.peerCertificates = certs
+ c.ocspResponse = certificate.OCSPStaple
+ c.scts = certificate.SignedCertificateTimestamps
+
+ if len(certs) > 0 {
+ switch certs[0].PublicKey.(type) {
+ case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
+ default:
+ c.sendAlert(alertUnsupportedCertificate)
+ return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey)
+ }
+ }
+
if c.config.VerifyPeerCertificate != nil {
if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
c.sendAlert(alertBadCertificate)
}
}
- if len(certs) == 0 {
- return nil
- }
-
- switch certs[0].PublicKey.(type) {
- case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
- default:
- c.sendAlert(alertUnsupportedCertificate)
- return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey)
- }
-
- c.peerCertificates = certs
- c.ocspResponse = certificate.OCSPStaple
- c.scts = certificate.SignedCertificateTimestamps
return nil
}