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"
|
2020-08-01 12:18:31 +01:00
|
|
|
"context"
|
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"
|
2020-08-31 17:09:57 -04:00
|
|
|
"hash"
|
2009-12-15 15:33:31 -08:00
|
|
|
"io"
|
2014-01-22 18:24:03 -05:00
|
|
|
"net"
|
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
|
2020-08-01 12:18:31 +01:00
|
|
|
ctx context.Context
|
2014-01-22 18:24:03 -05:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2019-08-27 17:27:45 -04:00
|
|
|
supportedVersions := config.supportedVersions()
|
2018-10-31 09:34:10 -04:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2020-04-29 17:54:24 -04:00
|
|
|
clientHelloVersion := config.maxSupportedVersion()
|
2018-10-31 09:34:10 -04:00
|
|
|
// 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},
|
|
|
|
|
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[:]
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: make cipher suite preference ordering automatic
We now have a (well, two, depending on AES hardware support) universal
cipher suite preference order, based on their security and performance.
Peer and application lists are now treated as filters (and AES hardware
support hints) that are applied to this universal order.
This removes a complex and nuanced decision from the application's
responsibilities, one which we are better equipped to make and which
applications usually don't need to have an opinion about. It also lets
us worry less about what suites we support or enable, because we can be
confident that bad ones won't be selected over good ones.
This also moves 3DES suites to InsecureCipherSuites(), even if they are
not disabled by default. Just because we can keep them as a last resort
it doesn't mean they are secure. Thankfully we had not promised that
Insecure means disabled by default.
Notable test changes:
- TestCipherSuiteCertPreferenceECDSA was testing that we'd pick the
right certificate regardless of CipherSuite ordering, which is now
completely ignored, as tested by TestCipherSuitePreference. Removed.
- The openssl command of TestHandshakeServerExportKeyingMaterial was
broken for TLS 1.0 in CL 262857, but its golden file was not
regenerated, so the test kept passing. It now broke because the
selected suite from the ones in the golden file changed.
- In TestAESCipherReordering, "server strongly prefers AES-GCM" is
removed because there is no way for a server to express a strong
preference anymore; "client prefers AES-GCM and AES-CBC over ChaCha"
switched to ChaCha20 when the server lacks AES hardware; and finally
"client supports multiple AES-GCM" changed to always prefer AES-128
per the universal preference list.
* this is going back on an explicit decision from CL 262857, and
while that client order is weird and does suggest a strong dislike
for ChaCha20, we have a strong dislike for software AES, so it
didn't feel worth making the logic more complex
- All Client-* golden files had to be regenerated because the
ClientHello cipher suites have changed.
(Even when Config.CipherSuites was limited to one suite, the TLS 1.3
default order changed.)
Fixes #45430
Fixes #41476 (as 3DES is now always the last resort)
Change-Id: If5f5d356c0f8d1f1c7542fb06644a478d6bad1e5
Reviewed-on: https://go-review.googlesource.com/c/go/+/314609
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Trust: Filippo Valsorda <filippo@golang.org>
2021-04-28 01:37:09 -04:00
|
|
|
preferenceOrder := cipherSuitesPreferenceOrder
|
|
|
|
|
if !hasAESGCMHardwareSupport {
|
|
|
|
|
preferenceOrder = cipherSuitesPreferenceOrderNoAES
|
|
|
|
|
}
|
|
|
|
|
configCipherSuites := config.cipherSuites()
|
|
|
|
|
hello.cipherSuites = make([]uint16, 0, len(configCipherSuites))
|
|
|
|
|
|
|
|
|
|
for _, suiteId := range preferenceOrder {
|
|
|
|
|
suite := mutualCipherSuite(configCipherSuites, suiteId)
|
|
|
|
|
if suite == nil {
|
|
|
|
|
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 {
|
|
|
|
|
continue
|
2013-09-26 17:09:56 -04:00
|
|
|
}
|
crypto/tls: make cipher suite preference ordering automatic
We now have a (well, two, depending on AES hardware support) universal
cipher suite preference order, based on their security and performance.
Peer and application lists are now treated as filters (and AES hardware
support hints) that are applied to this universal order.
This removes a complex and nuanced decision from the application's
responsibilities, one which we are better equipped to make and which
applications usually don't need to have an opinion about. It also lets
us worry less about what suites we support or enable, because we can be
confident that bad ones won't be selected over good ones.
This also moves 3DES suites to InsecureCipherSuites(), even if they are
not disabled by default. Just because we can keep them as a last resort
it doesn't mean they are secure. Thankfully we had not promised that
Insecure means disabled by default.
Notable test changes:
- TestCipherSuiteCertPreferenceECDSA was testing that we'd pick the
right certificate regardless of CipherSuite ordering, which is now
completely ignored, as tested by TestCipherSuitePreference. Removed.
- The openssl command of TestHandshakeServerExportKeyingMaterial was
broken for TLS 1.0 in CL 262857, but its golden file was not
regenerated, so the test kept passing. It now broke because the
selected suite from the ones in the golden file changed.
- In TestAESCipherReordering, "server strongly prefers AES-GCM" is
removed because there is no way for a server to express a strong
preference anymore; "client prefers AES-GCM and AES-CBC over ChaCha"
switched to ChaCha20 when the server lacks AES hardware; and finally
"client supports multiple AES-GCM" changed to always prefer AES-128
per the universal preference list.
* this is going back on an explicit decision from CL 262857, and
while that client order is weird and does suggest a strong dislike
for ChaCha20, we have a strong dislike for software AES, so it
didn't feel worth making the logic more complex
- All Client-* golden files had to be regenerated because the
ClientHello cipher suites have changed.
(Even when Config.CipherSuites was limited to one suite, the TLS 1.3
default order changed.)
Fixes #45430
Fixes #41476 (as 3DES is now always the last resort)
Change-Id: If5f5d356c0f8d1f1c7542fb06644a478d6bad1e5
Reviewed-on: https://go-review.googlesource.com/c/go/+/314609
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Trust: Filippo Valsorda <filippo@golang.org>
2021-04-28 01:37:09 -04:00
|
|
|
hello.cipherSuites = append(hello.cipherSuites, suiteId)
|
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 {
|
crypto/tls: make cipher suite preference ordering automatic
We now have a (well, two, depending on AES hardware support) universal
cipher suite preference order, based on their security and performance.
Peer and application lists are now treated as filters (and AES hardware
support hints) that are applied to this universal order.
This removes a complex and nuanced decision from the application's
responsibilities, one which we are better equipped to make and which
applications usually don't need to have an opinion about. It also lets
us worry less about what suites we support or enable, because we can be
confident that bad ones won't be selected over good ones.
This also moves 3DES suites to InsecureCipherSuites(), even if they are
not disabled by default. Just because we can keep them as a last resort
it doesn't mean they are secure. Thankfully we had not promised that
Insecure means disabled by default.
Notable test changes:
- TestCipherSuiteCertPreferenceECDSA was testing that we'd pick the
right certificate regardless of CipherSuite ordering, which is now
completely ignored, as tested by TestCipherSuitePreference. Removed.
- The openssl command of TestHandshakeServerExportKeyingMaterial was
broken for TLS 1.0 in CL 262857, but its golden file was not
regenerated, so the test kept passing. It now broke because the
selected suite from the ones in the golden file changed.
- In TestAESCipherReordering, "server strongly prefers AES-GCM" is
removed because there is no way for a server to express a strong
preference anymore; "client prefers AES-GCM and AES-CBC over ChaCha"
switched to ChaCha20 when the server lacks AES hardware; and finally
"client supports multiple AES-GCM" changed to always prefer AES-128
per the universal preference list.
* this is going back on an explicit decision from CL 262857, and
while that client order is weird and does suggest a strong dislike
for ChaCha20, we have a strong dislike for software AES, so it
didn't feel worth making the logic more complex
- All Client-* golden files had to be regenerated because the
ClientHello cipher suites have changed.
(Even when Config.CipherSuites was limited to one suite, the TLS 1.3
default order changed.)
Fixes #45430
Fixes #41476 (as 3DES is now always the last resort)
Change-Id: If5f5d356c0f8d1f1c7542fb06644a478d6bad1e5
Reviewed-on: https://go-review.googlesource.com/c/go/+/314609
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Trust: Filippo Valsorda <filippo@golang.org>
2021-04-28 01:37:09 -04:00
|
|
|
if hasAESGCMHardwareSupport {
|
|
|
|
|
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...)
|
|
|
|
|
} else {
|
|
|
|
|
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...)
|
|
|
|
|
}
|
2018-11-01 01:01:09 -04:00
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2020-08-01 12:18:31 +01:00
|
|
|
func (c *Conn) clientHandshake(ctx context.Context) (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
|
|
|
|
|
}
|
2020-04-20 17:55:37 -04:00
|
|
|
c.serverName = hello.serverName
|
2017-05-30 12:53:11 -04:00
|
|
|
|
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
|
|
|
|
2020-04-29 17:54:24 -04:00
|
|
|
// If we are negotiating a protocol version that's lower than what we
|
|
|
|
|
// support, check for the server downgrade canaries.
|
|
|
|
|
// See RFC 8446, Section 4.1.3.
|
|
|
|
|
maxVers := c.config.maxSupportedVersion()
|
|
|
|
|
tls12Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS12
|
|
|
|
|
tls11Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS11
|
|
|
|
|
if maxVers == VersionTLS13 && c.vers <= VersionTLS12 && (tls12Downgrade || tls11Downgrade) ||
|
|
|
|
|
maxVers == VersionTLS12 && c.vers <= VersionTLS11 && tls11Downgrade {
|
|
|
|
|
c.sendAlert(alertIllegalParameter)
|
|
|
|
|
return errors.New("tls: downgrade attempt detected, possibly due to a MitM attack or a broken middlebox")
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
if c.vers == VersionTLS13 {
|
|
|
|
|
hs := &clientHandshakeStateTLS13{
|
|
|
|
|
c: c,
|
2020-08-01 12:18:31 +01:00
|
|
|
ctx: ctx,
|
2018-11-01 01:01:09 -04:00
|
|
|
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,
|
2020-08-01 12:18:31 +01:00
|
|
|
ctx: ctx,
|
2018-11-04 18:41:37 -05:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2019-08-27 17:27:45 -04:00
|
|
|
vers, ok := c.config.mutualVersion([]uint16{peerVersion})
|
2018-11-01 01:01:09 -04:00
|
|
|
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
|
2020-04-20 17:55:37 -04:00
|
|
|
c.didResume = isResume
|
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
|
2020-04-20 17:55:37 -04:00
|
|
|
// Make sure the connection is still being verified whether or not this
|
|
|
|
|
// is a resumption. Resumptions currently don't reverify certificates so
|
|
|
|
|
// they don't call verifyServerCertificate. See Issue 31641.
|
|
|
|
|
if c.config.VerifyConnection != nil {
|
|
|
|
|
if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
|
|
|
|
|
c.sendAlert(alertBadCertificate)
|
|
|
|
|
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
|
|
|
|
|
}
|
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)
|
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
|
|
|
|
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
|
|
|
|
2020-04-20 17:55:37 -04:00
|
|
|
if c.handshakes == 0 {
|
|
|
|
|
// If this is the first handshake on a connection, process and
|
|
|
|
|
// (optionally) verify the server's certificates.
|
|
|
|
|
if err := c.verifyServerCertificate(certMsg.certificates); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
} 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")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
2020-08-01 12:18:31 +01:00
|
|
|
cri := certificateRequestInfoFromMsg(hs.ctx, c.vers, certReq)
|
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 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 {
|
crypto/tls: refactor certificate and signature algorithm logic
This refactors a lot of the certificate support logic to make it cleaner
and reusable where possible. These changes will make the following CLs
much simpler.
In particular, the heavily overloaded pickSignatureAlgorithm is gone.
That function used to cover both signing and verifying side, would work
both for pre-signature_algorithms TLS 1.0/1.1 and TLS 1.2, and returned
sigalg, type and hash.
Now, TLS 1.0/1.1 and 1.2 are differentiated at the caller, as they have
effectively completely different logic. TLS 1.0/1.1 simply use
legacyTypeAndHashFromPublicKey as they employ a fixed hash function and
signature algorithm for each public key type. TLS 1.2 is instead routed
through selectSignatureScheme (on the signing side) or
isSupportedSignatureAlgorithm (on the verifying side) and
typeAndHashFromSignatureScheme, like TLS 1.3.
On the signing side, signatureSchemesForCertificate was already version
aware (for PKCS#1 v1.5 vs PSS support), so selectSignatureScheme just
had to learn the Section 7.4.1.4.1 defaults for a missing
signature_algorithms to replace pickSignatureAlgorithm.
On the verifying side, pickSignatureAlgorithm was also checking the
public key type, while isSupportedSignatureAlgorithm +
typeAndHashFromSignatureScheme are not, but that check was redundant
with the one in verifyHandshakeSignature.
There should be no major change in behavior so far. A few minor changes
came from the refactor: we now correctly require signature_algorithms in
TLS 1.3 when using a certificate; we won't use Ed25519 in TLS 1.2 if the
client didn't send signature_algorithms; and we don't send
ec_points_format in the ServerHello (a compatibility measure) if we are
not doing ECDHE anyway because there are no mutually supported curves.
The tests also got simpler because they test simpler functions. The
caller logic switching between TLS 1.0/1.1 and 1.2 is tested by the
transcript tests.
Updates #32426
Change-Id: Ice9dcaea78d204718f661f8d60efdb408ba41577
Reviewed-on: https://go-review.googlesource.com/c/go/+/205061
Reviewed-by: Katie Hockman <katie@golang.org>
2019-11-01 19:00:33 -04:00
|
|
|
certVerify := &certificateVerifyMsg{}
|
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: refactor certificate and signature algorithm logic
This refactors a lot of the certificate support logic to make it cleaner
and reusable where possible. These changes will make the following CLs
much simpler.
In particular, the heavily overloaded pickSignatureAlgorithm is gone.
That function used to cover both signing and verifying side, would work
both for pre-signature_algorithms TLS 1.0/1.1 and TLS 1.2, and returned
sigalg, type and hash.
Now, TLS 1.0/1.1 and 1.2 are differentiated at the caller, as they have
effectively completely different logic. TLS 1.0/1.1 simply use
legacyTypeAndHashFromPublicKey as they employ a fixed hash function and
signature algorithm for each public key type. TLS 1.2 is instead routed
through selectSignatureScheme (on the signing side) or
isSupportedSignatureAlgorithm (on the verifying side) and
typeAndHashFromSignatureScheme, like TLS 1.3.
On the signing side, signatureSchemesForCertificate was already version
aware (for PKCS#1 v1.5 vs PSS support), so selectSignatureScheme just
had to learn the Section 7.4.1.4.1 defaults for a missing
signature_algorithms to replace pickSignatureAlgorithm.
On the verifying side, pickSignatureAlgorithm was also checking the
public key type, while isSupportedSignatureAlgorithm +
typeAndHashFromSignatureScheme are not, but that check was redundant
with the one in verifyHandshakeSignature.
There should be no major change in behavior so far. A few minor changes
came from the refactor: we now correctly require signature_algorithms in
TLS 1.3 when using a certificate; we won't use Ed25519 in TLS 1.2 if the
client didn't send signature_algorithms; and we don't send
ec_points_format in the ServerHello (a compatibility measure) if we are
not doing ECDHE anyway because there are no mutually supported curves.
The tests also got simpler because they test simpler functions. The
caller logic switching between TLS 1.0/1.1 and 1.2 is tested by the
transcript tests.
Updates #32426
Change-Id: Ice9dcaea78d204718f661f8d60efdb408ba41577
Reviewed-on: https://go-review.googlesource.com/c/go/+/205061
Reviewed-by: Katie Hockman <katie@golang.org>
2019-11-01 19:00:33 -04:00
|
|
|
var sigType uint8
|
|
|
|
|
var sigHash crypto.Hash
|
|
|
|
|
if c.vers >= VersionTLS12 {
|
|
|
|
|
signatureAlgorithm, err := selectSignatureScheme(c.vers, chainToSend, certReq.supportedSignatureAlgorithms)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertIllegalParameter)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return c.sendAlert(alertInternalError)
|
|
|
|
|
}
|
|
|
|
|
certVerify.hasSignatureAlgorithm = true
|
2017-11-22 18:25:20 +00:00
|
|
|
certVerify.signatureAlgorithm = signatureAlgorithm
|
crypto/tls: refactor certificate and signature algorithm logic
This refactors a lot of the certificate support logic to make it cleaner
and reusable where possible. These changes will make the following CLs
much simpler.
In particular, the heavily overloaded pickSignatureAlgorithm is gone.
That function used to cover both signing and verifying side, would work
both for pre-signature_algorithms TLS 1.0/1.1 and TLS 1.2, and returned
sigalg, type and hash.
Now, TLS 1.0/1.1 and 1.2 are differentiated at the caller, as they have
effectively completely different logic. TLS 1.0/1.1 simply use
legacyTypeAndHashFromPublicKey as they employ a fixed hash function and
signature algorithm for each public key type. TLS 1.2 is instead routed
through selectSignatureScheme (on the signing side) or
isSupportedSignatureAlgorithm (on the verifying side) and
typeAndHashFromSignatureScheme, like TLS 1.3.
On the signing side, signatureSchemesForCertificate was already version
aware (for PKCS#1 v1.5 vs PSS support), so selectSignatureScheme just
had to learn the Section 7.4.1.4.1 defaults for a missing
signature_algorithms to replace pickSignatureAlgorithm.
On the verifying side, pickSignatureAlgorithm was also checking the
public key type, while isSupportedSignatureAlgorithm +
typeAndHashFromSignatureScheme are not, but that check was redundant
with the one in verifyHandshakeSignature.
There should be no major change in behavior so far. A few minor changes
came from the refactor: we now correctly require signature_algorithms in
TLS 1.3 when using a certificate; we won't use Ed25519 in TLS 1.2 if the
client didn't send signature_algorithms; and we don't send
ec_points_format in the ServerHello (a compatibility measure) if we are
not doing ECDHE anyway because there are no mutually supported curves.
The tests also got simpler because they test simpler functions. The
caller logic switching between TLS 1.0/1.1 and 1.2 is tested by the
transcript tests.
Updates #32426
Change-Id: Ice9dcaea78d204718f661f8d60efdb408ba41577
Reviewed-on: https://go-review.googlesource.com/c/go/+/205061
Reviewed-by: Katie Hockman <katie@golang.org>
2019-11-01 19:00:33 -04:00
|
|
|
} else {
|
|
|
|
|
sigType, sigHash, err = legacyTypeAndHashFromPublicKey(key.Public())
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertIllegalParameter)
|
|
|
|
|
return err
|
|
|
|
|
}
|
2013-07-17 12:33:16 -04:00
|
|
|
}
|
crypto/tls: refactor certificate and signature algorithm logic
This refactors a lot of the certificate support logic to make it cleaner
and reusable where possible. These changes will make the following CLs
much simpler.
In particular, the heavily overloaded pickSignatureAlgorithm is gone.
That function used to cover both signing and verifying side, would work
both for pre-signature_algorithms TLS 1.0/1.1 and TLS 1.2, and returned
sigalg, type and hash.
Now, TLS 1.0/1.1 and 1.2 are differentiated at the caller, as they have
effectively completely different logic. TLS 1.0/1.1 simply use
legacyTypeAndHashFromPublicKey as they employ a fixed hash function and
signature algorithm for each public key type. TLS 1.2 is instead routed
through selectSignatureScheme (on the signing side) or
isSupportedSignatureAlgorithm (on the verifying side) and
typeAndHashFromSignatureScheme, like TLS 1.3.
On the signing side, signatureSchemesForCertificate was already version
aware (for PKCS#1 v1.5 vs PSS support), so selectSignatureScheme just
had to learn the Section 7.4.1.4.1 defaults for a missing
signature_algorithms to replace pickSignatureAlgorithm.
On the verifying side, pickSignatureAlgorithm was also checking the
public key type, while isSupportedSignatureAlgorithm +
typeAndHashFromSignatureScheme are not, but that check was redundant
with the one in verifyHandshakeSignature.
There should be no major change in behavior so far. A few minor changes
came from the refactor: we now correctly require signature_algorithms in
TLS 1.3 when using a certificate; we won't use Ed25519 in TLS 1.2 if the
client didn't send signature_algorithms; and we don't send
ec_points_format in the ServerHello (a compatibility measure) if we are
not doing ECDHE anyway because there are no mutually supported curves.
The tests also got simpler because they test simpler functions. The
caller logic switching between TLS 1.0/1.1 and 1.2 is tested by the
transcript tests.
Updates #32426
Change-Id: Ice9dcaea78d204718f661f8d60efdb408ba41577
Reviewed-on: https://go-review.googlesource.com/c/go/+/205061
Reviewed-by: Katie Hockman <katie@golang.org>
2019-11-01 19:00:33 -04:00
|
|
|
|
|
|
|
|
signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash, hs.masterSecret)
|
|
|
|
|
signOpts := crypto.SignerOpts(sigHash)
|
2017-11-22 19:27:20 +00:00
|
|
|
if sigType == signatureRSAPSS {
|
crypto/tls: refactor certificate and signature algorithm logic
This refactors a lot of the certificate support logic to make it cleaner
and reusable where possible. These changes will make the following CLs
much simpler.
In particular, the heavily overloaded pickSignatureAlgorithm is gone.
That function used to cover both signing and verifying side, would work
both for pre-signature_algorithms TLS 1.0/1.1 and TLS 1.2, and returned
sigalg, type and hash.
Now, TLS 1.0/1.1 and 1.2 are differentiated at the caller, as they have
effectively completely different logic. TLS 1.0/1.1 simply use
legacyTypeAndHashFromPublicKey as they employ a fixed hash function and
signature algorithm for each public key type. TLS 1.2 is instead routed
through selectSignatureScheme (on the signing side) or
isSupportedSignatureAlgorithm (on the verifying side) and
typeAndHashFromSignatureScheme, like TLS 1.3.
On the signing side, signatureSchemesForCertificate was already version
aware (for PKCS#1 v1.5 vs PSS support), so selectSignatureScheme just
had to learn the Section 7.4.1.4.1 defaults for a missing
signature_algorithms to replace pickSignatureAlgorithm.
On the verifying side, pickSignatureAlgorithm was also checking the
public key type, while isSupportedSignatureAlgorithm +
typeAndHashFromSignatureScheme are not, but that check was redundant
with the one in verifyHandshakeSignature.
There should be no major change in behavior so far. A few minor changes
came from the refactor: we now correctly require signature_algorithms in
TLS 1.3 when using a certificate; we won't use Ed25519 in TLS 1.2 if the
client didn't send signature_algorithms; and we don't send
ec_points_format in the ServerHello (a compatibility measure) if we are
not doing ECDHE anyway because there are no mutually supported curves.
The tests also got simpler because they test simpler functions. The
caller logic switching between TLS 1.0/1.1 and 1.2 is tested by the
transcript tests.
Updates #32426
Change-Id: Ice9dcaea78d204718f661f8d60efdb408ba41577
Reviewed-on: https://go-review.googlesource.com/c/go/+/205061
Reviewed-by: Katie Hockman <katie@golang.org>
2019-11-01 19:00:33 -04:00
|
|
|
signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
|
2017-11-22 19:27:20 +00:00
|
|
|
}
|
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{}
|
2020-08-31 17:09:57 -04:00
|
|
|
var clientHash, serverHash hash.Hash
|
2014-01-22 18:24:03 -05:00
|
|
|
if hs.suite.cipher != nil {
|
|
|
|
|
clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
|
2020-08-31 17:09:57 -04:00
|
|
|
clientHash = hs.suite.mac(clientMAC)
|
2014-01-22 18:24:03 -05:00
|
|
|
serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */)
|
2020-08-31 17:09:57 -04:00
|
|
|
serverHash = hs.suite.mac(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")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-24 17:01:00 -04:00
|
|
|
if hs.serverHello.alpnProtocol != "" {
|
|
|
|
|
if len(hs.hello.alpnProtocols) == 0 {
|
|
|
|
|
c.sendAlert(alertUnsupportedExtension)
|
|
|
|
|
return false, errors.New("tls: server advertised unrequested ALPN extension")
|
|
|
|
|
}
|
|
|
|
|
if mutualProtocol([]string{hs.serverHello.alpnProtocol}, hs.hello.alpnProtocols) == "" {
|
|
|
|
|
c.sendAlert(alertUnsupportedExtension)
|
|
|
|
|
return false, errors.New("tls: server selected unadvertised ALPN protocol")
|
|
|
|
|
}
|
2014-08-05 11:36:20 -07:00
|
|
|
c.clientProtocol = hs.serverHello.alpnProtocol
|
|
|
|
|
}
|
2020-06-24 17:01:00 -04:00
|
|
|
|
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")
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-15 12:49:04 -07:00
|
|
|
// Restore masterSecret, peerCerts, and ocspResponse from previous state
|
2016-03-14 03:35:13 -06:00
|
|
|
hs.masterSecret = hs.session.masterSecret
|
|
|
|
|
c.peerCertificates = hs.session.serverCertificates
|
|
|
|
|
c.verifiedChains = hs.session.verifiedChains
|
2020-05-15 12:49:04 -07:00
|
|
|
c.ocspResponse = hs.session.ocspResponse
|
|
|
|
|
// Let the ServerHello SCTs override the session SCTs from the original
|
|
|
|
|
// connection, if any are provided
|
|
|
|
|
if len(c.scts) == 0 && len(hs.session.scts) != 0 {
|
|
|
|
|
c.scts = hs.session.scts
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-14 03:35:13 -06:00
|
|
|
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(),
|
2020-05-15 12:49:04 -07:00
|
|
|
ocspResponse: c.ocspResponse,
|
|
|
|
|
scts: c.scts,
|
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
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
2020-04-20 17:55:37 -04:00
|
|
|
if c.config.VerifyPeerCertificate != nil {
|
|
|
|
|
if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
|
|
|
|
|
c.sendAlert(alertBadCertificate)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if c.config.VerifyConnection != nil {
|
|
|
|
|
if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
|
|
|
|
|
c.sendAlert(alertBadCertificate)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-01 01:01:09 -04:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
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.
|
2020-08-01 12:18:31 +01:00
|
|
|
func certificateRequestInfoFromMsg(ctx context.Context, vers uint16, certReq *certificateRequestMsg) *CertificateRequestInfo {
|
2019-11-01 19:40:05 -04:00
|
|
|
cri := &CertificateRequestInfo{
|
|
|
|
|
AcceptableCAs: certReq.certificateAuthorities,
|
|
|
|
|
Version: vers,
|
2020-08-01 12:18:31 +01:00
|
|
|
ctx: ctx,
|
2019-11-01 19:40:05 -04:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
if !certReq.hasSignatureAlgorithm {
|
2019-11-21 13:48:38 -05:00
|
|
|
// Prior to TLS 1.2, signature schemes did not exist. In this case we
|
|
|
|
|
// make up a list based on the acceptable certificate types, to help
|
|
|
|
|
// GetClientCertificate and SupportsCertificate select the right certificate.
|
|
|
|
|
// The hash part of the SignatureScheme is a lie here, because
|
|
|
|
|
// TLS 1.0 and 1.1 always use MD5+SHA1 for RSA and SHA1 for ECDSA.
|
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
|
|
|
switch {
|
2019-05-16 19:13:29 -04:00
|
|
|
case rsaAvail && ecAvail:
|
2019-11-21 13:48:38 -05:00
|
|
|
cri.SignatureSchemes = []SignatureScheme{
|
|
|
|
|
ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512,
|
|
|
|
|
PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1,
|
|
|
|
|
}
|
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 rsaAvail:
|
2019-11-21 13:48:38 -05:00
|
|
|
cri.SignatureSchemes = []SignatureScheme{
|
|
|
|
|
PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1,
|
|
|
|
|
}
|
2019-05-16 19:13:29 -04:00
|
|
|
case ecAvail:
|
2019-11-21 13:48:38 -05:00
|
|
|
cri.SignatureSchemes = []SignatureScheme{
|
|
|
|
|
ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512,
|
|
|
|
|
}
|
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
|
|
|
|
|
}
|
|
|
|
|
|
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 {
|
2019-10-29 16:46:26 -04:00
|
|
|
sigType, _, err := typeAndHashFromSignatureScheme(sigScheme)
|
|
|
|
|
if err != nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
switch sigType {
|
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
|
|
|
|
2019-11-01 19:40:05 -04:00
|
|
|
for _, chain := range c.config.Certificates {
|
|
|
|
|
if err := cri.SupportsCertificate(&chain); err != nil {
|
2016-10-26 10:05:03 -07:00
|
|
|
continue
|
|
|
|
|
}
|
2019-11-01 19:40:05 -04:00
|
|
|
return &chain, nil
|
2016-10-26 10:05:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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()
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-24 17:01:00 -04:00
|
|
|
// mutualProtocol finds the mutual ALPN protocol given list of possible
|
|
|
|
|
// protocols and a list of the preference order.
|
|
|
|
|
func mutualProtocol(protos, preferenceProtos []string) string {
|
2014-08-05 11:36:20 -07:00
|
|
|
for _, s := range preferenceProtos {
|
|
|
|
|
for _, c := range protos {
|
2011-03-29 17:53:09 -04:00
|
|
|
if s == c {
|
2020-06-24 17:01:00 -04:00
|
|
|
return s
|
2011-03-29 17:53:09 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-24 17:01:00 -04:00
|
|
|
return ""
|
2011-03-29 17:53:09 -04:00
|
|
|
}
|
2016-02-19 16:25:52 +09:00
|
|
|
|
2019-09-08 19:36:13 +03:00
|
|
|
// hostnameInSNI converts name into an appropriate hostname for SNI.
|
2016-02-19 16:25:52 +09:00
|
|
|
// 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
|
|
|
|
|
}
|