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"
|
2024-11-09 16:23:22 +01:00
|
|
|
"crypto/internal/fips/tls13"
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
"crypto/internal/hpke"
|
2024-05-18 20:15:38 +02:00
|
|
|
"crypto/internal/mlkem768"
|
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"
|
2024-05-18 20:15:38 +02:00
|
|
|
"internal/byteorder"
|
2023-08-08 18:25:59 -07:00
|
|
|
"internal/godebug"
|
2009-12-15 15:33:31 -08:00
|
|
|
"io"
|
2014-01-22 18:24:03 -05:00
|
|
|
"net"
|
2023-08-08 18:25:59 -07:00
|
|
|
"strconv"
|
2016-02-19 16:25:52 +09:00
|
|
|
"strings"
|
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
|
2023-05-21 21:17:56 +02:00
|
|
|
session *SessionState // the session being resumed
|
|
|
|
|
ticket []byte // a fresh ticket received during this handshake
|
2014-01-22 18:24:03 -05:00
|
|
|
}
|
|
|
|
|
|
2022-04-27 09:02:52 -04:00
|
|
|
var testingOnlyForceClientHelloSignatureAlgorithms []SignatureScheme
|
|
|
|
|
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echContext, error) {
|
2018-11-01 01:01:09 -04:00
|
|
|
config := c.config
|
2017-05-30 12:53:11 -04:00
|
|
|
if len(config.ServerName) == 0 && !config.InsecureSkipVerify {
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
return nil, 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 {
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
return nil, nil, nil, errors.New("tls: invalid NextProtos value")
|
2014-08-05 11:36:20 -07:00
|
|
|
} else {
|
|
|
|
|
nextProtosLength += 1 + l
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if nextProtosLength > 0xffff {
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
return nil, nil, nil, errors.New("tls: NextProtos values too large")
|
2014-08-05 11:36:20 -07:00
|
|
|
}
|
|
|
|
|
|
2021-10-31 23:13:18 -04:00
|
|
|
supportedVersions := config.supportedVersions(roleClient)
|
2018-10-31 09:34:10 -04:00
|
|
|
if len(supportedVersions) == 0 {
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
return nil, nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion")
|
2018-10-31 09:34:10 -04:00
|
|
|
}
|
2024-05-18 20:15:38 +02:00
|
|
|
maxVersion := config.maxSupportedVersion(roleClient)
|
2018-10-31 09:34:10 -04:00
|
|
|
|
2009-11-21 15:53:03 -08:00
|
|
|
hello := &clientHelloMsg{
|
2024-05-18 20:15:38 +02:00
|
|
|
vers: maxVersion,
|
2016-04-26 10:45:35 -07:00
|
|
|
compressionMethods: []uint8{compressionNone},
|
|
|
|
|
random: make([]byte, 32),
|
2023-05-24 01:55:45 +02:00
|
|
|
extendedMasterSecret: true,
|
2016-04-26 10:45:35 -07:00
|
|
|
ocspStapling: true,
|
|
|
|
|
scts: true,
|
2017-05-30 12:53:11 -04:00
|
|
|
serverName: hostnameInSNI(config.ServerName),
|
2024-05-18 20:15:38 +02:00
|
|
|
supportedCurves: config.curvePreferences(maxVersion),
|
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,
|
2016-04-26 10:45:35 -07:00
|
|
|
}
|
2018-11-01 01:01:09 -04:00
|
|
|
|
2024-05-18 20:15:38 +02: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 hello.vers > VersionTLS12 {
|
|
|
|
|
hello.vers = VersionTLS12
|
|
|
|
|
}
|
|
|
|
|
|
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))
|
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
|
|
|
for _, suiteId := range preferenceOrder {
|
|
|
|
|
suite := mutualCipherSuite(configCipherSuites, suiteId)
|
|
|
|
|
if suite == nil {
|
|
|
|
|
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
|
|
|
// Don't advertise TLS 1.2-only cipher suites unless
|
|
|
|
|
// we're attempting TLS 1.2.
|
2024-05-18 20:15:38 +02:00
|
|
|
if maxVersion < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
|
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
|
|
|
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 {
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
return nil, nil, nil, errors.New("tls: short read from Rand: " + err.Error())
|
2018-11-01 01:01:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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).
|
2022-10-14 10:48:42 -07:00
|
|
|
//
|
|
|
|
|
// The session ID is not set for QUIC connections (see RFC 9001, Section 8.4).
|
|
|
|
|
if c.quic == nil {
|
|
|
|
|
hello.sessionId = make([]byte, 32)
|
|
|
|
|
if _, err := io.ReadFull(config.rand(), hello.sessionId); err != nil {
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
return nil, nil, nil, errors.New("tls: short read from Rand: " + err.Error())
|
2022-10-14 10:48:42 -07:00
|
|
|
}
|
2009-11-21 15:53:03 -08:00
|
|
|
}
|
|
|
|
|
|
2024-05-18 20:15:38 +02:00
|
|
|
if maxVersion >= VersionTLS12 {
|
2019-02-27 15:39:47 -05:00
|
|
|
hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
|
2017-12-06 00:35:28 -05:00
|
|
|
}
|
|
|
|
|
if testingOnlyForceClientHelloSignatureAlgorithms != nil {
|
|
|
|
|
hello.supportedSignatureAlgorithms = testingOnlyForceClientHelloSignatureAlgorithms
|
2017-09-20 13:50:35 -04:00
|
|
|
}
|
|
|
|
|
|
2024-05-18 20:15:38 +02:00
|
|
|
var keyShareKeys *keySharePrivateKeys
|
2018-11-01 01:01:09 -04:00
|
|
|
if hello.supportedVersions[0] == VersionTLS13 {
|
2023-01-13 00:37:56 +00:00
|
|
|
// Reset the list of ciphers when the client only supports TLS 1.3.
|
|
|
|
|
if len(hello.supportedVersions) == 1 {
|
|
|
|
|
hello.cipherSuites = nil
|
|
|
|
|
}
|
2023-12-14 22:13:29 +01:00
|
|
|
if needFIPS() {
|
|
|
|
|
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13FIPS...)
|
|
|
|
|
} else if hasAESGCMHardwareSupport {
|
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, defaultCipherSuitesTLS13...)
|
|
|
|
|
} else {
|
|
|
|
|
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...)
|
|
|
|
|
}
|
2018-11-01 01:01:09 -04:00
|
|
|
|
2023-12-14 22:13:29 +01:00
|
|
|
if len(hello.supportedCurves) == 0 {
|
|
|
|
|
return nil, nil, nil, errors.New("tls: no supported elliptic curves for ECDHE")
|
|
|
|
|
}
|
|
|
|
|
curveID := hello.supportedCurves[0]
|
2024-05-18 20:15:38 +02:00
|
|
|
keyShareKeys = &keySharePrivateKeys{curveID: curveID}
|
|
|
|
|
if curveID == x25519Kyber768Draft00 {
|
|
|
|
|
keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), X25519)
|
|
|
|
|
if err != nil {
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
return nil, nil, nil, err
|
2024-05-18 20:15:38 +02:00
|
|
|
}
|
|
|
|
|
seed := make([]byte, mlkem768.SeedSize)
|
|
|
|
|
if _, err := io.ReadFull(config.rand(), seed); err != nil {
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
return nil, nil, nil, err
|
2024-05-18 20:15:38 +02:00
|
|
|
}
|
2024-10-21 16:29:23 +02:00
|
|
|
keyShareKeys.kyber, err = mlkem768.NewDecapsulationKey768(seed)
|
2024-05-18 20:15:38 +02:00
|
|
|
if err != nil {
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
return nil, nil, nil, err
|
2024-05-18 20:15:38 +02:00
|
|
|
}
|
|
|
|
|
// For draft-tls-westerbaan-xyber768d00-03, we send both a hybrid
|
|
|
|
|
// and a standard X25519 key share, since most servers will only
|
|
|
|
|
// support the latter. We reuse the same X25519 ephemeral key for
|
|
|
|
|
// both, as allowed by draft-ietf-tls-hybrid-design-09, Section 3.2.
|
|
|
|
|
hello.keyShares = []keyShare{
|
|
|
|
|
{group: x25519Kyber768Draft00, data: append(keyShareKeys.ecdhe.PublicKey().Bytes(),
|
2024-10-21 14:30:46 +02:00
|
|
|
keyShareKeys.kyber.EncapsulationKey().Bytes()...)},
|
2024-05-18 20:15:38 +02:00
|
|
|
{group: X25519, data: keyShareKeys.ecdhe.PublicKey().Bytes()},
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if _, ok := curveForCurveID(curveID); !ok {
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
return nil, nil, nil, errors.New("tls: CurvePreferences includes unsupported curve")
|
2024-05-18 20:15:38 +02:00
|
|
|
}
|
|
|
|
|
keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), curveID)
|
|
|
|
|
if err != nil {
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
return nil, nil, nil, err
|
2024-05-18 20:15:38 +02:00
|
|
|
}
|
|
|
|
|
hello.keyShares = []keyShare{{group: curveID, data: keyShareKeys.ecdhe.PublicKey().Bytes()}}
|
2018-11-01 01:01:09 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-14 10:48:42 -07:00
|
|
|
if c.quic != nil {
|
|
|
|
|
p, err := c.quicGetTransportParameters()
|
|
|
|
|
if err != nil {
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
return nil, nil, nil, err
|
2022-10-14 10:48:42 -07:00
|
|
|
}
|
|
|
|
|
if p == nil {
|
|
|
|
|
p = []byte{}
|
|
|
|
|
}
|
|
|
|
|
hello.quicTransportParameters = p
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
var ech *echContext
|
|
|
|
|
if c.config.EncryptedClientHelloConfigList != nil {
|
|
|
|
|
if c.config.MinVersion != 0 && c.config.MinVersion < VersionTLS13 {
|
|
|
|
|
return nil, nil, nil, errors.New("tls: MinVersion must be >= VersionTLS13 if EncryptedClientHelloConfigList is populated")
|
|
|
|
|
}
|
|
|
|
|
if c.config.MaxVersion != 0 && c.config.MaxVersion <= VersionTLS12 {
|
|
|
|
|
return nil, nil, nil, errors.New("tls: MaxVersion must be >= VersionTLS13 if EncryptedClientHelloConfigList is populated")
|
|
|
|
|
}
|
|
|
|
|
echConfigs, err := parseECHConfigList(c.config.EncryptedClientHelloConfigList)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, nil, nil, err
|
|
|
|
|
}
|
|
|
|
|
echConfig := pickECHConfig(echConfigs)
|
|
|
|
|
if echConfig == nil {
|
|
|
|
|
return nil, nil, nil, errors.New("tls: EncryptedClientHelloConfigList contains no valid configs")
|
|
|
|
|
}
|
|
|
|
|
ech = &echContext{config: echConfig}
|
|
|
|
|
hello.encryptedClientHello = []byte{1} // indicate inner hello
|
|
|
|
|
// We need to explicitly set these 1.2 fields to nil, as we do not
|
|
|
|
|
// marshal them when encoding the inner hello, otherwise transcripts
|
|
|
|
|
// will later mismatch.
|
|
|
|
|
hello.supportedPoints = nil
|
|
|
|
|
hello.ticketSupported = false
|
|
|
|
|
hello.secureRenegotiationSupported = false
|
|
|
|
|
hello.extendedMasterSecret = false
|
|
|
|
|
|
|
|
|
|
echPK, err := hpke.ParseHPKEPublicKey(ech.config.KemID, ech.config.PublicKey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, nil, nil, err
|
|
|
|
|
}
|
|
|
|
|
suite, err := pickECHCipherSuite(ech.config.SymmetricCipherSuite)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, nil, nil, err
|
|
|
|
|
}
|
|
|
|
|
ech.kdfID, ech.aeadID = suite.KDFID, suite.AEADID
|
|
|
|
|
info := append([]byte("tls ech\x00"), ech.config.raw...)
|
|
|
|
|
ech.encapsulatedKey, ech.hpkeContext, err = hpke.SetupSender(ech.config.KemID, suite.KDFID, suite.AEADID, echPK, info)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, nil, nil, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return hello, keyShareKeys, ech, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type echContext struct {
|
|
|
|
|
config *echConfig
|
|
|
|
|
hpkeContext *hpke.Sender
|
|
|
|
|
encapsulatedKey []byte
|
|
|
|
|
innerHello *clientHelloMsg
|
|
|
|
|
innerTranscript hash.Hash
|
|
|
|
|
kdfID uint16
|
|
|
|
|
aeadID uint16
|
|
|
|
|
echRejected bool
|
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
|
|
|
|
|
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
hello, keyShareKeys, ech, err := c.makeClientHello()
|
2017-05-30 12:53:11 -04:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-21 21:17:56 +02:00
|
|
|
session, earlySecret, binderKey, err := c.loadSession(hello)
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2023-05-21 21:17:56 +02:00
|
|
|
if session != nil {
|
2018-11-04 18:41:37 -05:00
|
|
|
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 {
|
2023-05-21 21:17:56 +02:00
|
|
|
if cacheKey := c.clientSessionCacheKey(); cacheKey != "" {
|
|
|
|
|
c.config.ClientSessionCache.Put(cacheKey, nil)
|
|
|
|
|
}
|
2018-11-04 18:41:37 -05:00
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
}
|
2018-11-01 01:01:09 -04:00
|
|
|
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
if ech != nil {
|
|
|
|
|
// Split hello into inner and outer
|
|
|
|
|
ech.innerHello = hello.clone()
|
|
|
|
|
|
|
|
|
|
// Overwrite the server name in the outer hello with the public facing
|
|
|
|
|
// name.
|
|
|
|
|
hello.serverName = string(ech.config.PublicName)
|
|
|
|
|
// Generate a new random for the outer hello.
|
|
|
|
|
hello.random = make([]byte, 32)
|
|
|
|
|
_, err = io.ReadFull(c.config.rand(), hello.random)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.New("tls: short read from Rand: " + err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NOTE: we don't do PSK GREASE, in line with boringssl, it's meant to
|
|
|
|
|
// work around _possibly_ broken middleboxes, but there is little-to-no
|
|
|
|
|
// evidence that this is actually a problem.
|
|
|
|
|
|
|
|
|
|
if err := computeAndUpdateOuterECHExtension(hello, ech.innerHello, ech, true); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.serverName = hello.serverName
|
|
|
|
|
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
if _, err := c.writeHandshakeRecord(hello, nil); err != nil {
|
2018-11-01 01:01:09 -04:00
|
|
|
return err
|
2013-07-02 19:58:56 -04:00
|
|
|
}
|
|
|
|
|
|
2023-05-22 19:23:04 +02:00
|
|
|
if hello.earlyData {
|
|
|
|
|
suite := cipherSuiteTLS13ByID(session.cipherSuite)
|
|
|
|
|
transcript := suite.hash.New()
|
|
|
|
|
if err := transcriptMsg(hello, transcript); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2024-11-09 16:23:22 +01:00
|
|
|
earlyTrafficSecret := earlySecret.ClientEarlyTrafficSecret(transcript)
|
2023-05-22 19:23:04 +02:00
|
|
|
c.quicSetWriteSecret(QUICEncryptionLevelEarly, suite.id, earlyTrafficSecret)
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
// serverHelloMsg is not included in the transcript
|
|
|
|
|
msg, err := c.readHandshake(nil)
|
2018-11-01 01:01:09 -04:00
|
|
|
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.
|
2021-10-31 23:13:18 -04:00
|
|
|
maxVers := c.config.maxSupportedVersion(roleClient)
|
2020-04-29 17:54:24 -04:00
|
|
|
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{
|
2024-05-18 20:15:38 +02:00
|
|
|
c: c,
|
|
|
|
|
ctx: ctx,
|
|
|
|
|
serverHello: serverHello,
|
|
|
|
|
hello: hello,
|
|
|
|
|
keyShareKeys: keyShareKeys,
|
|
|
|
|
session: session,
|
|
|
|
|
earlySecret: earlySecret,
|
|
|
|
|
binderKey: binderKey,
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
echContext: ech,
|
2018-11-01 01:01:09 -04:00
|
|
|
}
|
2018-11-04 18:41:37 -05:00
|
|
|
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,
|
|
|
|
|
}
|
2024-05-18 20:15:38 +02:00
|
|
|
return hs.handshake()
|
2017-05-30 12:53:11 -04:00
|
|
|
}
|
|
|
|
|
|
2023-05-21 21:17:56 +02:00
|
|
|
func (c *Conn) loadSession(hello *clientHelloMsg) (
|
2024-11-09 16:23:22 +01:00
|
|
|
session *SessionState, earlySecret *tls13.EarlySecret, binderKey []byte, err error) {
|
2018-11-01 01:01:09 -04:00
|
|
|
if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil {
|
2023-05-21 21:17:56 +02:00
|
|
|
return nil, nil, nil, nil
|
2018-11-01 01:01:09 -04:00
|
|
|
}
|
2017-05-30 12:53:11 -04:00
|
|
|
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
echInner := bytes.Equal(hello.encryptedClientHello, []byte{1})
|
|
|
|
|
|
|
|
|
|
// ticketSupported is a TLS 1.2 extension (as TLS 1.3 replaced tickets with PSK
|
|
|
|
|
// identities) and ECH requires and forces TLS 1.3.
|
|
|
|
|
hello.ticketSupported = true && !echInner
|
2018-11-01 01:01:09 -04:00
|
|
|
|
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 {
|
2023-05-21 21:17:56 +02:00
|
|
|
return nil, 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.
|
2023-05-21 21:17:56 +02:00
|
|
|
cacheKey := c.clientSessionCacheKey()
|
2022-10-14 10:48:42 -07:00
|
|
|
if cacheKey == "" {
|
2023-05-21 21:17:56 +02:00
|
|
|
return nil, nil, nil, nil
|
2022-10-14 10:48:42 -07:00
|
|
|
}
|
2023-05-21 21:17:56 +02:00
|
|
|
cs, ok := c.config.ClientSessionCache.Get(cacheKey)
|
|
|
|
|
if !ok || cs == nil {
|
|
|
|
|
return nil, nil, nil, nil
|
2009-11-21 15:53:03 -08:00
|
|
|
}
|
2023-05-21 21:17:56 +02:00
|
|
|
session = cs.session
|
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 {
|
2023-05-21 21:17:56 +02:00
|
|
|
if v == session.version {
|
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 {
|
2023-05-21 21:17:56 +02:00
|
|
|
return nil, nil, nil, nil
|
2018-11-04 18:41:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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.
|
2023-05-24 15:49:56 +02:00
|
|
|
if c.config.time().After(session.peerCertificates[0].NotAfter) {
|
|
|
|
|
// Expired certificate, delete the entry.
|
|
|
|
|
c.config.ClientSessionCache.Put(cacheKey, nil)
|
|
|
|
|
return nil, nil, nil, nil
|
|
|
|
|
}
|
2018-11-04 18:41:37 -05:00
|
|
|
if !c.config.InsecureSkipVerify {
|
|
|
|
|
if len(session.verifiedChains) == 0 {
|
|
|
|
|
// The original connection had InsecureSkipVerify, while this doesn't.
|
2023-05-21 21:17:56 +02:00
|
|
|
return nil, nil, nil, nil
|
2018-11-04 18:41:37 -05:00
|
|
|
}
|
2023-05-24 15:49:56 +02:00
|
|
|
if err := session.peerCertificates[0].VerifyHostname(c.config.ServerName); err != nil {
|
2023-05-21 21:17:56 +02:00
|
|
|
return nil, nil, nil, nil
|
2018-11-04 18:41:37 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-21 21:17:56 +02:00
|
|
|
if session.version != VersionTLS13 {
|
2018-11-04 18:41:37 -05:00
|
|
|
// 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 {
|
2023-05-21 21:17:56 +02:00
|
|
|
return nil, nil, nil, nil
|
2018-11-04 18:41:37 -05:00
|
|
|
}
|
2013-07-02 19:58:56 -04:00
|
|
|
|
2023-10-22 16:31:59 -04:00
|
|
|
hello.sessionTicket = session.ticket
|
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.
|
2023-05-21 21:17:56 +02:00
|
|
|
if c.config.time().After(time.Unix(int64(session.useBy), 0)) {
|
2018-11-04 18:41:37 -05:00
|
|
|
c.config.ClientSessionCache.Put(cacheKey, nil)
|
2023-05-21 21:17:56 +02:00
|
|
|
return nil, nil, nil, nil
|
2018-11-01 01:01:09 -04:00
|
|
|
}
|
|
|
|
|
|
2018-11-04 18:41:37 -05:00
|
|
|
// 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 {
|
2023-05-21 21:17:56 +02:00
|
|
|
return nil, nil, nil, nil
|
2018-11-04 18:41:37 -05:00
|
|
|
}
|
|
|
|
|
cipherSuiteOk := false
|
|
|
|
|
for _, offeredID := range hello.cipherSuites {
|
|
|
|
|
offeredSuite := cipherSuiteTLS13ByID(offeredID)
|
|
|
|
|
if offeredSuite != nil && offeredSuite.hash == cipherSuite.hash {
|
|
|
|
|
cipherSuiteOk = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !cipherSuiteOk {
|
2023-05-21 21:17:56 +02:00
|
|
|
return nil, nil, nil, nil
|
2018-11-04 18:41:37 -05:00
|
|
|
}
|
|
|
|
|
|
2023-10-22 16:31:59 -04:00
|
|
|
if c.quic != nil {
|
2024-06-24 10:01:47 -07:00
|
|
|
if c.quic.enableSessionEvents {
|
|
|
|
|
c.quicResumeSession(session)
|
|
|
|
|
}
|
2023-10-22 16:31:59 -04:00
|
|
|
|
2023-05-22 19:23:04 +02:00
|
|
|
// For 0-RTT, the cipher suite has to match exactly, and we need to be
|
|
|
|
|
// offering the same ALPN.
|
2023-10-22 16:31:59 -04:00
|
|
|
if session.EarlyData && mutualCipherSuiteTLS13(hello.cipherSuites, session.cipherSuite) != nil {
|
2023-05-22 19:23:04 +02:00
|
|
|
for _, alpn := range hello.alpnProtocols {
|
|
|
|
|
if alpn == session.alpnProtocol {
|
|
|
|
|
hello.earlyData = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-04 18:41:37 -05:00
|
|
|
// Set the pre_shared_key extension. See RFC 8446, Section 4.2.11.1.
|
2023-05-21 21:17:56 +02:00
|
|
|
ticketAge := c.config.time().Sub(time.Unix(int64(session.createdAt), 0))
|
2018-11-04 18:41:37 -05:00
|
|
|
identity := pskIdentity{
|
2023-10-22 16:31:59 -04:00
|
|
|
label: session.ticket,
|
2023-05-21 21:17:56 +02:00
|
|
|
obfuscatedTicketAge: uint32(ticketAge/time.Millisecond) + session.ageAdd,
|
2018-11-04 18:41:37 -05:00
|
|
|
}
|
|
|
|
|
hello.pskIdentities = []pskIdentity{identity}
|
|
|
|
|
hello.pskBinders = [][]byte{make([]byte, cipherSuite.hash.Size())}
|
|
|
|
|
|
|
|
|
|
// Compute the PSK binders. See RFC 8446, Section 4.2.11.2.
|
2024-11-09 16:23:22 +01:00
|
|
|
earlySecret = tls13.NewEarlySecret(cipherSuite.hash.New, session.secret)
|
|
|
|
|
binderKey = earlySecret.ResumptionBinderKey()
|
2018-11-04 18:41:37 -05:00
|
|
|
transcript := cipherSuite.hash.New()
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
if err := computeAndUpdatePSK(hello, binderKey, transcript, cipherSuite.finishedHash); err != nil {
|
2023-05-21 21:17:56 +02:00
|
|
|
return nil, nil, nil, err
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
}
|
2018-11-04 18:41:37 -05:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2021-10-31 23:13:18 -04:00
|
|
|
vers, ok := c.config.mutualVersion(roleClient, []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()
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
if err := transcriptMsg(hs.hello, &hs.finishedHash); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if err := transcriptMsg(hs.serverHello, &hs.finishedHash); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
|
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
|
|
|
}
|
2023-05-21 21:17:56 +02:00
|
|
|
if err := hs.saveSessionTicket(); err != nil {
|
|
|
|
|
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)
|
2022-08-09 09:36:17 -07:00
|
|
|
c.isHandshakeComplete.Store(true)
|
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")
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-29 12:14:32 +02:00
|
|
|
if hs.c.config.CipherSuites == nil && !needFIPS() && rsaKexCiphers[hs.suite.id] {
|
2024-05-20 11:07:28 +02:00
|
|
|
tlsrsakex.Value() // ensure godebug is initialized
|
2023-11-21 23:16:56 +01:00
|
|
|
tlsrsakex.IncNonDefault()
|
|
|
|
|
}
|
2024-05-22 11:39:41 +02:00
|
|
|
if hs.c.config.CipherSuites == nil && !needFIPS() && tdesCiphers[hs.suite.id] {
|
|
|
|
|
tls3des.Value() // ensure godebug is initialized
|
|
|
|
|
tls3des.IncNonDefault()
|
|
|
|
|
}
|
2023-11-21 23:16:56 +01:00
|
|
|
|
2017-05-30 12:53:11 -04:00
|
|
|
hs.c.cipherSuite = hs.suite.id
|
2014-01-22 18:24:03 -05:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *clientHandshakeState) doFullHandshake() error {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
msg, err := c.readHandshake(&hs.finishedHash)
|
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
|
|
|
}
|
|
|
|
|
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
msg, err = c.readHandshake(&hs.finishedHash)
|
2018-01-04 00:42:10 -06:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2018-10-28 18:04:54 -04:00
|
|
|
c.ocspResponse = cs.response
|
2010-07-14 10:40:15 -04:00
|
|
|
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
msg, err = c.readHandshake(&hs.finishedHash)
|
2018-01-04 00:42:10 -06:00
|
|
|
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 {
|
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
|
|
|
|
|
}
|
2024-05-18 20:15:38 +02:00
|
|
|
if len(skx.key) >= 3 && skx.key[0] == 3 /* named curve */ {
|
|
|
|
|
c.curveID = CurveID(byteorder.BeUint16(skx.key[1:]))
|
|
|
|
|
}
|
2010-12-16 17:10:50 -05:00
|
|
|
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
msg, err = c.readHandshake(&hs.finishedHash)
|
2010-12-16 17:10:50 -05:00
|
|
|
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
|
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
|
|
|
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
msg, err = c.readHandshake(&hs.finishedHash)
|
2010-08-16 11:22:22 -04:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
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
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil {
|
2016-02-26 14:17:29 -05:00
|
|
|
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 {
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
if _, err := hs.c.writeHandshakeRecord(ckx, &hs.finishedHash); err != nil {
|
2016-02-26 14:17:29 -05:00
|
|
|
return err
|
|
|
|
|
}
|
2009-11-21 15:53:03 -08:00
|
|
|
}
|
|
|
|
|
|
2023-05-24 01:55:45 +02:00
|
|
|
if hs.serverHello.extendedMasterSecret {
|
|
|
|
|
c.extMasterSecret = true
|
|
|
|
|
hs.masterSecret = extMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
|
|
|
|
|
hs.finishedHash.Sum())
|
|
|
|
|
} else {
|
|
|
|
|
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
|
|
|
|
|
hs.hello.random, hs.serverHello.random)
|
|
|
|
|
}
|
|
|
|
|
if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.hello.random, hs.masterSecret); err != nil {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
return errors.New("tls: failed to write to key log: " + err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
2022-04-13 12:58:29 +00:00
|
|
|
signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash)
|
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 := 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
|
|
|
}
|
|
|
|
|
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
if _, err := hs.c.writeHandshakeRecord(certVerify, &hs.finishedHash); err != nil {
|
2016-02-26 14:17:29 -05:00
|
|
|
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.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)
|
2021-12-01 12:15:45 -05:00
|
|
|
var clientCipher, serverCipher any
|
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")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-14 10:48:42 -07:00
|
|
|
if err := checkALPN(hs.hello.alpnProtocols, hs.serverHello.alpnProtocol, false); err != nil {
|
2021-06-07 08:24:22 -04:00
|
|
|
c.sendAlert(alertUnsupportedExtension)
|
|
|
|
|
return false, err
|
2014-08-05 11:36:20 -07:00
|
|
|
}
|
2021-06-07 08:24:22 -04: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
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-21 21:17:56 +02:00
|
|
|
if hs.session.version != c.vers {
|
2016-02-15 11:51:54 -05:00
|
|
|
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")
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-24 01:55:45 +02:00
|
|
|
// RFC 7627, Section 5.3
|
|
|
|
|
if hs.session.extMasterSecret != hs.serverHello.extendedMasterSecret {
|
|
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
|
return false, errors.New("tls: server resumed a session with a different EMS extension")
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-21 21:17:56 +02:00
|
|
|
// Restore master secret and certificates from previous state
|
|
|
|
|
hs.masterSecret = hs.session.secret
|
2023-05-24 01:55:45 +02:00
|
|
|
c.extMasterSecret = hs.session.extMasterSecret
|
2023-05-21 21:17:56 +02:00
|
|
|
c.peerCertificates = hs.session.peerCertificates
|
|
|
|
|
c.activeCertHandles = hs.c.activeCertHandles
|
2016-03-14 03:35:13 -06:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2021-06-07 08:24:22 -04:00
|
|
|
// checkALPN ensure that the server's choice of ALPN protocol is compatible with
|
|
|
|
|
// the protocols that we advertised in the Client Hello.
|
2022-10-14 10:48:42 -07:00
|
|
|
func checkALPN(clientProtos []string, serverProto string, quic bool) error {
|
2021-06-07 08:24:22 -04:00
|
|
|
if serverProto == "" {
|
2022-10-14 10:48:42 -07:00
|
|
|
if quic && len(clientProtos) > 0 {
|
|
|
|
|
// RFC 9001, Section 8.1
|
|
|
|
|
return errors.New("tls: server did not select an ALPN protocol")
|
|
|
|
|
}
|
2021-06-07 08:24:22 -04:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
if len(clientProtos) == 0 {
|
|
|
|
|
return errors.New("tls: server advertised unrequested ALPN extension")
|
|
|
|
|
}
|
|
|
|
|
for _, proto := range clientProtos {
|
|
|
|
|
if proto == serverProto {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return errors.New("tls: server selected unadvertised ALPN protocol")
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
// finishedMsg is included in the transcript, but not until after we
|
|
|
|
|
// check the client version, since the state before this message was
|
|
|
|
|
// sent is used during verification.
|
|
|
|
|
msg, err := c.readHandshake(nil)
|
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
|
|
|
}
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
|
|
|
|
|
if err := transcriptMsg(serverFinished, &hs.finishedHash); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
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
|
2023-05-21 21:17:56 +02:00
|
|
|
|
|
|
|
|
if !hs.hello.ticketSupported {
|
|
|
|
|
c.sendAlert(alertIllegalParameter)
|
|
|
|
|
return errors.New("tls: server sent unrequested session ticket")
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
msg, err := c.readHandshake(&hs.finishedHash)
|
2014-01-22 18:24:03 -05:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2023-05-21 21:17:56 +02:00
|
|
|
hs.ticket = sessionTicketMsg.ticket
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *clientHandshakeState) saveSessionTicket() error {
|
|
|
|
|
if hs.ticket == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
|
|
|
|
cacheKey := c.clientSessionCacheKey()
|
|
|
|
|
if cacheKey == "" {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-17 21:46:35 +01:00
|
|
|
session := c.sessionState()
|
2023-05-21 21:17:56 +02:00
|
|
|
session.secret = hs.masterSecret
|
2023-10-22 16:31:59 -04:00
|
|
|
session.ticket = hs.ticket
|
2014-01-22 18:24:03 -05:00
|
|
|
|
2023-10-22 16:31:59 -04:00
|
|
|
cs := &ClientSessionState{session: session}
|
2023-05-21 21:17:56 +02:00
|
|
|
c.config.ClientSessionCache.Put(cacheKey, cs)
|
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
|
|
|
|
|
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
if err := c.writeChangeCipherRecord(); err != nil {
|
2016-02-26 14:17:29 -05:00
|
|
|
return err
|
|
|
|
|
}
|
2014-01-22 18:24:03 -05:00
|
|
|
|
|
|
|
|
finished := new(finishedMsg)
|
|
|
|
|
finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
|
crypto/tls: replace all usages of BytesOrPanic
Message marshalling makes use of BytesOrPanic a lot, under the
assumption that it will never panic. This assumption was incorrect, and
specifically crafted handshakes could trigger panics. Rather than just
surgically replacing the usages of BytesOrPanic in paths that could
panic, replace all usages of it with proper error returns in case there
are other ways of triggering panics which we didn't find.
In one specific case, the tree routed by expandLabel, we replace the
usage of BytesOrPanic, but retain a panic. This function already
explicitly panicked elsewhere, and returning an error from it becomes
rather painful because it requires changing a large number of APIs.
The marshalling is unlikely to ever panic, as the inputs are all either
fixed length, or already limited to the sizes required. If it were to
panic, it'd likely only be during development. A close inspection shows
no paths for a user to cause a panic currently.
This patches ends up being rather large, since it requires routing
errors back through functions which previously had no error returns.
Where possible I've tried to use helpers that reduce the verbosity
of frequently repeated stanzas, and to make the diffs as minimal as
possible.
Thanks to Marten Seemann for reporting this issue.
Fixes #58001
Fixes CVE-2022-41724
Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436
Reviewed-by: Julie Qiu <julieqiu@google.com>
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/468125
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
2022-12-14 09:43:16 -08:00
|
|
|
if _, err := hs.c.writeHandshakeRecord(finished, &hs.finishedHash); err != nil {
|
2016-02-26 14:17:29 -05:00
|
|
|
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
|
|
|
|
2023-08-08 18:25:59 -07:00
|
|
|
// defaultMaxRSAKeySize is the maximum RSA key size in bits that we are willing
|
2023-06-07 15:27:13 -07:00
|
|
|
// to verify the signatures of during a TLS handshake.
|
2023-08-08 18:25:59 -07:00
|
|
|
const defaultMaxRSAKeySize = 8192
|
|
|
|
|
|
|
|
|
|
var tlsmaxrsasize = godebug.New("tlsmaxrsasize")
|
|
|
|
|
|
|
|
|
|
func checkKeySize(n int) (max int, ok bool) {
|
|
|
|
|
if v := tlsmaxrsasize.Value(); v != "" {
|
|
|
|
|
if max, err := strconv.Atoi(v); err == nil {
|
|
|
|
|
if (n <= max) != (n <= defaultMaxRSAKeySize) {
|
|
|
|
|
tlsmaxrsasize.IncNonDefault()
|
|
|
|
|
}
|
|
|
|
|
return max, n <= max
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return defaultMaxRSAKeySize, n <= defaultMaxRSAKeySize
|
|
|
|
|
}
|
2023-06-07 15:27:13 -07: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 {
|
2022-08-29 09:40:50 -07:00
|
|
|
activeHandles := make([]*activeCert, len(certificates))
|
2018-11-01 01:01:09 -04:00
|
|
|
certs := make([]*x509.Certificate, len(certificates))
|
|
|
|
|
for i, asn1Data := range certificates {
|
2023-05-21 21:17:56 +02:00
|
|
|
cert, err := globalCertCache.newCert(asn1Data)
|
2018-11-01 01:01:09 -04:00
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertBadCertificate)
|
|
|
|
|
return errors.New("tls: failed to parse certificate from server: " + err.Error())
|
|
|
|
|
}
|
2023-08-08 18:25:59 -07:00
|
|
|
if cert.cert.PublicKeyAlgorithm == x509.RSA {
|
|
|
|
|
n := cert.cert.PublicKey.(*rsa.PublicKey).N.BitLen()
|
|
|
|
|
if max, ok := checkKeySize(n); !ok {
|
|
|
|
|
c.sendAlert(alertBadCertificate)
|
|
|
|
|
return fmt.Errorf("tls: server sent certificate containing RSA key larger than %d bits", max)
|
|
|
|
|
}
|
2023-06-07 15:27:13 -07:00
|
|
|
}
|
2022-08-29 09:40:50 -07:00
|
|
|
activeHandles[i] = cert
|
|
|
|
|
certs[i] = cert.cert
|
2018-11-01 01:01:09 -04:00
|
|
|
}
|
|
|
|
|
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
echRejected := c.config.EncryptedClientHelloConfigList != nil && !c.echAccepted
|
|
|
|
|
if echRejected {
|
|
|
|
|
if c.config.EncryptedClientHelloRejectionVerify != nil {
|
|
|
|
|
if err := c.config.EncryptedClientHelloRejectionVerify(c.connectionStateLocked()); err != nil {
|
|
|
|
|
c.sendAlert(alertBadCertificate)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
opts := x509.VerifyOptions{
|
|
|
|
|
Roots: c.config.RootCAs,
|
|
|
|
|
CurrentTime: c.config.time(),
|
|
|
|
|
DNSName: c.serverName,
|
|
|
|
|
Intermediates: x509.NewCertPool(),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, cert := range certs[1:] {
|
|
|
|
|
opts.Intermediates.AddCert(cert)
|
|
|
|
|
}
|
|
|
|
|
var err error
|
|
|
|
|
c.verifiedChains, err = certs[0].Verify(opts)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertBadCertificate)
|
|
|
|
|
return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if !c.config.InsecureSkipVerify {
|
2018-11-01 01:01:09 -04:00
|
|
|
opts := x509.VerifyOptions{
|
|
|
|
|
Roots: c.config.RootCAs,
|
|
|
|
|
CurrentTime: c.config.time(),
|
|
|
|
|
DNSName: c.config.ServerName,
|
|
|
|
|
Intermediates: x509.NewCertPool(),
|
|
|
|
|
}
|
2022-04-27 09:02:53 -04:00
|
|
|
|
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)
|
2022-11-18 07:59:03 +00:00
|
|
|
return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
|
2018-11-01 01:01:09 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-29 09:40:50 -07:00
|
|
|
c.activeCertHandles = activeHandles
|
2018-11-01 01:01:09 -04:00
|
|
|
c.peerCertificates = certs
|
|
|
|
|
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
if c.config.VerifyPeerCertificate != nil && !echRejected {
|
2020-04-20 17:55:37 -04:00
|
|
|
if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
|
|
|
|
|
c.sendAlert(alertBadCertificate)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
if c.config.VerifyConnection != nil && !echRejected {
|
2020-04-20 17:55:37 -04:00
|
|
|
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.
|
2022-10-14 10:48:42 -07:00
|
|
|
func (c *Conn) clientSessionCacheKey() string {
|
|
|
|
|
if len(c.config.ServerName) > 0 {
|
|
|
|
|
return c.config.ServerName
|
|
|
|
|
}
|
|
|
|
|
if c.conn != nil {
|
|
|
|
|
return c.conn.RemoteAddr().String()
|
2014-01-22 18:24:03 -05:00
|
|
|
}
|
2022-10-14 10:48:42 -07:00
|
|
|
return ""
|
2014-01-22 18:24:03 -05: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]
|
|
|
|
|
}
|
|
|
|
|
if i := strings.LastIndex(host, "%"); i > 0 {
|
|
|
|
|
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
|
|
|
|
|
}
|
crypto/tls: add ech client support
This CL adds a (very opinionated) client-side ECH implementation.
In particular, if a user configures a ECHConfigList, by setting the
Config.EncryptedClientHelloConfigList, but we determine that none of
the configs are appropriate, we will not fallback to plaintext SNI, and
will instead return an error. It is then up to the user to decide if
they wish to fallback to plaintext themselves (by removing the config
list).
Additionally if Config.EncryptedClientHelloConfigList is provided, we
will not offer TLS support lower than 1.3, since negotiating any other
version, while offering ECH, is a hard error anyway. Similarly, if a
user wishes to fallback to plaintext SNI by using 1.2, they may do so
by removing the config list.
With regard to PSK GREASE, we match the boringssl behavior, which does
not include PSK identities/binders in the outer hello when doing ECH.
If the server rejects ECH, we will return a ECHRejectionError error,
which, if provided by the server, will contain a ECHConfigList in the
RetryConfigList field containing configs that should be used if the user
wishes to retry. It is up to the user to replace their existing
Config.EncryptedClientHelloConfigList with the retry config list.
Fixes #63369
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
Change-Id: I9bc373c044064221a647a388ac61624efd6bbdbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/578575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-04-11 08:50:36 -07:00
|
|
|
|
|
|
|
|
func computeAndUpdatePSK(m *clientHelloMsg, binderKey []byte, transcript hash.Hash, finishedHash func([]byte, hash.Hash) []byte) error {
|
|
|
|
|
helloBytes, err := m.marshalWithoutBinders()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
transcript.Write(helloBytes)
|
|
|
|
|
pskBinders := [][]byte{finishedHash(binderKey, transcript)}
|
|
|
|
|
return m.updateBinders(pskBinders)
|
|
|
|
|
}
|