TUN-4961: Update quic-go to latest

- Updates fips-go to be the latest on cfsetup.yaml
- Updates sumtype's x/tools to be latest to avoid Internal: nil pkg
  errors with fips.
This commit is contained in:
Sudarsan Reddy
2021-08-27 12:26:00 +01:00
parent d0a1daac3b
commit 414cb12f02
585 changed files with 61873 additions and 6255 deletions

View File

@@ -1,6 +0,0 @@
# qtls
[![Godoc Reference](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](https://godoc.org/github.com/marten-seemann/qtls)
[![CircleCI Build Status](https://img.shields.io/circleci/project/github/marten-seemann/qtls.svg?style=flat-square&label=CircleCI+build)](https://circleci.com/gh/marten-seemann/qtls)
This repository contains a modified version of the standard library's TLS implementation, modified for the QUIC protocol. It is used by [quic-go](https://github.com/lucas-clemente/quic-go).

View File

@@ -1,9 +0,0 @@
module github.com/marten-seemann/qtls-go1-15
go 1.15
require (
github.com/golang/mock v1.4.4
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae
)

View File

@@ -1,14 +0,0 @@
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=

View File

@@ -67,7 +67,11 @@ func (ka rsaKeyAgreement) generateClientKeyExchange(config *config, clientHello
return nil, nil, err
}
encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), preMasterSecret)
rsaKey, ok := cert.PublicKey.(*rsa.PublicKey)
if !ok {
return nil, nil, errors.New("tls: server certificate contains incorrect key type for selected ciphersuite")
}
encrypted, err := rsa.EncryptPKCS1v15(config.rand(), rsaKey, preMasterSecret)
if err != nil {
return nil, nil, err
}

View File

@@ -5,7 +5,6 @@
package qtls
import (
"crypto"
"crypto/elliptic"
"crypto/hmac"
"errors"
@@ -32,20 +31,8 @@ const (
trafficUpdateLabel = "traffic upd"
)
// HkdfExtract generates a pseudorandom key for use with Expand from an input secret and an optional independent salt.
func HkdfExtract(hash crypto.Hash, newSecret, currentSecret []byte) []byte {
if newSecret == nil {
newSecret = make([]byte, hash.Size())
}
return hkdf.Extract(hash.New, newSecret, currentSecret)
}
// HkdfExpandLabel HKDF expands a label
func HkdfExpandLabel(hash crypto.Hash, secret, hashValue []byte, label string, L int) []byte {
return hkdfExpandLabel(hash, secret, hashValue, label, L)
}
func hkdfExpandLabel(hash crypto.Hash, secret, context []byte, label string, length int) []byte {
// expandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1.
func (c *cipherSuiteTLS13) expandLabel(secret []byte, label string, context []byte, length int) []byte {
var hkdfLabel cryptobyte.Builder
hkdfLabel.AddUint16(uint16(length))
hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
@@ -56,18 +43,13 @@ func hkdfExpandLabel(hash crypto.Hash, secret, context []byte, label string, len
b.AddBytes(context)
})
out := make([]byte, length)
n, err := hkdf.Expand(hash.New, secret, hkdfLabel.BytesOrPanic()).Read(out)
n, err := hkdf.Expand(c.hash.New, secret, hkdfLabel.BytesOrPanic()).Read(out)
if err != nil || n != length {
panic("tls: HKDF-Expand-Label invocation failed unexpectedly")
}
return out
}
// expandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1.
func (c *cipherSuiteTLS13) expandLabel(secret []byte, label string, context []byte, length int) []byte {
return hkdfExpandLabel(c.hash, secret, context, label, length)
}
// deriveSecret implements Derive-Secret from RFC 8446, Section 7.1.
func (c *cipherSuiteTLS13) deriveSecret(secret []byte, label string, transcript hash.Hash) []byte {
if transcript == nil {
@@ -78,7 +60,10 @@ func (c *cipherSuiteTLS13) deriveSecret(secret []byte, label string, transcript
// extract implements HKDF-Extract with the cipher suite hash.
func (c *cipherSuiteTLS13) extract(newSecret, currentSecret []byte) []byte {
return HkdfExtract(c.hash, newSecret, currentSecret)
if newSecret == nil {
newSecret = make([]byte, c.hash.Size())
}
return hkdf.Extract(c.hash.New, newSecret, currentSecret)
}
// nextTrafficSecret generates the next traffic secret, given the current one,

View File

@@ -0,0 +1,6 @@
# qtls
[![Go Reference](https://pkg.go.dev/badge/github.com/marten-seemann/qtls-go1-17.svg)](https://pkg.go.dev/github.com/marten-seemann/qtls-go1-17)
[![.github/workflows/go-test.yml](https://github.com/marten-seemann/qtls-go1-17/actions/workflows/go-test.yml/badge.svg)](https://github.com/marten-seemann/qtls-go1-17/actions/workflows/go-test.yml)
This repository contains a modified version of the standard library's TLS implementation, modified for the QUIC protocol. It is used by [quic-go](https://github.com/lucas-clemente/quic-go).

View File

@@ -13,11 +13,12 @@ import (
"crypto/rc4"
"crypto/sha1"
"crypto/sha256"
"crypto/x509"
"fmt"
"hash"
"runtime"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/sys/cpu"
)
// CipherSuite is a TLS cipher suite. Note that most functions in this package
@@ -46,10 +47,10 @@ var (
// InsecureCipherSuites.
//
// The list is sorted by ID. Note that the default cipher suites selected by
// this package might depend on logic that can't be captured by a static list.
// this package might depend on logic that can't be captured by a static list,
// and might not match those returned by this function.
func CipherSuites() []*CipherSuite {
return []*CipherSuite{
{TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, false},
{TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false},
{TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false},
{TLS_RSA_WITH_AES_128_GCM_SHA256, "TLS_RSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false},
@@ -61,7 +62,6 @@ func CipherSuites() []*CipherSuite {
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false},
{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false},
{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, false},
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false},
{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false},
{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false},
@@ -79,13 +79,15 @@ func CipherSuites() []*CipherSuite {
// Most applications should not use the cipher suites in this list, and should
// only use those returned by CipherSuites.
func InsecureCipherSuites() []*CipherSuite {
// RC4 suites are broken because RC4 is.
// CBC-SHA256 suites have no Lucky13 countermeasures.
// This list includes RC4, CBC_SHA256, and 3DES cipher suites. See
// cipherSuitesPreferenceOrder for details.
return []*CipherSuite{
{TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA", supportedUpToTLS12, true},
{TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, true},
{TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true},
{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", supportedUpToTLS12, true},
{TLS_ECDHE_RSA_WITH_RC4_128_SHA, "TLS_ECDHE_RSA_WITH_RC4_128_SHA", supportedUpToTLS12, true},
{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, true},
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true},
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true},
}
@@ -108,25 +110,6 @@ func CipherSuiteName(id uint16) string {
return fmt.Sprintf("0x%04X", id)
}
// a keyAgreement implements the client and server side of a TLS key agreement
// protocol by generating and processing key exchange messages.
type keyAgreement interface {
// On the server side, the first two methods are called in order.
// In the case that the key agreement protocol doesn't use a
// ServerKeyExchange message, generateServerKeyExchange can return nil,
// nil.
generateServerKeyExchange(*config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
processClientKeyExchange(*config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error)
// On the client side, the next two methods are called in order.
// This method may not be called if the server doesn't send a
// ServerKeyExchange message.
processServerKeyExchange(*config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error
generateClientKeyExchange(*config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error)
}
const (
// suiteECDHE indicates that the cipher suite involves elliptic curve
// Diffie-Hellman. This means that it should only be selected when the
@@ -144,12 +127,10 @@ const (
// suiteSHA384 indicates that the cipher suite uses SHA384 as the
// handshake hash.
suiteSHA384
// suiteDefaultOff indicates that this cipher suite is not included by
// default.
suiteDefaultOff
)
// A cipherSuite is a specific combination of key agreement, cipher and MAC function.
// A cipherSuite is a TLS 1.01.2 cipher suite, and defines the key exchange
// mechanism, as well as the cipher+MAC pair or the AEAD.
type cipherSuite struct {
id uint16
// the lengths, in bytes, of the key material needed for each component.
@@ -160,41 +141,37 @@ type cipherSuite struct {
// flags is a bitmask of the suite* values, above.
flags int
cipher func(key, iv []byte, isRead bool) interface{}
mac func(version uint16, macKey []byte) macFunction
mac func(key []byte) hash.Hash
aead func(key, fixedNonce []byte) aead
}
var cipherSuites = []*cipherSuite{
// Ciphersuite order is chosen so that ECDHE comes before plain RSA and
// AEADs are the top preference.
var cipherSuites = []*cipherSuite{ // TODO: replace with a map, since the order doesn't matter.
{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadAESGCM},
{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12, cipherAES, macSHA256, nil},
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, cipherAES, macSHA256, nil},
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherAES, macSHA1, nil},
{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherAES, macSHA1, nil},
{TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM},
{TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
{TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
{TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12, cipherAES, macSHA256, nil},
{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil},
// RC4-based cipher suites are disabled by default.
{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil},
{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil},
{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteDefaultOff, cipherRC4, macSHA1, nil},
{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, 0, cipherRC4, macSHA1, nil},
{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE, cipherRC4, macSHA1, nil},
{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherRC4, macSHA1, nil},
}
// selectCipherSuite returns the first cipher suite from ids which is also in
// supportedIDs and passes the ok filter.
// selectCipherSuite returns the first TLS 1.01.2 cipher suite from ids which
// is also in supportedIDs and passes the ok filter.
func selectCipherSuite(ids, supportedIDs []uint16, ok func(*cipherSuite) bool) *cipherSuite {
for _, id := range ids {
candidate := cipherSuiteByID(id)
@@ -231,12 +208,208 @@ func (c *CipherSuiteTLS13) IVLen() int {
return aeadNonceLength
}
var cipherSuitesTLS13 = []*cipherSuiteTLS13{
var cipherSuitesTLS13 = []*cipherSuiteTLS13{ // TODO: replace with a map.
{TLS_AES_128_GCM_SHA256, 16, aeadAESGCMTLS13, crypto.SHA256},
{TLS_CHACHA20_POLY1305_SHA256, 32, aeadChaCha20Poly1305, crypto.SHA256},
{TLS_AES_256_GCM_SHA384, 32, aeadAESGCMTLS13, crypto.SHA384},
}
// cipherSuitesPreferenceOrder is the order in which we'll select (on the
// server) or advertise (on the client) TLS 1.01.2 cipher suites.
//
// Cipher suites are filtered but not reordered based on the application and
// peer's preferences, meaning we'll never select a suite lower in this list if
// any higher one is available. This makes it more defensible to keep weaker
// cipher suites enabled, especially on the server side where we get the last
// word, since there are no known downgrade attacks on cipher suites selection.
//
// The list is sorted by applying the following priority rules, stopping at the
// first (most important) applicable one:
//
// - Anything else comes before RC4
//
// RC4 has practically exploitable biases. See https://www.rc4nomore.com.
//
// - Anything else comes before CBC_SHA256
//
// SHA-256 variants of the CBC ciphersuites don't implement any Lucky13
// countermeasures. See http://www.isg.rhul.ac.uk/tls/Lucky13.html and
// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
//
// - Anything else comes before 3DES
//
// 3DES has 64-bit blocks, which makes it fundamentally susceptible to
// birthday attacks. See https://sweet32.info.
//
// - ECDHE comes before anything else
//
// Once we got the broken stuff out of the way, the most important
// property a cipher suite can have is forward secrecy. We don't
// implement FFDHE, so that means ECDHE.
//
// - AEADs come before CBC ciphers
//
// Even with Lucky13 countermeasures, MAC-then-Encrypt CBC cipher suites
// are fundamentally fragile, and suffered from an endless sequence of
// padding oracle attacks. See https://eprint.iacr.org/2015/1129,
// https://www.imperialviolet.org/2014/12/08/poodleagain.html, and
// https://blog.cloudflare.com/yet-another-padding-oracle-in-openssl-cbc-ciphersuites/.
//
// - AES comes before ChaCha20
//
// When AES hardware is available, AES-128-GCM and AES-256-GCM are faster
// than ChaCha20Poly1305.
//
// When AES hardware is not available, AES-128-GCM is one or more of: much
// slower, way more complex, and less safe (because not constant time)
// than ChaCha20Poly1305.
//
// We use this list if we think both peers have AES hardware, and
// cipherSuitesPreferenceOrderNoAES otherwise.
//
// - AES-128 comes before AES-256
//
// The only potential advantages of AES-256 are better multi-target
// margins, and hypothetical post-quantum properties. Neither apply to
// TLS, and AES-256 is slower due to its four extra rounds (which don't
// contribute to the advantages above).
//
// - ECDSA comes before RSA
//
// The relative order of ECDSA and RSA cipher suites doesn't matter,
// as they depend on the certificate. Pick one to get a stable order.
//
var cipherSuitesPreferenceOrder = []uint16{
// AEADs w/ ECDHE
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
// CBC w/ ECDHE
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
// AEADs w/o ECDHE
TLS_RSA_WITH_AES_128_GCM_SHA256,
TLS_RSA_WITH_AES_256_GCM_SHA384,
// CBC w/o ECDHE
TLS_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_AES_256_CBC_SHA,
// 3DES
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
// CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
TLS_RSA_WITH_AES_128_CBC_SHA256,
// RC4
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA,
TLS_RSA_WITH_RC4_128_SHA,
}
var cipherSuitesPreferenceOrderNoAES = []uint16{
// ChaCha20Poly1305
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
// AES-GCM w/ ECDHE
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
// The rest of cipherSuitesPreferenceOrder.
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_AES_128_GCM_SHA256,
TLS_RSA_WITH_AES_256_GCM_SHA384,
TLS_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
TLS_RSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA,
TLS_RSA_WITH_RC4_128_SHA,
}
// disabledCipherSuites are not used unless explicitly listed in
// Config.CipherSuites. They MUST be at the end of cipherSuitesPreferenceOrder.
var disabledCipherSuites = []uint16{
// CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
TLS_RSA_WITH_AES_128_CBC_SHA256,
// RC4
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA,
TLS_RSA_WITH_RC4_128_SHA,
}
var (
defaultCipherSuitesLen = len(cipherSuitesPreferenceOrder) - len(disabledCipherSuites)
defaultCipherSuites = cipherSuitesPreferenceOrder[:defaultCipherSuitesLen]
)
// defaultCipherSuitesTLS13 is also the preference order, since there are no
// disabled by default TLS 1.3 cipher suites. The same AES vs ChaCha20 logic as
// cipherSuitesPreferenceOrder applies.
var defaultCipherSuitesTLS13 = []uint16{
TLS_AES_128_GCM_SHA256,
TLS_AES_256_GCM_SHA384,
TLS_CHACHA20_POLY1305_SHA256,
}
var defaultCipherSuitesTLS13NoAES = []uint16{
TLS_CHACHA20_POLY1305_SHA256,
TLS_AES_128_GCM_SHA256,
TLS_AES_256_GCM_SHA384,
}
var (
hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ
hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL
// Keep in sync with crypto/aes/cipher_s390x.go.
hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR &&
(cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)
hasAESGCMHardwareSupport = runtime.GOARCH == "amd64" && hasGCMAsmAMD64 ||
runtime.GOARCH == "arm64" && hasGCMAsmARM64 ||
runtime.GOARCH == "s390x" && hasGCMAsmS390X
)
var aesgcmCiphers = map[uint16]bool{
// TLS 1.2
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: true,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: true,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: true,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: true,
// TLS 1.3
TLS_AES_128_GCM_SHA256: true,
TLS_AES_256_GCM_SHA384: true,
}
var nonAESGCMAEADCiphers = map[uint16]bool{
// TLS 1.2
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305: true,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: true,
// TLS 1.3
TLS_CHACHA20_POLY1305_SHA256: true,
}
// aesgcmPreferred returns whether the first known cipher in the preference list
// is an AES-GCM cipher, implying the peer has hardware support for it.
func aesgcmPreferred(ciphers []uint16) bool {
for _, cID := range ciphers {
if c := cipherSuiteByID(cID); c != nil {
return aesgcmCiphers[cID]
}
if c := cipherSuiteTLS13ByID(cID); c != nil {
return aesgcmCiphers[cID]
}
}
return false
}
func cipherRC4(key, iv []byte, isRead bool) interface{} {
cipher, _ := rc4.NewCipher(key)
return cipher
@@ -258,24 +431,15 @@ func cipherAES(key, iv []byte, isRead bool) interface{} {
return cipher.NewCBCEncrypter(block, iv)
}
// macSHA1 returns a macFunction for the given protocol version.
func macSHA1(version uint16, key []byte) macFunction {
return tls10MAC{h: hmac.New(newConstantTimeHash(sha1.New), key)}
// macSHA1 returns a SHA-1 based constant time MAC.
func macSHA1(key []byte) hash.Hash {
return hmac.New(newConstantTimeHash(sha1.New), key)
}
// macSHA256 returns a SHA-256 based MAC. These are only supported in TLS 1.2
// so the given version is ignored.
func macSHA256(version uint16, key []byte) macFunction {
return tls10MAC{h: hmac.New(sha256.New, key)}
}
type macFunction interface {
// Size returns the length of the MAC.
Size() int
// MAC appends the MAC of (seq, header, data) to out. The extra data is fed
// into the MAC after obtaining the result to normalize timing. The result
// is only valid until the next invocation of MAC as the buffer is reused.
MAC(seq, header, data, extra []byte) []byte
// macSHA256 returns a SHA-256 based MAC. This is only supported in TLS 1.2 and
// is currently only used in disabled-by-default cipher suites.
func macSHA256(key []byte) hash.Hash {
return hmac.New(sha256.New, key)
}
type aead interface {
@@ -428,26 +592,14 @@ func newConstantTimeHash(h func() hash.Hash) func() hash.Hash {
}
// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, Section 6.2.3.
type tls10MAC struct {
h hash.Hash
buf []byte
}
func (s tls10MAC) Size() int {
return s.h.Size()
}
// MAC is guaranteed to take constant time, as long as
// len(seq)+len(header)+len(data)+len(extra) is constant. extra is not fed into
// the MAC, but is only provided to make the timing profile constant.
func (s tls10MAC) MAC(seq, header, data, extra []byte) []byte {
s.h.Reset()
s.h.Write(seq)
s.h.Write(header)
s.h.Write(data)
res := s.h.Sum(s.buf[:0])
func tls10MAC(h hash.Hash, out, seq, header, data, extra []byte) []byte {
h.Reset()
h.Write(seq)
h.Write(header)
h.Write(data)
res := h.Sum(out)
if extra != nil {
s.h.Write(extra)
h.Write(extra)
}
return res
}

View File

@@ -7,6 +7,7 @@ package qtls
import (
"bytes"
"container/list"
"context"
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
@@ -23,8 +24,6 @@ import (
"strings"
"sync"
"time"
"golang.org/x/sys/cpu"
)
const (
@@ -241,9 +240,6 @@ type connectionState struct {
CipherSuite uint16
// NegotiatedProtocol is the application protocol negotiated with ALPN.
//
// Note that on the client side, this is currently not guaranteed to be from
// Config.NextProtos.
NegotiatedProtocol string
// NegotiatedProtocolIsMutual used to indicate a mutual NPN negotiation.
@@ -349,7 +345,7 @@ type clientSessionState struct {
// goroutines. Up to TLS 1.2, only ticket-based resumption is supported, not
// SessionID-based resumption. In TLS 1.3 they were merged into PSK modes, which
// are supported via this interface.
//go:generate sh -c "mockgen -package qtls -destination mock_client_session_cache_test.go github.com/marten-seemann/qtls-go1-15 ClientSessionCache"
//go:generate sh -c "mockgen -package qtls -destination mock_client_session_cache_test.go github.com/marten-seemann/qtls-go1-17 ClientSessionCache"
type ClientSessionCache = tls.ClientSessionCache
// SignatureScheme is a tls.SignatureScheme
@@ -430,6 +426,16 @@ type clientHelloInfo struct {
// config is embedded by the GetCertificate or GetConfigForClient caller,
// for use with SupportsCertificate.
config *Config
// ctx is the context of the handshake that is in progress.
ctx context.Context
}
// Context returns the context of the handshake that is in progress.
// This context is a child of the context passed to HandshakeContext,
// if any, and is canceled when the handshake concludes.
func (c *clientHelloInfo) Context() context.Context {
return c.ctx
}
// CertificateRequestInfo contains information from a server's
@@ -437,6 +443,31 @@ type clientHelloInfo struct {
// of control from a client.
type CertificateRequestInfo = tls.CertificateRequestInfo
type certificateRequestInfo struct {
// AcceptableCAs contains zero or more, DER-encoded, X.501
// Distinguished Names. These are the names of root or intermediate CAs
// that the server wishes the returned certificate to be signed by. An
// empty slice indicates that the server has no preference.
AcceptableCAs [][]byte
// SignatureSchemes lists the signature schemes that the server is
// willing to verify.
SignatureSchemes []SignatureScheme
// Version is the TLS version that was negotiated for this connection.
Version uint16
// ctx is the context of the handshake that is in progress.
ctx context.Context
}
// Context returns the context of the handshake that is in progress.
// This context is a child of the context passed to HandshakeContext,
// if any, and is canceled when the handshake concludes.
func (c *certificateRequestInfo) Context() context.Context {
return c.ctx
}
// RenegotiationSupport enumerates the different levels of support for TLS
// renegotiation. TLS renegotiation is the act of performing subsequent
// handshakes on a connection after the first. This significantly complicates
@@ -573,7 +604,11 @@ type config struct {
RootCAs *x509.CertPool
// NextProtos is a list of supported application level protocols, in
// order of preference.
// order of preference. If both peers support ALPN, the selected
// protocol will be one from this list, and the connection will fail
// if there is no mutually supported protocol. If NextProtos is empty
// or the peer doesn't support ALPN, the connection will succeed and
// ConnectionState.NegotiatedProtocol will be empty.
NextProtos []string
// ServerName is used to verify the hostname on the returned
@@ -599,17 +634,21 @@ type config struct {
// testing or in combination with VerifyConnection or VerifyPeerCertificate.
InsecureSkipVerify bool
// CipherSuites is a list of supported cipher suites for TLS versions up to
// TLS 1.2. If CipherSuites is nil, a default list of secure cipher suites
// is used, with a preference order based on hardware performance. The
// default cipher suites might change over Go versions. Note that TLS 1.3
// ciphersuites are not configurable.
// CipherSuites is a list of enabled TLS 1.01.2 cipher suites. The order of
// the list is ignored. Note that TLS 1.3 ciphersuites are not configurable.
//
// If CipherSuites is nil, a safe default list is used. The default cipher
// suites might change over time.
CipherSuites []uint16
// PreferServerCipherSuites controls whether the server selects the
// client's most preferred ciphersuite, or the server's most preferred
// ciphersuite. If true then the server's preference, as expressed in
// the order of elements in CipherSuites, is used.
// PreferServerCipherSuites is a legacy field and has no effect.
//
// It used to control whether the server would follow the client's or the
// server's preference. Servers now select the best mutually supported
// cipher suite based on logic that takes into account inferred client
// hardware, server hardware, and security.
//
// Deprected: PreferServerCipherSuites is ignored.
PreferServerCipherSuites bool
// SessionTicketsDisabled may be set to true to disable session ticket and
@@ -806,9 +845,12 @@ func (c *config) ticketKeyFromBytes(b [32]byte) (key ticketKey) {
// ticket, and the lifetime we set for tickets we send.
const maxSessionTicketLifetime = 7 * 24 * time.Hour
// Clone returns a shallow clone of c. It is safe to clone a Config that is
// Clone returns a shallow clone of c or nil if c is nil. It is safe to clone a Config that is
// being used concurrently by a TLS client or server.
func (c *config) Clone() *config {
if c == nil {
return nil
}
c.mutex.RLock()
defer c.mutex.RUnlock()
return &config{
@@ -986,11 +1028,10 @@ func (c *config) time() time.Time {
}
func (c *config) cipherSuites() []uint16 {
s := c.CipherSuites
if s == nil {
s = defaultCipherSuites()
if c.CipherSuites != nil {
return c.CipherSuites
}
return s
return defaultCipherSuites
}
var supportedVersions = []uint16{
@@ -1292,7 +1333,9 @@ func (c *config) BuildNameToCertificate() {
if err != nil {
continue
}
if len(x509Cert.Subject.CommonName) > 0 {
// If SANs are *not* present, some clients will consider the certificate
// valid for the name in the Common Name.
if x509Cert.Subject.CommonName != "" && len(x509Cert.DNSNames) == 0 {
c.NameToCertificate[x509Cert.Subject.CommonName] = cert
}
for _, san := range x509Cert.DNSNames {
@@ -1428,89 +1471,6 @@ func defaultConfig() *Config {
return &emptyConfig
}
var (
once sync.Once
varDefaultCipherSuites []uint16
varDefaultCipherSuitesTLS13 []uint16
)
func defaultCipherSuites() []uint16 {
once.Do(initDefaultCipherSuites)
return varDefaultCipherSuites
}
func defaultCipherSuitesTLS13() []uint16 {
once.Do(initDefaultCipherSuites)
return varDefaultCipherSuitesTLS13
}
func initDefaultCipherSuites() {
var topCipherSuites []uint16
// Check the cpu flags for each platform that has optimized GCM implementations.
// Worst case, these variables will just all be false.
var (
hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ
hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL
// Keep in sync with crypto/aes/cipher_s390x.go.
// TODO: check for s390
// hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)
hasGCMAsmS390X = false
hasGCMAsm = hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X
)
if hasGCMAsm {
// If AES-GCM hardware is provided then prioritise AES-GCM
// cipher suites.
topCipherSuites = []uint16{
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
}
varDefaultCipherSuitesTLS13 = []uint16{
TLS_AES_128_GCM_SHA256,
TLS_CHACHA20_POLY1305_SHA256,
TLS_AES_256_GCM_SHA384,
}
} else {
// Without AES-GCM hardware, we put the ChaCha20-Poly1305
// cipher suites first.
topCipherSuites = []uint16{
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
}
varDefaultCipherSuitesTLS13 = []uint16{
TLS_CHACHA20_POLY1305_SHA256,
TLS_AES_128_GCM_SHA256,
TLS_AES_256_GCM_SHA384,
}
}
varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites))
varDefaultCipherSuites = append(varDefaultCipherSuites, topCipherSuites...)
NextCipherSuite:
for _, suite := range cipherSuites {
if suite.flags&suiteDefaultOff != 0 {
continue
}
for _, existing := range varDefaultCipherSuites {
if existing == suite.id {
continue NextCipherSuite
}
}
varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id)
}
}
func unexpectedMessageError(wanted, got interface{}) error {
return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted)
}

View File

@@ -8,11 +8,13 @@ package qtls
import (
"bytes"
"context"
"crypto/cipher"
"crypto/subtle"
"crypto/x509"
"errors"
"fmt"
"hash"
"io"
"net"
"sync"
@@ -26,7 +28,7 @@ type Conn struct {
// constant
conn net.Conn
isClient bool
handshakeFn func() error // (*Conn).clientHandshake or serverHandshake
handshakeFn func(context.Context) error // (*Conn).clientHandshake or serverHandshake
// handshakeStatus is 1 if the connection is currently transferring
// application data (i.e. is not currently processing a handshake).
@@ -93,15 +95,14 @@ type Conn struct {
clientFinished [12]byte
serverFinished [12]byte
clientProtocol string
clientProtocolFallback bool
// clientProtocol is the negotiated ALPN protocol.
clientProtocol string
// input/output
in, out halfConn
rawInput bytes.Buffer // raw input, starting with a record header
input bytes.Reader // application data waiting to be read, from rawInput.Next
hand bytes.Buffer // handshake data waiting to be read
outBuf []byte // scratch buffer used by out.encrypt
buffering bool // whether records are buffered in sendBuf
sendBuf []byte // a buffer of records waiting to be sent
@@ -164,33 +165,34 @@ func (c *Conn) SetWriteDeadline(t time.Time) error {
type halfConn struct {
sync.Mutex
err error // first permanent error
version uint16 // protocol version
cipher interface{} // cipher algorithm
mac macFunction
seq [8]byte // 64-bit sequence number
additionalData [13]byte // to avoid allocs; interface method args escape
err error // first permanent error
version uint16 // protocol version
cipher interface{} // cipher algorithm
mac hash.Hash
seq [8]byte // 64-bit sequence number
scratchBuf [13]byte // to avoid allocs; interface method args escape
nextCipher interface{} // next encryption state
nextMac macFunction // next MAC algorithm
nextMac hash.Hash // next MAC algorithm
trafficSecret []byte // current TLS 1.3 traffic secret
setKeyCallback func(encLevel EncryptionLevel, suite *CipherSuiteTLS13, trafficSecret []byte)
}
type permamentError struct {
type permanentError struct {
err net.Error
}
func (e *permamentError) Error() string { return e.err.Error() }
func (e *permamentError) Unwrap() error { return e.err }
func (e *permamentError) Timeout() bool { return e.err.Timeout() }
func (e *permamentError) Temporary() bool { return false }
func (e *permanentError) Error() string { return e.err.Error() }
func (e *permanentError) Unwrap() error { return e.err }
func (e *permanentError) Timeout() bool { return e.err.Timeout() }
func (e *permanentError) Temporary() bool { return false }
func (hc *halfConn) setErrorLocked(err error) error {
if e, ok := err.(net.Error); ok {
hc.err = &permamentError{err: e}
hc.err = &permanentError{err: e}
} else {
hc.err = err
}
@@ -199,7 +201,7 @@ func (hc *halfConn) setErrorLocked(err error) error {
// prepareCipherSpec sets the encryption and MAC states
// that a subsequent changeCipherSpec will use.
func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) {
func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac hash.Hash) {
hc.version = version
hc.nextCipher = cipher
hc.nextMac = mac
@@ -373,15 +375,14 @@ func (hc *halfConn) decrypt(record []byte) ([]byte, recordType, error) {
}
payload = payload[explicitNonceLen:]
additionalData := hc.additionalData[:]
var additionalData []byte
if hc.version == VersionTLS13 {
additionalData = record[:recordHeaderLen]
} else {
copy(additionalData, hc.seq[:])
copy(additionalData[8:], record[:3])
additionalData = append(hc.scratchBuf[:0], hc.seq[:]...)
additionalData = append(additionalData, record[:3]...)
n := len(payload) - c.Overhead()
additionalData[11] = byte(n >> 8)
additionalData[12] = byte(n)
additionalData = append(additionalData, byte(n>>8), byte(n))
}
var err error
@@ -447,7 +448,7 @@ func (hc *halfConn) decrypt(record []byte) ([]byte, recordType, error) {
record[3] = byte(n >> 8)
record[4] = byte(n)
remoteMAC := payload[n : n+macSize]
localMAC := hc.mac.MAC(hc.seq[0:], record[:recordHeaderLen], payload[:n], payload[n+macSize:])
localMAC := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload[:n], payload[n+macSize:])
// This is equivalent to checking the MACs and paddingGood
// separately, but in constant-time to prevent distinguishing
@@ -490,7 +491,7 @@ func sliceForAppend(in []byte, n int) (head, tail []byte) {
}
// encrypt encrypts payload, adding the appropriate nonce and/or MAC, and
// appends it to record, which contains the record header.
// appends it to record, which must already contain the record header.
func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, error) {
if hc.cipher == nil {
return append(record, payload...), nil
@@ -507,7 +508,7 @@ func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, err
// an 8 bytes nonce but its nonces must be unpredictable (see RFC
// 5246, Appendix F.3), forcing us to use randomness. That's not
// 3DES' biggest problem anyway because the birthday bound on block
// collision is reached first due to its simlarly small block size
// collision is reached first due to its similarly small block size
// (see the Sweet32 attack).
copy(explicitNonce, hc.seq[:])
} else {
@@ -517,14 +518,10 @@ func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, err
}
}
var mac []byte
if hc.mac != nil {
mac = hc.mac.MAC(hc.seq[:], record[:recordHeaderLen], payload, nil)
}
var dst []byte
switch c := hc.cipher.(type) {
case cipher.Stream:
mac := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload, nil)
record, dst = sliceForAppend(record, len(payload)+len(mac))
c.XORKeyStream(dst[:len(payload)], payload)
c.XORKeyStream(dst[len(payload):], mac)
@@ -548,11 +545,12 @@ func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, err
record = c.Seal(record[:recordHeaderLen],
nonce, record[recordHeaderLen:], record[:recordHeaderLen])
} else {
copy(hc.additionalData[:], hc.seq[:])
copy(hc.additionalData[8:], record)
record = c.Seal(record, nonce, payload, hc.additionalData[:])
additionalData := append(hc.scratchBuf[:0], hc.seq[:]...)
additionalData = append(additionalData, record[:recordHeaderLen]...)
record = c.Seal(record, nonce, payload, additionalData)
}
case cbcMode:
mac := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload, nil)
blockSize := c.BlockSize()
plaintextLen := len(payload) + len(mac)
paddingLen := blockSize - plaintextLen%blockSize
@@ -963,9 +961,28 @@ func (c *Conn) flush() (int, error) {
return n, err
}
// outBufPool pools the record-sized scratch buffers used by writeRecordLocked.
var outBufPool = sync.Pool{
New: func() interface{} {
return new([]byte)
},
}
// writeRecordLocked writes a TLS record with the given type and payload to the
// connection and updates the record layer state.
func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
outBufPtr := outBufPool.Get().(*[]byte)
outBuf := *outBufPtr
defer func() {
// You might be tempted to simplify this by just passing &outBuf to Put,
// but that would make the local copy of the outBuf slice header escape
// to the heap, causing an allocation. Instead, we keep around the
// pointer to the slice header returned by Get, which is already on the
// heap, and overwrite and return that.
*outBufPtr = outBuf
outBufPool.Put(outBufPtr)
}()
var n int
for len(data) > 0 {
m := len(data)
@@ -973,8 +990,8 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
m = maxPayload
}
_, c.outBuf = sliceForAppend(c.outBuf[:0], recordHeaderLen)
c.outBuf[0] = byte(typ)
_, outBuf = sliceForAppend(outBuf[:0], recordHeaderLen)
outBuf[0] = byte(typ)
vers := c.vers
if vers == 0 {
// Some TLS servers fail if the record version is
@@ -985,17 +1002,17 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
// See RFC 8446, Section 5.1.
vers = VersionTLS12
}
c.outBuf[1] = byte(vers >> 8)
c.outBuf[2] = byte(vers)
c.outBuf[3] = byte(m >> 8)
c.outBuf[4] = byte(m)
outBuf[1] = byte(vers >> 8)
outBuf[2] = byte(vers)
outBuf[3] = byte(m >> 8)
outBuf[4] = byte(m)
var err error
c.outBuf, err = c.out.encrypt(c.outBuf, data[:m], c.config.rand())
outBuf, err = c.out.encrypt(outBuf, data[:m], c.config.rand())
if err != nil {
return n, err
}
if _, err := c.write(c.outBuf); err != nil {
if _, err := c.write(outBuf); err != nil {
return n, err
}
n += m
@@ -1121,17 +1138,21 @@ func (c *Conn) readHandshake() (interface{}, error) {
}
var (
errClosed = errors.New("tls: use of closed connection")
errShutdown = errors.New("tls: protocol is shutdown")
)
// Write writes data to the connection.
//
// As Write calls Handshake, in order to prevent indefinite blocking a deadline
// must be set for both Read and Write before Write is called when the handshake
// has not yet completed. See SetDeadline, SetReadDeadline, and
// SetWriteDeadline.
func (c *Conn) Write(b []byte) (int, error) {
// interlock with Close below
for {
x := atomic.LoadInt32(&c.activeCall)
if x&1 != 0 {
return 0, errClosed
return 0, net.ErrClosed
}
if atomic.CompareAndSwapInt32(&c.activeCall, x, x+2) {
break
@@ -1221,7 +1242,7 @@ func (c *Conn) handleRenegotiation() error {
defer c.handshakeMutex.Unlock()
atomic.StoreUint32(&c.handshakeStatus, 0)
if c.handshakeErr = c.clientHandshake(); c.handshakeErr == nil {
if c.handshakeErr = c.clientHandshake(context.Background()); c.handshakeErr == nil {
c.handshakes++
}
return c.handshakeErr
@@ -1288,8 +1309,12 @@ func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error {
return nil
}
// Read can be made to time out and return a net.Error with Timeout() == true
// after a fixed time limit; see SetDeadline and SetReadDeadline.
// Read reads data from the connection.
//
// As Read calls Handshake, in order to prevent indefinite blocking a deadline
// must be set for both Read and Write before Read is called when the handshake
// has not yet completed. See SetDeadline, SetReadDeadline, and
// SetWriteDeadline.
func (c *Conn) Read(b []byte) (int, error) {
if err := c.Handshake(); err != nil {
return 0, err
@@ -1340,7 +1365,7 @@ func (c *Conn) Close() error {
for {
x = atomic.LoadInt32(&c.activeCall)
if x&1 != 0 {
return errClosed
return net.ErrClosed
}
if atomic.CompareAndSwapInt32(&c.activeCall, x, x|1) {
break
@@ -1357,9 +1382,10 @@ func (c *Conn) Close() error {
}
var alertErr error
if c.handshakeComplete() {
alertErr = c.closeNotify()
if err := c.closeNotify(); err != nil {
alertErr = fmt.Errorf("tls: failed to send closeNotify alert (but connection was closed anyway): %w", err)
}
}
if err := c.conn.Close(); err != nil {
@@ -1386,8 +1412,12 @@ func (c *Conn) closeNotify() error {
defer c.out.Unlock()
if !c.closeNotifySent {
// Set a Write Deadline to prevent possibly blocking forever.
c.SetWriteDeadline(time.Now().Add(time.Second * 5))
c.closeNotifyErr = c.sendAlertLocked(alertCloseNotify)
c.closeNotifySent = true
// Any subsequent writes will fail.
c.SetWriteDeadline(time.Now())
}
return c.closeNotifyErr
}
@@ -1399,8 +1429,61 @@ func (c *Conn) closeNotify() error {
// first Read or Write will call it automatically.
//
// For control over canceling or setting a timeout on a handshake, use
// the Dialer's DialContext method.
// HandshakeContext or the Dialer's DialContext method instead.
func (c *Conn) Handshake() error {
return c.HandshakeContext(context.Background())
}
// HandshakeContext runs the client or server handshake
// protocol if it has not yet been run.
//
// The provided Context must be non-nil. If the context is canceled before
// the handshake is complete, the handshake is interrupted and an error is returned.
// Once the handshake has completed, cancellation of the context will not affect the
// connection.
//
// Most uses of this package need not call HandshakeContext explicitly: the
// first Read or Write will call it automatically.
func (c *Conn) HandshakeContext(ctx context.Context) error {
// Delegate to unexported method for named return
// without confusing documented signature.
return c.handshakeContext(ctx)
}
func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
handshakeCtx, cancel := context.WithCancel(ctx)
// Note: defer this before starting the "interrupter" goroutine
// so that we can tell the difference between the input being canceled and
// this cancellation. In the former case, we need to close the connection.
defer cancel()
// Start the "interrupter" goroutine, if this context might be canceled.
// (The background context cannot).
//
// The interrupter goroutine waits for the input context to be done and
// closes the connection if this happens before the function returns.
if ctx.Done() != nil {
done := make(chan struct{})
interruptRes := make(chan error, 1)
defer func() {
close(done)
if ctxErr := <-interruptRes; ctxErr != nil {
// Return context error to user.
ret = ctxErr
}
}()
go func() {
select {
case <-handshakeCtx.Done():
// Close the connection, discarding the error
_ = c.conn.Close()
interruptRes <- handshakeCtx.Err()
case <-done:
interruptRes <- nil
}
}()
}
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
@@ -1414,7 +1497,7 @@ func (c *Conn) Handshake() error {
c.in.Lock()
defer c.in.Unlock()
c.handshakeErr = c.handshakeFn()
c.handshakeErr = c.handshakeFn(handshakeCtx)
if c.handshakeErr == nil {
c.handshakes++
} else {
@@ -1453,7 +1536,7 @@ func (c *Conn) connectionStateLocked() ConnectionState {
state.Version = c.vers
state.NegotiatedProtocol = c.clientProtocol
state.DidResume = c.didResume
state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback
state.NegotiatedProtocolIsMutual = true
state.ServerName = c.serverName
state.CipherSuite = c.cipherSuite
state.PeerCertificates = c.peerCertificates

10
vendor/github.com/marten-seemann/qtls-go1-17/go.mod generated vendored Normal file
View File

@@ -0,0 +1,10 @@
module github.com/marten-seemann/qtls-go1-17
go 1.17
require (
github.com/golang/mock v1.6.0
github.com/marten-seemann/qtls-go1-15 v0.1.4 // indirect
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d
golang.org/x/sys v0.0.0-20210510120138-977fb7262007
)

34
vendor/github.com/marten-seemann/qtls-go1-17/go.sum generated vendored Normal file
View File

@@ -0,0 +1,34 @@
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/marten-seemann/qtls-go1-15 v0.1.4 h1:RehYMOyRW8hPVEja1KBVsFVNSm35Jj9Mvs5yNoZZ28A=
github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -6,6 +6,7 @@ package qtls
import (
"bytes"
"context"
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
@@ -14,6 +15,7 @@ import (
"crypto/x509"
"errors"
"fmt"
"hash"
"io"
"net"
"strings"
@@ -27,6 +29,7 @@ const clientSessionStateVersion = 1
type clientHandshakeState struct {
c *Conn
ctx context.Context
serverHello *serverHelloMsg
hello *clientHelloMsg
suite *cipherSuite
@@ -95,25 +98,24 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
hello.secureRenegotiation = c.clientFinished[:]
}
possibleCipherSuites := config.cipherSuites()
hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites))
preferenceOrder := cipherSuitesPreferenceOrder
if !hasAESGCMHardwareSupport {
preferenceOrder = cipherSuitesPreferenceOrderNoAES
}
configCipherSuites := config.cipherSuites()
hello.cipherSuites = make([]uint16, 0, len(configCipherSuites))
// add non-TLS 1.3 cipher suites
if c.config.MinVersion <= VersionTLS12 {
for _, suiteId := range possibleCipherSuites {
for _, suite := range cipherSuites {
if suite.id != suiteId {
continue
}
// Don't advertise TLS 1.2-only cipher suites unless
// we're attempting TLS 1.2.
if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
break
}
hello.cipherSuites = append(hello.cipherSuites, suiteId)
break
}
for _, suiteId := range preferenceOrder {
suite := mutualCipherSuite(configCipherSuites, suiteId)
if suite == nil {
continue
}
// Don't advertise TLS 1.2-only cipher suites unless
// we're attempting TLS 1.2.
if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
continue
}
hello.cipherSuites = append(hello.cipherSuites, suiteId)
}
_, err := io.ReadFull(config.rand(), hello.random)
@@ -137,18 +139,22 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
var params ecdheParameters
if hello.supportedVersions[0] == VersionTLS13 {
var hasTLS13CipherSuite bool
// add TLS 1.3 cipher suites
for _, suiteID := range possibleCipherSuites {
var suites []uint16
for _, suiteID := range configCipherSuites {
for _, suite := range cipherSuitesTLS13 {
if suite.id == suiteID {
hasTLS13CipherSuite = true
hello.cipherSuites = append(hello.cipherSuites, suiteID)
suites = append(suites, suiteID)
}
}
}
if !hasTLS13CipherSuite {
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13()...)
if len(suites) > 0 {
hello.cipherSuites = suites
} else {
if hasAESGCMHardwareSupport {
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...)
} else {
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...)
}
}
curveID := config.curvePreferences()[0]
@@ -169,7 +175,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
return hello, params, nil
}
func (c *Conn) clientHandshake() (err error) {
func (c *Conn) clientHandshake(ctx context.Context) (err error) {
if c.config == nil {
c.config = fromConfig(defaultConfig())
}
@@ -253,6 +259,7 @@ func (c *Conn) clientHandshake() (err error) {
if c.vers == VersionTLS13 {
hs := &clientHandshakeStateTLS13{
c: c,
ctx: ctx,
serverHello: serverHello,
hello: hello,
ecdheParams: ecdheParams,
@@ -267,6 +274,7 @@ func (c *Conn) clientHandshake() (err error) {
hs := &clientHandshakeState{
c: c,
ctx: ctx,
serverHello: serverHello,
hello: hello,
session: session,
@@ -640,7 +648,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
certRequested = true
hs.finishedHash.Write(certReq.marshal())
cri := certificateRequestInfoFromMsg(c.vers, certReq)
cri := certificateRequestInfoFromMsg(hs.ctx, c.vers, certReq)
if chainToSend, err = c.getClientCertificate(cri); err != nil {
c.sendAlert(alertInternalError)
return err
@@ -748,12 +756,12 @@ func (hs *clientHandshakeState) establishKeys() error {
clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
var clientCipher, serverCipher interface{}
var clientHash, serverHash macFunction
var clientHash, serverHash hash.Hash
if hs.suite.cipher != nil {
clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
clientHash = hs.suite.mac(c.vers, clientMAC)
clientHash = hs.suite.mac(clientMAC)
serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */)
serverHash = hs.suite.mac(c.vers, serverMAC)
serverHash = hs.suite.mac(serverMAC)
} else {
clientCipher = hs.suite.aead(clientKey, clientIV)
serverCipher = hs.suite.aead(serverKey, serverIV)
@@ -801,18 +809,12 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
}
}
clientDidALPN := len(hs.hello.alpnProtocols) > 0
serverHasALPN := len(hs.serverHello.alpnProtocol) > 0
if !clientDidALPN && serverHasALPN {
c.sendAlert(alertHandshakeFailure)
return false, errors.New("tls: server advertised unrequested ALPN extension")
if err := checkALPN(hs.hello.alpnProtocols, hs.serverHello.alpnProtocol); err != nil {
c.sendAlert(alertUnsupportedExtension)
return false, err
}
c.clientProtocol = hs.serverHello.alpnProtocol
if serverHasALPN {
c.clientProtocol = hs.serverHello.alpnProtocol
c.clientProtocolFallback = false
}
c.scts = hs.serverHello.scts
if !hs.serverResumedSession() {
@@ -843,6 +845,23 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
return true, nil
}
// checkALPN ensure that the server's choice of ALPN protocol is compatible with
// the protocols that we advertised in the Client Hello.
func checkALPN(clientProtos []string, serverProto string) error {
if serverProto == "" {
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")
}
func (hs *clientHandshakeState) readFinished(out []byte) error {
c := hs.c
@@ -980,10 +999,11 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
// certificateRequestInfoFromMsg generates a CertificateRequestInfo from a TLS
// <= 1.2 CertificateRequest, making an effort to fill in missing information.
func certificateRequestInfoFromMsg(vers uint16, certReq *certificateRequestMsg) *CertificateRequestInfo {
cri := &CertificateRequestInfo{
func certificateRequestInfoFromMsg(ctx context.Context, vers uint16, certReq *certificateRequestMsg) *CertificateRequestInfo {
cri := &certificateRequestInfo{
AcceptableCAs: certReq.certificateAuthorities,
Version: vers,
ctx: ctx,
}
var rsaAvail, ecAvail bool
@@ -1017,7 +1037,7 @@ func certificateRequestInfoFromMsg(vers uint16, certReq *certificateRequestMsg)
ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512,
}
}
return cri
return toCertificateRequestInfo(cri)
}
// Filter the signature schemes based on the certificate types.
@@ -1040,7 +1060,7 @@ func certificateRequestInfoFromMsg(vers uint16, certReq *certificateRequestMsg)
}
}
return cri
return toCertificateRequestInfo(cri)
}
func (c *Conn) getClientCertificate(cri *CertificateRequestInfo) (*Certificate, error) {
@@ -1070,22 +1090,6 @@ func clientSessionCacheKey(serverAddr net.Addr, config *config) string {
return clientSessionCacheKeyPrefix + serverAddr.String()
}
// mutualProtocol finds the mutual Next Protocol Negotiation or ALPN protocol
// given list of possible protocols and a list of the preference order. The
// first list must not be empty. It returns the resulting protocol and flag
// indicating if the fallback case was reached.
func mutualProtocol(protos, preferenceProtos []string) (string, bool) {
for _, s := range preferenceProtos {
for _, c := range protos {
if s == c {
return s, false
}
}
}
return protos[0], true
}
// hostnameInSNI converts name into an appropriate hostname for SNI.
// Literal IP addresses and absolute FQDNs are not permitted as SNI values.
// See RFC 6066, Section 3.

View File

@@ -6,12 +6,12 @@ package qtls
import (
"bytes"
"context"
"crypto"
"crypto/hmac"
"crypto/rsa"
"encoding/binary"
"errors"
"fmt"
"hash"
"sync/atomic"
"time"
@@ -21,6 +21,7 @@ import (
type clientHandshakeStateTLS13 struct {
c *Conn
ctx context.Context
serverHello *serverHelloMsg
hello *clientHelloMsg
ecdheParams ecdheParameters
@@ -413,23 +414,19 @@ func (hs *clientHandshakeStateTLS13) readServerParameters() error {
}
hs.transcript.Write(encryptedExtensions.marshal())
if len(encryptedExtensions.alpnProtocol) != 0 && len(hs.hello.alpnProtocols) == 0 {
if err := checkALPN(hs.hello.alpnProtocols, encryptedExtensions.alpnProtocol); err != nil {
c.sendAlert(alertUnsupportedExtension)
return errors.New("tls: server advertised unrequested ALPN extension")
return err
}
c.clientProtocol = encryptedExtensions.alpnProtocol
if c.extraConfig != nil && c.extraConfig.EnforceNextProtoSelection {
if len(encryptedExtensions.alpnProtocol) == 0 {
// the server didn't select an ALPN
c.sendAlert(alertNoApplicationProtocol)
return errors.New("ALPN negotiation failed. Server didn't offer any protocols")
}
if _, fallback := mutualProtocol([]string{encryptedExtensions.alpnProtocol}, hs.c.config.NextProtos); fallback {
// the protocol selected by the server was not offered
c.sendAlert(alertNoApplicationProtocol)
return fmt.Errorf("ALPN negotiation failed. Server offered: %q", encryptedExtensions.alpnProtocol)
}
}
c.clientProtocol = encryptedExtensions.alpnProtocol
return nil
}
@@ -576,11 +573,12 @@ func (hs *clientHandshakeStateTLS13) sendClientCertificate() error {
return nil
}
cert, err := c.getClientCertificate(&CertificateRequestInfo{
cert, err := c.getClientCertificate(toCertificateRequestInfo(&certificateRequestInfo{
AcceptableCAs: hs.certReq.certificateAuthorities,
SignatureSchemes: hs.certReq.supportedSignatureAlgorithms,
Version: c.vers,
})
ctx: hs.ctx,
}))
if err != nil {
return err
}

View File

@@ -5,6 +5,7 @@
package qtls
import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
@@ -13,6 +14,7 @@ import (
"crypto/x509"
"errors"
"fmt"
"hash"
"io"
"sync/atomic"
"time"
@@ -22,6 +24,7 @@ import (
// It's discarded once the handshake has completed.
type serverHandshakeState struct {
c *Conn
ctx context.Context
clientHello *clientHelloMsg
hello *serverHelloMsg
suite *cipherSuite
@@ -36,10 +39,10 @@ type serverHandshakeState struct {
}
// serverHandshake performs a TLS handshake as a server.
func (c *Conn) serverHandshake() error {
func (c *Conn) serverHandshake(ctx context.Context) error {
c.setAlternativeRecordLayer()
clientHello, err := c.readClientHello()
clientHello, err := c.readClientHello(ctx)
if err != nil {
return err
}
@@ -47,6 +50,7 @@ func (c *Conn) serverHandshake() error {
if c.vers == VersionTLS13 {
hs := serverHandshakeStateTLS13{
c: c,
ctx: ctx,
clientHello: clientHello,
}
return hs.handshake()
@@ -60,6 +64,7 @@ func (c *Conn) serverHandshake() error {
hs := serverHandshakeState{
c: c,
ctx: ctx,
clientHello: clientHello,
}
return hs.handshake()
@@ -131,7 +136,7 @@ func (hs *serverHandshakeState) handshake() error {
}
// readClientHello reads a ClientHello message and selects the protocol version.
func (c *Conn) readClientHello() (*clientHelloMsg, error) {
func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) {
msg, err := c.readHandshake()
if err != nil {
return nil, err
@@ -145,7 +150,7 @@ func (c *Conn) readClientHello() (*clientHelloMsg, error) {
var configForClient *config
originalConfig := c.config
if c.config.GetConfigForClient != nil {
chi := newClientHelloInfo(c, clientHello)
chi := newClientHelloInfo(ctx, c, clientHello)
if cfc, err := c.config.GetConfigForClient(chi); err != nil {
c.sendAlert(alertInternalError)
return nil, err
@@ -242,14 +247,15 @@ func (hs *serverHandshakeState) processClientHello() error {
c.serverName = hs.clientHello.serverName
}
if len(hs.clientHello.alpnProtocols) > 0 {
if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback {
hs.hello.alpnProtocol = selectedProto
c.clientProtocol = selectedProto
}
selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols)
if err != nil {
c.sendAlert(alertNoApplicationProtocol)
return err
}
hs.hello.alpnProtocol = selectedProto
c.clientProtocol = selectedProto
hs.cert, err = c.config.getCertificate(newClientHelloInfo(c, hs.clientHello))
hs.cert, err = c.config.getCertificate(newClientHelloInfo(hs.ctx, c, hs.clientHello))
if err != nil {
if err == errNoCertificates {
c.sendAlert(alertUnrecognizedName)
@@ -299,6 +305,34 @@ func (hs *serverHandshakeState) processClientHello() error {
return nil
}
// negotiateALPN picks a shared ALPN protocol that both sides support in server
// preference order. If ALPN is not configured or the peer doesn't support it,
// it returns "" and no error.
func negotiateALPN(serverProtos, clientProtos []string) (string, error) {
if len(serverProtos) == 0 || len(clientProtos) == 0 {
return "", nil
}
var http11fallback bool
for _, s := range serverProtos {
for _, c := range clientProtos {
if s == c {
return s, nil
}
if s == "h2" && c == "http/1.1" {
http11fallback = true
}
}
}
// As a special case, let http/1.1 clients connect to h2 servers as if they
// didn't support ALPN. We used not to enforce protocol overlap, so over
// time a number of HTTP servers were configured with only "h2", but
// expected to accept connections from "http/1.1" clients. See Issue 46310.
if http11fallback {
return "", nil
}
return "", fmt.Errorf("tls: client requested unsupported application protocols (%s)", clientProtos)
}
// supportsECDHE returns whether ECDHE key exchanges can be used with this
// pre-TLS 1.3 client.
func supportsECDHE(c *config, supportedCurves []CurveID, supportedPoints []uint8) bool {
@@ -324,16 +358,23 @@ func supportsECDHE(c *config, supportedCurves []CurveID, supportedPoints []uint8
func (hs *serverHandshakeState) pickCipherSuite() error {
c := hs.c
var preferenceList, supportedList []uint16
if c.config.PreferServerCipherSuites {
preferenceList = c.config.cipherSuites()
supportedList = hs.clientHello.cipherSuites
} else {
preferenceList = hs.clientHello.cipherSuites
supportedList = c.config.cipherSuites()
preferenceOrder := cipherSuitesPreferenceOrder
if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) {
preferenceOrder = cipherSuitesPreferenceOrderNoAES
}
hs.suite = selectCipherSuite(preferenceList, supportedList, hs.cipherSuiteOk)
configCipherSuites := c.config.cipherSuites()
preferenceList := make([]uint16, 0, len(configCipherSuites))
for _, suiteID := range preferenceOrder {
for _, id := range configCipherSuites {
if id == suiteID {
preferenceList = append(preferenceList, id)
break
}
}
}
hs.suite = selectCipherSuite(preferenceList, hs.clientHello.cipherSuites, hs.cipherSuiteOk)
if hs.suite == nil {
c.sendAlert(alertHandshakeFailure)
return errors.New("tls: no cipher suite supported by both client and server")
@@ -671,13 +712,13 @@ func (hs *serverHandshakeState) establishKeys() error {
keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
var clientCipher, serverCipher interface{}
var clientHash, serverHash macFunction
var clientHash, serverHash hash.Hash
if hs.suite.aead == nil {
clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */)
clientHash = hs.suite.mac(c.vers, clientMAC)
clientHash = hs.suite.mac(clientMAC)
serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */)
serverHash = hs.suite.mac(c.vers, serverMAC)
serverHash = hs.suite.mac(serverMAC)
} else {
clientCipher = hs.suite.aead(clientKey, clientIV)
serverCipher = hs.suite.aead(serverKey, serverIV)
@@ -843,7 +884,7 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
return nil
}
func newClientHelloInfo(c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
func newClientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
supportedVersions := clientHello.supportedVersions
if len(clientHello.supportedVersions) == 0 {
supportedVersions = supportedVersionsFromMax(clientHello.vers)
@@ -859,5 +900,6 @@ func newClientHelloInfo(c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
SupportedVersions: supportedVersions,
Conn: c.conn,
config: toConfig(c.config),
ctx: ctx,
})
}

View File

@@ -6,11 +6,11 @@ package qtls
import (
"bytes"
"context"
"crypto"
"crypto/hmac"
"crypto/rsa"
"errors"
"fmt"
"hash"
"io"
"sync/atomic"
@@ -24,8 +24,10 @@ const maxClientPSKIdentities = 5
type serverHandshakeStateTLS13 struct {
c *Conn
ctx context.Context
clientHello *clientHelloMsg
hello *serverHelloMsg
alpnNegotiationErr error
encryptedExtensions *encryptedExtensionsMsg
sentDummyCCS bool
usingPSK bool
@@ -139,28 +141,27 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error {
hs.hello.sessionId = hs.clientHello.sessionId
hs.hello.compressionMethod = compressionNone
var preferenceList, supportedList, ourList []uint16
for _, suiteID := range c.config.CipherSuites {
for _, suite := range cipherSuitesTLS13 {
if suite.id == suiteID {
ourList = append(ourList, suiteID)
if hs.suite == nil {
var preferenceList []uint16
for _, suiteID := range c.config.CipherSuites {
for _, suite := range cipherSuitesTLS13 {
if suite.id == suiteID {
preferenceList = append(preferenceList, suiteID)
break
}
}
}
}
if len(ourList) == 0 {
ourList = defaultCipherSuitesTLS13()
}
if c.config.PreferServerCipherSuites {
preferenceList = ourList
supportedList = hs.clientHello.cipherSuites
} else {
preferenceList = hs.clientHello.cipherSuites
supportedList = ourList
}
for _, suiteID := range preferenceList {
hs.suite = mutualCipherSuiteTLS13(supportedList, suiteID)
if hs.suite != nil {
break
if len(preferenceList) == 0 {
preferenceList = defaultCipherSuitesTLS13
if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) {
preferenceList = defaultCipherSuitesTLS13NoAES
}
}
for _, suiteID := range preferenceList {
hs.suite = mutualCipherSuiteTLS13(hs.clientHello.cipherSuites, suiteID)
if hs.suite != nil {
break
}
}
}
if hs.suite == nil {
@@ -227,12 +228,12 @@ GroupSelection:
c.extraConfig.ReceivedExtensions(typeClientHello, hs.clientHello.additionalExtensions)
}
if len(hs.clientHello.alpnProtocols) > 0 {
if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback {
hs.encryptedExtensions.alpnProtocol = selectedProto
c.clientProtocol = selectedProto
}
selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols)
if err != nil {
hs.alpnNegotiationErr = err
}
hs.encryptedExtensions.alpnProtocol = selectedProto
c.clientProtocol = selectedProto
return nil
}
@@ -283,7 +284,7 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
return errors.New("tls: client sent unexpected early data")
}
if sessionState.alpn == c.clientProtocol &&
if hs.alpnNegotiationErr == nil && sessionState.alpn == c.clientProtocol &&
c.extraConfig != nil && c.extraConfig.MaxEarlyData > 0 &&
c.extraConfig.Accept0RTT != nil && c.extraConfig.Accept0RTT(sessionState.appData) {
hs.encryptedExtensions.earlyData = true
@@ -400,7 +401,7 @@ func (hs *serverHandshakeStateTLS13) pickCertificate() error {
return c.sendAlert(alertMissingExtension)
}
certificate, err := c.config.getCertificate(newClientHelloInfo(c, hs.clientHello))
certificate, err := c.config.getCertificate(newClientHelloInfo(hs.ctx, c, hs.clientHello))
if err != nil {
if err == errNoCertificates {
c.sendAlert(alertUnrecognizedName)
@@ -559,11 +560,6 @@ func illegalClientHelloChange(ch, ch1 *clientHelloMsg) bool {
func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
c := hs.c
if c.extraConfig != nil && c.extraConfig.EnforceNextProtoSelection && len(c.clientProtocol) == 0 {
c.sendAlert(alertNoApplicationProtocol)
return fmt.Errorf("ALPN negotiation failed. Client offered: %q", hs.clientHello.alpnProtocols)
}
hs.transcript.Write(hs.clientHello.marshal())
hs.transcript.Write(hs.hello.marshal())
if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
@@ -601,6 +597,10 @@ func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
return err
}
if hs.alpnNegotiationErr != nil {
c.sendAlert(alertNoApplicationProtocol)
return hs.alpnNegotiationErr
}
if hs.c.extraConfig != nil && hs.c.extraConfig.GetExtensions != nil {
hs.encryptedExtensions.additionalExtensions = hs.c.extraConfig.GetExtensions(typeEncryptedExtensions)
}

View File

@@ -15,6 +15,25 @@ import (
"io"
)
// a keyAgreement implements the client and server side of a TLS key agreement
// protocol by generating and processing key exchange messages.
type keyAgreement interface {
// On the server side, the first two methods are called in order.
// In the case that the key agreement protocol doesn't use a
// ServerKeyExchange message, generateServerKeyExchange can return nil,
// nil.
generateServerKeyExchange(*config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
processClientKeyExchange(*config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error)
// On the client side, the next two methods are called in order.
// This method may not be called if the server doesn't send a
// ServerKeyExchange message.
processServerKeyExchange(*config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error
generateClientKeyExchange(*config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error)
}
var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message")
@@ -67,7 +86,11 @@ func (ka rsaKeyAgreement) generateClientKeyExchange(config *config, clientHello
return nil, nil, err
}
encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), preMasterSecret)
rsaKey, ok := cert.PublicKey.(*rsa.PublicKey)
if !ok {
return nil, nil, errors.New("tls: server certificate contains incorrect key type for selected ciphersuite")
}
encrypted, err := rsa.EncryptPKCS1v15(config.rand(), rsaKey, preMasterSecret)
if err != nil {
return nil, nil, err
}

View File

@@ -5,7 +5,6 @@
package qtls
import (
"crypto"
"crypto/elliptic"
"crypto/hmac"
"errors"
@@ -32,20 +31,8 @@ const (
trafficUpdateLabel = "traffic upd"
)
// HkdfExtract generates a pseudorandom key for use with Expand from an input secret and an optional independent salt.
func HkdfExtract(hash crypto.Hash, newSecret, currentSecret []byte) []byte {
if newSecret == nil {
newSecret = make([]byte, hash.Size())
}
return hkdf.Extract(hash.New, newSecret, currentSecret)
}
// HkdfExpandLabel HKDF expands a label
func HkdfExpandLabel(hash crypto.Hash, secret, hashValue []byte, label string, L int) []byte {
return hkdfExpandLabel(hash, secret, hashValue, label, L)
}
func hkdfExpandLabel(hash crypto.Hash, secret, context []byte, label string, length int) []byte {
// expandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1.
func (c *cipherSuiteTLS13) expandLabel(secret []byte, label string, context []byte, length int) []byte {
var hkdfLabel cryptobyte.Builder
hkdfLabel.AddUint16(uint16(length))
hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
@@ -56,18 +43,13 @@ func hkdfExpandLabel(hash crypto.Hash, secret, context []byte, label string, len
b.AddBytes(context)
})
out := make([]byte, length)
n, err := hkdf.Expand(hash.New, secret, hkdfLabel.BytesOrPanic()).Read(out)
n, err := hkdf.Expand(c.hash.New, secret, hkdfLabel.BytesOrPanic()).Read(out)
if err != nil || n != length {
panic("tls: HKDF-Expand-Label invocation failed unexpectedly")
}
return out
}
// expandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1.
func (c *cipherSuiteTLS13) expandLabel(secret []byte, label string, context []byte, length int) []byte {
return hkdfExpandLabel(c.hash, secret, context, label, length)
}
// deriveSecret implements Derive-Secret from RFC 8446, Section 7.1.
func (c *cipherSuiteTLS13) deriveSecret(secret []byte, label string, transcript hash.Hash) []byte {
if transcript == nil {
@@ -78,7 +60,10 @@ func (c *cipherSuiteTLS13) deriveSecret(secret []byte, label string, transcript
// extract implements HKDF-Extract with the cipher suite hash.
func (c *cipherSuiteTLS13) extract(newSecret, currentSecret []byte) []byte {
return HkdfExtract(c.hash, newSecret, currentSecret)
if newSecret == nil {
newSecret = make([]byte, c.hash.Size())
}
return hkdf.Extract(c.hash.New, newSecret, currentSecret)
}
// nextTrafficSecret generates the next traffic secret, given the current one,

View File

@@ -22,10 +22,9 @@ import (
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"net"
"os"
"strings"
"time"
)
// Server returns a new TLS server side connection
@@ -115,33 +114,24 @@ func (timeoutError) Temporary() bool { return true }
//
// DialWithDialer interprets a nil configuration as equivalent to the zero
// configuration; see the documentation of Config for the defaults.
//
// DialWithDialer uses context.Background internally; to specify the context,
// use Dialer.DialContext with NetDialer set to the desired dialer.
func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config, extraConfig *ExtraConfig) (*Conn, error) {
return dial(context.Background(), dialer, network, addr, config, extraConfig)
}
func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, config *Config, extraConfig *ExtraConfig) (*Conn, error) {
// We want the Timeout and Deadline values from dialer to cover the
// whole process: TCP connection and TLS handshake. This means that we
// also need to start our own timers now.
timeout := netDialer.Timeout
if netDialer.Timeout != 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, netDialer.Timeout)
defer cancel()
}
if !netDialer.Deadline.IsZero() {
deadlineTimeout := time.Until(netDialer.Deadline)
if timeout == 0 || deadlineTimeout < timeout {
timeout = deadlineTimeout
}
}
// hsErrCh is non-nil if we might not wait for Handshake to complete.
var hsErrCh chan error
if timeout != 0 || ctx.Done() != nil {
hsErrCh = make(chan error, 2)
}
if timeout != 0 {
timer := time.AfterFunc(timeout, func() {
hsErrCh <- timeoutError{}
})
defer timer.Stop()
var cancel context.CancelFunc
ctx, cancel = context.WithDeadline(ctx, netDialer.Deadline)
defer cancel()
}
rawConn, err := netDialer.DialContext(ctx, network, addr)
@@ -168,34 +158,10 @@ func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, conf
}
conn := Client(rawConn, config, extraConfig)
if hsErrCh == nil {
err = conn.Handshake()
} else {
go func() {
hsErrCh <- conn.Handshake()
}()
select {
case <-ctx.Done():
err = ctx.Err()
case err = <-hsErrCh:
if err != nil {
// If the error was due to the context
// closing, prefer the context's error, rather
// than some random network teardown error.
if e := ctx.Err(); e != nil {
err = e
}
}
}
}
if err != nil {
if err := conn.HandshakeContext(ctx); err != nil {
rawConn.Close()
return nil, err
}
return conn, nil
}
@@ -230,6 +196,9 @@ type Dialer struct {
// handshake, returning the resulting TLS connection.
//
// The returned Conn, if any, will always be of type *Conn.
//
// Dial uses context.Background internally; to specify the context,
// use DialContext.
func (d *Dialer) Dial(network, addr string) (net.Conn, error) {
return d.DialContext(context.Background(), network, addr)
}
@@ -265,11 +234,11 @@ func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Con
// form a certificate chain. On successful return, Certificate.Leaf will
// be nil because the parsed form of the certificate is not retained.
func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
certPEMBlock, err := ioutil.ReadFile(certFile)
certPEMBlock, err := os.ReadFile(certFile)
if err != nil {
return Certificate{}, err
}
keyPEMBlock, err := ioutil.ReadFile(keyFile)
keyPEMBlock, err := os.ReadFile(keyFile)
if err != nil {
return Certificate{}, err
}

View File

@@ -13,6 +13,9 @@ func init() {
if !structsEqual(&tls.ClientSessionState{}, &clientSessionState{}) {
panic("qtls.ClientSessionState doesn't match")
}
if !structsEqual(&tls.CertificateRequestInfo{}, &certificateRequestInfo{}) {
panic("qtls.CertificateRequestInfo doesn't match")
}
if !structsEqual(&tls.Config{}, &config{}) {
panic("qtls.Config doesn't match")
}
@@ -33,6 +36,10 @@ func fromClientSessionState(s *ClientSessionState) *clientSessionState {
return (*clientSessionState)(unsafe.Pointer(s))
}
func toCertificateRequestInfo(i *certificateRequestInfo) *CertificateRequestInfo {
return (*CertificateRequestInfo)(unsafe.Pointer(i))
}
func toConfig(c *config) *Config {
return (*Config)(unsafe.Pointer(c))
}