2009-11-21 15:53:03 -08: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 (
|
2012-01-05 12:05:38 -05:00
|
|
|
"bytes"
|
2014-08-29 12:36:30 -07:00
|
|
|
"crypto"
|
2013-07-17 12:33:16 -04:00
|
|
|
"crypto/ecdsa"
|
2019-05-16 19:13:29 -04:00
|
|
|
"crypto/ed25519"
|
2009-12-15 15:33:31 -08:00
|
|
|
"crypto/rsa"
|
|
|
|
|
"crypto/subtle"
|
|
|
|
|
"crypto/x509"
|
2011-11-01 22:04:37 -04:00
|
|
|
"errors"
|
2014-02-12 11:20:01 -05:00
|
|
|
"fmt"
|
2009-12-15 15:33:31 -08:00
|
|
|
"io"
|
2014-01-22 18:24:03 -05:00
|
|
|
"net"
|
2012-01-05 12:05:38 -05:00
|
|
|
"strconv"
|
2016-02-19 16:25:52 +09:00
|
|
|
"strings"
|
2018-01-26 09:17:46 +00:00
|
|
|
"sync/atomic"
|
2018-11-04 18:41:37 -05:00
|
|
|
"time"
|
2009-11-21 15:53:03 -08:00
|
|
|
)
|
|
|
|
|
|
2014-01-22 18:24:03 -05:00
|
|
|
type clientHandshakeState struct {
|
|
|
|
|
c *Conn
|
|
|
|
|
serverHello *serverHelloMsg
|
|
|
|
|
hello *clientHelloMsg
|
|
|
|
|
suite *cipherSuite
|
|
|
|
|
finishedHash finishedHash
|
|
|
|
|
masterSecret []byte
|
|
|
|
|
session *ClientSessionState
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
|
|
|
|
|
config := c.config
|
2017-05-30 12:53:11 -04:00
|
|
|
if len(config.ServerName) == 0 && !config.InsecureSkipVerify {
|
2018-11-01 01:01:09 -04:00
|
|
|
return nil, nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
|
2014-02-21 15:56:41 -05:00
|
|
|
}
|
|
|
|
|
|
2014-08-05 11:36:20 -07:00
|
|
|
nextProtosLength := 0
|
2017-05-30 12:53:11 -04:00
|
|
|
for _, proto := range config.NextProtos {
|
2014-08-05 11:36:20 -07:00
|
|
|
if l := len(proto); l == 0 || l > 255 {
|
2018-11-01 01:01:09 -04:00
|
|
|
return nil, nil, errors.New("tls: invalid NextProtos value")
|
2014-08-05 11:36:20 -07:00
|
|
|
} else {
|
|
|
|
|
nextProtosLength += 1 + l
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if nextProtosLength > 0xffff {
|
2018-11-01 01:01:09 -04:00
|
|
|
return nil, nil, errors.New("tls: NextProtos values too large")
|
2014-08-05 11:36:20 -07:00
|
|
|
}
|
|
|
|
|
|
2018-10-31 09:34:10 -04:00
|
|
|
supportedVersions := config.supportedVersions(true)
|
|
|
|
|
if len(supportedVersions) == 0 {
|
2018-11-01 01:01:09 -04:00
|
|
|
return nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion")
|
2018-10-31 09:34:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clientHelloVersion := supportedVersions[0]
|
|
|
|
|
// The version at the beginning of the ClientHello was capped at TLS 1.2
|
|
|
|
|
// for compatibility reasons. The supported_versions extension is used
|
|
|
|
|
// to negotiate versions now. See RFC 8446, Section 4.2.1.
|
|
|
|
|
if clientHelloVersion > VersionTLS12 {
|
|
|
|
|
clientHelloVersion = VersionTLS12
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-21 15:53:03 -08:00
|
|
|
hello := &clientHelloMsg{
|
2018-10-31 09:34:10 -04:00
|
|
|
vers: clientHelloVersion,
|
2016-04-26 10:45:35 -07:00
|
|
|
compressionMethods: []uint8{compressionNone},
|
|
|
|
|
random: make([]byte, 32),
|
2018-11-01 01:01:09 -04:00
|
|
|
sessionId: make([]byte, 32),
|
2016-04-26 10:45:35 -07:00
|
|
|
ocspStapling: true,
|
|
|
|
|
scts: true,
|
2017-05-30 12:53:11 -04:00
|
|
|
serverName: hostnameInSNI(config.ServerName),
|
|
|
|
|
supportedCurves: config.curvePreferences(),
|
2016-04-26 10:45:35 -07:00
|
|
|
supportedPoints: []uint8{pointFormatUncompressed},
|
2017-05-30 12:53:11 -04:00
|
|
|
nextProtoNeg: len(config.NextProtos) > 0,
|
2016-04-26 10:45:35 -07:00
|
|
|
secureRenegotiationSupported: true,
|
2017-05-30 12:53:11 -04:00
|
|
|
alpnProtocols: config.NextProtos,
|
2018-10-31 09:34:10 -04:00
|
|
|
supportedVersions: supportedVersions,
|
2009-12-15 15:33:31 -08:00
|
|
|
}
|
2018-11-01 01:01:09 -04:00
|
|
|
|
|
|
|
|
if c.handshakes > 0 {
|
|
|
|
|
hello.secureRenegotiation = c.clientFinished[:]
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-30 12:53:11 -04:00
|
|
|
possibleCipherSuites := config.cipherSuites()
|
2013-09-26 17:09:56 -04:00
|
|
|
hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites))
|
|
|
|
|
|
|
|
|
|
for _, suiteId := range possibleCipherSuites {
|
|
|
|
|
for _, suite := range cipherSuites {
|
|
|
|
|
if suite.id != suiteId {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
// Don't advertise TLS 1.2-only cipher suites unless
|
|
|
|
|
// we're attempting TLS 1.2.
|
|
|
|
|
if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
|
2019-01-22 16:21:32 -05:00
|
|
|
break
|
2013-09-26 17:09:56 -04:00
|
|
|
}
|
|
|
|
|
hello.cipherSuites = append(hello.cipherSuites, suiteId)
|
2019-01-22 16:21:32 -05:00
|
|
|
break
|
2013-09-26 17:09:56 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-30 12:53:11 -04:00
|
|
|
_, err := io.ReadFull(config.rand(), hello.random)
|
2009-11-21 15:53:03 -08:00
|
|
|
if err != nil {
|
2018-11-01 01:01:09 -04:00
|
|
|
return nil, nil, errors.New("tls: short read from Rand: " + err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A random session ID is used to detect when the server accepted a ticket
|
|
|
|
|
// and is resuming a session (see RFC 5077). In TLS 1.3, it's always set as
|
|
|
|
|
// a compatibility measure (see RFC 8446, Section 4.1.2).
|
|
|
|
|
if _, err := io.ReadFull(config.rand(), hello.sessionId); err != nil {
|
|
|
|
|
return nil, nil, errors.New("tls: short read from Rand: " + err.Error())
|
2009-11-21 15:53:03 -08:00
|
|
|
}
|
|
|
|
|
|
2013-07-02 19:58:56 -04:00
|
|
|
if hello.vers >= VersionTLS12 {
|
2017-09-07 17:50:10 +01:00
|
|
|
hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms
|
2013-07-02 19:58:56 -04:00
|
|
|
}
|
|
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
var params ecdheParameters
|
|
|
|
|
if hello.supportedVersions[0] == VersionTLS13 {
|
|
|
|
|
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13()...)
|
|
|
|
|
|
|
|
|
|
curveID := config.curvePreferences()[0]
|
|
|
|
|
if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok {
|
|
|
|
|
return nil, nil, errors.New("tls: CurvePreferences includes unsupported curve")
|
|
|
|
|
}
|
|
|
|
|
params, err = generateECDHEParameters(config.rand(), curveID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, nil, err
|
|
|
|
|
}
|
|
|
|
|
hello.keyShares = []keyShare{{group: curveID, data: params.PublicKey()}}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return hello, params, nil
|
2017-05-30 12:53:11 -04:00
|
|
|
}
|
|
|
|
|
|
2018-11-04 18:41:37 -05:00
|
|
|
func (c *Conn) clientHandshake() (err error) {
|
2017-05-30 12:53:11 -04:00
|
|
|
if c.config == nil {
|
|
|
|
|
c.config = defaultConfig()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This may be a renegotiation handshake, in which case some fields
|
|
|
|
|
// need to be reset.
|
|
|
|
|
c.didResume = false
|
|
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
hello, ecdheParams, err := c.makeClientHello()
|
2017-05-30 12:53:11 -04:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-04 18:41:37 -05:00
|
|
|
cacheKey, session, earlySecret, binderKey := c.loadSession(hello)
|
|
|
|
|
if cacheKey != "" && session != nil {
|
|
|
|
|
defer func() {
|
|
|
|
|
// If we got a handshake failure when resuming a session, throw away
|
|
|
|
|
// the session ticket. See RFC 5077, Section 3.2.
|
|
|
|
|
//
|
|
|
|
|
// RFC 8446 makes no mention of dropping tickets on failure, but it
|
|
|
|
|
// does require servers to abort on invalid binders, so we need to
|
|
|
|
|
// delete tickets to recover from a corrupted PSK.
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.config.ClientSessionCache.Put(cacheKey, nil)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
}
|
2018-11-01 01:01:09 -04:00
|
|
|
|
|
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, hello.marshal()); err != nil {
|
|
|
|
|
return err
|
2017-05-30 12:53:11 -04:00
|
|
|
}
|
|
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
msg, err := c.readHandshake()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
2014-01-22 18:24:03 -05:00
|
|
|
}
|
|
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
serverHello, ok := msg.(*serverHelloMsg)
|
|
|
|
|
if !ok {
|
|
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
|
|
|
|
return unexpectedMessageError(serverHello, msg)
|
2016-04-26 10:45:35 -07:00
|
|
|
}
|
2014-01-22 18:24:03 -05:00
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
if err := c.pickTLSVersion(serverHello); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2014-01-22 18:24:03 -05:00
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
if c.vers == VersionTLS13 {
|
|
|
|
|
hs := &clientHandshakeStateTLS13{
|
|
|
|
|
c: c,
|
|
|
|
|
serverHello: serverHello,
|
|
|
|
|
hello: hello,
|
|
|
|
|
ecdheParams: ecdheParams,
|
|
|
|
|
session: session,
|
2018-11-04 18:41:37 -05:00
|
|
|
earlySecret: earlySecret,
|
|
|
|
|
binderKey: binderKey,
|
2018-11-01 01:01:09 -04:00
|
|
|
}
|
2018-10-31 09:34:10 -04:00
|
|
|
|
2018-11-04 18:41:37 -05:00
|
|
|
// In TLS 1.3, session tickets are delivered after the handshake.
|
|
|
|
|
return hs.handshake()
|
|
|
|
|
}
|
2014-01-22 18:24:03 -05:00
|
|
|
|
2018-11-04 18:41:37 -05:00
|
|
|
hs := &clientHandshakeState{
|
|
|
|
|
c: c,
|
|
|
|
|
serverHello: serverHello,
|
|
|
|
|
hello: hello,
|
|
|
|
|
session: session,
|
|
|
|
|
}
|
2017-05-30 12:53:11 -04:00
|
|
|
|
2018-11-04 18:41:37 -05:00
|
|
|
if err := hs.handshake(); err != nil {
|
|
|
|
|
return err
|
2017-05-30 12:53:11 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we had a successful handshake and hs.session is different from
|
2018-11-01 01:01:09 -04:00
|
|
|
// the one already cached - cache a new one.
|
2018-11-04 18:41:37 -05:00
|
|
|
if cacheKey != "" && hs.session != nil && session != hs.session {
|
|
|
|
|
c.config.ClientSessionCache.Put(cacheKey, hs.session)
|
2017-05-30 12:53:11 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-04 18:41:37 -05:00
|
|
|
func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
|
|
|
|
session *ClientSessionState, earlySecret, binderKey []byte) {
|
2018-11-01 01:01:09 -04:00
|
|
|
if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil {
|
2018-11-04 18:41:37 -05:00
|
|
|
return "", nil, nil, nil
|
2018-11-01 01:01:09 -04:00
|
|
|
}
|
2017-05-30 12:53:11 -04:00
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
hello.ticketSupported = true
|
|
|
|
|
|
2018-11-04 18:41:37 -05:00
|
|
|
if hello.supportedVersions[0] == VersionTLS13 {
|
|
|
|
|
// Require DHE on resumption as it guarantees forward secrecy against
|
|
|
|
|
// compromise of the session ticket key. See RFC 8446, Section 4.2.9.
|
|
|
|
|
hello.pskModes = []uint8{pskModeDHE}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
// Session resumption is not allowed if renegotiating because
|
|
|
|
|
// renegotiation is primarily used to allow a client to send a client
|
|
|
|
|
// certificate, which would be skipped if session resumption occurred.
|
|
|
|
|
if c.handshakes != 0 {
|
2018-11-04 18:41:37 -05:00
|
|
|
return "", nil, nil, nil
|
2016-02-26 14:17:29 -05:00
|
|
|
}
|
2009-11-21 15:53:03 -08:00
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
// Try to resume a previously negotiated TLS session, if available.
|
|
|
|
|
cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
|
2018-11-04 18:41:37 -05:00
|
|
|
session, ok := c.config.ClientSessionCache.Get(cacheKey)
|
|
|
|
|
if !ok || session == nil {
|
|
|
|
|
return cacheKey, nil, nil, nil
|
2009-11-21 15:53:03 -08:00
|
|
|
}
|
|
|
|
|
|
2018-11-04 18:41:37 -05:00
|
|
|
// Check that version used for the previous session is still valid.
|
2018-11-01 01:01:09 -04:00
|
|
|
versOk := false
|
|
|
|
|
for _, v := range hello.supportedVersions {
|
2018-11-04 18:41:37 -05:00
|
|
|
if v == session.vers {
|
2018-11-01 01:01:09 -04:00
|
|
|
versOk = true
|
|
|
|
|
break
|
|
|
|
|
}
|
2014-01-22 18:24:03 -05:00
|
|
|
}
|
2018-11-04 18:41:37 -05:00
|
|
|
if !versOk {
|
|
|
|
|
return cacheKey, nil, nil, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check that the cached server certificate is not expired, and that it's
|
|
|
|
|
// valid for the ServerName. This should be ensured by the cache key, but
|
|
|
|
|
// protect the application from a faulty ClientSessionCache implementation.
|
|
|
|
|
if !c.config.InsecureSkipVerify {
|
|
|
|
|
if len(session.verifiedChains) == 0 {
|
|
|
|
|
// The original connection had InsecureSkipVerify, while this doesn't.
|
|
|
|
|
return cacheKey, nil, nil, nil
|
|
|
|
|
}
|
|
|
|
|
serverCert := session.serverCertificates[0]
|
|
|
|
|
if c.config.time().After(serverCert.NotAfter) {
|
|
|
|
|
// Expired certificate, delete the entry.
|
|
|
|
|
c.config.ClientSessionCache.Put(cacheKey, nil)
|
|
|
|
|
return cacheKey, nil, nil, nil
|
|
|
|
|
}
|
|
|
|
|
if err := serverCert.VerifyHostname(c.config.ServerName); err != nil {
|
|
|
|
|
return cacheKey, nil, nil, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if session.vers != VersionTLS13 {
|
|
|
|
|
// In TLS 1.2 the cipher suite must match the resumed session. Ensure we
|
|
|
|
|
// are still offering it.
|
|
|
|
|
if mutualCipherSuite(hello.cipherSuites, session.cipherSuite) == nil {
|
|
|
|
|
return cacheKey, nil, nil, nil
|
|
|
|
|
}
|
2013-07-02 19:58:56 -04:00
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
hello.sessionTicket = session.sessionTicket
|
2018-11-04 18:41:37 -05:00
|
|
|
return
|
2018-11-01 01:01:09 -04:00
|
|
|
}
|
|
|
|
|
|
2018-11-04 18:41:37 -05:00
|
|
|
// Check that the session ticket is not expired.
|
|
|
|
|
if c.config.time().After(session.useBy) {
|
|
|
|
|
c.config.ClientSessionCache.Put(cacheKey, nil)
|
|
|
|
|
return cacheKey, nil, nil, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// In TLS 1.3 the KDF hash must match the resumed session. Ensure we
|
|
|
|
|
// offer at least one cipher suite with that hash.
|
|
|
|
|
cipherSuite := cipherSuiteTLS13ByID(session.cipherSuite)
|
|
|
|
|
if cipherSuite == nil {
|
|
|
|
|
return cacheKey, nil, nil, nil
|
|
|
|
|
}
|
|
|
|
|
cipherSuiteOk := false
|
|
|
|
|
for _, offeredID := range hello.cipherSuites {
|
|
|
|
|
offeredSuite := cipherSuiteTLS13ByID(offeredID)
|
|
|
|
|
if offeredSuite != nil && offeredSuite.hash == cipherSuite.hash {
|
|
|
|
|
cipherSuiteOk = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !cipherSuiteOk {
|
|
|
|
|
return cacheKey, nil, nil, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set the pre_shared_key extension. See RFC 8446, Section 4.2.11.1.
|
|
|
|
|
ticketAge := uint32(c.config.time().Sub(session.receivedAt) / time.Millisecond)
|
|
|
|
|
identity := pskIdentity{
|
|
|
|
|
label: session.sessionTicket,
|
|
|
|
|
obfuscatedTicketAge: ticketAge + session.ageAdd,
|
|
|
|
|
}
|
|
|
|
|
hello.pskIdentities = []pskIdentity{identity}
|
|
|
|
|
hello.pskBinders = [][]byte{make([]byte, cipherSuite.hash.Size())}
|
|
|
|
|
|
|
|
|
|
// Compute the PSK binders. See RFC 8446, Section 4.2.11.2.
|
|
|
|
|
psk := cipherSuite.expandLabel(session.masterSecret, "resumption",
|
|
|
|
|
session.nonce, cipherSuite.hash.Size())
|
|
|
|
|
earlySecret = cipherSuite.extract(psk, nil)
|
|
|
|
|
binderKey = cipherSuite.deriveSecret(earlySecret, resumptionBinderLabel, nil)
|
|
|
|
|
transcript := cipherSuite.hash.New()
|
|
|
|
|
transcript.Write(hello.marshalWithoutBinders())
|
|
|
|
|
pskBinders := [][]byte{cipherSuite.finishedHash(binderKey, transcript)}
|
|
|
|
|
hello.updateBinders(pskBinders)
|
|
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *Conn) pickTLSVersion(serverHello *serverHelloMsg) error {
|
|
|
|
|
peerVersion := serverHello.vers
|
|
|
|
|
if serverHello.supportedVersion != 0 {
|
|
|
|
|
peerVersion = serverHello.supportedVersion
|
2009-11-21 15:53:03 -08:00
|
|
|
}
|
|
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
vers, ok := c.config.mutualVersion(true, []uint16{peerVersion})
|
|
|
|
|
if !ok {
|
|
|
|
|
c.sendAlert(alertProtocolVersion)
|
|
|
|
|
return fmt.Errorf("tls: server selected unsupported protocol version %x", peerVersion)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.vers = vers
|
|
|
|
|
c.haveVers = true
|
|
|
|
|
c.in.version = vers
|
|
|
|
|
c.out.version = vers
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-04 18:41:37 -05:00
|
|
|
// Does the handshake, either a full one or resumes old session. Requires hs.c,
|
|
|
|
|
// hs.hello, hs.serverHello, and, optionally, hs.session to be set.
|
2018-11-01 01:01:09 -04:00
|
|
|
func (hs *clientHandshakeState) handshake() error {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
2014-01-22 18:24:03 -05:00
|
|
|
isResume, err := hs.processServerHello()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
2011-03-29 17:53:09 -04:00
|
|
|
}
|
|
|
|
|
|
2017-05-30 12:53:11 -04:00
|
|
|
hs.finishedHash = newFinishedHash(c.vers, hs.suite)
|
|
|
|
|
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
// No signatures of the handshake are needed in a resumption.
|
|
|
|
|
// Otherwise, in a full handshake, if we don't have any certificates
|
|
|
|
|
// configured then we will never send a CertificateVerify message and
|
|
|
|
|
// thus no signatures are needed in that case either.
|
2016-10-26 10:05:03 -07:00
|
|
|
if isResume || (len(c.config.Certificates) == 0 && c.config.GetClientCertificate == nil) {
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
hs.finishedHash.discardHandshakeBuffer()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hs.finishedHash.Write(hs.hello.marshal())
|
|
|
|
|
hs.finishedHash.Write(hs.serverHello.marshal())
|
|
|
|
|
|
2016-06-01 14:41:09 -07:00
|
|
|
c.buffering = true
|
2014-01-22 18:24:03 -05:00
|
|
|
if isResume {
|
|
|
|
|
if err := hs.establishKeys(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if err := hs.readSessionTicket(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2016-04-26 10:45:35 -07:00
|
|
|
if err := hs.readFinished(c.serverFinished[:]); err != nil {
|
2014-01-22 18:24:03 -05:00
|
|
|
return err
|
|
|
|
|
}
|
2016-04-26 10:45:35 -07:00
|
|
|
c.clientFinishedIsFirst = false
|
|
|
|
|
if err := hs.sendFinished(c.clientFinished[:]); err != nil {
|
2014-01-22 18:24:03 -05:00
|
|
|
return err
|
|
|
|
|
}
|
2016-06-01 14:41:09 -07:00
|
|
|
if _, err := c.flush(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2014-01-22 18:24:03 -05:00
|
|
|
} else {
|
|
|
|
|
if err := hs.doFullHandshake(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if err := hs.establishKeys(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2016-04-26 10:45:35 -07:00
|
|
|
if err := hs.sendFinished(c.clientFinished[:]); err != nil {
|
2014-01-22 18:24:03 -05:00
|
|
|
return err
|
|
|
|
|
}
|
2016-06-01 14:41:09 -07:00
|
|
|
if _, err := c.flush(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2016-04-26 10:45:35 -07:00
|
|
|
c.clientFinishedIsFirst = true
|
2014-01-22 18:24:03 -05:00
|
|
|
if err := hs.readSessionTicket(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2016-04-26 10:45:35 -07:00
|
|
|
if err := hs.readFinished(c.serverFinished[:]); err != nil {
|
2014-01-22 18:24:03 -05:00
|
|
|
return err
|
|
|
|
|
}
|
2010-12-15 11:49:55 -05:00
|
|
|
}
|
|
|
|
|
|
2017-12-20 19:47:49 -08:00
|
|
|
c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random)
|
2014-01-22 18:24:03 -05:00
|
|
|
c.didResume = isResume
|
2018-01-26 09:17:46 +00:00
|
|
|
atomic.StoreUint32(&c.handshakeStatus, 1)
|
2017-05-30 12:53:11 -04:00
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *clientHandshakeState) pickCipherSuite() error {
|
|
|
|
|
if hs.suite = mutualCipherSuite(hs.hello.cipherSuites, hs.serverHello.cipherSuite); hs.suite == nil {
|
|
|
|
|
hs.c.sendAlert(alertHandshakeFailure)
|
|
|
|
|
return errors.New("tls: server chose an unconfigured cipher suite")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hs.c.cipherSuite = hs.suite.id
|
2014-01-22 18:24:03 -05:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *clientHandshakeState) doFullHandshake() error {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
|
|
|
|
msg, err := c.readHandshake()
|
2010-04-26 22:19:04 -07:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
certMsg, ok := msg.(*certificateMsg)
|
2009-11-21 15:53:03 -08:00
|
|
|
if !ok || len(certMsg.certificates) == 0 {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
|
|
|
|
return unexpectedMessageError(certMsg, msg)
|
2009-11-21 15:53:03 -08:00
|
|
|
}
|
2014-01-22 18:24:03 -05:00
|
|
|
hs.finishedHash.Write(certMsg.marshal())
|
2009-11-21 15:53:03 -08:00
|
|
|
|
2016-04-26 10:45:35 -07:00
|
|
|
if c.handshakes == 0 {
|
|
|
|
|
// If this is the first handshake on a connection, process and
|
|
|
|
|
// (optionally) verify the server's certificates.
|
2018-11-01 01:01:09 -04:00
|
|
|
if err := c.verifyServerCertificate(certMsg.certificates); err != nil {
|
|
|
|
|
return err
|
2009-11-21 15:53:03 -08:00
|
|
|
}
|
2016-04-26 10:45:35 -07:00
|
|
|
} else {
|
|
|
|
|
// This is a renegotiation handshake. We require that the
|
|
|
|
|
// server's identity (i.e. leaf certificate) is unchanged and
|
|
|
|
|
// thus any previous trust decision is still valid.
|
|
|
|
|
//
|
|
|
|
|
// See https://mitls.org/pages/attacks/3SHAKE for the
|
|
|
|
|
// motivation behind this requirement.
|
|
|
|
|
if !bytes.Equal(c.peerCertificates[0].Raw, certMsg.certificates[0]) {
|
|
|
|
|
c.sendAlert(alertBadCertificate)
|
|
|
|
|
return errors.New("tls: server's identity changed during renegotiation")
|
|
|
|
|
}
|
2009-11-21 15:53:03 -08:00
|
|
|
}
|
|
|
|
|
|
2018-01-04 00:42:10 -06:00
|
|
|
msg, err = c.readHandshake()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cs, ok := msg.(*certificateStatusMsg)
|
|
|
|
|
if ok {
|
|
|
|
|
// RFC4366 on Certificate Status Request:
|
|
|
|
|
// The server MAY return a "certificate_status" message.
|
|
|
|
|
|
|
|
|
|
if !hs.serverHello.ocspStapling {
|
|
|
|
|
// If a server returns a "CertificateStatus" message, then the
|
|
|
|
|
// server MUST have included an extension of type "status_request"
|
|
|
|
|
// with empty "extension_data" in the extended server hello.
|
|
|
|
|
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
2018-01-04 00:42:10 -06:00
|
|
|
return errors.New("tls: received unexpected CertificateStatus message")
|
2010-07-14 10:40:15 -04:00
|
|
|
}
|
2014-01-22 18:24:03 -05:00
|
|
|
hs.finishedHash.Write(cs.marshal())
|
2010-07-14 10:40:15 -04:00
|
|
|
|
2018-10-28 18:04:54 -04:00
|
|
|
c.ocspResponse = cs.response
|
2010-07-14 10:40:15 -04:00
|
|
|
|
2018-01-04 00:42:10 -06:00
|
|
|
msg, err = c.readHandshake()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2010-04-26 22:19:04 -07:00
|
|
|
}
|
2010-08-16 11:22:22 -04:00
|
|
|
|
2014-01-22 18:24:03 -05:00
|
|
|
keyAgreement := hs.suite.ka(c.vers)
|
2010-12-16 17:10:50 -05:00
|
|
|
|
|
|
|
|
skx, ok := msg.(*serverKeyExchangeMsg)
|
|
|
|
|
if ok {
|
2014-01-22 18:24:03 -05:00
|
|
|
hs.finishedHash.Write(skx.marshal())
|
2016-04-26 10:45:35 -07:00
|
|
|
err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, c.peerCertificates[0], skx)
|
2010-12-16 17:10:50 -05:00
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msg, err = c.readHandshake()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-29 11:21:32 -04:00
|
|
|
var chainToSend *Certificate
|
2012-03-19 12:34:35 -04:00
|
|
|
var certRequested bool
|
2010-08-16 11:22:22 -04:00
|
|
|
certReq, ok := msg.(*certificateRequestMsg)
|
|
|
|
|
if ok {
|
2012-03-19 12:34:35 -04:00
|
|
|
certRequested = true
|
2014-01-22 18:24:03 -05:00
|
|
|
hs.finishedHash.Write(certReq.marshal())
|
2012-01-05 12:05:38 -05:00
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
cri := certificateRequestInfoFromMsg(certReq)
|
|
|
|
|
if chainToSend, err = c.getClientCertificate(cri); err != nil {
|
2016-10-26 10:05:03 -07:00
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
return err
|
2012-01-05 12:05:38 -05:00
|
|
|
}
|
2010-08-16 11:22:22 -04:00
|
|
|
|
|
|
|
|
msg, err = c.readHandshake()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-26 22:19:04 -07:00
|
|
|
shd, ok := msg.(*serverHelloDoneMsg)
|
2009-11-21 15:53:03 -08:00
|
|
|
if !ok {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
|
|
|
|
return unexpectedMessageError(shd, msg)
|
2009-11-21 15:53:03 -08:00
|
|
|
}
|
2014-01-22 18:24:03 -05:00
|
|
|
hs.finishedHash.Write(shd.marshal())
|
2009-11-21 15:53:03 -08:00
|
|
|
|
2012-03-19 12:34:35 -04:00
|
|
|
// If the server requested a certificate then we have to send a
|
|
|
|
|
// Certificate message, even if it's empty because we don't have a
|
|
|
|
|
// certificate to send.
|
|
|
|
|
if certRequested {
|
2010-08-16 11:22:22 -04:00
|
|
|
certMsg = new(certificateMsg)
|
2016-10-26 10:05:03 -07:00
|
|
|
certMsg.certificates = chainToSend.Certificate
|
2014-01-22 18:24:03 -05:00
|
|
|
hs.finishedHash.Write(certMsg.marshal())
|
2016-02-26 14:17:29 -05:00
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2010-08-16 11:22:22 -04:00
|
|
|
}
|
|
|
|
|
|
2016-04-26 10:45:35 -07:00
|
|
|
preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, c.peerCertificates[0])
|
2009-11-21 15:53:03 -08:00
|
|
|
if err != nil {
|
2010-12-16 17:10:50 -05:00
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
return err
|
2009-11-21 15:53:03 -08:00
|
|
|
}
|
2010-12-16 17:10:50 -05:00
|
|
|
if ckx != nil {
|
2014-01-22 18:24:03 -05:00
|
|
|
hs.finishedHash.Write(ckx.marshal())
|
2016-02-26 14:17:29 -05:00
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, ckx.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2009-11-21 15:53:03 -08:00
|
|
|
}
|
|
|
|
|
|
2016-10-26 10:05:03 -07:00
|
|
|
if chainToSend != nil && len(chainToSend.Certificate) > 0 {
|
2013-09-16 16:39:42 -04:00
|
|
|
certVerify := &certificateVerifyMsg{
|
2018-10-24 21:22:00 -04:00
|
|
|
hasSignatureAlgorithm: c.vers >= VersionTLS12,
|
2013-09-16 16:39:42 -04:00
|
|
|
}
|
|
|
|
|
|
2014-08-29 12:36:30 -07:00
|
|
|
key, ok := chainToSend.PrivateKey.(crypto.Signer)
|
|
|
|
|
if !ok {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
|
|
|
|
|
}
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
|
crypto/tls: disable RSA-PSS in TLS 1.2 again
Signing with RSA-PSS can uncover faulty crypto.Signer implementations,
and it can fail for (broken) small keys. We'll have to take that
breakage eventually, but it would be nice for it to be opt-out at first.
TLS 1.3 requires RSA-PSS and is opt-out in Go 1.13. Instead of making a
TLS 1.3 opt-out influence a TLS 1.2 behavior, let's wait to add RSA-PSS
to TLS 1.2 until TLS 1.3 is on without opt-out.
Note that since the Client Hello is sent before a protocol version is
selected, we have to advertise RSA-PSS there to support TLS 1.3.
That means that we still support RSA-PSS on the client in TLS 1.2 for
verifying server certificates, which is fine, as all issues arise on the
signing side. We have to be careful not to pick (or consider available)
RSA-PSS on the client for client certificates, though.
We'd expect tests to change only in TLS 1.2:
* the server won't pick PSS to sign the key exchange
(Server-TLSv12-* w/ RSA, TestHandshakeServerRSAPSS);
* the server won't advertise PSS in CertificateRequest
(Server-TLSv12-ClientAuthRequested*, TestClientAuth);
* and the client won't pick PSS for its CertificateVerify
(Client-TLSv12-ClientCert-RSA-*, TestHandshakeClientCertRSAPSS,
Client-TLSv12-Renegotiate* because "R" requests a client cert).
Client-TLSv13-ClientCert-RSA-RSAPSS was updated because of a fix in the test.
This effectively reverts 88343530720a52c96b21f2bd5488c8fb607605d7.
Testing was made more complex by the undocumented semantics of OpenSSL's
-[client_]sigalgs (see openssl/openssl#9172).
Updates #32425
Change-Id: Iaddeb2df1f5c75cd090cc8321df2ac8e8e7db349
Reviewed-on: https://go-review.googlesource.com/c/go/+/182339
Reviewed-by: Adam Langley <agl@golang.org>
2019-06-13 18:33:33 -04:00
|
|
|
signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(key.Public(), certReq.supportedSignatureAlgorithms, supportedSignatureAlgorithmsTLS12, c.vers)
|
2017-11-22 18:25:20 +00:00
|
|
|
if err != nil {
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
c.sendAlert(alertInternalError)
|
2017-11-22 18:25:20 +00:00
|
|
|
return err
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
}
|
2017-09-07 17:50:10 +01:00
|
|
|
// SignatureAndHashAlgorithm was introduced in TLS 1.2.
|
2018-10-24 21:22:00 -04:00
|
|
|
if certVerify.hasSignatureAlgorithm {
|
2017-11-22 18:25:20 +00:00
|
|
|
certVerify.signatureAlgorithm = signatureAlgorithm
|
2013-07-17 12:33:16 -04:00
|
|
|
}
|
2019-05-16 19:13:29 -04:00
|
|
|
signed, err := hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret)
|
2010-08-16 11:22:22 -04:00
|
|
|
if err != nil {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertInternalError)
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
return err
|
|
|
|
|
}
|
2017-11-22 19:27:20 +00:00
|
|
|
signOpts := crypto.SignerOpts(hashFunc)
|
|
|
|
|
if sigType == signatureRSAPSS {
|
|
|
|
|
signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc}
|
|
|
|
|
}
|
2019-05-16 19:13:29 -04:00
|
|
|
certVerify.signature, err = key.Sign(c.config.rand(), signed, signOpts)
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
return err
|
2010-08-16 11:22:22 -04:00
|
|
|
}
|
|
|
|
|
|
2014-01-22 18:24:03 -05:00
|
|
|
hs.finishedHash.Write(certVerify.marshal())
|
2016-02-26 14:17:29 -05:00
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, certVerify.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2010-08-16 11:22:22 -04:00
|
|
|
}
|
|
|
|
|
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
|
2018-11-03 18:13:05 -04:00
|
|
|
if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.hello.random, hs.masterSecret); err != nil {
|
2016-08-20 14:41:42 +03:00
|
|
|
c.sendAlert(alertInternalError)
|
2016-09-30 12:55:25 -07:00
|
|
|
return errors.New("tls: failed to write to key log: " + err.Error())
|
2016-08-20 14:41:42 +03:00
|
|
|
}
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
|
|
|
|
|
hs.finishedHash.discardHandshakeBuffer()
|
|
|
|
|
|
2014-01-22 18:24:03 -05:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *clientHandshakeState) establishKeys() error {
|
|
|
|
|
c := hs.c
|
2010-04-26 22:19:04 -07:00
|
|
|
|
2014-01-22 18:24:03 -05:00
|
|
|
clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
|
2014-01-22 18:24:03 -05:00
|
|
|
var clientCipher, serverCipher interface{}
|
|
|
|
|
var clientHash, serverHash macFunction
|
|
|
|
|
if hs.suite.cipher != nil {
|
|
|
|
|
clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
|
|
|
|
|
clientHash = hs.suite.mac(c.vers, clientMAC)
|
|
|
|
|
serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */)
|
|
|
|
|
serverHash = hs.suite.mac(c.vers, serverMAC)
|
2013-08-29 17:18:59 -04:00
|
|
|
} else {
|
2014-01-22 18:24:03 -05:00
|
|
|
clientCipher = hs.suite.aead(clientKey, clientIV)
|
|
|
|
|
serverCipher = hs.suite.aead(serverKey, serverIV)
|
2013-08-29 17:18:59 -04:00
|
|
|
}
|
2014-01-22 18:24:03 -05:00
|
|
|
|
|
|
|
|
c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
|
2011-09-14 15:32:19 -04:00
|
|
|
c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
|
2014-01-22 18:24:03 -05:00
|
|
|
return nil
|
|
|
|
|
}
|
2009-11-21 15:53:03 -08:00
|
|
|
|
2014-01-22 18:24:03 -05:00
|
|
|
func (hs *clientHandshakeState) serverResumedSession() bool {
|
|
|
|
|
// If the server responded with the same sessionId then it means the
|
|
|
|
|
// sessionTicket is being used to resume a TLS session.
|
|
|
|
|
return hs.session != nil && hs.hello.sessionId != nil &&
|
|
|
|
|
bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId)
|
|
|
|
|
}
|
2011-03-29 17:53:09 -04:00
|
|
|
|
2014-01-22 18:24:03 -05:00
|
|
|
func (hs *clientHandshakeState) processServerHello() (bool, error) {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
if err := hs.pickCipherSuite(); err != nil {
|
|
|
|
|
return false, err
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-22 18:24:03 -05:00
|
|
|
if hs.serverHello.compressionMethod != compressionNone {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
|
|
|
|
return false, errors.New("tls: server selected unsupported compression format")
|
2011-03-29 17:53:09 -04:00
|
|
|
}
|
|
|
|
|
|
2016-04-26 10:45:35 -07:00
|
|
|
if c.handshakes == 0 && hs.serverHello.secureRenegotiationSupported {
|
|
|
|
|
c.secureRenegotiation = true
|
|
|
|
|
if len(hs.serverHello.secureRenegotiation) != 0 {
|
|
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
|
return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if c.handshakes > 0 && c.secureRenegotiation {
|
|
|
|
|
var expectedSecureRenegotiation [24]byte
|
|
|
|
|
copy(expectedSecureRenegotiation[:], c.clientFinished[:])
|
|
|
|
|
copy(expectedSecureRenegotiation[12:], c.serverFinished[:])
|
|
|
|
|
if !bytes.Equal(hs.serverHello.secureRenegotiation, expectedSecureRenegotiation[:]) {
|
|
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
|
return false, errors.New("tls: incorrect renegotiation extension contents")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-05 11:36:20 -07:00
|
|
|
clientDidNPN := hs.hello.nextProtoNeg
|
|
|
|
|
clientDidALPN := len(hs.hello.alpnProtocols) > 0
|
|
|
|
|
serverHasNPN := hs.serverHello.nextProtoNeg
|
|
|
|
|
serverHasALPN := len(hs.serverHello.alpnProtocol) > 0
|
|
|
|
|
|
|
|
|
|
if !clientDidNPN && serverHasNPN {
|
2014-01-22 18:24:03 -05:00
|
|
|
c.sendAlert(alertHandshakeFailure)
|
2016-04-12 10:43:44 -07:00
|
|
|
return false, errors.New("tls: server advertised unrequested NPN extension")
|
2014-01-22 18:24:03 -05:00
|
|
|
}
|
2009-11-21 15:53:03 -08:00
|
|
|
|
2014-08-05 11:36:20 -07:00
|
|
|
if !clientDidALPN && serverHasALPN {
|
|
|
|
|
c.sendAlert(alertHandshakeFailure)
|
2016-04-12 10:43:44 -07:00
|
|
|
return false, errors.New("tls: server advertised unrequested ALPN extension")
|
2014-08-05 11:36:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if serverHasNPN && serverHasALPN {
|
|
|
|
|
c.sendAlert(alertHandshakeFailure)
|
2016-04-12 10:43:44 -07:00
|
|
|
return false, errors.New("tls: server advertised both NPN and ALPN extensions")
|
2014-08-05 11:36:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if serverHasALPN {
|
|
|
|
|
c.clientProtocol = hs.serverHello.alpnProtocol
|
|
|
|
|
c.clientProtocolFallback = false
|
|
|
|
|
}
|
2015-04-16 14:59:22 -04:00
|
|
|
c.scts = hs.serverHello.scts
|
2014-08-05 11:36:20 -07:00
|
|
|
|
2016-03-14 03:35:13 -06:00
|
|
|
if !hs.serverResumedSession() {
|
|
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-15 11:51:54 -05:00
|
|
|
if hs.session.vers != c.vers {
|
|
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
|
return false, errors.New("tls: server resumed a session with a different version")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if hs.session.cipherSuite != hs.suite.id {
|
|
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
|
return false, errors.New("tls: server resumed a session with a different cipher suite")
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-14 03:35:13 -06:00
|
|
|
// Restore masterSecret and peerCerts from previous state
|
|
|
|
|
hs.masterSecret = hs.session.masterSecret
|
|
|
|
|
c.peerCertificates = hs.session.serverCertificates
|
|
|
|
|
c.verifiedChains = hs.session.verifiedChains
|
|
|
|
|
return true, nil
|
2014-01-22 18:24:03 -05:00
|
|
|
}
|
|
|
|
|
|
2014-08-11 16:40:42 -07:00
|
|
|
func (hs *clientHandshakeState) readFinished(out []byte) error {
|
2014-01-22 18:24:03 -05:00
|
|
|
c := hs.c
|
|
|
|
|
|
2018-11-03 18:29:09 -04:00
|
|
|
if err := c.readChangeCipherSpec(); err != nil {
|
|
|
|
|
return err
|
2010-04-26 22:19:04 -07:00
|
|
|
}
|
2009-11-21 15:53:03 -08:00
|
|
|
|
2014-01-22 18:24:03 -05:00
|
|
|
msg, err := c.readHandshake()
|
2010-04-26 22:19:04 -07:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
serverFinished, ok := msg.(*finishedMsg)
|
2009-11-21 15:53:03 -08:00
|
|
|
if !ok {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
|
|
|
|
return unexpectedMessageError(serverFinished, msg)
|
2009-11-21 15:53:03 -08:00
|
|
|
}
|
|
|
|
|
|
2014-01-22 18:24:03 -05:00
|
|
|
verify := hs.finishedHash.serverSum(hs.masterSecret)
|
2009-11-21 15:53:03 -08:00
|
|
|
if len(verify) != len(serverFinished.verifyData) ||
|
|
|
|
|
subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
|
return errors.New("tls: server's Finished message was incorrect")
|
2009-11-21 15:53:03 -08:00
|
|
|
}
|
2014-01-22 18:24:03 -05:00
|
|
|
hs.finishedHash.Write(serverFinished.marshal())
|
2014-08-11 16:40:42 -07:00
|
|
|
copy(out, verify)
|
2014-01-22 18:24:03 -05:00
|
|
|
return nil
|
|
|
|
|
}
|
2009-11-21 15:53:03 -08:00
|
|
|
|
2014-01-22 18:24:03 -05:00
|
|
|
func (hs *clientHandshakeState) readSessionTicket() error {
|
|
|
|
|
if !hs.serverHello.ticketSupported {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c := hs.c
|
|
|
|
|
msg, err := c.readHandshake()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
sessionTicketMsg, ok := msg.(*newSessionTicketMsg)
|
|
|
|
|
if !ok {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
|
|
|
|
return unexpectedMessageError(sessionTicketMsg, msg)
|
2014-01-22 18:24:03 -05:00
|
|
|
}
|
|
|
|
|
hs.finishedHash.Write(sessionTicketMsg.marshal())
|
|
|
|
|
|
|
|
|
|
hs.session = &ClientSessionState{
|
|
|
|
|
sessionTicket: sessionTicketMsg.ticket,
|
|
|
|
|
vers: c.vers,
|
|
|
|
|
cipherSuite: hs.suite.id,
|
|
|
|
|
masterSecret: hs.masterSecret,
|
|
|
|
|
serverCertificates: c.peerCertificates,
|
2015-08-05 09:53:56 -04:00
|
|
|
verifiedChains: c.verifiedChains,
|
2018-11-04 18:41:37 -05:00
|
|
|
receivedAt: c.config.time(),
|
2014-01-22 18:24:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-11 16:40:42 -07:00
|
|
|
func (hs *clientHandshakeState) sendFinished(out []byte) error {
|
2014-01-22 18:24:03 -05:00
|
|
|
c := hs.c
|
|
|
|
|
|
2016-02-26 14:17:29 -05:00
|
|
|
if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2014-01-22 18:24:03 -05:00
|
|
|
if hs.serverHello.nextProtoNeg {
|
|
|
|
|
nextProto := new(nextProtoMsg)
|
|
|
|
|
proto, fallback := mutualProtocol(c.config.NextProtos, hs.serverHello.nextProtos)
|
|
|
|
|
nextProto.proto = proto
|
|
|
|
|
c.clientProtocol = proto
|
|
|
|
|
c.clientProtocolFallback = fallback
|
|
|
|
|
|
|
|
|
|
hs.finishedHash.Write(nextProto.marshal())
|
2016-02-26 14:17:29 -05:00
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, nextProto.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2014-01-22 18:24:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
finished := new(finishedMsg)
|
|
|
|
|
finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
|
|
|
|
|
hs.finishedHash.Write(finished.marshal())
|
2016-02-26 14:17:29 -05:00
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2014-08-11 16:40:42 -07:00
|
|
|
copy(out, finished.verifyData)
|
2010-04-26 22:19:04 -07:00
|
|
|
return nil
|
2009-11-21 15:53:03 -08:00
|
|
|
}
|
2011-03-29 17:53:09 -04:00
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
// verifyServerCertificate parses and verifies the provided chain, setting
|
|
|
|
|
// c.verifiedChains and c.peerCertificates or sending the appropriate alert.
|
|
|
|
|
func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
|
|
|
|
|
certs := make([]*x509.Certificate, len(certificates))
|
|
|
|
|
for i, asn1Data := range certificates {
|
|
|
|
|
cert, err := x509.ParseCertificate(asn1Data)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertBadCertificate)
|
|
|
|
|
return errors.New("tls: failed to parse certificate from server: " + err.Error())
|
|
|
|
|
}
|
|
|
|
|
certs[i] = cert
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !c.config.InsecureSkipVerify {
|
|
|
|
|
opts := x509.VerifyOptions{
|
|
|
|
|
Roots: c.config.RootCAs,
|
|
|
|
|
CurrentTime: c.config.time(),
|
|
|
|
|
DNSName: c.config.ServerName,
|
|
|
|
|
Intermediates: x509.NewCertPool(),
|
|
|
|
|
}
|
2019-03-20 03:58:42 +11:00
|
|
|
for _, cert := range certs[1:] {
|
2018-11-01 01:01:09 -04:00
|
|
|
opts.Intermediates.AddCert(cert)
|
|
|
|
|
}
|
|
|
|
|
var err error
|
|
|
|
|
c.verifiedChains, err = certs[0].Verify(opts)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertBadCertificate)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if c.config.VerifyPeerCertificate != nil {
|
|
|
|
|
if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
|
|
|
|
|
c.sendAlert(alertBadCertificate)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch certs[0].PublicKey.(type) {
|
2019-05-16 19:13:29 -04:00
|
|
|
case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey:
|
2018-11-01 01:01:09 -04:00
|
|
|
break
|
|
|
|
|
default:
|
|
|
|
|
c.sendAlert(alertUnsupportedCertificate)
|
|
|
|
|
return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.peerCertificates = certs
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-26 10:05:03 -07:00
|
|
|
// tls11SignatureSchemes contains the signature schemes that we synthesise for
|
|
|
|
|
// a TLS <= 1.1 connection, based on the supported certificate types.
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
var (
|
|
|
|
|
tls11SignatureSchemes = []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1}
|
|
|
|
|
tls11SignatureSchemesECDSA = tls11SignatureSchemes[:3]
|
|
|
|
|
tls11SignatureSchemesRSA = tls11SignatureSchemes[3:]
|
2016-10-26 10:05:03 -07:00
|
|
|
)
|
|
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
// certificateRequestInfoFromMsg generates a CertificateRequestInfo from a TLS
|
|
|
|
|
// <= 1.2 CertificateRequest, making an effort to fill in missing information.
|
|
|
|
|
func certificateRequestInfoFromMsg(certReq *certificateRequestMsg) *CertificateRequestInfo {
|
2019-05-16 19:13:29 -04:00
|
|
|
var rsaAvail, ecAvail bool
|
2016-10-26 10:05:03 -07:00
|
|
|
for _, certType := range certReq.certificateTypes {
|
|
|
|
|
switch certType {
|
|
|
|
|
case certTypeRSASign:
|
|
|
|
|
rsaAvail = true
|
|
|
|
|
case certTypeECDSASign:
|
2019-05-16 19:13:29 -04:00
|
|
|
ecAvail = true
|
2016-10-26 10:05:03 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
cri := &CertificateRequestInfo{
|
|
|
|
|
AcceptableCAs: certReq.certificateAuthorities,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !certReq.hasSignatureAlgorithm {
|
|
|
|
|
// Prior to TLS 1.2, the signature schemes were not
|
|
|
|
|
// included in the certificate request message. In this
|
|
|
|
|
// case we use a plausible list based on the acceptable
|
|
|
|
|
// certificate types.
|
|
|
|
|
switch {
|
2019-05-16 19:13:29 -04:00
|
|
|
case rsaAvail && ecAvail:
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
cri.SignatureSchemes = tls11SignatureSchemes
|
|
|
|
|
case rsaAvail:
|
|
|
|
|
cri.SignatureSchemes = tls11SignatureSchemesRSA
|
2019-05-16 19:13:29 -04:00
|
|
|
case ecAvail:
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
cri.SignatureSchemes = tls11SignatureSchemesECDSA
|
|
|
|
|
}
|
|
|
|
|
return cri
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: disable RSA-PSS in TLS 1.2 again
Signing with RSA-PSS can uncover faulty crypto.Signer implementations,
and it can fail for (broken) small keys. We'll have to take that
breakage eventually, but it would be nice for it to be opt-out at first.
TLS 1.3 requires RSA-PSS and is opt-out in Go 1.13. Instead of making a
TLS 1.3 opt-out influence a TLS 1.2 behavior, let's wait to add RSA-PSS
to TLS 1.2 until TLS 1.3 is on without opt-out.
Note that since the Client Hello is sent before a protocol version is
selected, we have to advertise RSA-PSS there to support TLS 1.3.
That means that we still support RSA-PSS on the client in TLS 1.2 for
verifying server certificates, which is fine, as all issues arise on the
signing side. We have to be careful not to pick (or consider available)
RSA-PSS on the client for client certificates, though.
We'd expect tests to change only in TLS 1.2:
* the server won't pick PSS to sign the key exchange
(Server-TLSv12-* w/ RSA, TestHandshakeServerRSAPSS);
* the server won't advertise PSS in CertificateRequest
(Server-TLSv12-ClientAuthRequested*, TestClientAuth);
* and the client won't pick PSS for its CertificateVerify
(Client-TLSv12-ClientCert-RSA-*, TestHandshakeClientCertRSAPSS,
Client-TLSv12-Renegotiate* because "R" requests a client cert).
Client-TLSv13-ClientCert-RSA-RSAPSS was updated because of a fix in the test.
This effectively reverts 88343530720a52c96b21f2bd5488c8fb607605d7.
Testing was made more complex by the undocumented semantics of OpenSSL's
-[client_]sigalgs (see openssl/openssl#9172).
Updates #32425
Change-Id: Iaddeb2df1f5c75cd090cc8321df2ac8e8e7db349
Reviewed-on: https://go-review.googlesource.com/c/go/+/182339
Reviewed-by: Adam Langley <agl@golang.org>
2019-06-13 18:33:33 -04:00
|
|
|
// Filter the signature schemes based on the certificate types.
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
// See RFC 5246, Section 7.4.4 (where it calls this "somewhat complicated").
|
|
|
|
|
cri.SignatureSchemes = make([]SignatureScheme, 0, len(certReq.supportedSignatureAlgorithms))
|
|
|
|
|
for _, sigScheme := range certReq.supportedSignatureAlgorithms {
|
|
|
|
|
switch signatureFromSignatureScheme(sigScheme) {
|
2019-05-16 19:13:29 -04:00
|
|
|
case signatureECDSA, signatureEd25519:
|
|
|
|
|
if ecAvail {
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
cri.SignatureSchemes = append(cri.SignatureSchemes, sigScheme)
|
2016-10-26 10:05:03 -07:00
|
|
|
}
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
case signatureRSAPSS, signaturePKCS1v15:
|
|
|
|
|
if rsaAvail {
|
|
|
|
|
cri.SignatureSchemes = append(cri.SignatureSchemes, sigScheme)
|
2016-10-26 10:05:03 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
return cri
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *Conn) getClientCertificate(cri *CertificateRequestInfo) (*Certificate, error) {
|
|
|
|
|
if c.config.GetClientCertificate != nil {
|
|
|
|
|
return c.config.GetClientCertificate(cri)
|
|
|
|
|
}
|
2016-10-26 10:05:03 -07:00
|
|
|
|
|
|
|
|
// We need to search our list of client certs for one
|
|
|
|
|
// where SignatureAlgorithm is acceptable to the server and the
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
// Issuer is in AcceptableCAs.
|
2016-10-26 10:05:03 -07:00
|
|
|
for i, chain := range c.config.Certificates {
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
sigOK := false
|
2018-11-29 01:38:07 -05:00
|
|
|
for _, alg := range signatureSchemesForCertificate(c.vers, &chain) {
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
if isSupportedSignatureAlgorithm(alg, cri.SignatureSchemes) {
|
|
|
|
|
sigOK = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !sigOK {
|
2016-10-26 10:05:03 -07:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
if len(cri.AcceptableCAs) == 0 {
|
|
|
|
|
return &chain, nil
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-26 10:05:03 -07:00
|
|
|
for j, cert := range chain.Certificate {
|
|
|
|
|
x509Cert := chain.Leaf
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
// Parse the certificate if this isn't the leaf node, or if
|
|
|
|
|
// chain.Leaf was nil.
|
2016-10-26 10:05:03 -07:00
|
|
|
if j != 0 || x509Cert == nil {
|
|
|
|
|
var err error
|
|
|
|
|
if x509Cert, err = x509.ParseCertificate(cert); err != nil {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
return nil, errors.New("tls: failed to parse configured certificate chain #" + strconv.Itoa(i) + ": " + err.Error())
|
2016-10-26 10:05:03 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
for _, ca := range cri.AcceptableCAs {
|
2016-10-26 10:05:03 -07:00
|
|
|
if bytes.Equal(x509Cert.RawIssuer, ca) {
|
|
|
|
|
return &chain, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// No acceptable certificate found. Don't send a certificate.
|
|
|
|
|
return new(Certificate), nil
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-22 18:24:03 -05:00
|
|
|
// clientSessionCacheKey returns a key used to cache sessionTickets that could
|
|
|
|
|
// be used to resume previously negotiated TLS sessions with a server.
|
|
|
|
|
func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
|
|
|
|
|
if len(config.ServerName) > 0 {
|
|
|
|
|
return config.ServerName
|
|
|
|
|
}
|
|
|
|
|
return serverAddr.String()
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-05 11:36:20 -07:00
|
|
|
// mutualProtocol finds the mutual Next Protocol Negotiation or ALPN protocol
|
|
|
|
|
// given list of possible protocols and a list of the preference order. The
|
|
|
|
|
// first list must not be empty. It returns the resulting protocol and flag
|
2011-03-29 17:53:09 -04:00
|
|
|
// indicating if the fallback case was reached.
|
2014-08-05 11:36:20 -07:00
|
|
|
func mutualProtocol(protos, preferenceProtos []string) (string, bool) {
|
|
|
|
|
for _, s := range preferenceProtos {
|
|
|
|
|
for _, c := range protos {
|
2011-03-29 17:53:09 -04:00
|
|
|
if s == c {
|
|
|
|
|
return s, false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-05 11:36:20 -07:00
|
|
|
return protos[0], true
|
2011-03-29 17:53:09 -04:00
|
|
|
}
|
2016-02-19 16:25:52 +09:00
|
|
|
|
|
|
|
|
// hostnameInSNI converts name into an approriate hostname for SNI.
|
|
|
|
|
// Literal IP addresses and absolute FQDNs are not permitted as SNI values.
|
2018-10-12 17:07:04 -04:00
|
|
|
// See RFC 6066, Section 3.
|
2016-02-19 16:25:52 +09:00
|
|
|
func hostnameInSNI(name string) string {
|
|
|
|
|
host := name
|
|
|
|
|
if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
|
|
|
|
|
host = host[1 : len(host)-1]
|
|
|
|
|
}
|
2017-10-05 15:50:11 +02:00
|
|
|
if i := strings.LastIndex(host, "%"); i > 0 {
|
2016-02-19 16:25:52 +09:00
|
|
|
host = host[:i]
|
|
|
|
|
}
|
|
|
|
|
if net.ParseIP(host) != nil {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
2016-12-05 10:24:30 -08:00
|
|
|
for len(name) > 0 && name[len(name)-1] == '.' {
|
2016-02-19 16:25:52 +09:00
|
|
|
name = name[:len(name)-1]
|
|
|
|
|
}
|
|
|
|
|
return name
|
|
|
|
|
}
|